long xgsdtof(int *buf, int h, int wrt) { register OFD *f ; register int *b ; b = buf ; f = getofd(h) ; if ( !wrt ) { b[0] = f->o_time ; b[1] = f->o_date ; } swpw(b[0]); swpw(b[1]); if ( wrt ) { f->o_time = b[0] ; f->o_date = b[1] ; f->o_flag |= O_DIRTY; /* M01.01.0918.01 */ swpw(b[0]); /* M01.01.0918.01 */ swpw(b[1]); /* M01.01.0918.01 */ } return E_OK; }
static void makbuf(FCB *f, DTAINFO *dt) { /* M01.01.03 */ dt->dt_fattr = f->f_attrib ; dt->dt_time = f->f_time ; swpw(dt->dt_time) ; dt->dt_date = f->f_date ; swpw(dt->dt_date) ; dt->dt_fileln = f->f_fileln ; swpl( dt->dt_fileln ) ; if( f->f_attrib & FA_VOL ) { memcpy(&dt->dt_fname[0], &f->f_name[0], 11); dt->dt_fname[11] = '\0' ; } else { packit(&f->f_name[0],&dt->dt_fname[0]); } }
/* ** ixdel - internal delete file. ** ** Traverse the list of files open for this directory node. ** If a file is found that has the same position in the directory as the one ** we are to delete, then scan the system file table to see if this process is ** then owner. If so, then close it, otherwise abort. ** ** NOTE: both 'for' loops scan for the entire length of their ** respective data structures, and do not drop out of the loop on ** the first occurrence of a match. ** Used by ** ixcreat() ** xunlink() ** xrmdir() ** */ long ixdel(DND *dn, FCB *f, long pos) { OFD *fd; DMD *dm; int n2; int n; char c; for (fd = dn->d_files; fd; fd = fd->o_link) if (fd->o_dirbyt == pos) for (n = 0; n < OPNFILES; n++) if (sft[n].f_ofd == fd) { if (sft[n].f_own == run) ixclose(fd,0); else return EACCDN; } /* * Traverse this file's chain of allocated clusters, freeing them. */ dm = dn->d_drv; n = f->f_clust; swpw(n); while (n && !endofchain(n)) { n2 = getrealcl(n,dm); clfix(n,FREECLUSTER,dm); n = n2; } /* * Mark the directory entry as erased. */ fd = dn->d_ofd; ixlseek(fd,pos); c = (char)ERASE_MARKER; ixwrite(fd,1L,&c); ixclose(fd,CL_DIR); /* * NOTE that the preceding routines that do physical disk operations * will 'longjmp' on failure at the BIOS level, thereby allowing us to * simply return with E_OK. */ return E_OK; }
/* ** makopn - make an open file for sft handle h ** */ static long makopn(FCB *f, DND *dn, int h, int mod) { OFD *p; OFD *p2; DMD *dm; /* M01.01.03 */ dm = dn->d_drv; p = MGET(OFD); /* MGET(OFD) only returns if it succeeds */ p->o_mod = mod; /* set mode */ p->o_dmd = dm; /* link OFD to media */ sft[h-NUMSTD].f_ofd = p; p->o_usecnt = 0; /* init usage */ p->o_curcl = 0; /* init file pointer info */ p->o_curbyt = 0; /* " */ p->o_dnode = dn; /* link to directory */ p->o_dirfil = dn->d_ofd; /* link to dir's ofd */ p->o_dirbyt = dn->d_ofd->o_bytnum - 32; /* offset of fcb in dir*/ for (p2 = dn->d_files; p2; p2 = p2->o_link) if (p2->o_dirbyt == p->o_dirbyt) break; /* same dir, same dcnt */ p->o_link = dn->d_files; dn->d_files = p; if (p2) { /* steal time/date,startcl,fileln (a bit clumsily) */ memcpy(&p->o_td,&p2->o_td,sizeof(DOSTIME)+sizeof(CLNO)+sizeof(long)); /* not used yet... TBA *********/ p2->o_thread = p; } else { p->o_strtcl = f->f_clust; /* 1st cluster of file */ swpw(p->o_strtcl); p->o_fileln = f->f_fileln; /* init length of file */ swpl(p->o_fileln); p->o_td.date = f->f_td.date; /* note: OFD time/date are */ p->o_td.time = f->f_td.time; /* actually little-endian! */ } return h; }
/* 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; }
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); }
static DND *makdnd(DND *p, FCB *b) { register DND *p1; register DND **prev; OFD *fd; register int i; int in_use; fd = p->d_ofd; /* ** scavenge a DND at this level if we can find one that has not ** d_left */ for (prev = &p->d_left; (p1 = *prev) ; prev = &p1->d_right) { if (!p1->d_left) { /* check dirtbl[] to see if anyone is using this guy */ in_use = 0; for (i = 1; i < NCURDIR; i++) if (diruse[i] && dirtbl[i] == p1) { in_use = 1; break; } #if DBGFSDIR kprintf("\n makdnd check dirtbl (%d)", in_use); #endif if( !in_use && p1->d_files == NULLPTR ) { /* M01.01.KTB.SCC.02 */ /* clean out this DND for reuse */ p1->d_flag = 0; p1->d_scan = 0L; p1->d_files = (OFD *) 0; if (p1->d_ofd) { xmfreblk((char *)p1->d_ofd); } break; } } } /* we didn't find one that qualifies, so allocate a new one */ if (!p1) { #if DBGFSDIR kprintf("\n makdnd new"); #endif if (!(p1 = MGET(DND))) return ( (DND *) 0 ); /* ran out of system memory */ /* do this init only on a newly allocated DND */ p1->d_right = p->d_left; p->d_left = p1; p1->d_parent = p; } /* complete the initialization */ p1->d_ofd = (OFD *) 0; p1->d_strtcl = b->f_clust; swpw(p1->d_strtcl); p1->d_drv = p->d_drv; p1->d_dirfil = fd; p1->d_dirpos = fd->o_bytnum - 32; p1->d_time = b->f_time; p1->d_date = b->f_date; memcpy(p1->d_name, b->f_name, 11); #if DBGFSDIR kprintf("\n makdnd(%08lx)", (long)p1); #endif return(p1); }