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*52983Smckusick static char sccsid[] = "@(#)inode.c 5.20 (Berkeley) 03/16/92"; 1039976Smckusick #endif /* not lint */ 1116261Smckusick 1216261Smckusick #include <sys/param.h> 1351532Sbostic #include <ufs/ufs/dinode.h> 1451532Sbostic #include <ufs/ufs/dir.h> 1551532Sbostic #include <ufs/ffs/fs.h> 1636963Sbostic #include <pwd.h> 1744934Smckusick #include <stdlib.h> 1844934Smckusick #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 3144998Smckusick if (idesc->id_fix != IGNORE) 3244998Smckusick idesc->id_fix = DONTKNOW; 3318000Smckusick idesc->id_entryno = 0; 3418000Smckusick idesc->id_filesize = dp->di_size; 3539973Smckusick if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR) 3616261Smckusick return (KEEPON); 3716261Smckusick dino = *dp; 3816261Smckusick ndb = howmany(dino.di_size, sblock.fs_bsize); 3916261Smckusick for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 4016261Smckusick if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 4116261Smckusick idesc->id_numfrags = 4216261Smckusick numfrags(&sblock, fragroundup(&sblock, offset)); 4316261Smckusick else 4416261Smckusick idesc->id_numfrags = sblock.fs_frag; 4516261Smckusick if (*ap == 0) 4616261Smckusick continue; 4716261Smckusick idesc->id_blkno = *ap; 4816261Smckusick if (idesc->id_type == ADDR) 4916261Smckusick ret = (*idesc->id_func)(idesc); 5016261Smckusick else 5116261Smckusick ret = dirscan(idesc); 5216261Smckusick if (ret & STOP) 5316261Smckusick return (ret); 5416261Smckusick } 5516261Smckusick idesc->id_numfrags = sblock.fs_frag; 5617930Smckusick for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 5716261Smckusick if (*ap) { 5816261Smckusick idesc->id_blkno = *ap; 5916261Smckusick ret = iblock(idesc, n, 6016261Smckusick dino.di_size - sblock.fs_bsize * NDADDR); 6116261Smckusick if (ret & STOP) 6216261Smckusick return (ret); 6316261Smckusick } 6416261Smckusick } 6516261Smckusick return (KEEPON); 6616261Smckusick } 6716261Smckusick 6816261Smckusick iblock(idesc, ilevel, isize) 6916261Smckusick struct inodesc *idesc; 7039973Smckusick register long ilevel; 71*52983Smckusick quad_t isize; 7216261Smckusick { 7316261Smckusick register daddr_t *ap; 7416261Smckusick register daddr_t *aplim; 7517930Smckusick int i, n, (*func)(), nif, sizepb; 7639973Smckusick register struct bufarea *bp; 7723876Smckusick char buf[BUFSIZ]; 7833083Sbostic extern int dirscan(), pass1check(); 7916261Smckusick 8016261Smckusick if (idesc->id_type == ADDR) { 8116261Smckusick func = idesc->id_func; 8216261Smckusick if (((n = (*func)(idesc)) & KEEPON) == 0) 8316261Smckusick return (n); 8416261Smckusick } else 8516261Smckusick func = dirscan; 8639973Smckusick if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 8716261Smckusick return (SKIP); 8834225Smckusick bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 8916261Smckusick ilevel--; 9017930Smckusick for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 9117930Smckusick sizepb *= NINDIR(&sblock); 9217930Smckusick nif = isize / sizepb + 1; 9316261Smckusick if (nif > NINDIR(&sblock)) 9416261Smckusick nif = NINDIR(&sblock); 9517950Smckusick if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 9634225Smckusick aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 9734225Smckusick for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 9817950Smckusick if (*ap == 0) 9917950Smckusick continue; 10044934Smckusick (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 10123876Smckusick idesc->id_number); 10223876Smckusick if (dofix(idesc, buf)) { 10317950Smckusick *ap = 0; 10434225Smckusick dirty(bp); 10517950Smckusick } 10617950Smckusick } 10739973Smckusick flush(fswritefd, bp); 10817950Smckusick } 10934225Smckusick aplim = &bp->b_un.b_indir[nif]; 11034225Smckusick for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) { 11116261Smckusick if (*ap) { 11216261Smckusick idesc->id_blkno = *ap; 11316261Smckusick if (ilevel > 0) 11417930Smckusick n = iblock(idesc, ilevel, isize - i * sizepb); 11516261Smckusick else 11616261Smckusick n = (*func)(idesc); 11734225Smckusick if (n & STOP) { 11834225Smckusick bp->b_flags &= ~B_INUSE; 11916261Smckusick return (n); 12034225Smckusick } 12116261Smckusick } 12234225Smckusick } 12334225Smckusick bp->b_flags &= ~B_INUSE; 12416261Smckusick return (KEEPON); 12516261Smckusick } 12616261Smckusick 12739973Smckusick /* 12839973Smckusick * Check that a block in a legal block number. 12939973Smckusick * Return 0 if in range, 1 if out of range. 13039973Smckusick */ 13139973Smckusick chkrange(blk, cnt) 13216261Smckusick daddr_t blk; 13316261Smckusick int cnt; 13416261Smckusick { 13516261Smckusick register int c; 13616261Smckusick 13739973Smckusick if ((unsigned)(blk + cnt) > maxfsblock) 13816261Smckusick return (1); 13916261Smckusick c = dtog(&sblock, blk); 14016261Smckusick if (blk < cgdmin(&sblock, c)) { 14139973Smckusick if ((blk + cnt) > cgsblock(&sblock, c)) { 14216261Smckusick if (debug) { 14344934Smckusick printf("blk %ld < cgdmin %ld;", 14416261Smckusick blk, cgdmin(&sblock, c)); 14544934Smckusick printf(" blk + cnt %ld > cgsbase %ld\n", 14639973Smckusick blk + cnt, cgsblock(&sblock, c)); 14716261Smckusick } 14816261Smckusick return (1); 14916261Smckusick } 15016261Smckusick } else { 15139973Smckusick if ((blk + cnt) > cgbase(&sblock, c+1)) { 15216261Smckusick if (debug) { 15344934Smckusick printf("blk %ld >= cgdmin %ld;", 15416261Smckusick blk, cgdmin(&sblock, c)); 15544934Smckusick printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 15616261Smckusick blk+cnt, sblock.fs_fpg); 15716261Smckusick } 15816261Smckusick return (1); 15916261Smckusick } 16016261Smckusick } 16116261Smckusick return (0); 16216261Smckusick } 16316261Smckusick 16440024Smckusick /* 16540024Smckusick * General purpose interface for reading inodes. 16640024Smckusick */ 16739973Smckusick struct dinode * 16816261Smckusick ginode(inumber) 16916261Smckusick ino_t inumber; 17016261Smckusick { 17116261Smckusick daddr_t iblk; 17216261Smckusick 17339973Smckusick if (inumber < ROOTINO || inumber > maxino) 17417943Smckusick errexit("bad inode number %d to ginode\n", inumber); 17516261Smckusick if (startinum == 0 || 17616261Smckusick inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 17716261Smckusick iblk = itod(&sblock, inumber); 17834225Smckusick if (pbp != 0) 17934225Smckusick pbp->b_flags &= ~B_INUSE; 18034225Smckusick pbp = getdatablk(iblk, sblock.fs_bsize); 18116261Smckusick startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 18216261Smckusick } 18334225Smckusick return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 18416261Smckusick } 18516261Smckusick 18640024Smckusick /* 18740024Smckusick * Special purpose version of ginode used to optimize first pass 18840024Smckusick * over all the inodes in numerical order. 18940024Smckusick */ 19040024Smckusick ino_t nextino, lastinum; 19140024Smckusick long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 19240024Smckusick struct dinode *inodebuf; 19340024Smckusick 19440024Smckusick struct dinode * 19540024Smckusick getnextinode(inumber) 19640024Smckusick ino_t inumber; 19740024Smckusick { 19840024Smckusick long size; 19940024Smckusick daddr_t dblk; 20040024Smckusick static struct dinode *dp; 20140024Smckusick 20240024Smckusick if (inumber != nextino++ || inumber > maxino) 20340024Smckusick errexit("bad inode number %d to nextinode\n", inumber); 20440024Smckusick if (inumber >= lastinum) { 20540024Smckusick readcnt++; 20640024Smckusick dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 20740024Smckusick if (readcnt % readpercg == 0) { 20840024Smckusick size = partialsize; 20940024Smckusick lastinum += partialcnt; 21040024Smckusick } else { 21140024Smckusick size = inobufsize; 21240024Smckusick lastinum += fullcnt; 21340024Smckusick } 21444934Smckusick (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ 21540024Smckusick dp = inodebuf; 21640024Smckusick } 21740024Smckusick return (dp++); 21840024Smckusick } 21940024Smckusick 22040024Smckusick resetinodebuf() 22140024Smckusick { 22240024Smckusick 22340647Smckusick startinum = 0; 22440024Smckusick nextino = 0; 22540024Smckusick lastinum = 0; 22640024Smckusick readcnt = 0; 22740024Smckusick inobufsize = blkroundup(&sblock, INOBUFSIZE); 22840024Smckusick fullcnt = inobufsize / sizeof(struct dinode); 22940024Smckusick readpercg = sblock.fs_ipg / fullcnt; 23040024Smckusick partialcnt = sblock.fs_ipg % fullcnt; 23140024Smckusick partialsize = partialcnt * sizeof(struct dinode); 23240024Smckusick if (partialcnt != 0) { 23340024Smckusick readpercg++; 23440024Smckusick } else { 23540024Smckusick partialcnt = fullcnt; 23640024Smckusick partialsize = inobufsize; 23740024Smckusick } 23840024Smckusick if (inodebuf == NULL && 23940024Smckusick (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 24040024Smckusick errexit("Cannot allocate space for inode buffer\n"); 24140024Smckusick while (nextino < ROOTINO) 24244934Smckusick (void)getnextinode(nextino); 24340024Smckusick } 24440024Smckusick 24540024Smckusick freeinodebuf() 24640024Smckusick { 24740024Smckusick 24840024Smckusick if (inodebuf != NULL) 24940024Smckusick free((char *)inodebuf); 25040024Smckusick inodebuf = NULL; 25140024Smckusick } 25240024Smckusick 25340024Smckusick /* 25440024Smckusick * Routines to maintain information about directory inodes. 25540024Smckusick * This is built during the first pass and used during the 25640024Smckusick * second and third passes. 25740024Smckusick * 25840024Smckusick * Enter inodes into the cache. 25940024Smckusick */ 26039980Smckusick cacheino(dp, inumber) 26139980Smckusick register struct dinode *dp; 26239980Smckusick ino_t inumber; 26339980Smckusick { 26439980Smckusick register struct inoinfo *inp; 26539980Smckusick struct inoinfo **inpp; 26639980Smckusick unsigned int blks; 26739980Smckusick 26839980Smckusick blks = howmany(dp->di_size, sblock.fs_bsize); 26939980Smckusick if (blks > NDADDR) 27039980Smckusick blks = NDADDR + NIADDR; 27139980Smckusick inp = (struct inoinfo *) 27239980Smckusick malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); 27339980Smckusick if (inp == NULL) 27439980Smckusick return; 27540024Smckusick inpp = &inphead[inumber % numdirs]; 27640024Smckusick inp->i_nexthash = *inpp; 27739980Smckusick *inpp = inp; 27840024Smckusick inp->i_parent = (ino_t)0; 27940024Smckusick inp->i_dotdot = (ino_t)0; 28039980Smckusick inp->i_number = inumber; 28140024Smckusick inp->i_isize = dp->di_size; 28239980Smckusick inp->i_numblks = blks * sizeof(daddr_t); 28340024Smckusick bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], 28444934Smckusick (size_t)inp->i_numblks); 28540024Smckusick if (inplast == listmax) { 28640024Smckusick listmax += 100; 28740024Smckusick inpsort = (struct inoinfo **)realloc((char *)inpsort, 28840024Smckusick (unsigned)listmax * sizeof(struct inoinfo *)); 28940024Smckusick if (inpsort == NULL) 29040024Smckusick errexit("cannot increase directory list"); 29140024Smckusick } 29240024Smckusick inpsort[inplast++] = inp; 29339980Smckusick } 29439980Smckusick 29540024Smckusick /* 29640024Smckusick * Look up an inode cache structure. 29740024Smckusick */ 29840024Smckusick struct inoinfo * 29940024Smckusick getinoinfo(inumber) 30039980Smckusick ino_t inumber; 30139980Smckusick { 30239980Smckusick register struct inoinfo *inp; 30339980Smckusick 30440024Smckusick for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 30539980Smckusick if (inp->i_number != inumber) 30639980Smckusick continue; 30740024Smckusick return (inp); 30839980Smckusick } 30940024Smckusick errexit("cannot find inode %d\n", inumber); 31040024Smckusick return ((struct inoinfo *)0); 31139980Smckusick } 31239980Smckusick 31340024Smckusick /* 31440024Smckusick * Clean up all the inode cache structure. 31540024Smckusick */ 31639980Smckusick inocleanup() 31739980Smckusick { 31840024Smckusick register struct inoinfo **inpp; 31939980Smckusick 32039980Smckusick if (inphead == NULL) 32139980Smckusick return; 32240024Smckusick for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 32340024Smckusick free((char *)(*inpp)); 32440024Smckusick free((char *)inphead); 32540024Smckusick free((char *)inpsort); 32640024Smckusick inphead = inpsort = NULL; 32739980Smckusick } 32839980Smckusick 32934225Smckusick inodirty() 33034225Smckusick { 33134225Smckusick 33234225Smckusick dirty(pbp); 33334225Smckusick } 33434225Smckusick 33539973Smckusick clri(idesc, type, flag) 33616261Smckusick register struct inodesc *idesc; 33739973Smckusick char *type; 33839973Smckusick int flag; 33916261Smckusick { 34039973Smckusick register struct dinode *dp; 34116261Smckusick 34217943Smckusick dp = ginode(idesc->id_number); 34339973Smckusick if (flag == 1) { 34439973Smckusick pwarn("%s %s", type, 34539973Smckusick (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 34616261Smckusick pinode(idesc->id_number); 34716261Smckusick } 34816261Smckusick if (preen || reply("CLEAR") == 1) { 34916261Smckusick if (preen) 35016261Smckusick printf(" (CLEARED)\n"); 35116261Smckusick n_files--; 35216261Smckusick (void)ckinode(dp, idesc); 35339973Smckusick clearinode(dp); 35416261Smckusick statemap[idesc->id_number] = USTATE; 35516261Smckusick inodirty(); 35616261Smckusick } 35716261Smckusick } 35816261Smckusick 35917991Smckusick findname(idesc) 36017991Smckusick struct inodesc *idesc; 36117991Smckusick { 36239973Smckusick register struct direct *dirp = idesc->id_dirp; 36317991Smckusick 36417991Smckusick if (dirp->d_ino != idesc->id_parent) 36517991Smckusick return (KEEPON); 36644934Smckusick bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); 36730354Smckusick return (STOP|FOUND); 36817991Smckusick } 36917991Smckusick 37016261Smckusick findino(idesc) 37116261Smckusick struct inodesc *idesc; 37216261Smckusick { 37339973Smckusick register struct direct *dirp = idesc->id_dirp; 37416261Smckusick 37516261Smckusick if (dirp->d_ino == 0) 37616261Smckusick return (KEEPON); 37717991Smckusick if (strcmp(dirp->d_name, idesc->id_name) == 0 && 37839973Smckusick dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 37917991Smckusick idesc->id_parent = dirp->d_ino; 38030354Smckusick return (STOP|FOUND); 38116261Smckusick } 38216261Smckusick return (KEEPON); 38316261Smckusick } 38416261Smckusick 38516261Smckusick pinode(ino) 38616261Smckusick ino_t ino; 38716261Smckusick { 38839973Smckusick register struct dinode *dp; 38916261Smckusick register char *p; 39018102Smckusick struct passwd *pw; 39116261Smckusick char *ctime(); 39216261Smckusick 39344934Smckusick printf(" I=%lu ", ino); 39439973Smckusick if (ino < ROOTINO || ino > maxino) 39516261Smckusick return; 39617943Smckusick dp = ginode(ino); 39716261Smckusick printf(" OWNER="); 39818102Smckusick if ((pw = getpwuid((int)dp->di_uid)) != 0) 39918102Smckusick printf("%s ", pw->pw_name); 40018102Smckusick else 40144934Smckusick printf("%u ", (unsigned)dp->di_uid); 40216261Smckusick printf("MODE=%o\n", dp->di_mode); 40316261Smckusick if (preen) 40416261Smckusick printf("%s: ", devname); 40544934Smckusick printf("SIZE=%lu ", dp->di_size); 40616261Smckusick p = ctime(&dp->di_mtime); 40747579Smckusick printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 40816261Smckusick } 40916261Smckusick 41039973Smckusick blkerror(ino, type, blk) 41116261Smckusick ino_t ino; 41239973Smckusick char *type; 41316261Smckusick daddr_t blk; 41416261Smckusick { 41516261Smckusick 41644934Smckusick pfatal("%ld %s I=%lu", blk, type, ino); 41716261Smckusick printf("\n"); 41817936Smckusick switch (statemap[ino]) { 41917936Smckusick 42017936Smckusick case FSTATE: 42117936Smckusick statemap[ino] = FCLEAR; 42217936Smckusick return; 42317936Smckusick 42417936Smckusick case DSTATE: 42517936Smckusick statemap[ino] = DCLEAR; 42617936Smckusick return; 42717936Smckusick 42817936Smckusick case FCLEAR: 42917936Smckusick case DCLEAR: 43017936Smckusick return; 43117936Smckusick 43217936Smckusick default: 43317936Smckusick errexit("BAD STATE %d TO BLKERR", statemap[ino]); 43417936Smckusick /* NOTREACHED */ 43517936Smckusick } 43616261Smckusick } 43717955Smckusick 43817955Smckusick /* 43917955Smckusick * allocate an unused inode 44017955Smckusick */ 44117955Smckusick ino_t 44217955Smckusick allocino(request, type) 44317955Smckusick ino_t request; 44417955Smckusick int type; 44517955Smckusick { 44617955Smckusick register ino_t ino; 44739973Smckusick register struct dinode *dp; 44817955Smckusick 44917955Smckusick if (request == 0) 45017955Smckusick request = ROOTINO; 45117955Smckusick else if (statemap[request] != USTATE) 45217955Smckusick return (0); 45339973Smckusick for (ino = request; ino < maxino; ino++) 45417955Smckusick if (statemap[ino] == USTATE) 45517955Smckusick break; 45639973Smckusick if (ino == maxino) 45717955Smckusick return (0); 45817955Smckusick switch (type & IFMT) { 45917955Smckusick case IFDIR: 46017955Smckusick statemap[ino] = DSTATE; 46117955Smckusick break; 46217955Smckusick case IFREG: 46317955Smckusick case IFLNK: 46417955Smckusick statemap[ino] = FSTATE; 46517955Smckusick break; 46617955Smckusick default: 46717955Smckusick return (0); 46817955Smckusick } 46917955Smckusick dp = ginode(ino); 47039973Smckusick dp->di_db[0] = allocblk((long)1); 47117955Smckusick if (dp->di_db[0] == 0) { 47217955Smckusick statemap[ino] = USTATE; 47317955Smckusick return (0); 47417955Smckusick } 47517955Smckusick dp->di_mode = type; 47644934Smckusick (void)time(&dp->di_atime); 47717955Smckusick dp->di_mtime = dp->di_ctime = dp->di_atime; 47817955Smckusick dp->di_size = sblock.fs_fsize; 47917955Smckusick dp->di_blocks = btodb(sblock.fs_fsize); 48017955Smckusick n_files++; 48117955Smckusick inodirty(); 48217955Smckusick return (ino); 48317955Smckusick } 48417955Smckusick 48517955Smckusick /* 48617955Smckusick * deallocate an inode 48717955Smckusick */ 48817955Smckusick freeino(ino) 48917955Smckusick ino_t ino; 49017955Smckusick { 49117955Smckusick struct inodesc idesc; 49217955Smckusick extern int pass4check(); 49339973Smckusick struct dinode *dp; 49417955Smckusick 49517955Smckusick bzero((char *)&idesc, sizeof(struct inodesc)); 49617955Smckusick idesc.id_type = ADDR; 49717955Smckusick idesc.id_func = pass4check; 49817955Smckusick idesc.id_number = ino; 49917955Smckusick dp = ginode(ino); 50017955Smckusick (void)ckinode(dp, &idesc); 50139973Smckusick clearinode(dp); 50217955Smckusick inodirty(); 50317955Smckusick statemap[ino] = USTATE; 50417955Smckusick n_files--; 50517955Smckusick } 506