/*------------------------------------------------------------------------ * lflClose -- close a file by flushing output and freeing device entry *------------------------------------------------------------------------ */ devcall lflClose ( struct dentry *devptr /* entry in device switch table */ ) { struct lflcblk *lfptr; /* ptr to open file table entry */ /* Obtain exclusive use of the file */ lfptr = &lfltab[devptr->dvminor]; wait(lfptr->lfmutex); /* If file is not open, return an error */ if (lfptr->lfstate != LF_USED) { signal(lfptr->lfmutex); return SYSERR; } /* Write index or data blocks to disk if they have changed */ if (Lf_data.lf_dirdirty || lfptr->lfdbdirty || lfptr->lfibdirty) { lfflush(lfptr); } /* Set device state to FREE and return to caller */ lfptr->lfstate = LF_FREE; signal(lfptr->lfmutex); return OK; }
static status lflCloseHelper(char *fileName,struct lflcblk* lfptr) { struct lflcblk * dirCblk = &lfltab[Nlfl+1]; /*last entry is used for modifying the directory in which file is getting created.*/ struct lflcblk* parentDirCblk = &lfltab[Nlfl]; /*second last entry is used for parent of the directory in which file is getting created*/ struct dentry devPtr; struct dentry parentDevPtr; struct ldentry tempEntry; struct ldentry*dirEntry = &tempEntry; devPtr.dvminor=Nlfl+1; parentDevPtr.dvminor=Nlfl; bool8 found = 0; while(lflRead(&devPtr,(char*)dirEntry,sizeof(struct ldentry)) == sizeof(struct ldentry)) { if (strcmp(dirEntry->ld_name,fileName) && dirEntry->ld_used) { found = 1; break; } } if (!found) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } dirEntry->ld_ilist = lfptr->lffirstib; dirEntry->ld_size = lfptr->lfsize; uint32 writePos = dirCblk->lfpos - sizeof(struct ldentry); lflSeek(&devPtr,writePos); if (lflWrite(&devPtr,(char*)dirEntry,sizeof(struct ldentry)) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } /*Close the directory*/ if (lfflush(dirCblk) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; 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; }
/* * Creates an entry for file/directory in the directory currently loaded in * lfltab[Nllfl+1] and updates the size of the parent directory. * name is the name of the file/directory,type identifies whether we are * creating a file or directory and isReplace tells us whether we are updating * an existing unused entry or adding a new entry */ status touchdir(char*name,byte type,struct ldentry*dirEntry,bool8 isReplace) { struct lflcblk * dirCblk = &lfltab[Nlfl+1]; /*last entry is used for modifying the directory in which file is getting created.*/ struct lflcblk* parentDirCblk = &lfltab[Nlfl]; /*second last entry is used for parent of the directory in which file is getting created*/ struct dentry devPtr; struct dentry parentDevPtr; devPtr.dvminor=Nlfl+1; parentDevPtr.dvminor=Nlfl; /* * Initialize the entry */ dirEntry->ld_size = 0; dirEntry->ld_ilist = LF_INULL; dirEntry->ld_type = type; dirEntry->ld_used = true; strcpy(dirEntry->ld_name,name); if (lflWrite(&devPtr,(char*)dirEntry,sizeof(struct ldentry)) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } /*Close the current directory*/ if (lfflush(dirCblk) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } /* * If we reused an existing entry then we are done. */ if (isReplace) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return OK; } /* * Othewise increment the size of the parent directory */ /* * entry got added in the root directory so there is no * grandparent. */ if (LF_FREE == parentDirCblk->lfstate) { /*One entry got added to the root directory*/ dirCblk->lfstate = LF_FREE; wait(Lf_data.lf_mutex); Lf_data.lf_dir.lfd_size += sizeof(struct ldentry); Lf_data.lf_dirdirty = TRUE; signal(Lf_data.lf_mutex); return OK; } /*As we have created a new entry in this non-root directory update its entry in * the parent directory to reflect the increased size of this directory. * The lfPos of the parent directory is pointing to the location just * after this directory's entry. */ struct ldentry parentDirEntry; /* * Move to the poistion in grandparent at which the entry for the parent * begins. */ lflSeek(&parentDevPtr,parentDirCblk->lfpos - sizeof(struct ldentry)); if (lflRead(&parentDevPtr,(char*)&parentDirEntry,sizeof(struct ldentry)) ==SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } /* * Update that entry. */ parentDirEntry.ld_size += sizeof(struct ldentry); parentDirEntry.ld_ilist = dirCblk->lffirstib; /* * As we have just read that entry move back again so that * we can overwrite it. */ lflSeek(&parentDevPtr,parentDirCblk->lfpos - sizeof(struct ldentry)); /* * Write to the grandparent. */ if (lflWrite(&parentDevPtr,(char*)&parentDirEntry,sizeof(struct ldentry)) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } /*Close the parent directory*/ if (lfflush(parentDirCblk) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return OK; }
status createDirEntry(char *name, byte type, struct ldentry *dirEntry, bool8 isReplace) { struct lflcblk * dirCblk = &lfltab[Nlfl+1]; struct lflcblk* parentDirCblk = &lfltab[Nlfl]; struct dentry devPtr; struct dentry parentDevPtr; devPtr.dvminor=Nlfl+1; parentDevPtr.dvminor=Nlfl; dirEntry->ld_size = 0; dirEntry->ld_ilist = LF_INULL; dirEntry->type = type; dirEntry->isUsed = (bool8)1; strcpy(dirEntry->ld_name,name); if(lflWrite(&devPtr,(char*)dirEntry,sizeof(struct ldentry)) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } /*Close the current directory*/ if(lfflush(dirCblk) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } if(isReplace) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return OK; } if(LF_FREE == parentDirCblk->lfstate) { dirCblk->lfstate = LF_FREE; wait(Lf_data.lf_mutex); Lf_data.lf_dir.lfd_size += sizeof(struct ldentry); Lf_data.lf_dirdirty = TRUE; signal(Lf_data.lf_mutex); return OK; } struct ldentry parentDirEntry; lflSeek(&parentDevPtr,parentDirCblk->lfpos - sizeof(struct ldentry)); if(lflRead(&parentDevPtr,(char*)&parentDirEntry,sizeof(struct ldentry)) ==SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } parentDirEntry.ld_size += sizeof(struct ldentry); parentDirEntry.ld_ilist = dirCblk->firstIbId; lflSeek(&parentDevPtr,parentDirCblk->lfpos - sizeof(struct ldentry)); if(lflWrite(&parentDevPtr,(char*)&parentDirEntry,sizeof(struct ldentry)) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } if(lfflush(parentDirCblk) == SYSERR) { dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return SYSERR; } dirCblk->lfstate = LF_FREE; parentDirCblk->lfstate = LF_FREE; return OK; }