122046Sdist /* 239976Smckusick * Copyright (c) 1980, 1986 The Regents of the University of California. 339976Smckusick * All rights reserved. 439976Smckusick * 542701Sbostic * %sccs.include.redist.c% 622046Sdist */ 722046Sdist 816261Smckusick #ifndef lint 9*44934Smckusick static char sccsid[] = "@(#)inode.c 5.16 (Berkeley) 07/20/90"; 1039976Smckusick #endif /* not lint */ 1116261Smckusick 1216261Smckusick #include <sys/param.h> 1339383Smckusick #include <ufs/dinode.h> 1438336Smckusick #include <ufs/fs.h> 1538336Smckusick #include <ufs/dir.h> 1636963Sbostic #include <pwd.h> 17*44934Smckusick #include <stdlib.h> 18*44934Smckusick #include <string.h> 1916261Smckusick #include "fsck.h" 2016261Smckusick 2140647Smckusick static ino_t startinum; 2234225Smckusick 2316261Smckusick ckinode(dp, idesc) 2439973Smckusick struct dinode *dp; 2516261Smckusick register struct inodesc *idesc; 2616261Smckusick { 2716261Smckusick register daddr_t *ap; 2839973Smckusick long ret, n, ndb, offset; 2939973Smckusick struct dinode dino; 3016261Smckusick 3118000Smckusick idesc->id_fix = DONTKNOW; 3218000Smckusick idesc->id_entryno = 0; 3318000Smckusick idesc->id_filesize = dp->di_size; 3439973Smckusick if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR) 3516261Smckusick return (KEEPON); 3616261Smckusick dino = *dp; 3716261Smckusick ndb = howmany(dino.di_size, sblock.fs_bsize); 3816261Smckusick for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 3916261Smckusick if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 4016261Smckusick idesc->id_numfrags = 4116261Smckusick numfrags(&sblock, fragroundup(&sblock, offset)); 4216261Smckusick else 4316261Smckusick idesc->id_numfrags = sblock.fs_frag; 4416261Smckusick if (*ap == 0) 4516261Smckusick continue; 4616261Smckusick idesc->id_blkno = *ap; 4716261Smckusick if (idesc->id_type == ADDR) 4816261Smckusick ret = (*idesc->id_func)(idesc); 4916261Smckusick else 5016261Smckusick ret = dirscan(idesc); 5116261Smckusick if (ret & STOP) 5216261Smckusick return (ret); 5316261Smckusick } 5416261Smckusick idesc->id_numfrags = sblock.fs_frag; 5517930Smckusick for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 5616261Smckusick if (*ap) { 5716261Smckusick idesc->id_blkno = *ap; 5816261Smckusick ret = iblock(idesc, n, 5916261Smckusick dino.di_size - sblock.fs_bsize * NDADDR); 6016261Smckusick if (ret & STOP) 6116261Smckusick return (ret); 6216261Smckusick } 6316261Smckusick } 6416261Smckusick return (KEEPON); 6516261Smckusick } 6616261Smckusick 6716261Smckusick iblock(idesc, ilevel, isize) 6816261Smckusick struct inodesc *idesc; 6939973Smckusick register long ilevel; 70*44934Smckusick u_long isize; 7116261Smckusick { 7216261Smckusick register daddr_t *ap; 7316261Smckusick register daddr_t *aplim; 7417930Smckusick int i, n, (*func)(), nif, sizepb; 7539973Smckusick register struct bufarea *bp; 7623876Smckusick char buf[BUFSIZ]; 7733083Sbostic extern int dirscan(), pass1check(); 7816261Smckusick 7916261Smckusick if (idesc->id_type == ADDR) { 8016261Smckusick func = idesc->id_func; 8116261Smckusick if (((n = (*func)(idesc)) & KEEPON) == 0) 8216261Smckusick return (n); 8316261Smckusick } else 8416261Smckusick func = dirscan; 8539973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 8616261Smckusick return (SKIP); 8734225Smckusick bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 8816261Smckusick ilevel--; 8917930Smckusick for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 9017930Smckusick sizepb *= NINDIR(&sblock); 9117930Smckusick nif = isize / sizepb + 1; 9216261Smckusick if (nif > NINDIR(&sblock)) 9316261Smckusick nif = NINDIR(&sblock); 9417950Smckusick if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 9534225Smckusick aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 9634225Smckusick for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 9717950Smckusick if (*ap == 0) 9817950Smckusick continue; 99*44934Smckusick (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 10023876Smckusick idesc->id_number); 10123876Smckusick if (dofix(idesc, buf)) { 10217950Smckusick *ap = 0; 10334225Smckusick dirty(bp); 10417950Smckusick } 10517950Smckusick } 10639973Smckusick flush(fswritefd, bp); 10717950Smckusick } 10834225Smckusick aplim = &bp->b_un.b_indir[nif]; 10934225Smckusick for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) { 11016261Smckusick if (*ap) { 11116261Smckusick idesc->id_blkno = *ap; 11216261Smckusick if (ilevel > 0) 11317930Smckusick n = iblock(idesc, ilevel, isize - i * sizepb); 11416261Smckusick else 11516261Smckusick n = (*func)(idesc); 11634225Smckusick if (n & STOP) { 11734225Smckusick bp->b_flags &= ~B_INUSE; 11816261Smckusick return (n); 11934225Smckusick } 12016261Smckusick } 12134225Smckusick } 12234225Smckusick bp->b_flags &= ~B_INUSE; 12316261Smckusick return (KEEPON); 12416261Smckusick } 12516261Smckusick 12639973Smckusick /* 12739973Smckusick * Check that a block in a legal block number. 12839973Smckusick * Return 0 if in range, 1 if out of range. 12939973Smckusick */ 13039973Smckusick chkrange(blk, cnt) 13116261Smckusick daddr_t blk; 13216261Smckusick int cnt; 13316261Smckusick { 13416261Smckusick register int c; 13516261Smckusick 13639973Smckusick if ((unsigned)(blk + cnt) > maxfsblock) 13716261Smckusick return (1); 13816261Smckusick c = dtog(&sblock, blk); 13916261Smckusick if (blk < cgdmin(&sblock, c)) { 14039973Smckusick if ((blk + cnt) > cgsblock(&sblock, c)) { 14116261Smckusick if (debug) { 142*44934Smckusick printf("blk %ld < cgdmin %ld;", 14316261Smckusick blk, cgdmin(&sblock, c)); 144*44934Smckusick printf(" blk + cnt %ld > cgsbase %ld\n", 14539973Smckusick blk + cnt, cgsblock(&sblock, c)); 14616261Smckusick } 14716261Smckusick return (1); 14816261Smckusick } 14916261Smckusick } else { 15039973Smckusick if ((blk + cnt) > cgbase(&sblock, c+1)) { 15116261Smckusick if (debug) { 152*44934Smckusick printf("blk %ld >= cgdmin %ld;", 15316261Smckusick blk, cgdmin(&sblock, c)); 154*44934Smckusick printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 15516261Smckusick blk+cnt, sblock.fs_fpg); 15616261Smckusick } 15716261Smckusick return (1); 15816261Smckusick } 15916261Smckusick } 16016261Smckusick return (0); 16116261Smckusick } 16216261Smckusick 16340024Smckusick /* 16440024Smckusick * General purpose interface for reading inodes. 16540024Smckusick */ 16639973Smckusick struct dinode * 16716261Smckusick ginode(inumber) 16816261Smckusick ino_t inumber; 16916261Smckusick { 17016261Smckusick daddr_t iblk; 17116261Smckusick 17239973Smckusick if (inumber < ROOTINO || inumber > maxino) 17317943Smckusick errexit("bad inode number %d to ginode\n", inumber); 17416261Smckusick if (startinum == 0 || 17516261Smckusick inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 17616261Smckusick iblk = itod(&sblock, inumber); 17734225Smckusick if (pbp != 0) 17834225Smckusick pbp->b_flags &= ~B_INUSE; 17934225Smckusick pbp = getdatablk(iblk, sblock.fs_bsize); 18016261Smckusick startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 18116261Smckusick } 18234225Smckusick return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 18316261Smckusick } 18416261Smckusick 18540024Smckusick /* 18640024Smckusick * Special purpose version of ginode used to optimize first pass 18740024Smckusick * over all the inodes in numerical order. 18840024Smckusick */ 18940024Smckusick ino_t nextino, lastinum; 19040024Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 19140024Smckusick struct dinode *inodebuf; 19240024Smckusick 19340024Smckusick struct dinode * 19440024Smckusick getnextinode(inumber) 19540024Smckusick ino_t inumber; 19640024Smckusick { 19740024Smckusick long size; 19840024Smckusick daddr_t dblk; 19940024Smckusick static struct dinode *dp; 20040024Smckusick 20140024Smckusick if (inumber != nextino++ || inumber > maxino) 20240024Smckusick errexit("bad inode number %d to nextinode\n", inumber); 20340024Smckusick if (inumber >= lastinum) { 20440024Smckusick readcnt++; 20540024Smckusick dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 20640024Smckusick if (readcnt % readpercg == 0) { 20740024Smckusick size = partialsize; 20840024Smckusick lastinum += partialcnt; 20940024Smckusick } else { 21040024Smckusick size = inobufsize; 21140024Smckusick lastinum += fullcnt; 21240024Smckusick } 213*44934Smckusick (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ 21440024Smckusick dp = inodebuf; 21540024Smckusick } 21640024Smckusick return (dp++); 21740024Smckusick } 21840024Smckusick 21940024Smckusick resetinodebuf() 22040024Smckusick { 22140024Smckusick 22240647Smckusick startinum = 0; 22340024Smckusick nextino = 0; 22440024Smckusick lastinum = 0; 22540024Smckusick readcnt = 0; 22640024Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 22740024Smckusick fullcnt = inobufsize / sizeof(struct dinode); 22840024Smckusick readpercg = sblock.fs_ipg / fullcnt; 22940024Smckusick partialcnt = sblock.fs_ipg % fullcnt; 23040024Smckusick partialsize = partialcnt * sizeof(struct dinode); 23140024Smckusick if (partialcnt != 0) { 23240024Smckusick readpercg++; 23340024Smckusick } else { 23440024Smckusick partialcnt = fullcnt; 23540024Smckusick partialsize = inobufsize; 23640024Smckusick } 23740024Smckusick if (inodebuf == NULL && 23840024Smckusick (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 23940024Smckusick errexit("Cannot allocate space for inode buffer\n"); 24040024Smckusick while (nextino < ROOTINO) 241*44934Smckusick (void)getnextinode(nextino); 24240024Smckusick } 24340024Smckusick 24440024Smckusick freeinodebuf() 24540024Smckusick { 24640024Smckusick 24740024Smckusick if (inodebuf != NULL) 24840024Smckusick free((char *)inodebuf); 24940024Smckusick inodebuf = NULL; 25040024Smckusick } 25140024Smckusick 25240024Smckusick /* 25340024Smckusick * Routines to maintain information about directory inodes. 25440024Smckusick * This is built during the first pass and used during the 25540024Smckusick * second and third passes. 25640024Smckusick * 25740024Smckusick * Enter inodes into the cache. 25840024Smckusick */ 25939980Smckusick cacheino(dp, inumber) 26039980Smckusick register struct dinode *dp; 26139980Smckusick ino_t inumber; 26239980Smckusick { 26339980Smckusick register struct inoinfo *inp; 26439980Smckusick struct inoinfo **inpp; 26539980Smckusick unsigned int blks; 26639980Smckusick 26739980Smckusick blks = howmany(dp->di_size, sblock.fs_bsize); 26839980Smckusick if (blks > NDADDR) 26939980Smckusick blks = NDADDR + NIADDR; 27039980Smckusick inp = (struct inoinfo *) 27139980Smckusick malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); 27239980Smckusick if (inp == NULL) 27339980Smckusick return; 27440024Smckusick inpp = &inphead[inumber % numdirs]; 27540024Smckusick inp->i_nexthash = *inpp; 27639980Smckusick *inpp = inp; 27740024Smckusick inp->i_parent = (ino_t)0; 27840024Smckusick inp->i_dotdot = (ino_t)0; 27939980Smckusick inp->i_number = inumber; 28040024Smckusick inp->i_isize = dp->di_size; 28139980Smckusick inp->i_numblks = blks * sizeof(daddr_t); 28240024Smckusick bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], 283*44934Smckusick (size_t)inp->i_numblks); 28440024Smckusick if (inplast == listmax) { 28540024Smckusick listmax += 100; 28640024Smckusick inpsort = (struct inoinfo **)realloc((char *)inpsort, 28740024Smckusick (unsigned)listmax * sizeof(struct inoinfo *)); 28840024Smckusick if (inpsort == NULL) 28940024Smckusick errexit("cannot increase directory list"); 29040024Smckusick } 29140024Smckusick inpsort[inplast++] = inp; 29239980Smckusick } 29339980Smckusick 29440024Smckusick /* 29540024Smckusick * Look up an inode cache structure. 29640024Smckusick */ 29740024Smckusick struct inoinfo * 29840024Smckusick getinoinfo(inumber) 29939980Smckusick ino_t inumber; 30039980Smckusick { 30139980Smckusick register struct inoinfo *inp; 30239980Smckusick 30340024Smckusick for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 30439980Smckusick if (inp->i_number != inumber) 30539980Smckusick continue; 30640024Smckusick return (inp); 30739980Smckusick } 30840024Smckusick errexit("cannot find inode %d\n", inumber); 30940024Smckusick return ((struct inoinfo *)0); 31039980Smckusick } 31139980Smckusick 31240024Smckusick /* 31340024Smckusick * Clean up all the inode cache structure. 31440024Smckusick */ 31539980Smckusick inocleanup() 31639980Smckusick { 31740024Smckusick register struct inoinfo **inpp; 31839980Smckusick 31939980Smckusick if (inphead == NULL) 32039980Smckusick return; 32140024Smckusick for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 32240024Smckusick free((char *)(*inpp)); 32340024Smckusick free((char *)inphead); 32440024Smckusick free((char *)inpsort); 32540024Smckusick inphead = inpsort = NULL; 32639980Smckusick } 32739980Smckusick 32834225Smckusick inodirty() 32934225Smckusick { 33034225Smckusick 33134225Smckusick dirty(pbp); 33234225Smckusick } 33334225Smckusick 33439973Smckusick clri(idesc, type, flag) 33516261Smckusick register struct inodesc *idesc; 33639973Smckusick char *type; 33739973Smckusick int flag; 33816261Smckusick { 33939973Smckusick register struct dinode *dp; 34016261Smckusick 34117943Smckusick dp = ginode(idesc->id_number); 34239973Smckusick if (flag == 1) { 34339973Smckusick pwarn("%s %s", type, 34439973Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 34516261Smckusick pinode(idesc->id_number); 34616261Smckusick } 34716261Smckusick if (preen || reply("CLEAR") == 1) { 34816261Smckusick if (preen) 34916261Smckusick printf(" (CLEARED)\n"); 35016261Smckusick n_files--; 35116261Smckusick (void)ckinode(dp, idesc); 35239973Smckusick clearinode(dp); 35316261Smckusick statemap[idesc->id_number] = USTATE; 35416261Smckusick inodirty(); 35516261Smckusick } 35616261Smckusick } 35716261Smckusick 35817991Smckusick findname(idesc) 35917991Smckusick struct inodesc *idesc; 36017991Smckusick { 36139973Smckusick register struct direct *dirp = idesc->id_dirp; 36217991Smckusick 36317991Smckusick if (dirp->d_ino != idesc->id_parent) 36417991Smckusick return (KEEPON); 365*44934Smckusick bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); 36630354Smckusick return (STOP|FOUND); 36717991Smckusick } 36817991Smckusick 36916261Smckusick findino(idesc) 37016261Smckusick struct inodesc *idesc; 37116261Smckusick { 37239973Smckusick register struct direct *dirp = idesc->id_dirp; 37316261Smckusick 37416261Smckusick if (dirp->d_ino == 0) 37516261Smckusick return (KEEPON); 37617991Smckusick if (strcmp(dirp->d_name, idesc->id_name) == 0 && 37739973Smckusick dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 37817991Smckusick idesc->id_parent = dirp->d_ino; 37930354Smckusick return (STOP|FOUND); 38016261Smckusick } 38116261Smckusick return (KEEPON); 38216261Smckusick } 38316261Smckusick 38416261Smckusick pinode(ino) 38516261Smckusick ino_t ino; 38616261Smckusick { 38739973Smckusick register struct dinode *dp; 38816261Smckusick register char *p; 38918102Smckusick struct passwd *pw; 39016261Smckusick char *ctime(); 39116261Smckusick 392*44934Smckusick printf(" I=%lu ", ino); 39339973Smckusick if (ino < ROOTINO || ino > maxino) 39416261Smckusick return; 39517943Smckusick dp = ginode(ino); 39616261Smckusick printf(" OWNER="); 39718102Smckusick if ((pw = getpwuid((int)dp->di_uid)) != 0) 39818102Smckusick printf("%s ", pw->pw_name); 39918102Smckusick else 400*44934Smckusick printf("%u ", (unsigned)dp->di_uid); 40116261Smckusick printf("MODE=%o\n", dp->di_mode); 40216261Smckusick if (preen) 40316261Smckusick printf("%s: ", devname); 404*44934Smckusick printf("SIZE=%lu ", dp->di_size); 40516261Smckusick p = ctime(&dp->di_mtime); 40639973Smckusick printf("MTIME=%12.12s %4.4s ", p + 4, p + 20); 40716261Smckusick } 40816261Smckusick 40939973Smckusick blkerror(ino, type, blk) 41016261Smckusick ino_t ino; 41139973Smckusick char *type; 41216261Smckusick daddr_t blk; 41316261Smckusick { 41416261Smckusick 415*44934Smckusick pfatal("%ld %s I=%lu", blk, type, ino); 41616261Smckusick printf("\n"); 41717936Smckusick switch (statemap[ino]) { 41817936Smckusick 41917936Smckusick case FSTATE: 42017936Smckusick statemap[ino] = FCLEAR; 42117936Smckusick return; 42217936Smckusick 42317936Smckusick case DSTATE: 42417936Smckusick statemap[ino] = DCLEAR; 42517936Smckusick return; 42617936Smckusick 42717936Smckusick case FCLEAR: 42817936Smckusick case DCLEAR: 42917936Smckusick return; 43017936Smckusick 43117936Smckusick default: 43217936Smckusick errexit("BAD STATE %d TO BLKERR", statemap[ino]); 43317936Smckusick /* NOTREACHED */ 43417936Smckusick } 43516261Smckusick } 43617955Smckusick 43717955Smckusick /* 43817955Smckusick * allocate an unused inode 43917955Smckusick */ 44017955Smckusick ino_t 44117955Smckusick allocino(request, type) 44217955Smckusick ino_t request; 44317955Smckusick int type; 44417955Smckusick { 44517955Smckusick register ino_t ino; 44639973Smckusick register struct dinode *dp; 44717955Smckusick 44817955Smckusick if (request == 0) 44917955Smckusick request = ROOTINO; 45017955Smckusick else if (statemap[request] != USTATE) 45117955Smckusick return (0); 45239973Smckusick for (ino = request; ino < maxino; ino++) 45317955Smckusick if (statemap[ino] == USTATE) 45417955Smckusick break; 45539973Smckusick if (ino == maxino) 45617955Smckusick return (0); 45717955Smckusick switch (type & IFMT) { 45817955Smckusick case IFDIR: 45917955Smckusick statemap[ino] = DSTATE; 46017955Smckusick break; 46117955Smckusick case IFREG: 46217955Smckusick case IFLNK: 46317955Smckusick statemap[ino] = FSTATE; 46417955Smckusick break; 46517955Smckusick default: 46617955Smckusick return (0); 46717955Smckusick } 46817955Smckusick dp = ginode(ino); 46939973Smckusick dp->di_db[0] = allocblk((long)1); 47017955Smckusick if (dp->di_db[0] == 0) { 47117955Smckusick statemap[ino] = USTATE; 47217955Smckusick return (0); 47317955Smckusick } 47417955Smckusick dp->di_mode = type; 475*44934Smckusick (void)time(&dp->di_atime); 47617955Smckusick dp->di_mtime = dp->di_ctime = dp->di_atime; 47717955Smckusick dp->di_size = sblock.fs_fsize; 47817955Smckusick dp->di_blocks = btodb(sblock.fs_fsize); 47917955Smckusick n_files++; 48017955Smckusick inodirty(); 48117955Smckusick return (ino); 48217955Smckusick } 48317955Smckusick 48417955Smckusick /* 48517955Smckusick * deallocate an inode 48617955Smckusick */ 48717955Smckusick freeino(ino) 48817955Smckusick ino_t ino; 48917955Smckusick { 49017955Smckusick struct inodesc idesc; 49117955Smckusick extern int pass4check(); 49239973Smckusick struct dinode *dp; 49317955Smckusick 49417955Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 49517955Smckusick idesc.id_type = ADDR; 49617955Smckusick idesc.id_func = pass4check; 49717955Smckusick idesc.id_number = ino; 49817955Smckusick dp = ginode(ino); 49917955Smckusick (void)ckinode(dp, &idesc); 50039973Smckusick clearinode(dp); 50117955Smckusick inodirty(); 50217955Smckusick statemap[ino] = USTATE; 50317955Smckusick n_files--; 50417955Smckusick } 505