long xchmod(char *p, int wrt, char mod) { OFD *fd; DND *dn; /* M01.01.03 */ const char *s; long pos; if ((long)(dn = findit(p,&s,0)) < 0) /* M01.01.1212.01 */ return( (long)dn ); if (!(long)dn) /* M01.01.1214.01 */ return( EPTHNF ); pos = 0; if( ! scan( dn , s , FA_NORM , &pos ) ) /* M01.01.03 */ return( EFILNF ) ; pos -= 21; /* point at attribute in file */ fd = dn->d_ofd; ixlseek(fd,pos); if (!wrt) ixread(fd,1L,&mod); else { ixwrite(fd,1L,&mod); ixclose(fd,CL_DIR); /* for flush */ } return(mod); }
/* name: path name of file * attr: atttributes */ long ixcreat(char *name, char attr) { DND *dn; OFD *fd; FCB *f; const char *s; char n[2], a[11]; /* M01.01.03 */ int i, f2; /* M01.01.03 */ long pos, rc; n[0] = (char)ERASE_MARKER; n[1] = 0; /* first find path */ if ((long)(dn = findit(name,&s,0)) < 0) /* M01.01.1212.01 */ return (long)dn; if (!dn) /* M01.01.1214.01 */ return EPTHNF; if (!*s || (*s == '.')) /* no file name || '.' || '..' */ return EPTHNF; /* M01.01.0721.01 */ if (contains_illegal_characters(s)) return EACCDN; /* * if the volume label attribute is set, no others are allowed */ if ((attr&FA_VOL) && (attr != FA_VOL)) return EACCDN; /* * volume labels may only be created in the root */ if ((attr == FA_VOL) && dn->d_parent) return EACCDN; if (!(fd = dn->d_ofd)) fd = makofd(dn); /* makofd() also updates dn->d_ofd */ /* * if a matching file already exists, we delete it first. note * that the definition of matching, and the action taken, differs * depending on whether the file is a volume label or not: * . for a volume label, *any* existing volume label matches * and will be deleted (reference: Rainbow TOS Release Notes) * . for other files, the name must match, and the existing * file will be deleted unless (a) it's read-only or a folder * or (b) the file being created is a folder. */ pos = 0; if (attr == FA_VOL) f = scan(dn,"*.*",FA_VOL,&pos); else f = scan(dn,s,FA_NORM|FA_SUBDIR,&pos); if (f) /* found matching file / label */ { if (attr != FA_VOL) /* for normal files, need to check more stuff */ { /* M01.01.0730.01 */ if ((f->f_attrib & (FA_SUBDIR | FA_RO)) || (attr == FA_SUBDIR)) return EACCDN; /* subdir or read only */ } pos -= 32; ixdel(dn,f,pos); } else pos = 0; /* now scan for empty space */ /* M01.01.SCC.FS.02 */ while( !( f = scan(dn,n,0xff,&pos) ) ) { /* not in current dir, need to grow */ if (!fd->o_dnode) /* but can't grow root */ return EACCDN; if ( nextcl(fd,1) ) return EACCDN; f = dirinit(dn); pos = 0; } builds(s,a); pos -= 32; f->f_attrib = attr; for (i = 0; i < 10; i++) f->f_fill[i] = 0; f->f_td.time = current_time; swpw(f->f_td.time); f->f_td.date = current_date; swpw(f->f_td.date); f->f_clust = 0; f->f_fileln = 0; ixlseek(fd,pos); ixwrite(fd,11L,a); /* write name, set dirty flag */ ixclose(fd,CL_DIR); /* partial close to flush */ ixlseek(fd,pos); s = (char*) ixread(fd,32L,NULL); f2 = rc = opnfil((FCB*)s,dn,(f->f_attrib&FA_RO)?RO_MODE:RW_MODE); if (rc < 0) return rc; getofd(f2)->o_flag |= O_DIRTY; return f2; }
/* ** ixclose - ** ** Error returns EINTRN ** ** Last modified SCC 10 Apr 85 ** ** NOTE: I'm not sure that returning immediately upon an error from ** ixlseek() is the right thing to do. Some data structures may ** not be updated correctly. Watch out for this! ** Also, I'm not sure that the EINTRN return is ok. */ long ixclose(OFD *fd, int part) { /* M01.01.03 */ OFD *p, **q; int i; /* M01.01.03 */ BCB *b; /* * if the file or folder has been modified, we need to make sure * that the date/time, starting cluster, and file length in the * directory entry are updated. In addition, for files, we must * set the archive flag. * * The following code avoids multiple ixlseek()/ixlread()/ixlwrite() * sequences by just getting a pointer to a buffer containing the * FCB, and updating it directly. We must do an ixwrite() at the * end so that the buffer is marked as dirty and is subsequently * written. */ if (fd->o_flag & O_DIRTY) { FCB *fcb; UBYTE attr; ixlseek(fd->o_dirfil,fd->o_dirbyt); /* start of dir entry */ fcb = (FCB *)ixread(fd->o_dirfil,32L,NULL); attr = fcb->f_attrib; /* get attributes */ memcpy(&fcb->f_td,&fd->o_td,10); /* copy date/time, start, length */ swpw(fcb->f_clust); /* & fixup byte order */ swpl(fcb->f_fileln); if (part & CL_DIR) fcb->f_fileln = 0L; /* dir lengths on disk are zero */ else attr |= FA_ARCHIVE; /* set the archive flag for files */ ixlseek(fd->o_dirfil,fd->o_dirbyt+11); /* seek to attrib byte */ ixwrite(fd->o_dirfil,1,&attr); /* & rewrite it */ } if ((!part) || (part & CL_FULL)) { q = &fd->o_dnode->d_files; for (p = *q; p ; p = *(q = &p->o_link)) if (p == fd) break; /* someone else has this file open **** TBA */ if (p) *q = p->o_link; else return EINTRN; /* some kind of internal error */ } /* only flush to appropriate drive ***** TBA ******/ for (i = 0; i < 2; i++) for (b = bufl[i]; b; b = b->b_link) flush(b); return E_OK; }
/*ARGSUSED*/ long xrename(int n, char *p1, char *p2) { register OFD *fd2; OFD *f1,*fd; FCB *f; DND *dn1,*dn2; const char *s1,*s2; char buf[11]; int hnew,att; long rc, h1; if (!ixsfirst(p2,0,(DTAINFO *)0L)) return(EACCDN); if ((long)(dn1 = findit(p1,&s1,0)) < 0) /* M01.01.1212.01 */ return( (long)dn1 ); if (!dn1) /* M01.01.1214.01 */ return( EPTHNF ); if ((long)(dn2 = findit(p2,&s2,0)) < 0) /* M01.01.1212.01 */ return( (long)dn2 ); if (!dn2) /* M01.01.1214.01 */ return( EPTHNF ); if (contains_illegal_characters(s2)) return( EACCDN ) ; if ((h1 = xopen(p1, 2)) < 0L) return (h1); f1 = getofd ((int)h1); fd = f1->o_dirfil; buf[0] = 0xe5; ixlseek(fd,f1->o_dirbyt); if (dn1 != dn2) { /* get old attribute */ f = (FCB *) ixread(fd,32L,NULLPTR); att = f->f_attrib; /* erase (0xe5) old file */ ixlseek(fd,f1->o_dirbyt); ixwrite(fd,1L,buf); /* copy time/date/clust, etc. */ ixlseek(fd,f1->o_dirbyt + 22); ixread(fd,10L,buf); hnew = xcreat(p2,att); fd2 = getofd(hnew); ixlseek(fd2->o_dirfil,fd2->o_dirbyt + 22); ixwrite(fd2->o_dirfil,10L,buf); fd2->o_flag &= ~O_DIRTY; xclose(hnew); ixclose(fd2->o_dirfil,CL_DIR); } else { builds(s2,buf); ixwrite(fd,11L,buf); } if ((rc = xclose((int)h1)) < 0L) return(rc); return(ixclose(fd,CL_DIR)); }
long xrmdir(char *p) { register DND *d; DND *d1,**q; FCB *f; OFD *fd,*f2; /* M01.01.03 */ long pos; const char *s; register int i; if ((long)(d = findit(p,&s,1)) < 0) /* M01.01.1212.01 */ return( (long)d ); if (!d) /* M01.01.1214.01 */ return( EPTHNF ); /* M01.01.SCC.FS.09 */ if( ! d->d_parent ) /* Can't delete root */ return( EACCDN ) ; for( i = 1 ; i <= NCURDIR ; i++ ) /* Can't delete in use */ if( diruse[i] && dirtbl[i] == d ) return( EACCDN ) ; /* end M01.01.SCC.FS.09 */ if (!(fd = d->d_ofd)) if (!(fd = makofd(d))) return (ENSMEM); ixlseek(fd,0x40L); do { if (!(f = (FCB *) ixread(fd,32L,NULLPTR))) break; } while (f->f_name[0] == (char)0x0e5 || f->f_attrib == FA_LFN); if( f != (FCB*)NULLPTR && f->f_name[0] != 0 ) return(EACCDN); for(d1 = *(q = &d->d_parent->d_left); d1 != d; d1 = *(q = &d1->d_right)) ; /* follow sib-links */ if( d1 != d ) return(EINTRN); /* internal error */ if (d->d_files) return(EINTRN); /* open files ? - internal error */ if (d->d_left) return(EINTRN); /* subdir - internal error */ /* take him out ! */ *q = d->d_right; if (d->d_ofd) { xmfreblk((char *)d->d_ofd); } d1 = d->d_parent; xmfreblk((char *)d); ixlseek((f2 = fd->o_dirfil),(pos = fd->o_dirbyt)); f = (FCB *) ixread(f2,32L,NULLPTR); return(ixdel(d1,f,pos)); }
long xmkdir(char *s) { register OFD *f; register FCB *f2; OFD *fd,*f0; FCB *b; DND *dn; int h,cl,plen; long rc; if ((h = rc = ixcreat(s,FA_SUBDIR)) < 0) return(rc); f = getofd(h); /* build a DND in the tree */ fd = f->o_dirfil; ixlseek(fd,f->o_dirbyt); b = (FCB *) ixread(fd,32L,NULLPTR); /* is the total path length too long? */ /* M01.01.1107.01 */ plen = namlen( b->f_name ); for ( dn = f->o_dnode; dn; dn = dn->d_parent ) plen += namlen( dn->d_name ); if ( plen >= (LEN_ZPATH-3) ) { ixdel( f->o_dnode, b, f->o_dirbyt ); return ( EACCDN ); } if( (dn = makdnd(f->o_dnode,b)) == NULLPTR ) { ixdel( f->o_dnode, b, f->o_dirbyt ); /* M01.01.1103.01 */ return (ENSMEM); } if( (dn->d_ofd = f0 = makofd(dn)) == (OFD*)NULLPTR ) { ixdel( f->o_dnode, b, f->o_dirbyt ); /* M01.01.1103.01 */ f->o_dnode->d_left = NULLPTR; /* M01.01.1103.01 */ xmfreblk((char *)dn); return (ENSMEM); } /* initialize dir cluster */ if (nextcl(f0,1)) { ixdel( f->o_dnode, b, f->o_dirbyt ); /* M01.01.1103.01 */ f->o_dnode->d_left = NULLPTR; /* M01.01.1103.01 */ freednd(dn); /* M01.01.1031.02 */ return(EACCDN); } f2 = dirinit(dn); /* pointer to dirty dir block */ /* write identifier */ memcpy(f2, dots, 22); f2->f_attrib = FA_SUBDIR; f2->f_time = time; swpw( f2->f_time ) ; /* M01.01.SCC.FS.04 */ f2->f_date = date; swpw( f2->f_date ) ; /* M01.01.SCC.FS.04 */ cl = f0->o_strtcl; swpw(cl); f2->f_clust = cl; f2->f_fileln = 0; f2++; /* write parent entry .. */ memcpy(f2, dots, 22); f2->f_name[1] = '.'; /* This is .. */ f2->f_attrib = FA_SUBDIR; f2->f_time = time; swpw( f2->f_time ) ; /* M01.01.SCC.FS.06 */ f2->f_date = date; swpw( f2->f_date ) ; /* M01.01.SCC.FS.06 */ cl = f->o_dirfil->o_strtcl; if (!fd->o_dnode) /* if creating a folder in the root, the */ cl = 0; /* cluster# of the .. entry must be 0 */ swpw(cl); f2->f_clust = cl; f2->f_fileln = 0; memcpy(f, f0, sizeof(OFD)); f->o_flag |= O_DIRTY; ixclose(f,CL_DIR | CL_FULL); /* force flush and write */ xmfreblk((char*)f); sft[h-NUMSTD].f_own = 0; sft[h-NUMSTD].f_ofd = 0; return(E_OK); }
FCB *scan(register DND *dnd, const char *n, WORD att, LONG *posp) { char name[12]; register FCB *fcb; OFD *fd; DND *dnd1; BOOL m; /* T: found a matching FCB */ #if DBGFSDIR kprintf("scan(%p, '%s', 0x%x, %p)\n", dnd, n, att, posp); #endif m = 0; /* have_match = false */ builds(n,name); /* format name into dir format */ name[11] = att; dnd1 = 0; /* dummy to avoid warning */ /* ** if there is no open file descr for this directory, make one */ if (!(fd = dnd->d_ofd)) { if (!(dnd->d_ofd = (fd = makofd(dnd)))) { return ( (FCB *) 0 ); } } /* ** seek to desired starting position. If posp == -1, then start at ** the beginning. */ ixlseek( fd , (*posp == -1) ? 0L : *posp ) ; /* ** scan thru the directory file, looking for a match */ while ((fcb = (FCB *) ixread(fd,32L,NULLPTR)) && (fcb->f_name[0])) { /* ** Add New DND. ** ( iff after scan ptr && complete flag not set && not a . ** or .. && subdirectory && not deleted ) M01.01.0512.01 */ if( (fcb->f_attrib & FA_SUBDIR) && #if ! M0101052901 (!(fd->o_flag & O_COMPLETE)) && #endif (fcb->f_name[0] != '.') && (fcb->f_name[0] != (char)0xe5) ) { /* see if we already have it */ dnd1 = getdnd( &fcb->f_name[0] , dnd ) ; if (!dnd1) if (!(dnd1 = makdnd(dnd,fcb))) return( NULLPTR ) ; } if ( (m = match( name , fcb->f_name )) ) break; } #if DBGFSDIR kprintf("\n scan(pos=%ld DND=%08lx DNDfoundFile=%08lx name=%s name1=%s, %d)", (long)fd->o_bytnum, (long)dnd, (long)dnd1, fcb->f_name, name, m); #endif /* restore directory scanning pointer */ if( *posp != -1L ) *posp = fd->o_bytnum ; /* ** if there was no match, but we were looking for a deleted entry, ** then return a pointer to a deleted fcb. Otherwise, if there was ** no match, return a null pointer */ if (!m) { /* assumes that (*n != 0xe5) (if posp == -1) */ if( fcb && (*n == (char)0xe5) ) return(fcb) ; #if ! M0101052901 fd->o_flag |= O_COMPLETE; #endif return( (FCB *) 0 ); } if (*posp == -1) { /* seek to position of found entry */ ixlseek(fd,fd->o_bytnum - 32); return(((FCB *) dnd1)); } return(fcb); }