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*66898Smckusick static char sccsid[] = "@(#)inode.c 8.4 (Berkeley) 04/18/94"; 1039976Smckusick #endif /* not lint */ 1116261Smckusick 1216261Smckusick #include <sys/param.h> 1353821Smckusick #include <sys/time.h> 1451532Sbostic #include <ufs/ufs/dinode.h> 1551532Sbostic #include <ufs/ufs/dir.h> 1651532Sbostic #include <ufs/ffs/fs.h> 1736963Sbostic #include <pwd.h> 1844934Smckusick #include <stdlib.h> 1944934Smckusick #include <string.h> 2016261Smckusick #include "fsck.h" 2116261Smckusick 2240647Smckusick static ino_t startinum; 2334225Smckusick 2416261Smckusick ckinode(dp, idesc) 2539973Smckusick struct dinode *dp; 2616261Smckusick register struct inodesc *idesc; 2716261Smckusick { 2816261Smckusick register daddr_t *ap; 2939973Smckusick long ret, n, ndb, offset; 3039973Smckusick struct dinode dino; 3153825Smckusick quad_t remsize, sizepb; 3254599Smckusick mode_t mode; 3316261Smckusick 3444998Smckusick if (idesc->id_fix != IGNORE) 3544998Smckusick idesc->id_fix = DONTKNOW; 3618000Smckusick idesc->id_entryno = 0; 3718000Smckusick idesc->id_filesize = dp->di_size; 3854599Smckusick mode = dp->di_mode & IFMT; 3954599Smckusick if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 4054599Smckusick dp->di_size < sblock.fs_maxsymlinklen)) 4116261Smckusick return (KEEPON); 4216261Smckusick dino = *dp; 4316261Smckusick ndb = howmany(dino.di_size, sblock.fs_bsize); 4416261Smckusick for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 4516261Smckusick if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 4616261Smckusick idesc->id_numfrags = 4716261Smckusick numfrags(&sblock, fragroundup(&sblock, offset)); 4816261Smckusick else 4916261Smckusick idesc->id_numfrags = sblock.fs_frag; 5016261Smckusick if (*ap == 0) 5116261Smckusick continue; 5216261Smckusick idesc->id_blkno = *ap; 5316261Smckusick if (idesc->id_type == ADDR) 5416261Smckusick ret = (*idesc->id_func)(idesc); 5516261Smckusick else 5616261Smckusick ret = dirscan(idesc); 5716261Smckusick if (ret & STOP) 5816261Smckusick return (ret); 5916261Smckusick } 6016261Smckusick idesc->id_numfrags = sblock.fs_frag; 6153825Smckusick remsize = dino.di_size - sblock.fs_bsize * NDADDR; 6253825Smckusick sizepb = sblock.fs_bsize; 6317930Smckusick for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 6416261Smckusick if (*ap) { 6516261Smckusick idesc->id_blkno = *ap; 6653825Smckusick ret = iblock(idesc, n, remsize); 6716261Smckusick if (ret & STOP) 6816261Smckusick return (ret); 6916261Smckusick } 7053825Smckusick sizepb *= NINDIR(&sblock); 7153825Smckusick remsize -= sizepb; 7216261Smckusick } 7316261Smckusick return (KEEPON); 7416261Smckusick } 7516261Smckusick 7616261Smckusick iblock(idesc, ilevel, isize) 7716261Smckusick struct inodesc *idesc; 7853825Smckusick long ilevel; 7952983Smckusick quad_t isize; 8016261Smckusick { 8116261Smckusick register daddr_t *ap; 8216261Smckusick register daddr_t *aplim; 8339973Smckusick register struct bufarea *bp; 8453821Smckusick int i, n, (*func)(), nif; 8553821Smckusick quad_t sizepb; 8623876Smckusick char buf[BUFSIZ]; 8733083Sbostic extern int dirscan(), pass1check(); 8816261Smckusick 8916261Smckusick if (idesc->id_type == ADDR) { 9016261Smckusick func = idesc->id_func; 9116261Smckusick if (((n = (*func)(idesc)) & KEEPON) == 0) 9216261Smckusick return (n); 9316261Smckusick } else 9416261Smckusick func = dirscan; 9539973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 9616261Smckusick return (SKIP); 9734225Smckusick bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 9816261Smckusick ilevel--; 9917930Smckusick for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 10017930Smckusick sizepb *= NINDIR(&sblock); 10153825Smckusick nif = howmany(isize , sizepb); 10216261Smckusick if (nif > NINDIR(&sblock)) 10316261Smckusick nif = NINDIR(&sblock); 10417950Smckusick if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 10534225Smckusick aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 10634225Smckusick for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 10717950Smckusick if (*ap == 0) 10817950Smckusick continue; 10944934Smckusick (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 11023876Smckusick idesc->id_number); 11123876Smckusick if (dofix(idesc, buf)) { 11217950Smckusick *ap = 0; 11334225Smckusick dirty(bp); 11417950Smckusick } 11517950Smckusick } 11639973Smckusick flush(fswritefd, bp); 11717950Smckusick } 11834225Smckusick aplim = &bp->b_un.b_indir[nif]; 11953825Smckusick for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 12016261Smckusick if (*ap) { 12116261Smckusick idesc->id_blkno = *ap; 122*66898Smckusick if (ilevel == 0) 12316261Smckusick n = (*func)(idesc); 124*66898Smckusick else 12553825Smckusick n = iblock(idesc, ilevel, isize); 12634225Smckusick if (n & STOP) { 12734225Smckusick bp->b_flags &= ~B_INUSE; 12816261Smckusick return (n); 12934225Smckusick } 13016261Smckusick } 131*66898Smckusick isize -= sizepb; 13234225Smckusick } 13334225Smckusick bp->b_flags &= ~B_INUSE; 13416261Smckusick return (KEEPON); 13516261Smckusick } 13616261Smckusick 13739973Smckusick /* 13839973Smckusick * Check that a block in a legal block number. 13939973Smckusick * Return 0 if in range, 1 if out of range. 14039973Smckusick */ 14139973Smckusick chkrange(blk, cnt) 14216261Smckusick daddr_t blk; 14316261Smckusick int cnt; 14416261Smckusick { 14516261Smckusick register int c; 14616261Smckusick 14739973Smckusick if ((unsigned)(blk + cnt) > maxfsblock) 14816261Smckusick return (1); 14916261Smckusick c = dtog(&sblock, blk); 15016261Smckusick if (blk < cgdmin(&sblock, c)) { 15139973Smckusick if ((blk + cnt) > cgsblock(&sblock, c)) { 15216261Smckusick if (debug) { 15344934Smckusick printf("blk %ld < cgdmin %ld;", 15416261Smckusick blk, cgdmin(&sblock, c)); 15544934Smckusick printf(" blk + cnt %ld > cgsbase %ld\n", 15639973Smckusick blk + cnt, cgsblock(&sblock, c)); 15716261Smckusick } 15816261Smckusick return (1); 15916261Smckusick } 16016261Smckusick } else { 16139973Smckusick if ((blk + cnt) > cgbase(&sblock, c+1)) { 16216261Smckusick if (debug) { 16344934Smckusick printf("blk %ld >= cgdmin %ld;", 16416261Smckusick blk, cgdmin(&sblock, c)); 16544934Smckusick printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 16616261Smckusick blk+cnt, sblock.fs_fpg); 16716261Smckusick } 16816261Smckusick return (1); 16916261Smckusick } 17016261Smckusick } 17116261Smckusick return (0); 17216261Smckusick } 17316261Smckusick 17440024Smckusick /* 17540024Smckusick * General purpose interface for reading inodes. 17640024Smckusick */ 17739973Smckusick struct dinode * 17816261Smckusick ginode(inumber) 17916261Smckusick ino_t inumber; 18016261Smckusick { 18116261Smckusick daddr_t iblk; 18216261Smckusick 18339973Smckusick if (inumber < ROOTINO || inumber > maxino) 18417943Smckusick errexit("bad inode number %d to ginode\n", inumber); 18516261Smckusick if (startinum == 0 || 18616261Smckusick inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 18764639Sbostic iblk = ino_to_fsba(&sblock, inumber); 18834225Smckusick if (pbp != 0) 18934225Smckusick pbp->b_flags &= ~B_INUSE; 19034225Smckusick pbp = getdatablk(iblk, sblock.fs_bsize); 19116261Smckusick startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 19216261Smckusick } 19334225Smckusick return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 19416261Smckusick } 19516261Smckusick 19640024Smckusick /* 19740024Smckusick * Special purpose version of ginode used to optimize first pass 19840024Smckusick * over all the inodes in numerical order. 19940024Smckusick */ 20040024Smckusick ino_t nextino, lastinum; 20140024Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 20240024Smckusick struct dinode *inodebuf; 20340024Smckusick 20440024Smckusick struct dinode * 20540024Smckusick getnextinode(inumber) 20640024Smckusick ino_t inumber; 20740024Smckusick { 20840024Smckusick long size; 20940024Smckusick daddr_t dblk; 21040024Smckusick static struct dinode *dp; 21140024Smckusick 21240024Smckusick if (inumber != nextino++ || inumber > maxino) 21340024Smckusick errexit("bad inode number %d to nextinode\n", inumber); 21440024Smckusick if (inumber >= lastinum) { 21540024Smckusick readcnt++; 21664639Sbostic dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 21740024Smckusick if (readcnt % readpercg == 0) { 21840024Smckusick size = partialsize; 21940024Smckusick lastinum += partialcnt; 22040024Smckusick } else { 22140024Smckusick size = inobufsize; 22240024Smckusick lastinum += fullcnt; 22340024Smckusick } 22444934Smckusick (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ 22540024Smckusick dp = inodebuf; 22640024Smckusick } 22740024Smckusick return (dp++); 22840024Smckusick } 22940024Smckusick 23040024Smckusick resetinodebuf() 23140024Smckusick { 23240024Smckusick 23340647Smckusick startinum = 0; 23440024Smckusick nextino = 0; 23540024Smckusick lastinum = 0; 23640024Smckusick readcnt = 0; 23740024Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 23840024Smckusick fullcnt = inobufsize / sizeof(struct dinode); 23940024Smckusick readpercg = sblock.fs_ipg / fullcnt; 24040024Smckusick partialcnt = sblock.fs_ipg % fullcnt; 24140024Smckusick partialsize = partialcnt * sizeof(struct dinode); 24240024Smckusick if (partialcnt != 0) { 24340024Smckusick readpercg++; 24440024Smckusick } else { 24540024Smckusick partialcnt = fullcnt; 24640024Smckusick partialsize = inobufsize; 24740024Smckusick } 24840024Smckusick if (inodebuf == NULL && 24940024Smckusick (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 25040024Smckusick errexit("Cannot allocate space for inode buffer\n"); 25140024Smckusick while (nextino < ROOTINO) 25244934Smckusick (void)getnextinode(nextino); 25340024Smckusick } 25440024Smckusick 25540024Smckusick freeinodebuf() 25640024Smckusick { 25740024Smckusick 25840024Smckusick if (inodebuf != NULL) 25940024Smckusick free((char *)inodebuf); 26040024Smckusick inodebuf = NULL; 26140024Smckusick } 26240024Smckusick 26340024Smckusick /* 26440024Smckusick * Routines to maintain information about directory inodes. 26540024Smckusick * This is built during the first pass and used during the 26640024Smckusick * second and third passes. 26740024Smckusick * 26840024Smckusick * Enter inodes into the cache. 26940024Smckusick */ 27039980Smckusick cacheino(dp, inumber) 27139980Smckusick register struct dinode *dp; 27239980Smckusick ino_t inumber; 27339980Smckusick { 27439980Smckusick register struct inoinfo *inp; 27539980Smckusick struct inoinfo **inpp; 27639980Smckusick unsigned int blks; 27739980Smckusick 27839980Smckusick blks = howmany(dp->di_size, sblock.fs_bsize); 27939980Smckusick if (blks > NDADDR) 28039980Smckusick blks = NDADDR + NIADDR; 28139980Smckusick inp = (struct inoinfo *) 28239980Smckusick malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); 28339980Smckusick if (inp == NULL) 28439980Smckusick return; 28540024Smckusick inpp = &inphead[inumber % numdirs]; 28640024Smckusick inp->i_nexthash = *inpp; 28739980Smckusick *inpp = inp; 28840024Smckusick inp->i_parent = (ino_t)0; 28940024Smckusick inp->i_dotdot = (ino_t)0; 29039980Smckusick inp->i_number = inumber; 29140024Smckusick inp->i_isize = dp->di_size; 29239980Smckusick inp->i_numblks = blks * sizeof(daddr_t); 29340024Smckusick bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], 29444934Smckusick (size_t)inp->i_numblks); 29540024Smckusick if (inplast == listmax) { 29640024Smckusick listmax += 100; 29740024Smckusick inpsort = (struct inoinfo **)realloc((char *)inpsort, 29840024Smckusick (unsigned)listmax * sizeof(struct inoinfo *)); 29940024Smckusick if (inpsort == NULL) 30040024Smckusick errexit("cannot increase directory list"); 30140024Smckusick } 30240024Smckusick inpsort[inplast++] = inp; 30339980Smckusick } 30439980Smckusick 30540024Smckusick /* 30640024Smckusick * Look up an inode cache structure. 30740024Smckusick */ 30840024Smckusick struct inoinfo * 30940024Smckusick getinoinfo(inumber) 31039980Smckusick ino_t inumber; 31139980Smckusick { 31239980Smckusick register struct inoinfo *inp; 31339980Smckusick 31440024Smckusick for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 31539980Smckusick if (inp->i_number != inumber) 31639980Smckusick continue; 31740024Smckusick return (inp); 31839980Smckusick } 31940024Smckusick errexit("cannot find inode %d\n", inumber); 32040024Smckusick return ((struct inoinfo *)0); 32139980Smckusick } 32239980Smckusick 32340024Smckusick /* 32440024Smckusick * Clean up all the inode cache structure. 32540024Smckusick */ 32639980Smckusick inocleanup() 32739980Smckusick { 32840024Smckusick register struct inoinfo **inpp; 32939980Smckusick 33039980Smckusick if (inphead == NULL) 33139980Smckusick return; 33240024Smckusick for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 33340024Smckusick free((char *)(*inpp)); 33440024Smckusick free((char *)inphead); 33540024Smckusick free((char *)inpsort); 33640024Smckusick inphead = inpsort = NULL; 33739980Smckusick } 33839980Smckusick 33934225Smckusick inodirty() 34034225Smckusick { 34134225Smckusick 34234225Smckusick dirty(pbp); 34334225Smckusick } 34434225Smckusick 34539973Smckusick clri(idesc, type, flag) 34616261Smckusick register struct inodesc *idesc; 34739973Smckusick char *type; 34839973Smckusick int flag; 34916261Smckusick { 35039973Smckusick register struct dinode *dp; 35116261Smckusick 35217943Smckusick dp = ginode(idesc->id_number); 35339973Smckusick if (flag == 1) { 35439973Smckusick pwarn("%s %s", type, 35539973Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 35616261Smckusick pinode(idesc->id_number); 35716261Smckusick } 35816261Smckusick if (preen || reply("CLEAR") == 1) { 35916261Smckusick if (preen) 36016261Smckusick printf(" (CLEARED)\n"); 36116261Smckusick n_files--; 36216261Smckusick (void)ckinode(dp, idesc); 36339973Smckusick clearinode(dp); 36416261Smckusick statemap[idesc->id_number] = USTATE; 36516261Smckusick inodirty(); 36616261Smckusick } 36716261Smckusick } 36816261Smckusick 36917991Smckusick findname(idesc) 37017991Smckusick struct inodesc *idesc; 37117991Smckusick { 37239973Smckusick register struct direct *dirp = idesc->id_dirp; 37317991Smckusick 37417991Smckusick if (dirp->d_ino != idesc->id_parent) 37517991Smckusick return (KEEPON); 37644934Smckusick bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); 37730354Smckusick return (STOP|FOUND); 37817991Smckusick } 37917991Smckusick 38016261Smckusick findino(idesc) 38116261Smckusick struct inodesc *idesc; 38216261Smckusick { 38339973Smckusick register struct direct *dirp = idesc->id_dirp; 38416261Smckusick 38516261Smckusick if (dirp->d_ino == 0) 38616261Smckusick return (KEEPON); 38717991Smckusick if (strcmp(dirp->d_name, idesc->id_name) == 0 && 38839973Smckusick dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 38917991Smckusick idesc->id_parent = dirp->d_ino; 39030354Smckusick return (STOP|FOUND); 39116261Smckusick } 39216261Smckusick return (KEEPON); 39316261Smckusick } 39416261Smckusick 39516261Smckusick pinode(ino) 39616261Smckusick ino_t ino; 39716261Smckusick { 39839973Smckusick register struct dinode *dp; 39916261Smckusick register char *p; 40018102Smckusick struct passwd *pw; 40116261Smckusick char *ctime(); 40216261Smckusick 40344934Smckusick printf(" I=%lu ", ino); 40439973Smckusick if (ino < ROOTINO || ino > maxino) 40516261Smckusick return; 40617943Smckusick dp = ginode(ino); 40716261Smckusick printf(" OWNER="); 40818102Smckusick if ((pw = getpwuid((int)dp->di_uid)) != 0) 40918102Smckusick printf("%s ", pw->pw_name); 41018102Smckusick else 41144934Smckusick printf("%u ", (unsigned)dp->di_uid); 41216261Smckusick printf("MODE=%o\n", dp->di_mode); 41316261Smckusick if (preen) 41461110Sbostic printf("%s: ", cdevname); 41553821Smckusick printf("SIZE=%qu ", dp->di_size); 41654068Smckusick p = ctime(&dp->di_mtime.ts_sec); 41747579Smckusick printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 41816261Smckusick } 41916261Smckusick 42039973Smckusick blkerror(ino, type, blk) 42116261Smckusick ino_t ino; 42239973Smckusick char *type; 42316261Smckusick daddr_t blk; 42416261Smckusick { 42516261Smckusick 42644934Smckusick pfatal("%ld %s I=%lu", blk, type, ino); 42716261Smckusick printf("\n"); 42817936Smckusick switch (statemap[ino]) { 42917936Smckusick 43017936Smckusick case FSTATE: 43117936Smckusick statemap[ino] = FCLEAR; 43217936Smckusick return; 43317936Smckusick 43417936Smckusick case DSTATE: 43517936Smckusick statemap[ino] = DCLEAR; 43617936Smckusick return; 43717936Smckusick 43817936Smckusick case FCLEAR: 43917936Smckusick case DCLEAR: 44017936Smckusick return; 44117936Smckusick 44217936Smckusick default: 44317936Smckusick errexit("BAD STATE %d TO BLKERR", statemap[ino]); 44417936Smckusick /* NOTREACHED */ 44517936Smckusick } 44616261Smckusick } 44717955Smckusick 44817955Smckusick /* 44917955Smckusick * allocate an unused inode 45017955Smckusick */ 45117955Smckusick ino_t 45217955Smckusick allocino(request, type) 45317955Smckusick ino_t request; 45417955Smckusick int type; 45517955Smckusick { 45617955Smckusick register ino_t ino; 45739973Smckusick register struct dinode *dp; 45817955Smckusick 45917955Smckusick if (request == 0) 46017955Smckusick request = ROOTINO; 46117955Smckusick else if (statemap[request] != USTATE) 46217955Smckusick return (0); 46339973Smckusick for (ino = request; ino < maxino; ino++) 46417955Smckusick if (statemap[ino] == USTATE) 46517955Smckusick break; 46639973Smckusick if (ino == maxino) 46717955Smckusick return (0); 46817955Smckusick switch (type & IFMT) { 46917955Smckusick case IFDIR: 47017955Smckusick statemap[ino] = DSTATE; 47117955Smckusick break; 47217955Smckusick case IFREG: 47317955Smckusick case IFLNK: 47417955Smckusick statemap[ino] = FSTATE; 47517955Smckusick break; 47617955Smckusick default: 47717955Smckusick return (0); 47817955Smckusick } 47917955Smckusick dp = ginode(ino); 48039973Smckusick dp->di_db[0] = allocblk((long)1); 48117955Smckusick if (dp->di_db[0] == 0) { 48217955Smckusick statemap[ino] = USTATE; 48317955Smckusick return (0); 48417955Smckusick } 48517955Smckusick dp->di_mode = type; 48654068Smckusick (void)time(&dp->di_atime.ts_sec); 48717955Smckusick dp->di_mtime = dp->di_ctime = dp->di_atime; 48817955Smckusick dp->di_size = sblock.fs_fsize; 48917955Smckusick dp->di_blocks = btodb(sblock.fs_fsize); 49017955Smckusick n_files++; 49117955Smckusick inodirty(); 49266277Smkm if (newinofmt) 49366277Smkm typemap[ino] = IFTODT(type); 49417955Smckusick return (ino); 49517955Smckusick } 49617955Smckusick 49717955Smckusick /* 49817955Smckusick * deallocate an inode 49917955Smckusick */ 50017955Smckusick freeino(ino) 50117955Smckusick ino_t ino; 50217955Smckusick { 50317955Smckusick struct inodesc idesc; 50417955Smckusick extern int pass4check(); 50539973Smckusick struct dinode *dp; 50617955Smckusick 50717955Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 50817955Smckusick idesc.id_type = ADDR; 50917955Smckusick idesc.id_func = pass4check; 51017955Smckusick idesc.id_number = ino; 51117955Smckusick dp = ginode(ino); 51217955Smckusick (void)ckinode(dp, &idesc); 51339973Smckusick clearinode(dp); 51417955Smckusick inodirty(); 51517955Smckusick statemap[ino] = USTATE; 51617955Smckusick n_files--; 51717955Smckusick } 518