inode.c revision 63231
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 63231 2000-07-15 18:28:36Z mckusick $"; 401558Srgrimes#endif /* not lint */ 411558Srgrimes 421558Srgrimes#include <sys/param.h> 431558Srgrimes#include <sys/time.h> 4423675Speter 451558Srgrimes#include <ufs/ufs/dinode.h> 461558Srgrimes#include <ufs/ufs/dir.h> 471558Srgrimes#include <ufs/ffs/fs.h> 4823675Speter 4923675Speter#include <err.h> 501558Srgrimes#include <pwd.h> 511558Srgrimes#include <string.h> 5223675Speter 531558Srgrimes#include "fsck.h" 541558Srgrimes 551558Srgrimesstatic ino_t startinum; 561558Srgrimes 5723675Speterstatic int iblock __P((struct inodesc *, long ilevel, quad_t isize)); 587585Sbde 597585Sbdeint 601558Srgrimesckinode(dp, idesc) 611558Srgrimes struct dinode *dp; 621558Srgrimes register struct inodesc *idesc; 631558Srgrimes{ 6423675Speter ufs_daddr_t *ap; 6541474Sjulian int ret; 6641474Sjulian long n, ndb, offset; 671558Srgrimes struct dinode dino; 681558Srgrimes quad_t remsize, sizepb; 691558Srgrimes mode_t mode; 7018808Sguido char pathbuf[MAXPATHLEN + 1]; 711558Srgrimes 721558Srgrimes if (idesc->id_fix != IGNORE) 731558Srgrimes idesc->id_fix = DONTKNOW; 7462668Smckusick idesc->id_lbn = -1; 751558Srgrimes idesc->id_entryno = 0; 761558Srgrimes idesc->id_filesize = dp->di_size; 771558Srgrimes mode = dp->di_mode & IFMT; 781558Srgrimes if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 7941474Sjulian dp->di_size < (unsigned)sblock.fs_maxsymlinklen)) 801558Srgrimes return (KEEPON); 811558Srgrimes dino = *dp; 821558Srgrimes ndb = howmany(dino.di_size, sblock.fs_bsize); 831558Srgrimes for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 8462668Smckusick idesc->id_lbn++; 851558Srgrimes if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 861558Srgrimes idesc->id_numfrags = 871558Srgrimes numfrags(&sblock, fragroundup(&sblock, offset)); 881558Srgrimes else 891558Srgrimes idesc->id_numfrags = sblock.fs_frag; 9018808Sguido if (*ap == 0) { 9118808Sguido if (idesc->id_type == DATA && ndb >= 0) { 9218808Sguido /* An empty block in a directory XXX */ 9318808Sguido getpathname(pathbuf, idesc->id_number, 9418808Sguido idesc->id_number); 9518808Sguido pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 9618808Sguido pathbuf); 9718808Sguido if (reply("ADJUST LENGTH") == 1) { 9818808Sguido dp = ginode(idesc->id_number); 9918808Sguido dp->di_size = (ap - &dino.di_db[0]) * 10018808Sguido sblock.fs_bsize; 10118808Sguido printf( 10218808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 10318808Sguido rerun = 1; 10418808Sguido inodirty(); 10518808Sguido 10618808Sguido } 10718808Sguido } 1081558Srgrimes continue; 10918808Sguido } 1101558Srgrimes idesc->id_blkno = *ap; 11162668Smckusick if (idesc->id_type != DATA) 1121558Srgrimes ret = (*idesc->id_func)(idesc); 1131558Srgrimes else 1141558Srgrimes ret = dirscan(idesc); 1151558Srgrimes if (ret & STOP) 1161558Srgrimes return (ret); 1171558Srgrimes } 1181558Srgrimes idesc->id_numfrags = sblock.fs_frag; 1191558Srgrimes remsize = dino.di_size - sblock.fs_bsize * NDADDR; 1201558Srgrimes sizepb = sblock.fs_bsize; 1211558Srgrimes for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 12262668Smckusick sizepb *= NINDIR(&sblock); 1231558Srgrimes if (*ap) { 1241558Srgrimes idesc->id_blkno = *ap; 1251558Srgrimes ret = iblock(idesc, n, remsize); 1261558Srgrimes if (ret & STOP) 1271558Srgrimes return (ret); 12818808Sguido } else { 12962668Smckusick idesc->id_lbn += sizepb / sblock.fs_bsize; 13018808Sguido if (idesc->id_type == DATA && remsize > 0) { 13118808Sguido /* An empty block in a directory XXX */ 13218808Sguido getpathname(pathbuf, idesc->id_number, 13318808Sguido idesc->id_number); 13418808Sguido pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 13518808Sguido pathbuf); 13618808Sguido if (reply("ADJUST LENGTH") == 1) { 13718808Sguido dp = ginode(idesc->id_number); 13818808Sguido dp->di_size -= remsize; 13918808Sguido remsize = 0; 14018808Sguido printf( 14118808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 14218808Sguido rerun = 1; 14318808Sguido inodirty(); 14418808Sguido break; 14518808Sguido } 14618808Sguido } 1471558Srgrimes } 1481558Srgrimes remsize -= sizepb; 1491558Srgrimes } 1501558Srgrimes return (KEEPON); 1511558Srgrimes} 1521558Srgrimes 1537585Sbdestatic int 1541558Srgrimesiblock(idesc, ilevel, isize) 1551558Srgrimes struct inodesc *idesc; 1561558Srgrimes long ilevel; 1571558Srgrimes quad_t isize; 1581558Srgrimes{ 15923675Speter ufs_daddr_t *ap; 16023675Speter ufs_daddr_t *aplim; 16123675Speter struct bufarea *bp; 1621558Srgrimes int i, n, (*func)(), nif; 1631558Srgrimes quad_t sizepb; 1641558Srgrimes char buf[BUFSIZ]; 16518808Sguido char pathbuf[MAXPATHLEN + 1]; 16618808Sguido struct dinode *dp; 1671558Srgrimes 16862668Smckusick if (idesc->id_type != DATA) { 1691558Srgrimes func = idesc->id_func; 1701558Srgrimes if (((n = (*func)(idesc)) & KEEPON) == 0) 1711558Srgrimes return (n); 1721558Srgrimes } else 1731558Srgrimes func = dirscan; 1741558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 1751558Srgrimes return (SKIP); 1761558Srgrimes bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 1771558Srgrimes ilevel--; 1781558Srgrimes for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 1791558Srgrimes sizepb *= NINDIR(&sblock); 1801558Srgrimes nif = howmany(isize , sizepb); 1811558Srgrimes if (nif > NINDIR(&sblock)) 1821558Srgrimes nif = NINDIR(&sblock); 1831558Srgrimes if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 1841558Srgrimes aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 1851558Srgrimes for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 1861558Srgrimes if (*ap == 0) 1871558Srgrimes continue; 1881558Srgrimes (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 18937236Sbde (u_long)idesc->id_number); 1901558Srgrimes if (dofix(idesc, buf)) { 1911558Srgrimes *ap = 0; 1921558Srgrimes dirty(bp); 1931558Srgrimes } 1941558Srgrimes } 1951558Srgrimes flush(fswritefd, bp); 1961558Srgrimes } 1971558Srgrimes aplim = &bp->b_un.b_indir[nif]; 1981558Srgrimes for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 19962668Smckusick if (ilevel == 0) 20062668Smckusick idesc->id_lbn++; 2011558Srgrimes if (*ap) { 2021558Srgrimes idesc->id_blkno = *ap; 2031558Srgrimes if (ilevel == 0) 2041558Srgrimes n = (*func)(idesc); 2051558Srgrimes else 2061558Srgrimes n = iblock(idesc, ilevel, isize); 2071558Srgrimes if (n & STOP) { 2081558Srgrimes bp->b_flags &= ~B_INUSE; 2091558Srgrimes return (n); 2101558Srgrimes } 21118808Sguido } else { 21218808Sguido if (idesc->id_type == DATA && isize > 0) { 21318808Sguido /* An empty block in a directory XXX */ 21418808Sguido getpathname(pathbuf, idesc->id_number, 21518808Sguido idesc->id_number); 21618808Sguido pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 21718808Sguido pathbuf); 21818808Sguido if (reply("ADJUST LENGTH") == 1) { 21918808Sguido dp = ginode(idesc->id_number); 22018808Sguido dp->di_size -= isize; 22118808Sguido isize = 0; 22218808Sguido printf( 22318808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 22418808Sguido rerun = 1; 22518808Sguido inodirty(); 22618808Sguido bp->b_flags &= ~B_INUSE; 22718808Sguido return(STOP); 22818808Sguido } 22918808Sguido } 2301558Srgrimes } 2311558Srgrimes isize -= sizepb; 2321558Srgrimes } 2331558Srgrimes bp->b_flags &= ~B_INUSE; 2341558Srgrimes return (KEEPON); 2351558Srgrimes} 2361558Srgrimes 2371558Srgrimes/* 2381558Srgrimes * Check that a block in a legal block number. 2391558Srgrimes * Return 0 if in range, 1 if out of range. 2401558Srgrimes */ 2417585Sbdeint 2421558Srgrimeschkrange(blk, cnt) 24323675Speter ufs_daddr_t blk; 2441558Srgrimes int cnt; 2451558Srgrimes{ 2461558Srgrimes register int c; 2471558Srgrimes 24841474Sjulian if (cnt <= 0 || blk <= 0 || blk > maxfsblock || 24941474Sjulian cnt - 1 > maxfsblock - blk) 2501558Srgrimes return (1); 25141474Sjulian if (cnt > sblock.fs_frag || 25241474Sjulian fragnum(&sblock, blk) + cnt > sblock.fs_frag) { 25341474Sjulian if (debug) 25441474Sjulian printf("bad size: blk %ld, offset %ld, size %ld\n", 25541474Sjulian blk, fragnum(&sblock, blk), cnt); 25641474Sjulian return (1); 25741474Sjulian } 2581558Srgrimes c = dtog(&sblock, blk); 2591558Srgrimes if (blk < cgdmin(&sblock, c)) { 2601558Srgrimes if ((blk + cnt) > cgsblock(&sblock, c)) { 2611558Srgrimes if (debug) { 2621558Srgrimes printf("blk %ld < cgdmin %ld;", 26337236Sbde (long)blk, (long)cgdmin(&sblock, c)); 2641558Srgrimes printf(" blk + cnt %ld > cgsbase %ld\n", 26537236Sbde (long)(blk + cnt), 26637236Sbde (long)cgsblock(&sblock, c)); 2671558Srgrimes } 2681558Srgrimes return (1); 2691558Srgrimes } 2701558Srgrimes } else { 2711558Srgrimes if ((blk + cnt) > cgbase(&sblock, c+1)) { 2721558Srgrimes if (debug) { 2731558Srgrimes printf("blk %ld >= cgdmin %ld;", 27437236Sbde (long)blk, (long)cgdmin(&sblock, c)); 2751558Srgrimes printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 27637236Sbde (long)(blk + cnt), (long)sblock.fs_fpg); 2771558Srgrimes } 2781558Srgrimes return (1); 2791558Srgrimes } 2801558Srgrimes } 2811558Srgrimes return (0); 2821558Srgrimes} 2831558Srgrimes 2841558Srgrimes/* 2851558Srgrimes * General purpose interface for reading inodes. 2861558Srgrimes */ 2871558Srgrimesstruct dinode * 2881558Srgrimesginode(inumber) 2891558Srgrimes ino_t inumber; 2901558Srgrimes{ 29123675Speter ufs_daddr_t iblk; 2921558Srgrimes 2931558Srgrimes if (inumber < ROOTINO || inumber > maxino) 29423675Speter errx(EEXIT, "bad inode number %d to ginode", inumber); 2951558Srgrimes if (startinum == 0 || 2961558Srgrimes inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 2971558Srgrimes iblk = ino_to_fsba(&sblock, inumber); 2981558Srgrimes if (pbp != 0) 2991558Srgrimes pbp->b_flags &= ~B_INUSE; 3001558Srgrimes pbp = getdatablk(iblk, sblock.fs_bsize); 3011558Srgrimes startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 3021558Srgrimes } 3031558Srgrimes return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 3041558Srgrimes} 3051558Srgrimes 3061558Srgrimes/* 3071558Srgrimes * Special purpose version of ginode used to optimize first pass 3081558Srgrimes * over all the inodes in numerical order. 3091558Srgrimes */ 31063231Smckusickino_t nextino, lastinum, lastvalidinum; 3111558Srgrimeslong readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 3121558Srgrimesstruct dinode *inodebuf; 3131558Srgrimes 3141558Srgrimesstruct dinode * 3151558Srgrimesgetnextinode(inumber) 3161558Srgrimes ino_t inumber; 3171558Srgrimes{ 3181558Srgrimes long size; 31923675Speter ufs_daddr_t dblk; 3201558Srgrimes static struct dinode *dp; 3211558Srgrimes 32263231Smckusick if (inumber != nextino++ || inumber > lastvalidinum) 32323675Speter errx(EEXIT, "bad inode number %d to nextinode", inumber); 3241558Srgrimes if (inumber >= lastinum) { 3251558Srgrimes readcnt++; 3261558Srgrimes dblk = fsbtodb(&sblock, ino_to_fsba(&sblock, lastinum)); 3271558Srgrimes if (readcnt % readpercg == 0) { 3281558Srgrimes size = partialsize; 3291558Srgrimes lastinum += partialcnt; 3301558Srgrimes } else { 3311558Srgrimes size = inobufsize; 3321558Srgrimes lastinum += fullcnt; 3331558Srgrimes } 33441474Sjulian /* 33541474Sjulian * If bread returns an error, it will already have zeroed 33641474Sjulian * out the buffer, so we do not need to do so here. 33741474Sjulian */ 33841474Sjulian (void)bread(fsreadfd, (char *)inodebuf, dblk, size); 3391558Srgrimes dp = inodebuf; 3401558Srgrimes } 3411558Srgrimes return (dp++); 3421558Srgrimes} 3431558Srgrimes 3447585Sbdevoid 34541474Sjuliansetinodebuf(inum) 34641474Sjulian ino_t inum; 3471558Srgrimes{ 3481558Srgrimes 34941474Sjulian if (inum % sblock.fs_ipg != 0) 35041474Sjulian errx(EEXIT, "bad inode number %d to setinodebuf", inum); 35163231Smckusick lastvalidinum = inum + sblock.fs_ipg - 1; 3521558Srgrimes startinum = 0; 35341474Sjulian nextino = inum; 35441474Sjulian lastinum = inum; 3551558Srgrimes readcnt = 0; 35641474Sjulian if (inodebuf != NULL) 35741474Sjulian return; 3581558Srgrimes inobufsize = blkroundup(&sblock, INOBUFSIZE); 3591558Srgrimes fullcnt = inobufsize / sizeof(struct dinode); 3601558Srgrimes readpercg = sblock.fs_ipg / fullcnt; 3611558Srgrimes partialcnt = sblock.fs_ipg % fullcnt; 3621558Srgrimes partialsize = partialcnt * sizeof(struct dinode); 3631558Srgrimes if (partialcnt != 0) { 3641558Srgrimes readpercg++; 3651558Srgrimes } else { 3661558Srgrimes partialcnt = fullcnt; 3671558Srgrimes partialsize = inobufsize; 3681558Srgrimes } 36941474Sjulian if ((inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 37037000Scharnier errx(EEXIT, "cannot allocate space for inode buffer"); 3711558Srgrimes} 3721558Srgrimes 3737585Sbdevoid 3741558Srgrimesfreeinodebuf() 3751558Srgrimes{ 3761558Srgrimes 3771558Srgrimes if (inodebuf != NULL) 3781558Srgrimes free((char *)inodebuf); 3791558Srgrimes inodebuf = NULL; 3801558Srgrimes} 3811558Srgrimes 3821558Srgrimes/* 3831558Srgrimes * Routines to maintain information about directory inodes. 3841558Srgrimes * This is built during the first pass and used during the 3851558Srgrimes * second and third passes. 3861558Srgrimes * 3871558Srgrimes * Enter inodes into the cache. 3881558Srgrimes */ 3897585Sbdevoid 3901558Srgrimescacheino(dp, inumber) 3911558Srgrimes register struct dinode *dp; 3921558Srgrimes ino_t inumber; 3931558Srgrimes{ 3941558Srgrimes register struct inoinfo *inp; 3951558Srgrimes struct inoinfo **inpp; 39638002Sdfr int blks; 3971558Srgrimes 3981558Srgrimes blks = howmany(dp->di_size, sblock.fs_bsize); 3991558Srgrimes if (blks > NDADDR) 4001558Srgrimes blks = NDADDR + NIADDR; 4011558Srgrimes inp = (struct inoinfo *) 40223675Speter malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs_daddr_t)); 4031558Srgrimes if (inp == NULL) 40441474Sjulian errx(EEXIT, "cannot increase directory list"); 40557573Smckusick inpp = &inphead[inumber % dirhash]; 4061558Srgrimes inp->i_nexthash = *inpp; 4071558Srgrimes *inpp = inp; 40841474Sjulian inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0; 4091558Srgrimes inp->i_dotdot = (ino_t)0; 4101558Srgrimes inp->i_number = inumber; 4111558Srgrimes inp->i_isize = dp->di_size; 41223675Speter inp->i_numblks = blks * sizeof(ufs_daddr_t); 41323675Speter memmove(&inp->i_blks[0], &dp->di_db[0], (size_t)inp->i_numblks); 4141558Srgrimes if (inplast == listmax) { 4151558Srgrimes listmax += 100; 4161558Srgrimes inpsort = (struct inoinfo **)realloc((char *)inpsort, 4171558Srgrimes (unsigned)listmax * sizeof(struct inoinfo *)); 4181558Srgrimes if (inpsort == NULL) 41923675Speter errx(EEXIT, "cannot increase directory list"); 4201558Srgrimes } 4211558Srgrimes inpsort[inplast++] = inp; 4221558Srgrimes} 4231558Srgrimes 4241558Srgrimes/* 4251558Srgrimes * Look up an inode cache structure. 4261558Srgrimes */ 4271558Srgrimesstruct inoinfo * 4281558Srgrimesgetinoinfo(inumber) 4291558Srgrimes ino_t inumber; 4301558Srgrimes{ 4311558Srgrimes register struct inoinfo *inp; 4321558Srgrimes 43357573Smckusick for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { 4341558Srgrimes if (inp->i_number != inumber) 4351558Srgrimes continue; 4361558Srgrimes return (inp); 4371558Srgrimes } 43823675Speter errx(EEXIT, "cannot find inode %d", inumber); 4391558Srgrimes return ((struct inoinfo *)0); 4401558Srgrimes} 4411558Srgrimes 4421558Srgrimes/* 4431558Srgrimes * Clean up all the inode cache structure. 4441558Srgrimes */ 4457585Sbdevoid 4461558Srgrimesinocleanup() 4471558Srgrimes{ 4481558Srgrimes register struct inoinfo **inpp; 4491558Srgrimes 4501558Srgrimes if (inphead == NULL) 4511558Srgrimes return; 4521558Srgrimes for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 4531558Srgrimes free((char *)(*inpp)); 4541558Srgrimes free((char *)inphead); 4551558Srgrimes free((char *)inpsort); 4561558Srgrimes inphead = inpsort = NULL; 4571558Srgrimes} 4588871Srgrimes 4597585Sbdevoid 4601558Srgrimesinodirty() 4611558Srgrimes{ 46223797Sbde 4631558Srgrimes dirty(pbp); 4641558Srgrimes} 4651558Srgrimes 4667585Sbdevoid 4671558Srgrimesclri(idesc, type, flag) 4681558Srgrimes register struct inodesc *idesc; 4691558Srgrimes char *type; 4701558Srgrimes int flag; 4711558Srgrimes{ 4721558Srgrimes register struct dinode *dp; 4731558Srgrimes 4741558Srgrimes dp = ginode(idesc->id_number); 4751558Srgrimes if (flag == 1) { 4761558Srgrimes pwarn("%s %s", type, 4771558Srgrimes (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 4781558Srgrimes pinode(idesc->id_number); 4791558Srgrimes } 4801558Srgrimes if (preen || reply("CLEAR") == 1) { 4811558Srgrimes if (preen) 4821558Srgrimes printf(" (CLEARED)\n"); 4831558Srgrimes n_files--; 4841558Srgrimes (void)ckinode(dp, idesc); 4851558Srgrimes clearinode(dp); 48641474Sjulian inoinfo(idesc->id_number)->ino_state = USTATE; 4871558Srgrimes inodirty(); 4881558Srgrimes } 4891558Srgrimes} 4901558Srgrimes 4917585Sbdeint 4921558Srgrimesfindname(idesc) 4931558Srgrimes struct inodesc *idesc; 4941558Srgrimes{ 4951558Srgrimes register struct direct *dirp = idesc->id_dirp; 4961558Srgrimes 49741474Sjulian if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 49841474Sjulian idesc->id_entryno++; 4991558Srgrimes return (KEEPON); 50041474Sjulian } 50123675Speter memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 5021558Srgrimes return (STOP|FOUND); 5031558Srgrimes} 5041558Srgrimes 5057585Sbdeint 5061558Srgrimesfindino(idesc) 5071558Srgrimes struct inodesc *idesc; 5081558Srgrimes{ 5091558Srgrimes register struct direct *dirp = idesc->id_dirp; 5101558Srgrimes 5111558Srgrimes if (dirp->d_ino == 0) 5121558Srgrimes return (KEEPON); 5131558Srgrimes if (strcmp(dirp->d_name, idesc->id_name) == 0 && 5141558Srgrimes dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 5151558Srgrimes idesc->id_parent = dirp->d_ino; 5161558Srgrimes return (STOP|FOUND); 5171558Srgrimes } 5181558Srgrimes return (KEEPON); 5191558Srgrimes} 5201558Srgrimes 52141474Sjulianint 52241474Sjulianclearentry(idesc) 52341474Sjulian struct inodesc *idesc; 52441474Sjulian{ 52541474Sjulian register struct direct *dirp = idesc->id_dirp; 52641474Sjulian 52741474Sjulian if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 52841474Sjulian idesc->id_entryno++; 52941474Sjulian return (KEEPON); 53041474Sjulian } 53141474Sjulian dirp->d_ino = 0; 53241474Sjulian return (STOP|FOUND|ALTERED); 53341474Sjulian} 53441474Sjulian 5357585Sbdevoid 5361558Srgrimespinode(ino) 5371558Srgrimes ino_t ino; 5381558Srgrimes{ 5391558Srgrimes register struct dinode *dp; 5401558Srgrimes register char *p; 5411558Srgrimes struct passwd *pw; 54224002Speter time_t t; 5431558Srgrimes 54437236Sbde printf(" I=%lu ", (u_long)ino); 5451558Srgrimes if (ino < ROOTINO || ino > maxino) 5461558Srgrimes return; 5471558Srgrimes dp = ginode(ino); 5481558Srgrimes printf(" OWNER="); 5491558Srgrimes if ((pw = getpwuid((int)dp->di_uid)) != 0) 5501558Srgrimes printf("%s ", pw->pw_name); 5511558Srgrimes else 5521558Srgrimes printf("%u ", (unsigned)dp->di_uid); 5531558Srgrimes printf("MODE=%o\n", dp->di_mode); 5541558Srgrimes if (preen) 5551558Srgrimes printf("%s: ", cdevname); 5561558Srgrimes printf("SIZE=%qu ", dp->di_size); 55724002Speter t = dp->di_mtime; 55824002Speter p = ctime(&t); 5591558Srgrimes printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 5601558Srgrimes} 5611558Srgrimes 5627585Sbdevoid 5631558Srgrimesblkerror(ino, type, blk) 5641558Srgrimes ino_t ino; 5651558Srgrimes char *type; 56623675Speter ufs_daddr_t blk; 5671558Srgrimes{ 5681558Srgrimes 5691558Srgrimes pfatal("%ld %s I=%lu", blk, type, ino); 5701558Srgrimes printf("\n"); 57141474Sjulian switch (inoinfo(ino)->ino_state) { 5721558Srgrimes 5731558Srgrimes case FSTATE: 57441474Sjulian inoinfo(ino)->ino_state = FCLEAR; 5751558Srgrimes return; 5761558Srgrimes 5771558Srgrimes case DSTATE: 57841474Sjulian inoinfo(ino)->ino_state = DCLEAR; 5791558Srgrimes return; 5801558Srgrimes 5811558Srgrimes case FCLEAR: 5821558Srgrimes case DCLEAR: 5831558Srgrimes return; 5841558Srgrimes 5851558Srgrimes default: 58641474Sjulian errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state); 5871558Srgrimes /* NOTREACHED */ 5881558Srgrimes } 5891558Srgrimes} 5901558Srgrimes 5911558Srgrimes/* 5921558Srgrimes * allocate an unused inode 5931558Srgrimes */ 5941558Srgrimesino_t 5951558Srgrimesallocino(request, type) 5961558Srgrimes ino_t request; 5971558Srgrimes int type; 5981558Srgrimes{ 5991558Srgrimes register ino_t ino; 6001558Srgrimes register struct dinode *dp; 60134266Sjulian struct cg *cgp = &cgrp; 60234266Sjulian int cg; 6031558Srgrimes 6041558Srgrimes if (request == 0) 6051558Srgrimes request = ROOTINO; 60641474Sjulian else if (inoinfo(request)->ino_state != USTATE) 6071558Srgrimes return (0); 6081558Srgrimes for (ino = request; ino < maxino; ino++) 60941474Sjulian if (inoinfo(ino)->ino_state == USTATE) 6101558Srgrimes break; 6111558Srgrimes if (ino == maxino) 6121558Srgrimes return (0); 61334266Sjulian cg = ino_to_cg(&sblock, ino); 61434266Sjulian getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); 61534266Sjulian if (!cg_chkmagic(cgp)) 61634266Sjulian pfatal("CG %d: BAD MAGIC NUMBER\n", cg); 61734266Sjulian setbit(cg_inosused(cgp), ino % sblock.fs_ipg); 61834266Sjulian cgp->cg_cs.cs_nifree--; 6191558Srgrimes switch (type & IFMT) { 6201558Srgrimes case IFDIR: 62141474Sjulian inoinfo(ino)->ino_state = DSTATE; 62234266Sjulian cgp->cg_cs.cs_ndir++; 6231558Srgrimes break; 6241558Srgrimes case IFREG: 6251558Srgrimes case IFLNK: 62641474Sjulian inoinfo(ino)->ino_state = FSTATE; 6271558Srgrimes break; 6281558Srgrimes default: 6291558Srgrimes return (0); 6301558Srgrimes } 63134266Sjulian cgdirty(); 6321558Srgrimes dp = ginode(ino); 6331558Srgrimes dp->di_db[0] = allocblk((long)1); 6341558Srgrimes if (dp->di_db[0] == 0) { 63541474Sjulian inoinfo(ino)->ino_state = USTATE; 6361558Srgrimes return (0); 6371558Srgrimes } 63841474Sjulian dp->di_mode = type; 63934266Sjulian dp->di_flags = 0; 64024002Speter dp->di_atime = time(NULL); 6411558Srgrimes dp->di_mtime = dp->di_ctime = dp->di_atime; 64241477Sjulian dp->di_mtimensec = dp->di_ctimensec = dp->di_atimensec = 0; 6431558Srgrimes dp->di_size = sblock.fs_fsize; 6441558Srgrimes dp->di_blocks = btodb(sblock.fs_fsize); 6451558Srgrimes n_files++; 6461558Srgrimes inodirty(); 6471558Srgrimes if (newinofmt) 64841474Sjulian inoinfo(ino)->ino_type = IFTODT(type); 6491558Srgrimes return (ino); 6501558Srgrimes} 6511558Srgrimes 6521558Srgrimes/* 6531558Srgrimes * deallocate an inode 6541558Srgrimes */ 6557585Sbdevoid 6561558Srgrimesfreeino(ino) 6571558Srgrimes ino_t ino; 6581558Srgrimes{ 6591558Srgrimes struct inodesc idesc; 6601558Srgrimes struct dinode *dp; 6611558Srgrimes 66223675Speter memset(&idesc, 0, sizeof(struct inodesc)); 6631558Srgrimes idesc.id_type = ADDR; 6641558Srgrimes idesc.id_func = pass4check; 6651558Srgrimes idesc.id_number = ino; 6661558Srgrimes dp = ginode(ino); 6671558Srgrimes (void)ckinode(dp, &idesc); 6681558Srgrimes clearinode(dp); 6691558Srgrimes inodirty(); 67041474Sjulian inoinfo(ino)->ino_state = USTATE; 6711558Srgrimes n_files--; 6721558Srgrimes} 673