/*------------------------------------------------------------------------ * lfflush - flush data block and index blocks for an open file * (assumes file mutex is held) *------------------------------------------------------------------------ */ status lfflush ( struct lflcblk *lfptr /* ptr to file pseudo device */ ) { if (lfptr->lfstate == LF_FREE) { return SYSERR; } /* Write data block if it has changed */ if (lfptr->lfdbdirty) { write(Lf_data.lf_dskdev, lfptr->lfdblock, lfptr->lfdnum); lfptr->lfdbdirty = FALSE; } /* Write i-block if it has changed */ if (lfptr->lfibdirty) { lfibput(Lf_data.lf_dskdev, lfptr->lfinum, &lfptr->lfiblock); lfptr->lfibdirty = FALSE; } return OK; }
/*------------------------------------------------------------------------ * lfscreate -- Create an initially-empty file system on a disk *------------------------------------------------------------------------ */ status lfscreate ( did32 disk, /* ID of an open disk device */ ibid32 lfiblks, /* num. of index blocks on disk */ uint32 dsiz /* total size of disk in bytes */ ) { uint32 sectors; /* number of sectors to use */ uint32 ibsectors; /* number of sectors of i-blocks*/ uint32 ibpersector; /* number of i-blocks per sector*/ struct lfdir dir; /* Buffer to hold the directory */ uint32 dblks; /* total free data blocks */ struct lfiblk iblock; /* space for one i-block */ struct lfdbfree dblock; /* data block on the free list */ dbid32 dbindex; /* index for data blocks */ int32 retval; /* return value from func call */ int32 i; /* loop index */ //ibid32 nextib; //dbid32 nextdb; //int32 lfiblks_free; /* total free index blocks */ /* Compute total sectors on disk */ sectors = dsiz / LF_BLKSIZ; /* truncate to full sector */ /* Compute number of sectors comprising i-blocks */ ibpersector = LF_BLKSIZ / sizeof(struct lfiblk); ibsectors = (lfiblks+(ibpersector-1)) / ibpersector; /* round up*/ lfiblks = ibsectors * ibpersector; if (ibsectors > sectors/2) { /* invalid arguments */ //kprintf("ibsectors > sectors/2 - invalid arguments\r\n"); return SYSERR; } /* Create an initial sector 0 */ memset((char *)&dir, NULLCH, sizeof(struct lfdir)); //dir.lfd_nfiles = 0; dbindex= (dbid32)(ibsectors + 1); dir.lfd_ifree = 1; dir.lfd_dfree = dbindex + 1; dblks = sectors - ibsectors - 1; /* Initialize root directory entry */ (dir.root_entry).ld_size = 0; (dir.root_entry).ld_ilist = 0; (dir.root_entry).ld_name[0] = '/'; (dir.root_entry).ld_name[1] = NULLCH; (dir.root_entry).ld_type = LF_TYPE_DIR; retval = write(disk,(char *)&dir, LF_AREA_DIR); if (retval == SYSERR) { //kprintf("cannot create an initial directory\r\n"); return SYSERR; } /* Create an initial root directory index block 0 */ memset((char *)&iblock, NULLCH, sizeof(struct lfiblk)); lfibclear(&iblock, 0); iblock.ib_next = LF_INULL; iblock.ib_dba[0] = dbindex; /* point to first data blk */ for(i =1; i < LF_IBLEN; i++) { iblock.ib_dba[i] = LF_DNULL; } lfibput(disk, 0, &iblock); /* Create list of free i-blocks on disk from i-bloack 1 */ lfibclear(&iblock, 0); for (i=1; i<lfiblks-1; i++) { iblock.ib_next = (ibid32)(i + 1); lfibput(disk, i, &iblock); } iblock.ib_next = LF_INULL; lfibput(disk, i, &iblock); /* Create an initial root directory data block 0 */ memset((char *)&dblock, NULLCH, LF_BLKSIZ); write(disk, (char *)&dblock, dbindex); /* Create list of free data blocks on disk */ memset((char*)&dblock, NULLCH, LF_BLKSIZ); for (i=1; i<dblks-1; i++) { dblock.lf_nextdb = dbindex + 2; retval = write(disk, (char *)&dblock, dbindex+1); if (retval == SYSERR) { //kprintf("cannot create list of free data blocks on disk\r\n"); return SYSERR; } dbindex++; } dblock.lf_nextdb = LF_DNULL; retval = write(disk, (char *)&dblock, dbindex+1); if (retval == SYSERR) { //kprintf("cannot create list of free data blocks on disk\r\n"); return SYSERR; } //close(disk); /* //kprintf("lfscreate Done\r\n"); retval = read(disk,(char *)&dir, LF_AREA_DIR); lfiblks_free = 0; nextib = dir.lfd_ifree; //kprintf("initial index block is %d\n\r", nextib); while (nextib != LF_INULL) { lfiblks_free++; lfibget(disk, nextib, &iblock); nextib = iblock.ib_next; } ibsectors = (lfiblks_free + 6) /7; //kprintf("Found %d index blocks (%d sectors)\n\r", lfiblks_free, ibsectors); */ /* Follow data block list */ /* dblks = 0; nextdb = dir.lfd_dfree; //kprintf("initial data block is %d\n\r", nextdb); while (nextdb != LF_DNULL) { dblks++; read(disk, (char *)&dblock, nextdb); nextdb = dblock.lf_nextdb; } //kprintf("Found %d data blocks\n\r", dblks);*/ return OK; }
/*------------------------------------------------------------------------ * lfsetup - Set a file's index block and data block for the current * file position (assumes file mutex held) *------------------------------------------------------------------------ */ status lfsetup ( struct lflcblk *lfptr /* Pointer to slave file device */ ) { dbid32 dnum; /* Data block to fetch */ ibid32 ibnum; /* I-block number during search */ struct ldentry *ldptr; /* Ptr to file entry in dir. */ struct lfiblk *ibptr; /* Ptr to in-memory index block */ uint32 newoffset; /* Computed data offset for */ /* next index block */ int32 dindex; /* Index into array in an index */ /* block */ /* Obtain exclusive access to the directory */ wait(Lf_data.lf_mutex); /* Get pointers to in-memory directory, file's entry in the */ /* directory, and the in-memory index block */ ldptr = lfptr->lfdirptr; ibptr = &lfptr->lfiblock; /* If existing index block or data block changed, write to disk */ if (lfptr->lfibdirty || lfptr->lfdbdirty) { lfflush(lfptr); } ibnum = lfptr->lfinum; /* Get ID of curr. index block */ /* If there is no index block in memory (e.g., because the file */ /* was just opened), either load the first index block of */ /* the file or allocate a new first index block */ if (ibnum == LF_INULL) { /* Check directory entry to see if index block exists */ ibnum = ldptr->ld_ilist; if (ibnum == LF_INULL) { /* Empty file - get new i-block*/ ibnum = lfiballoc(); lfibclear(ibptr, 0); ldptr->ld_ilist = ibnum; lfptr->lfibdirty = TRUE; } else { /* Nonempty - read first i-block*/ lfibget(Lf_data.lf_dskdev, ibnum, ibptr); } lfptr->lfinum = ibnum; /* Otherwise, if current file position has been moved to an */ /* offset before the current index block, start at the */ /* beginning of the index list for the file */ } else if (lfptr->lfpos < ibptr->ib_offset) { /* Load initial index block for the file (we know that */ /* at least one index block exists) */ ibnum = ldptr->ld_ilist; lfibget(Lf_data.lf_dskdev, ibnum, ibptr); lfptr->lfinum = ibnum; } /* At this point, an index block is in memory, but may cover */ /* an offset less than the current file position. Loop until */ /* the index block covers the current file position. */ while ((lfptr->lfpos & ~LF_IMASK) > ibptr->ib_offset ) { ibnum = ibptr->ib_next; if (ibnum == LF_INULL) { /* Allocate new index block to extend file */ ibnum = lfiballoc(); ibptr->ib_next = ibnum; lfibput(Lf_data.lf_dskdev, lfptr->lfinum, ibptr); lfptr->lfinum = ibnum; newoffset = ibptr->ib_offset + LF_IDATA; lfibclear(ibptr, newoffset); lfptr->lfibdirty = TRUE; } else { lfibget(Lf_data.lf_dskdev, ibnum, ibptr); lfptr->lfinum = ibnum; } lfptr->lfdnum = LF_DNULL; /* Invalidate old data block */ } /* At this point, the index block in lfiblock covers the */ /* current file position (i.e., position lfptr->lfpos). The */ /* next step consists of loading the correct data block. */ dindex = (lfptr->lfpos & LF_IMASK) >> 9; /* If data block index does not match current data block, read */ /* the correct data block from disk */ dnum = lfptr->lfiblock.ib_dba[dindex]; if (dnum == LF_DNULL) { /* Allocate new data block */ dnum = lfdballoc((struct lfdbfree *)&lfptr->lfdblock); lfptr->lfiblock.ib_dba[dindex] = dnum; lfptr->lfibdirty = TRUE; } else if ( dnum != lfptr->lfdnum) { read(Lf_data.lf_dskdev, (char *)lfptr->lfdblock, dnum); lfptr->lfdbdirty = FALSE; } lfptr->lfdnum = dnum; /* Use current file offset to set the pointer to the next byte */ /* within the data block */ lfptr->lfbyte = &lfptr->lfdblock[lfptr->lfpos & LF_DMASK]; signal(Lf_data.lf_mutex); return OK; }
/*------------------------------------------------------------------------ * lftruncate - truncate a file by freeing its index and data blocks * (assumes directory mutex held) *------------------------------------------------------------------------ */ status lftruncate ( struct lflcblk *lfptr /* ptr to file's cntl blk entry */ ) { //struct ldentry *ldptr; /* pointer to file's dir. entry */ struct lfiblk iblock; /* buffer for one index block */ ibid32 ifree; /* start of index blk free list */ ibid32 firstib; /* first index blk of the file */ ibid32 nextib; /* walks down list of the */ /* file's index blocks */ dbid32 nextdb; /* next data block to free */ int32 i; /* moves through data blocks in */ /* a given index block */ //ldptr = lfptr->lfdirptr; /* Get pointer to dir. entry */ if (lfptr->lfsize == 0) { /* file is already empty */ return OK; } /* Clean up the open local file first */ if ( (lfptr->lfibdirty) || (lfptr->lfdbdirty) ) { lfflush(lfptr); } lfptr->lfpos = 0; lfptr->lfinum = LF_INULL; lfptr->lfdnum = LF_DNULL; lfptr->lfbyte = &lfptr->lfdblock[LF_BLKSIZ]; /* Obtain ID of first index block on free list */ ifree = Lf_data.lf_dir.lfd_ifree; /* Record file's first i-block and clear directory entry */ firstib = lfptr->lffirstib; lfptr->lffirstib= LF_INULL; lfptr->lfsize = 0; Lf_data.lf_dirdirty = TRUE; /* Walk along index block list, disposing of each data block */ /* and clearing the corresponding pointer. A note on loop */ /* termination: last pointer is set to ifree below. */ for (nextib=firstib; nextib!=ifree; nextib=iblock.ib_next) { /* Obtain a copy of current index block from disk */ lfibget(Lf_data.lf_dskdev, nextib, &iblock); /* Free each data block in the index block */ for (i=0; i<LF_IBLEN; i++) { /* for each d-block */ /* Free the data block */ nextdb = iblock.ib_dba[i]; if (nextdb != LF_DNULL) { lfdbfree(Lf_data.lf_dskdev, nextdb); } /* Clear entry in i-block for this d-block */ iblock.ib_dba[i] = LF_DNULL; } /* Clear offset (just to make debugging easier) */ iblock.ib_offset = 0; /* For the last index block on the list, make it point */ /* to the current free list */ if (iblock.ib_next == LF_INULL) { iblock.ib_next = ifree; } /* Write cleared i-block back to disk */ lfibput(Lf_data.lf_dskdev, nextib, &iblock); } /* Last index block on the file list now points to first node */ /* on the current free list. Once we make the free list */ /* point to the first index block on the file list, the */ /* entire set of index blocks will be on the free list */ Lf_data.lf_dir.lfd_ifree = firstib; /* Indicate that directory has changed and return */ Lf_data.lf_dirdirty = TRUE; return OK; }
/*------------------------------------------------------------------------ * lfscreate - Create an initially-empty file system on a disk *------------------------------------------------------------------------ */ status lfscreate ( did32 disk, /* ID of an open disk device */ ibid32 lfiblks, /* Num. of index blocks on disk */ uint32 dsiz /* Total size of disk in bytes */ ) { uint32 sectors; /* Number of sectors to use */ uint32 ibsectors; /* Number of sectors of i-blocks*/ uint32 ibpersector; /* Number of i-blocks per sector*/ struct lfdir dir; /* Buffer to hold the directory */ uint32 dblks; /* Total free data blocks */ struct lfiblk iblock; /* Space for one i-block */ struct lfdbfree dblock; /* Data block on the free list */ dbid32 dbindex; /* Index for data blocks */ int32 retval; /* Return value from func call */ int32 i; /* Loop index */ /* Compute total sectors on disk */ sectors = dsiz / LF_BLKSIZ; /* Truncate to full sector */ /* Compute number of sectors comprising i-blocks */ ibpersector = LF_BLKSIZ / sizeof(struct lfiblk); ibsectors = (lfiblks+(ibpersector-1)) / ibpersector;/* Round up */ lfiblks = ibsectors * ibpersector; if (ibsectors > sectors/2) { /* Invalid arguments */ return SYSERR; } /* Create an initial directory */ memset((char *)&dir, NULLCH, sizeof(struct lfdir)); dir.lfd_nfiles = 0; dbindex= (dbid32)(ibsectors + 1); dir.lfd_dfree = dbindex; dblks = sectors - ibsectors - 1; retval = write(disk,(char *)&dir, LF_AREA_DIR); if (retval == SYSERR) { return SYSERR; } /* Create list of free i-blocks on disk */ lfibclear(&iblock, 0); for (i=0; i<lfiblks-1; i++) { iblock.ib_next = (ibid32)(i + 1); lfibput(disk, i, &iblock); } iblock.ib_next = LF_INULL; lfibput(disk, i, &iblock); /* Create list of free data blocks on disk */ memset((char*)&dblock, NULLCH, LF_BLKSIZ); for (i=0; i<dblks-1; i++) { dblock.lf_nextdb = dbindex + 1; write(disk, (char *)&dblock, dbindex); dbindex++; } dblock.lf_nextdb = LF_DNULL; write(disk, (char *)&dblock, dbindex); close(disk); return OK; }
/*------------------------------------------------------------------------ * lfstruncate - truncate a file by freeing its index and data blocks * (assumes directory mutex held) *------------------------------------------------------------------------ */ status lfstruncate ( char *name /* file name to truncate */ ) { char *nam, *cmp; /* ptrs used during comparison */ int32 i; /* general loop index */ struct lflcblk *lfptr; /* ptr to open file table entry */ struct lfdir *dirptr; /* ptr to in-memory directory */ bool8 found; /* was the name found? */ int32 retval; /* value returned from function */ struct ldentry *ldptr; /* ptr to an entry in directory */ ibid32 ifree; /* start of index blk free list */ ibid32 firstib; /* first index blk of the file */ ibid32 nextib; /* walks down list of the */ /* file's index blocks */ dbid32 nextdb; /* next data block to free */ struct lfiblk iblock; /* buffer for one index block */ /* Check length of name file (leaving space for NULLCH */ nam = name; for (i=0; i< LF_NAME_LEN; i++) { if (*nam++ == NULLCH) { break; } } if (i >= LF_NAME_LEN) { /* name is too long */ //kprintf("Name is too long\r\n"); return SYSERR; } /* Check if named file is open */ for (i=0; i<Nlfl; i++) { /* search file pseudo-devices */ lfptr = &lfltab[i]; if (lfptr->lfstate == LF_USED) { /* Compare requested name to name of open file */ nam = name; cmp = lfptr->lfname; while(*nam != NULLCH) { if (*nam != *cmp) { break; } nam++; cmp++; } /* if named file is open, call lftruncate directly */ if ( (*nam==NULLCH) && (*cmp == NULLCH) ) { //kprintf("file to truncate is open\r\n"); wait(lfptr->lfmutex); retval = lftruncate(lfptr); signal(lfptr->lfmutex); //kprintf("truncated the open file\r\n"); return retval; } } } /* Named file is not open */ /* Obtain copy of directory if not already present in memory */ dirptr = &Lf_data.lf_dir; if (! Lf_data.lf_dirpresent) { retval = read(Lf_data.lf_dskdev,(char *)dirptr,LF_AREA_DIR); if (retval == SYSERR ) { //kprintf("Cannot not read directory into memory\r\n"); return SYSERR; } Lf_data.lf_dirpresent = TRUE; } /* Search directory to see if file exists */ found = FALSE; for (i=0; i<dirptr->lfd_nfiles; i++) { ldptr = &dirptr->lfd_files[i]; nam = name; cmp = ldptr->ld_name; while(*nam != NULLCH) { if (*nam != *cmp) { break; } nam++; cmp++; } if ( (*nam==NULLCH) && (*cmp==NULLCH) ) { /* name found */ found = TRUE; break; } } /* if file does not exist, return SYSERR */ if (! found) { signal(Lf_data.lf_mutex); //kprintf("Named file to truncate does not exist\r\n"); return SYSERR; } /* if file is in directory, free its index and data blocks */ else { if (ldptr->ld_size == 0) { /* file is already empty */ return OK; } /* Obtain ID of first index block on free list */ ifree = Lf_data.lf_dir.lfd_ifree; /* Record file's first i-block and clear directory entry */ firstib = ldptr->ld_ilist; ldptr->ld_ilist = LF_INULL; ldptr->ld_size = 0; Lf_data.lf_dirdirty = TRUE; /* Walk along index block list, disposing of each data block*/ /* and clearing the corresponding pointer. A note on loop */ /* termination: last pointer is set to ifree below. */ for (nextib=firstib; nextib!=ifree; nextib=iblock.ib_next) { /* Obtain a copy of current index block from disk */ lfibget(Lf_data.lf_dskdev, nextib, &iblock); /* Free each data block in the index block */ for (i=0; i<LF_IBLEN; i++) { /* for each d-block */ /* Free the data block */ nextdb = iblock.ib_dba[i]; if (nextdb != LF_DNULL) { lfdbfree(Lf_data.lf_dskdev, nextdb); } /* Clear entry in i-block for this d-block */ iblock.ib_dba[i] = LF_DNULL; } /* Clear offset (just to make debugging easier) */ iblock.ib_offset = 0; /* For the last index block on the list, make it point */ /* to the current free list */ if (iblock.ib_next == LF_INULL) { iblock.ib_next = ifree; } /* Write cleared i-block back to disk */ lfibput(Lf_data.lf_dskdev, nextib, &iblock); } /* Last index block on the file list now points to first node */ /* on the current free list. Once we make the free list */ /* point to the first index block on the file list, the */ /* entire set of index blocks will be on the free list */ Lf_data.lf_dir.lfd_ifree = firstib; /* Indicate that directory has changed and return */ Lf_data.lf_dirdirty = TRUE; return OK; } }