/*------------------------------------------------------------------------ * lflControl - Provide control functions for a local file pseudo-device *------------------------------------------------------------------------ */ devcall lflControl ( struct dentry *devptr, /* entry in device switch table */ int32 func, /* a control function */ int32 arg1, /* argument #1 */ int32 arg2 /* argument #2 */ ) { struct lflcblk *lfptr; /* ptr to open file table entry */ int32 retval; /* return value from func. call */ /* 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; } switch (func) { /* Truncate a file */ case LF_CTL_TRUNC: wait(Lf_data.lf_mutex); retval = lftruncate(lfptr); signal(Lf_data.lf_mutex); signal(lfptr->lfmutex); return retval; default: kprintf("lfControl: function %d not valid\n\r", func); signal(lfptr->lfmutex); return SYSERR; } }
/*------------------------------------------------------------------------ * 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; } }