inode.c revision 92839
11558Srgrimes/* 21558Srgrimes * Copyright (c) 1980, 1986, 1993 31558Srgrimes * The Regents of the University of California. All rights reserved. 41558Srgrimes * 51558Srgrimes * Redistribution and use in source and binary forms, with or without 61558Srgrimes * modification, are permitted provided that the following conditions 71558Srgrimes * are met: 81558Srgrimes * 1. Redistributions of source code must retain the above copyright 91558Srgrimes * notice, this list of conditions and the following disclaimer. 101558Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111558Srgrimes * notice, this list of conditions and the following disclaimer in the 121558Srgrimes * documentation and/or other materials provided with the distribution. 131558Srgrimes * 3. All advertising materials mentioning features or use of this software 141558Srgrimes * must display the following acknowledgement: 151558Srgrimes * This product includes software developed by the University of 161558Srgrimes * California, Berkeley and its contributors. 171558Srgrimes * 4. Neither the name of the University nor the names of its contributors 181558Srgrimes * may be used to endorse or promote products derived from this software 191558Srgrimes * without specific prior written permission. 201558Srgrimes * 211558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311558Srgrimes * SUCH DAMAGE. 321558Srgrimes */ 331558Srgrimes 341558Srgrimes#ifndef lint 3541477Sjulian#if 0 3623675Speterstatic const char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95"; 3741477Sjulian#endif 3841477Sjulianstatic const char rcsid[] = 3950476Speter "$FreeBSD: head/sbin/fsck_ffs/inode.c 92839 2002-03-20 22:57:10Z imp $"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 431558Srgrimes#include <sys/time.h> 4474556Smckusick#include <sys/sysctl.h> 4523675Speter 461558Srgrimes#include <ufs/ufs/dinode.h> 471558Srgrimes#include <ufs/ufs/dir.h> 481558Srgrimes#include <ufs/ffs/fs.h> 4923675Speter 5023675Speter#include <err.h> 511558Srgrimes#include <pwd.h> 521558Srgrimes#include <string.h> 5323675Speter 541558Srgrimes#include "fsck.h" 551558Srgrimes 561558Srgrimesstatic ino_t startinum; 571558Srgrimes 5892839Simpstatic int iblock(struct inodesc *, long ilevel, quad_t isize); 597585Sbde 607585Sbdeint 6192839Simpckinode(struct dinode *dp, struct inodesc *idesc) 621558Srgrimes{ 6323675Speter ufs_daddr_t *ap; 6441474Sjulian int ret; 6541474Sjulian long n, ndb, offset; 661558Srgrimes struct dinode dino; 671558Srgrimes quad_t remsize, sizepb; 681558Srgrimes mode_t mode; 6918808Sguido char pathbuf[MAXPATHLEN + 1]; 701558Srgrimes 711558Srgrimes if (idesc->id_fix != IGNORE) 721558Srgrimes idesc->id_fix = DONTKNOW; 7362668Smckusick idesc->id_lbn = -1; 741558Srgrimes idesc->id_entryno = 0; 751558Srgrimes idesc->id_filesize = dp->di_size; 761558Srgrimes mode = dp->di_mode & IFMT; 771558Srgrimes if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 7841474Sjulian dp->di_size < (unsigned)sblock.fs_maxsymlinklen)) 791558Srgrimes return (KEEPON); 801558Srgrimes dino = *dp; 811558Srgrimes ndb = howmany(dino.di_size, sblock.fs_bsize); 821558Srgrimes for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 8362668Smckusick idesc->id_lbn++; 841558Srgrimes if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 851558Srgrimes idesc->id_numfrags = 861558Srgrimes numfrags(&sblock, fragroundup(&sblock, offset)); 871558Srgrimes else 881558Srgrimes idesc->id_numfrags = sblock.fs_frag; 8918808Sguido if (*ap == 0) { 9018808Sguido if (idesc->id_type == DATA && ndb >= 0) { 9118808Sguido /* An empty block in a directory XXX */ 9218808Sguido getpathname(pathbuf, idesc->id_number, 9318808Sguido idesc->id_number); 9418808Sguido pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 9518808Sguido pathbuf); 9618808Sguido if (reply("ADJUST LENGTH") == 1) { 9718808Sguido dp = ginode(idesc->id_number); 9818808Sguido dp->di_size = (ap - &dino.di_db[0]) * 9918808Sguido sblock.fs_bsize; 10018808Sguido printf( 10118808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 10218808Sguido rerun = 1; 10318808Sguido inodirty(); 10418808Sguido 10518808Sguido } 10618808Sguido } 1071558Srgrimes continue; 10818808Sguido } 1091558Srgrimes idesc->id_blkno = *ap; 11062668Smckusick if (idesc->id_type != DATA) 1111558Srgrimes ret = (*idesc->id_func)(idesc); 1121558Srgrimes else 1131558Srgrimes ret = dirscan(idesc); 1141558Srgrimes if (ret & STOP) 1151558Srgrimes return (ret); 1161558Srgrimes } 1171558Srgrimes idesc->id_numfrags = sblock.fs_frag; 1181558Srgrimes remsize = dino.di_size - sblock.fs_bsize * NDADDR; 1191558Srgrimes sizepb = sblock.fs_bsize; 1201558Srgrimes for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 12162668Smckusick sizepb *= NINDIR(&sblock); 1221558Srgrimes if (*ap) { 1231558Srgrimes idesc->id_blkno = *ap; 1241558Srgrimes ret = iblock(idesc, n, remsize); 1251558Srgrimes if (ret & STOP) 1261558Srgrimes return (ret); 12718808Sguido } else { 12862668Smckusick idesc->id_lbn += sizepb / sblock.fs_bsize; 12918808Sguido if (idesc->id_type == DATA && remsize > 0) { 13018808Sguido /* An empty block in a directory XXX */ 13118808Sguido getpathname(pathbuf, idesc->id_number, 13218808Sguido idesc->id_number); 13318808Sguido pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 13418808Sguido pathbuf); 13518808Sguido if (reply("ADJUST LENGTH") == 1) { 13618808Sguido dp = ginode(idesc->id_number); 13718808Sguido dp->di_size -= remsize; 13818808Sguido remsize = 0; 13918808Sguido printf( 14018808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 14118808Sguido rerun = 1; 14218808Sguido inodirty(); 14318808Sguido break; 14418808Sguido } 14518808Sguido } 1461558Srgrimes } 1471558Srgrimes remsize -= sizepb; 1481558Srgrimes } 1491558Srgrimes return (KEEPON); 1501558Srgrimes} 1511558Srgrimes 1527585Sbdestatic int 15392839Simpiblock(struct inodesc *idesc, long ilevel, quad_t isize) 1541558Srgrimes{ 15523675Speter ufs_daddr_t *ap; 15623675Speter ufs_daddr_t *aplim; 15723675Speter struct bufarea *bp; 1581558Srgrimes int i, n, (*func)(), nif; 1591558Srgrimes quad_t sizepb; 1601558Srgrimes char buf[BUFSIZ]; 16118808Sguido char pathbuf[MAXPATHLEN + 1]; 16218808Sguido struct dinode *dp; 1631558Srgrimes 16462668Smckusick if (idesc->id_type != DATA) { 1651558Srgrimes func = idesc->id_func; 1661558Srgrimes if (((n = (*func)(idesc)) & KEEPON) == 0) 1671558Srgrimes return (n); 1681558Srgrimes } else 1691558Srgrimes func = dirscan; 1701558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 1711558Srgrimes return (SKIP); 1721558Srgrimes bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 1731558Srgrimes ilevel--; 1741558Srgrimes for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 1751558Srgrimes sizepb *= NINDIR(&sblock); 1761558Srgrimes nif = howmany(isize , sizepb); 1771558Srgrimes if (nif > NINDIR(&sblock)) 1781558Srgrimes nif = NINDIR(&sblock); 1791558Srgrimes if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 1801558Srgrimes aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 1811558Srgrimes for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 1821558Srgrimes if (*ap == 0) 1831558Srgrimes continue; 1841558Srgrimes (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 18537236Sbde (u_long)idesc->id_number); 18676352Smckusick if (preen) { 18781911Skris pfatal("%s", buf); 18874556Smckusick } else if (dofix(idesc, buf)) { 1891558Srgrimes *ap = 0; 1901558Srgrimes dirty(bp); 1911558Srgrimes } 1921558Srgrimes } 1931558Srgrimes flush(fswritefd, bp); 1941558Srgrimes } 1951558Srgrimes aplim = &bp->b_un.b_indir[nif]; 1961558Srgrimes for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 19762668Smckusick if (ilevel == 0) 19862668Smckusick idesc->id_lbn++; 1991558Srgrimes if (*ap) { 2001558Srgrimes idesc->id_blkno = *ap; 2011558Srgrimes if (ilevel == 0) 2021558Srgrimes n = (*func)(idesc); 2031558Srgrimes else 2041558Srgrimes n = iblock(idesc, ilevel, isize); 2051558Srgrimes if (n & STOP) { 2061558Srgrimes bp->b_flags &= ~B_INUSE; 2071558Srgrimes return (n); 2081558Srgrimes } 20918808Sguido } else { 21018808Sguido if (idesc->id_type == DATA && isize > 0) { 21118808Sguido /* An empty block in a directory XXX */ 21218808Sguido getpathname(pathbuf, idesc->id_number, 21318808Sguido idesc->id_number); 21418808Sguido pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 21518808Sguido pathbuf); 21618808Sguido if (reply("ADJUST LENGTH") == 1) { 21718808Sguido dp = ginode(idesc->id_number); 21818808Sguido dp->di_size -= isize; 21918808Sguido isize = 0; 22018808Sguido printf( 22118808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 22218808Sguido rerun = 1; 22318808Sguido inodirty(); 22418808Sguido bp->b_flags &= ~B_INUSE; 22518808Sguido return(STOP); 22618808Sguido } 22718808Sguido } 2281558Srgrimes } 2291558Srgrimes isize -= sizepb; 2301558Srgrimes } 2311558Srgrimes bp->b_flags &= ~B_INUSE; 2321558Srgrimes return (KEEPON); 2331558Srgrimes} 2341558Srgrimes 2351558Srgrimes/* 2361558Srgrimes * Check that a block in a legal block number. 2371558Srgrimes * Return 0 if in range, 1 if out of range. 2381558Srgrimes */ 2397585Sbdeint 24092839Simpchkrange(ufs_daddr_t blk, int cnt) 2411558Srgrimes{ 24292806Sobrien int c; 2431558Srgrimes 24441474Sjulian if (cnt <= 0 || blk <= 0 || blk > maxfsblock || 24541474Sjulian cnt - 1 > maxfsblock - blk) 2461558Srgrimes return (1); 24741474Sjulian if (cnt > sblock.fs_frag || 24841474Sjulian fragnum(&sblock, blk) + cnt > sblock.fs_frag) { 24941474Sjulian if (debug) 25086514Siedowse printf("bad size: blk %ld, offset %i, size %d\n", 25186514Siedowse (long)blk, (int)fragnum(&sblock, blk), cnt); 25241474Sjulian return (1); 25341474Sjulian } 2541558Srgrimes c = dtog(&sblock, blk); 2551558Srgrimes if (blk < cgdmin(&sblock, c)) { 2561558Srgrimes if ((blk + cnt) > cgsblock(&sblock, c)) { 2571558Srgrimes if (debug) { 2581558Srgrimes printf("blk %ld < cgdmin %ld;", 25937236Sbde (long)blk, (long)cgdmin(&sblock, c)); 2601558Srgrimes printf(" blk + cnt %ld > cgsbase %ld\n", 26137236Sbde (long)(blk + cnt), 26237236Sbde (long)cgsblock(&sblock, c)); 2631558Srgrimes } 2641558Srgrimes return (1); 2651558Srgrimes } 2661558Srgrimes } else { 2671558Srgrimes if ((blk + cnt) > cgbase(&sblock, c+1)) { 2681558Srgrimes if (debug) { 2691558Srgrimes printf("blk %ld >= cgdmin %ld;", 27037236Sbde (long)blk, (long)cgdmin(&sblock, c)); 2711558Srgrimes printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 27237236Sbde (long)(blk + cnt), (long)sblock.fs_fpg); 2731558Srgrimes } 2741558Srgrimes return (1); 2751558Srgrimes } 2761558Srgrimes } 2771558Srgrimes return (0); 2781558Srgrimes} 2791558Srgrimes 2801558Srgrimes/* 2811558Srgrimes * General purpose interface for reading inodes. 2821558Srgrimes */ 2831558Srgrimesstruct dinode * 28492839Simpginode(ino_t inumber) 2851558Srgrimes{ 28623675Speter ufs_daddr_t iblk; 2871558Srgrimes 2881558Srgrimes if (inumber < ROOTINO || inumber > maxino) 28923675Speter errx(EEXIT, "bad inode number %d to ginode", inumber); 2901558Srgrimes if (startinum == 0 || 2911558Srgrimes inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 2921558Srgrimes iblk = ino_to_fsba(&sblock, inumber); 2931558Srgrimes if (pbp != 0) 2941558Srgrimes pbp->b_flags &= ~B_INUSE; 2951558Srgrimes pbp = getdatablk(iblk, sblock.fs_bsize); 2961558Srgrimes startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 2971558Srgrimes } 2981558Srgrimes return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 2991558Srgrimes} 3001558Srgrimes 3011558Srgrimes/* 3021558Srgrimes * Special purpose version of ginode used to optimize first pass 3031558Srgrimes * over all the inodes in numerical order. 3041558Srgrimes */ 30588413Salfredstatic ino_t nextino, lastinum, lastvalidinum; 30688413Salfredstatic long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 30788413Salfredstatic struct dinode *inodebuf; 3081558Srgrimes 3091558Srgrimesstruct dinode * 31092839Simpgetnextinode(ino_t inumber) 3111558Srgrimes{ 3121558Srgrimes long size; 31323675Speter ufs_daddr_t dblk; 3141558Srgrimes static struct dinode *dp; 3151558Srgrimes 31663231Smckusick if (inumber != nextino++ || inumber > lastvalidinum) 31723675Speter errx(EEXIT, "bad inode number %d to nextinode", inumber); 3181558Srgrimes if (inumber >= lastinum) { 3191558Srgrimes readcnt++; 3201558Srgrimes dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 3211558Srgrimes if (readcnt % readpercg == 0) { 3221558Srgrimes size = partialsize; 3231558Srgrimes lastinum += partialcnt; 3241558Srgrimes } else { 3251558Srgrimes size = inobufsize; 3261558Srgrimes lastinum += fullcnt; 3271558Srgrimes } 32841474Sjulian /* 32941474Sjulian * If bread returns an error, it will already have zeroed 33041474Sjulian * out the buffer, so we do not need to do so here. 33141474Sjulian */ 33241474Sjulian (void)bread(fsreadfd, (char *)inodebuf, dblk, size); 3331558Srgrimes dp = inodebuf; 3341558Srgrimes } 3351558Srgrimes return (dp++); 3361558Srgrimes} 3371558Srgrimes 3387585Sbdevoid 33992839Simpsetinodebuf(ino_t inum) 3401558Srgrimes{ 3411558Srgrimes 34241474Sjulian if (inum % sblock.fs_ipg != 0) 34341474Sjulian errx(EEXIT, "bad inode number %d to setinodebuf", inum); 34463231Smckusick lastvalidinum = inum + sblock.fs_ipg - 1; 3451558Srgrimes startinum = 0; 34641474Sjulian nextino = inum; 34741474Sjulian lastinum = inum; 3481558Srgrimes readcnt = 0; 34941474Sjulian if (inodebuf != NULL) 35041474Sjulian return; 3511558Srgrimes inobufsize = blkroundup(&sblock, INOBUFSIZE); 3521558Srgrimes fullcnt = inobufsize / sizeof(struct dinode); 3531558Srgrimes readpercg = sblock.fs_ipg / fullcnt; 3541558Srgrimes partialcnt = sblock.fs_ipg % fullcnt; 3551558Srgrimes partialsize = partialcnt * sizeof(struct dinode); 3561558Srgrimes if (partialcnt != 0) { 3571558Srgrimes readpercg++; 3581558Srgrimes } else { 3591558Srgrimes partialcnt = fullcnt; 3601558Srgrimes partialsize = inobufsize; 3611558Srgrimes } 36241474Sjulian if ((inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 36337000Scharnier errx(EEXIT, "cannot allocate space for inode buffer"); 3641558Srgrimes} 3651558Srgrimes 3667585Sbdevoid 36792839Simpfreeinodebuf(void) 3681558Srgrimes{ 3691558Srgrimes 3701558Srgrimes if (inodebuf != NULL) 3711558Srgrimes free((char *)inodebuf); 3721558Srgrimes inodebuf = NULL; 3731558Srgrimes} 3741558Srgrimes 3751558Srgrimes/* 3761558Srgrimes * Routines to maintain information about directory inodes. 3771558Srgrimes * This is built during the first pass and used during the 3781558Srgrimes * second and third passes. 3791558Srgrimes * 3801558Srgrimes * Enter inodes into the cache. 3811558Srgrimes */ 3827585Sbdevoid 38392839Simpcacheino(struct dinode *dp, ino_t inumber) 3841558Srgrimes{ 38592806Sobrien struct inoinfo *inp; 3861558Srgrimes struct inoinfo **inpp; 38738002Sdfr int blks; 3881558Srgrimes 3891558Srgrimes blks = howmany(dp->di_size, sblock.fs_bsize); 3901558Srgrimes if (blks > NDADDR) 3911558Srgrimes blks = NDADDR + NIADDR; 3921558Srgrimes inp = (struct inoinfo *) 39323675Speter malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t)); 3941558Srgrimes if (inp == NULL) 39541474Sjulian errx(EEXIT, "cannot increase directory list"); 39657573Smckusick inpp = &inphead[inumber % dirhash]; 3971558Srgrimes inp->i_nexthash = *inpp; 3981558Srgrimes *inpp = inp; 39941474Sjulian inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0; 4001558Srgrimes inp->i_dotdot = (ino_t)0; 4011558Srgrimes inp->i_number = inumber; 4021558Srgrimes inp->i_isize = dp->di_size; 40323675Speter inp->i_numblks = blks * sizeof(ufs_daddr_t); 40423675Speter memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks); 4051558Srgrimes if (inplast == listmax) { 4061558Srgrimes listmax += 100; 4071558Srgrimes inpsort = (struct inoinfo **)realloc((char *)inpsort, 4081558Srgrimes (unsigned)listmax * sizeof(struct inoinfo *)); 4091558Srgrimes if (inpsort == NULL) 41023675Speter errx(EEXIT, "cannot increase directory list"); 4111558Srgrimes } 4121558Srgrimes inpsort[inplast++] = inp; 4131558Srgrimes} 4141558Srgrimes 4151558Srgrimes/* 4161558Srgrimes * Look up an inode cache structure. 4171558Srgrimes */ 4181558Srgrimesstruct inoinfo * 41992839Simpgetinoinfo(ino_t inumber) 4201558Srgrimes{ 42192806Sobrien struct inoinfo *inp; 4221558Srgrimes 42357573Smckusick for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { 4241558Srgrimes if (inp->i_number != inumber) 4251558Srgrimes continue; 4261558Srgrimes return (inp); 4271558Srgrimes } 42823675Speter errx(EEXIT, "cannot find inode %d", inumber); 4291558Srgrimes return ((struct inoinfo *)0); 4301558Srgrimes} 4311558Srgrimes 4321558Srgrimes/* 4331558Srgrimes * Clean up all the inode cache structure. 4341558Srgrimes */ 4357585Sbdevoid 43692839Simpinocleanup(void) 4371558Srgrimes{ 43892806Sobrien struct inoinfo **inpp; 4391558Srgrimes 4401558Srgrimes if (inphead == NULL) 4411558Srgrimes return; 4421558Srgrimes for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 4431558Srgrimes free((char *)(*inpp)); 4441558Srgrimes free((char *)inphead); 4451558Srgrimes free((char *)inpsort); 4461558Srgrimes inphead = inpsort = NULL; 4471558Srgrimes} 4488871Srgrimes 4497585Sbdevoid 45092839Simpinodirty(void) 4511558Srgrimes{ 45223797Sbde 4531558Srgrimes dirty(pbp); 4541558Srgrimes} 4551558Srgrimes 4567585Sbdevoid 45792839Simpclri(struct inodesc *idesc, char *type, int flag) 4581558Srgrimes{ 45992806Sobrien struct dinode *dp; 4601558Srgrimes 4611558Srgrimes dp = ginode(idesc->id_number); 4621558Srgrimes if (flag == 1) { 4631558Srgrimes pwarn("%s %s", type, 4641558Srgrimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 4651558Srgrimes pinode(idesc->id_number); 4661558Srgrimes } 4671558Srgrimes if (preen || reply("CLEAR") == 1) { 4681558Srgrimes if (preen) 4691558Srgrimes printf(" (CLEARED)\n"); 4701558Srgrimes n_files--; 47174556Smckusick if (bkgrdflag == 0) { 47274556Smckusick (void)ckinode(dp, idesc); 47374556Smckusick inoinfo(idesc->id_number)->ino_state = USTATE; 47474556Smckusick clearinode(dp); 47574556Smckusick inodirty(); 47674556Smckusick } else { 47774556Smckusick cmd.value = idesc->id_number; 47874556Smckusick cmd.size = -dp->di_nlink; 47974556Smckusick if (debug) 48086514Siedowse printf("adjrefcnt ino %ld amt %ld\n", 48174556Smckusick (long)cmd.value, cmd.size); 48274556Smckusick if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 48374556Smckusick &cmd, sizeof cmd) == -1) 48474556Smckusick rwerror("ADJUST INODE", cmd.value); 48574556Smckusick } 4861558Srgrimes } 4871558Srgrimes} 4881558Srgrimes 4897585Sbdeint 49092839Simpfindname(struct inodesc *idesc) 4911558Srgrimes{ 49292806Sobrien struct direct *dirp = idesc->id_dirp; 4931558Srgrimes 49441474Sjulian if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 49541474Sjulian idesc->id_entryno++; 4961558Srgrimes return (KEEPON); 49741474Sjulian } 49823675Speter memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 4991558Srgrimes return (STOP|FOUND); 5001558Srgrimes} 5011558Srgrimes 5027585Sbdeint 50392839Simpfindino(struct inodesc *idesc) 5041558Srgrimes{ 50592806Sobrien struct direct *dirp = idesc->id_dirp; 5061558Srgrimes 5071558Srgrimes if (dirp->d_ino == 0) 5081558Srgrimes return (KEEPON); 5091558Srgrimes if (strcmp(dirp->d_name, idesc->id_name) == 0 && 5101558Srgrimes dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 5111558Srgrimes idesc->id_parent = dirp->d_ino; 5121558Srgrimes return (STOP|FOUND); 5131558Srgrimes } 5141558Srgrimes return (KEEPON); 5151558Srgrimes} 5161558Srgrimes 51741474Sjulianint 51892839Simpclearentry(struct inodesc *idesc) 51941474Sjulian{ 52092806Sobrien struct direct *dirp = idesc->id_dirp; 52141474Sjulian 52241474Sjulian if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 52341474Sjulian idesc->id_entryno++; 52441474Sjulian return (KEEPON); 52541474Sjulian } 52641474Sjulian dirp->d_ino = 0; 52741474Sjulian return (STOP|FOUND|ALTERED); 52841474Sjulian} 52941474Sjulian 5307585Sbdevoid 53192839Simppinode(ino_t ino) 5321558Srgrimes{ 53392806Sobrien struct dinode *dp; 53492806Sobrien char *p; 5351558Srgrimes struct passwd *pw; 53624002Speter time_t t; 5371558Srgrimes 53837236Sbde printf(" I=%lu ", (u_long)ino); 5391558Srgrimes if (ino < ROOTINO || ino > maxino) 5401558Srgrimes return; 5411558Srgrimes dp = ginode(ino); 5421558Srgrimes printf(" OWNER="); 5431558Srgrimes if ((pw = getpwuid((int)dp->di_uid)) != 0) 5441558Srgrimes printf("%s ", pw->pw_name); 5451558Srgrimes else 5461558Srgrimes printf("%u ", (unsigned)dp->di_uid); 5471558Srgrimes printf("MODE=%o\n", dp->di_mode); 5481558Srgrimes if (preen) 5491558Srgrimes printf("%s: ", cdevname); 5501558Srgrimes printf("SIZE=%qu ", dp->di_size); 55124002Speter t = dp->di_mtime; 55224002Speter p = ctime(&t); 5531558Srgrimes printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 5541558Srgrimes} 5551558Srgrimes 5567585Sbdevoid 55792839Simpblkerror(ino_t ino, char *type, ufs_daddr_t blk) 5581558Srgrimes{ 5591558Srgrimes 56086514Siedowse pfatal("%ld %s I=%lu", (long)blk, type, (u_long)ino); 5611558Srgrimes printf("\n"); 56241474Sjulian switch (inoinfo(ino)->ino_state) { 5631558Srgrimes 5641558Srgrimes case FSTATE: 56541474Sjulian inoinfo(ino)->ino_state = FCLEAR; 5661558Srgrimes return; 5671558Srgrimes 5681558Srgrimes case DSTATE: 56941474Sjulian inoinfo(ino)->ino_state = DCLEAR; 5701558Srgrimes return; 5711558Srgrimes 5721558Srgrimes case FCLEAR: 5731558Srgrimes case DCLEAR: 5741558Srgrimes return; 5751558Srgrimes 5761558Srgrimes default: 57741474Sjulian errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state); 5781558Srgrimes /* NOTREACHED */ 5791558Srgrimes } 5801558Srgrimes} 5811558Srgrimes 5821558Srgrimes/* 5831558Srgrimes * allocate an unused inode 5841558Srgrimes */ 5851558Srgrimesino_t 58692839Simpallocino(ino_t request, int type) 5871558Srgrimes{ 58892806Sobrien ino_t ino; 58992806Sobrien struct dinode *dp; 59034266Sjulian struct cg *cgp = &cgrp; 59134266Sjulian int cg; 5921558Srgrimes 5931558Srgrimes if (request == 0) 5941558Srgrimes request = ROOTINO; 59541474Sjulian else if (inoinfo(request)->ino_state != USTATE) 5961558Srgrimes return (0); 5971558Srgrimes for (ino = request; ino < maxino; ino++) 59841474Sjulian if (inoinfo(ino)->ino_state == USTATE) 5991558Srgrimes break; 6001558Srgrimes if (ino == maxino) 6011558Srgrimes return (0); 60234266Sjulian cg = ino_to_cg(&sblock, ino); 60334266Sjulian getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 60434266Sjulian if (!cg_chkmagic(cgp)) 60534266Sjulian pfatal("CG %d: BAD MAGIC NUMBER\n", cg); 60634266Sjulian setbit(cg_inosused(cgp), ino % sblock.fs_ipg); 60734266Sjulian cgp->cg_cs.cs_nifree--; 6081558Srgrimes switch (type & IFMT) { 6091558Srgrimes case IFDIR: 61041474Sjulian inoinfo(ino)->ino_state = DSTATE; 61134266Sjulian cgp->cg_cs.cs_ndir++; 6121558Srgrimes break; 6131558Srgrimes case IFREG: 6141558Srgrimes case IFLNK: 61541474Sjulian inoinfo(ino)->ino_state = FSTATE; 6161558Srgrimes break; 6171558Srgrimes default: 6181558Srgrimes return (0); 6191558Srgrimes } 62034266Sjulian cgdirty(); 6211558Srgrimes dp = ginode(ino); 6221558Srgrimes dp->di_db[0] = allocblk((long)1); 6231558Srgrimes if (dp->di_db[0] == 0) { 62441474Sjulian inoinfo(ino)->ino_state = USTATE; 6251558Srgrimes return (0); 6261558Srgrimes } 62741474Sjulian dp->di_mode = type; 62834266Sjulian dp->di_flags = 0; 62924002Speter dp->di_atime = time(NULL); 6301558Srgrimes dp->di_mtime = dp->di_ctime = dp->di_atime; 63141477Sjulian dp->di_mtimensec = dp->di_ctimensec = dp->di_atimensec = 0; 6321558Srgrimes dp->di_size = sblock.fs_fsize; 6331558Srgrimes dp->di_blocks = btodb(sblock.fs_fsize); 6341558Srgrimes n_files++; 6351558Srgrimes inodirty(); 6361558Srgrimes if (newinofmt) 63741474Sjulian inoinfo(ino)->ino_type = IFTODT(type); 6381558Srgrimes return (ino); 6391558Srgrimes} 6401558Srgrimes 6411558Srgrimes/* 6421558Srgrimes * deallocate an inode 6431558Srgrimes */ 6447585Sbdevoid 64592839Simpfreeino(ino_t ino) 6461558Srgrimes{ 6471558Srgrimes struct inodesc idesc; 6481558Srgrimes struct dinode *dp; 6491558Srgrimes 65023675Speter memset(&idesc, 0, sizeof(struct inodesc)); 6511558Srgrimes idesc.id_type = ADDR; 6521558Srgrimes idesc.id_func = pass4check; 6531558Srgrimes idesc.id_number = ino; 6541558Srgrimes dp = ginode(ino); 6551558Srgrimes (void)ckinode(dp, &idesc); 6561558Srgrimes clearinode(dp); 6571558Srgrimes inodirty(); 65841474Sjulian inoinfo(ino)->ino_state = USTATE; 6591558Srgrimes n_files--; 6601558Srgrimes} 661