122046Sdist /* 261492Sbostic * Copyright (c) 1980, 1986, 1993 361492Sbostic * The Regents of the University of California. All rights reserved. 439976Smckusick * 542701Sbostic * %sccs.include.redist.c% 622046Sdist */ 722046Sdist 816261Smckusick #ifndef lint 9*68908Smckusick static char sccsid[] = "@(#)inode.c 8.7 (Berkeley) 04/27/95"; 1039976Smckusick #endif /* not lint */ 1116261Smckusick 1216261Smckusick #include <sys/param.h> 1353821Smckusick #include <sys/time.h> 14*68908Smckusick 1551532Sbostic #include <ufs/ufs/dinode.h> 1651532Sbostic #include <ufs/ufs/dir.h> 1751532Sbostic #include <ufs/ffs/fs.h> 18*68908Smckusick 19*68908Smckusick #include <err.h> 2036963Sbostic #include <pwd.h> 2144934Smckusick #include <string.h> 22*68908Smckusick 2316261Smckusick #include "fsck.h" 2416261Smckusick 2540647Smckusick static ino_t startinum; 2634225Smckusick 27*68908Smckusick static int iblock __P((struct inodesc *, long ilevel, quad_t isize)); 28*68908Smckusick 29*68908Smckusick int 3016261Smckusick ckinode(dp, idesc) 3139973Smckusick struct dinode *dp; 3216261Smckusick register struct inodesc *idesc; 3316261Smckusick { 3468548Smckusick ufs_daddr_t *ap; 3539973Smckusick long ret, n, ndb, offset; 3639973Smckusick struct dinode dino; 3753825Smckusick quad_t remsize, sizepb; 3854599Smckusick mode_t mode; 3916261Smckusick 4044998Smckusick if (idesc->id_fix != IGNORE) 4144998Smckusick idesc->id_fix = DONTKNOW; 4218000Smckusick idesc->id_entryno = 0; 4318000Smckusick idesc->id_filesize = dp->di_size; 4454599Smckusick mode = dp->di_mode & IFMT; 4554599Smckusick if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 4654599Smckusick dp->di_size < sblock.fs_maxsymlinklen)) 4716261Smckusick return (KEEPON); 4816261Smckusick dino = *dp; 4916261Smckusick ndb = howmany(dino.di_size, sblock.fs_bsize); 5016261Smckusick for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 5116261Smckusick if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 5216261Smckusick idesc->id_numfrags = 5316261Smckusick numfrags(&sblock, fragroundup(&sblock, offset)); 5416261Smckusick else 5516261Smckusick idesc->id_numfrags = sblock.fs_frag; 5616261Smckusick if (*ap == 0) 5716261Smckusick continue; 5816261Smckusick idesc->id_blkno = *ap; 5916261Smckusick if (idesc->id_type == ADDR) 6016261Smckusick ret = (*idesc->id_func)(idesc); 6116261Smckusick else 6216261Smckusick ret = dirscan(idesc); 6316261Smckusick if (ret & STOP) 6416261Smckusick return (ret); 6516261Smckusick } 6616261Smckusick idesc->id_numfrags = sblock.fs_frag; 6753825Smckusick remsize = dino.di_size - sblock.fs_bsize * NDADDR; 6853825Smckusick sizepb = sblock.fs_bsize; 6917930Smckusick for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 7016261Smckusick if (*ap) { 7116261Smckusick idesc->id_blkno = *ap; 7253825Smckusick ret = iblock(idesc, n, remsize); 7316261Smckusick if (ret & STOP) 7416261Smckusick return (ret); 7516261Smckusick } 7653825Smckusick sizepb *= NINDIR(&sblock); 7753825Smckusick remsize -= sizepb; 7816261Smckusick } 7916261Smckusick return (KEEPON); 8016261Smckusick } 8116261Smckusick 82*68908Smckusick static int 8316261Smckusick iblock(idesc, ilevel, isize) 8416261Smckusick struct inodesc *idesc; 8553825Smckusick long ilevel; 8652983Smckusick quad_t isize; 8716261Smckusick { 8868548Smckusick ufs_daddr_t *ap; 8968548Smckusick ufs_daddr_t *aplim; 9068548Smckusick struct bufarea *bp; 9153821Smckusick int i, n, (*func)(), nif; 9253821Smckusick quad_t sizepb; 9323876Smckusick char buf[BUFSIZ]; 9416261Smckusick 9516261Smckusick if (idesc->id_type == ADDR) { 9616261Smckusick func = idesc->id_func; 9716261Smckusick if (((n = (*func)(idesc)) & KEEPON) == 0) 9816261Smckusick return (n); 9916261Smckusick } else 10016261Smckusick func = dirscan; 10139973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 10216261Smckusick return (SKIP); 10334225Smckusick bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 10416261Smckusick ilevel--; 10517930Smckusick for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 10617930Smckusick sizepb *= NINDIR(&sblock); 10753825Smckusick nif = howmany(isize , sizepb); 10816261Smckusick if (nif > NINDIR(&sblock)) 10916261Smckusick nif = NINDIR(&sblock); 11017950Smckusick if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 11134225Smckusick aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 11234225Smckusick for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 11317950Smckusick if (*ap == 0) 11417950Smckusick continue; 11544934Smckusick (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 11623876Smckusick idesc->id_number); 11723876Smckusick if (dofix(idesc, buf)) { 11817950Smckusick *ap = 0; 11934225Smckusick dirty(bp); 12017950Smckusick } 12117950Smckusick } 12239973Smckusick flush(fswritefd, bp); 12317950Smckusick } 12434225Smckusick aplim = &bp->b_un.b_indir[nif]; 12553825Smckusick for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 12616261Smckusick if (*ap) { 12716261Smckusick idesc->id_blkno = *ap; 12866898Smckusick if (ilevel == 0) 12916261Smckusick n = (*func)(idesc); 13066898Smckusick else 13153825Smckusick n = iblock(idesc, ilevel, isize); 13234225Smckusick if (n & STOP) { 13334225Smckusick bp->b_flags &= ~B_INUSE; 13416261Smckusick return (n); 13534225Smckusick } 13616261Smckusick } 13766898Smckusick isize -= sizepb; 13834225Smckusick } 13934225Smckusick bp->b_flags &= ~B_INUSE; 14016261Smckusick return (KEEPON); 14116261Smckusick } 14216261Smckusick 14339973Smckusick /* 14439973Smckusick * Check that a block in a legal block number. 14539973Smckusick * Return 0 if in range, 1 if out of range. 14639973Smckusick */ 147*68908Smckusick int 14839973Smckusick chkrange(blk, cnt) 14968548Smckusick ufs_daddr_t blk; 15016261Smckusick int cnt; 15116261Smckusick { 15216261Smckusick register int c; 15316261Smckusick 15439973Smckusick if ((unsigned)(blk + cnt) > maxfsblock) 15516261Smckusick return (1); 15616261Smckusick c = dtog(&sblock, blk); 15716261Smckusick if (blk < cgdmin(&sblock, c)) { 15839973Smckusick if ((blk + cnt) > cgsblock(&sblock, c)) { 15916261Smckusick if (debug) { 16044934Smckusick printf("blk %ld < cgdmin %ld;", 16116261Smckusick blk, cgdmin(&sblock, c)); 16244934Smckusick printf(" blk + cnt %ld > cgsbase %ld\n", 16339973Smckusick blk + cnt, cgsblock(&sblock, c)); 16416261Smckusick } 16516261Smckusick return (1); 16616261Smckusick } 16716261Smckusick } else { 16839973Smckusick if ((blk + cnt) > cgbase(&sblock, c+1)) { 16916261Smckusick if (debug) { 17044934Smckusick printf("blk %ld >= cgdmin %ld;", 17116261Smckusick blk, cgdmin(&sblock, c)); 17244934Smckusick printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 17316261Smckusick blk+cnt, sblock.fs_fpg); 17416261Smckusick } 17516261Smckusick return (1); 17616261Smckusick } 17716261Smckusick } 17816261Smckusick return (0); 17916261Smckusick } 18016261Smckusick 18140024Smckusick /* 18240024Smckusick * General purpose interface for reading inodes. 18340024Smckusick */ 18439973Smckusick struct dinode * 18516261Smckusick ginode(inumber) 18616261Smckusick ino_t inumber; 18716261Smckusick { 18868548Smckusick ufs_daddr_t iblk; 18916261Smckusick 19039973Smckusick if (inumber < ROOTINO || inumber > maxino) 191*68908Smckusick errx(EEXIT, "bad inode number %d to ginode", inumber); 19216261Smckusick if (startinum == 0 || 19316261Smckusick inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 19464639Sbostic iblk = ino_to_fsba(&sblock, inumber); 19534225Smckusick if (pbp != 0) 19634225Smckusick pbp->b_flags &= ~B_INUSE; 19734225Smckusick pbp = getdatablk(iblk, sblock.fs_bsize); 19816261Smckusick startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 19916261Smckusick } 20034225Smckusick return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 20116261Smckusick } 20216261Smckusick 20340024Smckusick /* 20440024Smckusick * Special purpose version of ginode used to optimize first pass 20540024Smckusick * over all the inodes in numerical order. 20640024Smckusick */ 20740024Smckusick ino_t nextino, lastinum; 20840024Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 20940024Smckusick struct dinode *inodebuf; 21040024Smckusick 21140024Smckusick struct dinode * 21240024Smckusick getnextinode(inumber) 21340024Smckusick ino_t inumber; 21440024Smckusick { 21540024Smckusick long size; 21668548Smckusick ufs_daddr_t dblk; 21740024Smckusick static struct dinode *dp; 21840024Smckusick 21940024Smckusick if (inumber != nextino++ || inumber > maxino) 220*68908Smckusick errx(EEXIT, "bad inode number %d to nextinode", inumber); 22140024Smckusick if (inumber >= lastinum) { 22240024Smckusick readcnt++; 22364639Sbostic dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 22440024Smckusick if (readcnt % readpercg == 0) { 22540024Smckusick size = partialsize; 22640024Smckusick lastinum += partialcnt; 22740024Smckusick } else { 22840024Smckusick size = inobufsize; 22940024Smckusick lastinum += fullcnt; 23040024Smckusick } 23144934Smckusick (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ 23240024Smckusick dp = inodebuf; 23340024Smckusick } 23440024Smckusick return (dp++); 23540024Smckusick } 23640024Smckusick 237*68908Smckusick void 23840024Smckusick resetinodebuf() 23940024Smckusick { 24040024Smckusick 24140647Smckusick startinum = 0; 24240024Smckusick nextino = 0; 24340024Smckusick lastinum = 0; 24440024Smckusick readcnt = 0; 24540024Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 24640024Smckusick fullcnt = inobufsize / sizeof(struct dinode); 24740024Smckusick readpercg = sblock.fs_ipg / fullcnt; 24840024Smckusick partialcnt = sblock.fs_ipg % fullcnt; 24940024Smckusick partialsize = partialcnt * sizeof(struct dinode); 25040024Smckusick if (partialcnt != 0) { 25140024Smckusick readpercg++; 25240024Smckusick } else { 25340024Smckusick partialcnt = fullcnt; 25440024Smckusick partialsize = inobufsize; 25540024Smckusick } 25640024Smckusick if (inodebuf == NULL && 25740024Smckusick (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 258*68908Smckusick errx(EEXIT, "Cannot allocate space for inode buffer"); 25940024Smckusick while (nextino < ROOTINO) 26044934Smckusick (void)getnextinode(nextino); 26140024Smckusick } 26240024Smckusick 263*68908Smckusick void 26440024Smckusick freeinodebuf() 26540024Smckusick { 26640024Smckusick 26740024Smckusick if (inodebuf != NULL) 26840024Smckusick free((char *)inodebuf); 26940024Smckusick inodebuf = NULL; 27040024Smckusick } 27140024Smckusick 27240024Smckusick /* 27340024Smckusick * Routines to maintain information about directory inodes. 27440024Smckusick * This is built during the first pass and used during the 27540024Smckusick * second and third passes. 27640024Smckusick * 27740024Smckusick * Enter inodes into the cache. 27840024Smckusick */ 279*68908Smckusick void 28039980Smckusick cacheino(dp, inumber) 28139980Smckusick register struct dinode *dp; 28239980Smckusick ino_t inumber; 28339980Smckusick { 28439980Smckusick register struct inoinfo *inp; 28539980Smckusick struct inoinfo **inpp; 28639980Smckusick unsigned int blks; 28739980Smckusick 28839980Smckusick blks = howmany(dp->di_size, sblock.fs_bsize); 28939980Smckusick if (blks > NDADDR) 29039980Smckusick blks = NDADDR + NIADDR; 29139980Smckusick inp = (struct inoinfo *) 29268548Smckusick malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t)); 29339980Smckusick if (inp == NULL) 29439980Smckusick return; 29540024Smckusick inpp = &inphead[inumber % numdirs]; 29640024Smckusick inp->i_nexthash = *inpp; 29739980Smckusick *inpp = inp; 29868249Smckusick if (inumber == ROOTINO) 29968249Smckusick inp->i_parent = ROOTINO; 30068249Smckusick else 30168249Smckusick inp->i_parent = (ino_t)0; 30240024Smckusick inp->i_dotdot = (ino_t)0; 30339980Smckusick inp->i_number = inumber; 30440024Smckusick inp->i_isize = dp->di_size; 30568548Smckusick inp->i_numblks = blks * sizeof(ufs_daddr_t); 30640024Smckusick bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], 30744934Smckusick (size_t)inp->i_numblks); 30840024Smckusick if (inplast == listmax) { 30940024Smckusick listmax += 100; 31040024Smckusick inpsort = (struct inoinfo **)realloc((char *)inpsort, 31140024Smckusick (unsigned)listmax * sizeof(struct inoinfo *)); 31240024Smckusick if (inpsort == NULL) 313*68908Smckusick errx(EEXIT, "cannot increase directory list"); 31440024Smckusick } 31540024Smckusick inpsort[inplast++] = inp; 31639980Smckusick } 31739980Smckusick 31840024Smckusick /* 31940024Smckusick * Look up an inode cache structure. 32040024Smckusick */ 32140024Smckusick struct inoinfo * 32240024Smckusick getinoinfo(inumber) 32339980Smckusick ino_t inumber; 32439980Smckusick { 32539980Smckusick register struct inoinfo *inp; 32639980Smckusick 32740024Smckusick for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 32839980Smckusick if (inp->i_number != inumber) 32939980Smckusick continue; 33040024Smckusick return (inp); 33139980Smckusick } 332*68908Smckusick errx(EEXIT, "cannot find inode %d", inumber); 33340024Smckusick return ((struct inoinfo *)0); 33439980Smckusick } 33539980Smckusick 33640024Smckusick /* 33740024Smckusick * Clean up all the inode cache structure. 33840024Smckusick */ 339*68908Smckusick void 34039980Smckusick inocleanup() 34139980Smckusick { 34240024Smckusick register struct inoinfo **inpp; 34339980Smckusick 34439980Smckusick if (inphead == NULL) 34539980Smckusick return; 34640024Smckusick for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 34740024Smckusick free((char *)(*inpp)); 34840024Smckusick free((char *)inphead); 34940024Smckusick free((char *)inpsort); 35040024Smckusick inphead = inpsort = NULL; 35139980Smckusick } 35239980Smckusick 353*68908Smckusick void 35434225Smckusick inodirty() 35534225Smckusick { 35634225Smckusick 35734225Smckusick dirty(pbp); 35834225Smckusick } 35934225Smckusick 360*68908Smckusick void 36139973Smckusick clri(idesc, type, flag) 36216261Smckusick register struct inodesc *idesc; 36339973Smckusick char *type; 36439973Smckusick int flag; 36516261Smckusick { 36639973Smckusick register struct dinode *dp; 36716261Smckusick 36817943Smckusick dp = ginode(idesc->id_number); 36939973Smckusick if (flag == 1) { 37039973Smckusick pwarn("%s %s", type, 37139973Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 37216261Smckusick pinode(idesc->id_number); 37316261Smckusick } 37416261Smckusick if (preen || reply("CLEAR") == 1) { 37516261Smckusick if (preen) 37616261Smckusick printf(" (CLEARED)\n"); 37716261Smckusick n_files--; 37816261Smckusick (void)ckinode(dp, idesc); 37939973Smckusick clearinode(dp); 38016261Smckusick statemap[idesc->id_number] = USTATE; 38116261Smckusick inodirty(); 38216261Smckusick } 38316261Smckusick } 38416261Smckusick 385*68908Smckusick int 38617991Smckusick findname(idesc) 38717991Smckusick struct inodesc *idesc; 38817991Smckusick { 38939973Smckusick register struct direct *dirp = idesc->id_dirp; 39017991Smckusick 39117991Smckusick if (dirp->d_ino != idesc->id_parent) 39217991Smckusick return (KEEPON); 39344934Smckusick bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); 39430354Smckusick return (STOP|FOUND); 39517991Smckusick } 39617991Smckusick 397*68908Smckusick int 39816261Smckusick findino(idesc) 39916261Smckusick struct inodesc *idesc; 40016261Smckusick { 40139973Smckusick register struct direct *dirp = idesc->id_dirp; 40216261Smckusick 40316261Smckusick if (dirp->d_ino == 0) 40416261Smckusick return (KEEPON); 40517991Smckusick if (strcmp(dirp->d_name, idesc->id_name) == 0 && 40639973Smckusick dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 40717991Smckusick idesc->id_parent = dirp->d_ino; 40830354Smckusick return (STOP|FOUND); 40916261Smckusick } 41016261Smckusick return (KEEPON); 41116261Smckusick } 41216261Smckusick 413*68908Smckusick void 41416261Smckusick pinode(ino) 41516261Smckusick ino_t ino; 41616261Smckusick { 41739973Smckusick register struct dinode *dp; 41816261Smckusick register char *p; 41918102Smckusick struct passwd *pw; 42016261Smckusick char *ctime(); 42116261Smckusick 42244934Smckusick printf(" I=%lu ", ino); 42339973Smckusick if (ino < ROOTINO || ino > maxino) 42416261Smckusick return; 42517943Smckusick dp = ginode(ino); 42616261Smckusick printf(" OWNER="); 42718102Smckusick if ((pw = getpwuid((int)dp->di_uid)) != 0) 42818102Smckusick printf("%s ", pw->pw_name); 42918102Smckusick else 43044934Smckusick printf("%u ", (unsigned)dp->di_uid); 43116261Smckusick printf("MODE=%o\n", dp->di_mode); 43216261Smckusick if (preen) 43361110Sbostic printf("%s: ", cdevname); 43453821Smckusick printf("SIZE=%qu ", dp->di_size); 43568548Smckusick p = ctime(&dp->di_mtime); 43647579Smckusick printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 43716261Smckusick } 43816261Smckusick 439*68908Smckusick void 44039973Smckusick blkerror(ino, type, blk) 44116261Smckusick ino_t ino; 44239973Smckusick char *type; 44368548Smckusick ufs_daddr_t blk; 44416261Smckusick { 44516261Smckusick 44644934Smckusick pfatal("%ld %s I=%lu", blk, type, ino); 44716261Smckusick printf("\n"); 44817936Smckusick switch (statemap[ino]) { 44917936Smckusick 45017936Smckusick case FSTATE: 45117936Smckusick statemap[ino] = FCLEAR; 45217936Smckusick return; 45317936Smckusick 45417936Smckusick case DSTATE: 45517936Smckusick statemap[ino] = DCLEAR; 45617936Smckusick return; 45717936Smckusick 45817936Smckusick case FCLEAR: 45917936Smckusick case DCLEAR: 46017936Smckusick return; 46117936Smckusick 46217936Smckusick default: 463*68908Smckusick errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]); 46417936Smckusick /* NOTREACHED */ 46517936Smckusick } 46616261Smckusick } 46717955Smckusick 46817955Smckusick /* 46917955Smckusick * allocate an unused inode 47017955Smckusick */ 47117955Smckusick ino_t 47217955Smckusick allocino(request, type) 47317955Smckusick ino_t request; 47417955Smckusick int type; 47517955Smckusick { 47617955Smckusick register ino_t ino; 47739973Smckusick register struct dinode *dp; 47817955Smckusick 47917955Smckusick if (request == 0) 48017955Smckusick request = ROOTINO; 48117955Smckusick else if (statemap[request] != USTATE) 48217955Smckusick return (0); 48339973Smckusick for (ino = request; ino < maxino; ino++) 48417955Smckusick if (statemap[ino] == USTATE) 48517955Smckusick break; 48639973Smckusick if (ino == maxino) 48717955Smckusick return (0); 48817955Smckusick switch (type & IFMT) { 48917955Smckusick case IFDIR: 49017955Smckusick statemap[ino] = DSTATE; 49117955Smckusick break; 49217955Smckusick case IFREG: 49317955Smckusick case IFLNK: 49417955Smckusick statemap[ino] = FSTATE; 49517955Smckusick break; 49617955Smckusick default: 49717955Smckusick return (0); 49817955Smckusick } 49917955Smckusick dp = ginode(ino); 50039973Smckusick dp->di_db[0] = allocblk((long)1); 50117955Smckusick if (dp->di_db[0] == 0) { 50217955Smckusick statemap[ino] = USTATE; 50317955Smckusick return (0); 50417955Smckusick } 50517955Smckusick dp->di_mode = type; 50668548Smckusick (void)time(&dp->di_atime); 50717955Smckusick dp->di_mtime = dp->di_ctime = dp->di_atime; 50817955Smckusick dp->di_size = sblock.fs_fsize; 50917955Smckusick dp->di_blocks = btodb(sblock.fs_fsize); 51017955Smckusick n_files++; 51117955Smckusick inodirty(); 51266277Smkm if (newinofmt) 51366277Smkm typemap[ino] = IFTODT(type); 51417955Smckusick return (ino); 51517955Smckusick } 51617955Smckusick 51717955Smckusick /* 51817955Smckusick * deallocate an inode 51917955Smckusick */ 520*68908Smckusick void 52117955Smckusick freeino(ino) 52217955Smckusick ino_t ino; 52317955Smckusick { 52417955Smckusick struct inodesc idesc; 52539973Smckusick struct dinode *dp; 52617955Smckusick 52717955Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 52817955Smckusick idesc.id_type = ADDR; 52917955Smckusick idesc.id_func = pass4check; 53017955Smckusick idesc.id_number = ino; 53117955Smckusick dp = ginode(ino); 53217955Smckusick (void)ckinode(dp, &idesc); 53339973Smckusick clearinode(dp); 53417955Smckusick inodirty(); 53517955Smckusick statemap[ino] = USTATE; 53617955Smckusick n_files--; 53717955Smckusick } 538