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 * 4. Neither the name of the University nor the names of its contributors 141558Srgrimes * may be used to endorse or promote products derived from this software 151558Srgrimes * without specific prior written permission. 161558Srgrimes * 171558Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181558Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191558Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201558Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211558Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221558Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231558Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241558Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251558Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261558Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271558Srgrimes * SUCH DAMAGE. 281558Srgrimes */ 291558Srgrimes 30114589Sobrien#if 0 311558Srgrimes#ifndef lint 3223675Speterstatic const char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95"; 33114589Sobrien#endif /* not lint */ 3441477Sjulian#endif 35114589Sobrien#include <sys/cdefs.h> 36114589Sobrien__FBSDID("$FreeBSD$"); 371558Srgrimes 381558Srgrimes#include <sys/param.h> 3998542Smckusick#include <sys/stdint.h> 4074556Smckusick#include <sys/sysctl.h> 4123675Speter 421558Srgrimes#include <ufs/ufs/dinode.h> 431558Srgrimes#include <ufs/ufs/dir.h> 441558Srgrimes#include <ufs/ffs/fs.h> 4523675Speter 4623675Speter#include <err.h> 471558Srgrimes#include <pwd.h> 481558Srgrimes#include <string.h> 49217769Smckusick#include <time.h> 5023675Speter 511558Srgrimes#include "fsck.h" 521558Srgrimes 531558Srgrimesstatic ino_t startinum; 541558Srgrimes 55249788Smckusickstatic int iblock(struct inodesc *, long ilevel, off_t isize, int type); 567585Sbde 577585Sbdeint 5898542Smckusickckinode(union dinode *dp, struct inodesc *idesc) 591558Srgrimes{ 6098542Smckusick off_t remsize, sizepb; 6198542Smckusick int i, offset, ret; 6298542Smckusick union dinode dino; 6398542Smckusick ufs2_daddr_t ndb; 641558Srgrimes mode_t mode; 6518808Sguido char pathbuf[MAXPATHLEN + 1]; 661558Srgrimes 671558Srgrimes if (idesc->id_fix != IGNORE) 681558Srgrimes idesc->id_fix = DONTKNOW; 6962668Smckusick idesc->id_lbn = -1; 701558Srgrimes idesc->id_entryno = 0; 7198542Smckusick idesc->id_filesize = DIP(dp, di_size); 7298542Smckusick mode = DIP(dp, di_mode) & IFMT; 731558Srgrimes if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 7498542Smckusick DIP(dp, di_size) < (unsigned)sblock.fs_maxsymlinklen)) 751558Srgrimes return (KEEPON); 7698542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 7798542Smckusick dino.dp1 = dp->dp1; 7898542Smckusick else 7998542Smckusick dino.dp2 = dp->dp2; 8098542Smckusick ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize); 8198542Smckusick for (i = 0; i < NDADDR; i++) { 8262668Smckusick idesc->id_lbn++; 8398542Smckusick if (--ndb == 0 && 8498542Smckusick (offset = blkoff(&sblock, DIP(&dino, di_size))) != 0) 851558Srgrimes idesc->id_numfrags = 861558Srgrimes numfrags(&sblock, fragroundup(&sblock, offset)); 871558Srgrimes else 881558Srgrimes idesc->id_numfrags = sblock.fs_frag; 8998542Smckusick if (DIP(&dino, di_db[i]) == 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); 94221110Sdes pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 9518808Sguido pathbuf); 96221110Sdes if (reply("ADJUST LENGTH") == 1) { 9718808Sguido dp = ginode(idesc->id_number); 98221110Sdes DIP_SET(dp, di_size, 99134589Sscottl i * sblock.fs_bsize); 10018808Sguido printf( 10118808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 10218808Sguido rerun = 1; 103221110Sdes inodirty(); 104221110Sdes 105221110Sdes } 10618808Sguido } 1071558Srgrimes continue; 10818808Sguido } 10998542Smckusick idesc->id_blkno = DIP(&dino, di_db[i]); 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; 11898542Smckusick remsize = DIP(&dino, di_size) - sblock.fs_bsize * NDADDR; 1191558Srgrimes sizepb = sblock.fs_bsize; 12098542Smckusick for (i = 0; i < NIADDR; i++) { 12162668Smckusick sizepb *= NINDIR(&sblock); 12298542Smckusick if (DIP(&dino, di_ib[i])) { 12398542Smckusick idesc->id_blkno = DIP(&dino, di_ib[i]); 124249788Smckusick ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i); 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); 133221110Sdes pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 13418808Sguido pathbuf); 135221110Sdes if (reply("ADJUST LENGTH") == 1) { 13618808Sguido dp = ginode(idesc->id_number); 137221110Sdes DIP_SET(dp, di_size, 138134589Sscottl DIP(dp, di_size) - remsize); 13918808Sguido remsize = 0; 14018808Sguido printf( 14118808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 14218808Sguido rerun = 1; 143221110Sdes inodirty(); 14418808Sguido break; 145221110Sdes } 14618808Sguido } 1471558Srgrimes } 1481558Srgrimes remsize -= sizepb; 1491558Srgrimes } 1501558Srgrimes return (KEEPON); 1511558Srgrimes} 1521558Srgrimes 1537585Sbdestatic int 154249788Smckusickiblock(struct inodesc *idesc, long ilevel, off_t isize, int type) 1551558Srgrimes{ 15623675Speter struct bufarea *bp; 157100935Sphk int i, n, (*func)(struct inodesc *), nif; 15898542Smckusick off_t sizepb; 1591558Srgrimes char buf[BUFSIZ]; 16018808Sguido char pathbuf[MAXPATHLEN + 1]; 16198542Smckusick union dinode *dp; 1621558Srgrimes 16362668Smckusick if (idesc->id_type != DATA) { 1641558Srgrimes func = idesc->id_func; 1651558Srgrimes if (((n = (*func)(idesc)) & KEEPON) == 0) 1661558Srgrimes return (n); 1671558Srgrimes } else 1681558Srgrimes func = dirscan; 1691558Srgrimes if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 1701558Srgrimes return (SKIP); 171249788Smckusick bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type); 1721558Srgrimes ilevel--; 1731558Srgrimes for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 1741558Srgrimes sizepb *= NINDIR(&sblock); 17598542Smckusick if (howmany(isize, sizepb) > NINDIR(&sblock)) 1761558Srgrimes nif = NINDIR(&sblock); 17798542Smckusick else 17898542Smckusick nif = howmany(isize, sizepb); 1791558Srgrimes if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 18098542Smckusick for (i = nif; i < NINDIR(&sblock); i++) { 18198542Smckusick if (IBLK(bp, i) == 0) 1821558Srgrimes continue; 1831558Srgrimes (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 18437236Sbde (u_long)idesc->id_number); 18576352Smckusick if (preen) { 18681911Skris pfatal("%s", buf); 18774556Smckusick } else if (dofix(idesc, buf)) { 188134589Sscottl IBLK_SET(bp, i, 0); 1891558Srgrimes dirty(bp); 1901558Srgrimes } 1911558Srgrimes } 1921558Srgrimes flush(fswritefd, bp); 1931558Srgrimes } 19498542Smckusick for (i = 0; i < nif; i++) { 19562668Smckusick if (ilevel == 0) 19662668Smckusick idesc->id_lbn++; 19798542Smckusick if (IBLK(bp, i)) { 19898542Smckusick idesc->id_blkno = IBLK(bp, i); 1991558Srgrimes if (ilevel == 0) 2001558Srgrimes n = (*func)(idesc); 2011558Srgrimes else 202249788Smckusick n = iblock(idesc, ilevel, isize, type); 2031558Srgrimes if (n & STOP) { 2041558Srgrimes bp->b_flags &= ~B_INUSE; 2051558Srgrimes return (n); 2061558Srgrimes } 20718808Sguido } else { 20818808Sguido if (idesc->id_type == DATA && isize > 0) { 20918808Sguido /* An empty block in a directory XXX */ 21018808Sguido getpathname(pathbuf, idesc->id_number, 21118808Sguido idesc->id_number); 212221110Sdes pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 21318808Sguido pathbuf); 214221110Sdes if (reply("ADJUST LENGTH") == 1) { 21518808Sguido dp = ginode(idesc->id_number); 216221110Sdes DIP_SET(dp, di_size, 217134589Sscottl DIP(dp, di_size) - isize); 21818808Sguido isize = 0; 21918808Sguido printf( 22018808Sguido "YOU MUST RERUN FSCK AFTERWARDS\n"); 22118808Sguido rerun = 1; 222221110Sdes inodirty(); 22318808Sguido bp->b_flags &= ~B_INUSE; 22418808Sguido return(STOP); 225221110Sdes } 22618808Sguido } 2271558Srgrimes } 2281558Srgrimes isize -= sizepb; 2291558Srgrimes } 2301558Srgrimes bp->b_flags &= ~B_INUSE; 2311558Srgrimes return (KEEPON); 2321558Srgrimes} 2331558Srgrimes 2341558Srgrimes/* 2351558Srgrimes * Check that a block in a legal block number. 2361558Srgrimes * Return 0 if in range, 1 if out of range. 2371558Srgrimes */ 2387585Sbdeint 23998542Smckusickchkrange(ufs2_daddr_t blk, int cnt) 2401558Srgrimes{ 24192806Sobrien int c; 2421558Srgrimes 24341474Sjulian if (cnt <= 0 || blk <= 0 || blk > maxfsblock || 24441474Sjulian cnt - 1 > maxfsblock - blk) 2451558Srgrimes return (1); 24641474Sjulian if (cnt > sblock.fs_frag || 24741474Sjulian fragnum(&sblock, blk) + cnt > sblock.fs_frag) { 24841474Sjulian if (debug) 24986514Siedowse printf("bad size: blk %ld, offset %i, size %d\n", 25086514Siedowse (long)blk, (int)fragnum(&sblock, blk), cnt); 25141474Sjulian return (1); 25241474Sjulian } 2531558Srgrimes c = dtog(&sblock, blk); 2541558Srgrimes if (blk < cgdmin(&sblock, c)) { 2551558Srgrimes if ((blk + cnt) > cgsblock(&sblock, c)) { 2561558Srgrimes if (debug) { 2571558Srgrimes printf("blk %ld < cgdmin %ld;", 25837236Sbde (long)blk, (long)cgdmin(&sblock, c)); 2591558Srgrimes printf(" blk + cnt %ld > cgsbase %ld\n", 26037236Sbde (long)(blk + cnt), 26137236Sbde (long)cgsblock(&sblock, c)); 2621558Srgrimes } 2631558Srgrimes return (1); 2641558Srgrimes } 2651558Srgrimes } else { 2661558Srgrimes if ((blk + cnt) > cgbase(&sblock, c+1)) { 2671558Srgrimes if (debug) { 2681558Srgrimes printf("blk %ld >= cgdmin %ld;", 26937236Sbde (long)blk, (long)cgdmin(&sblock, c)); 2701558Srgrimes printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 27137236Sbde (long)(blk + cnt), (long)sblock.fs_fpg); 2721558Srgrimes } 2731558Srgrimes return (1); 2741558Srgrimes } 2751558Srgrimes } 2761558Srgrimes return (0); 2771558Srgrimes} 2781558Srgrimes 2791558Srgrimes/* 2801558Srgrimes * General purpose interface for reading inodes. 2811558Srgrimes */ 28298542Smckusickunion dinode * 28392839Simpginode(ino_t inumber) 2841558Srgrimes{ 28598542Smckusick ufs2_daddr_t iblk; 2861558Srgrimes 2871558Srgrimes if (inumber < ROOTINO || inumber > maxino) 28823675Speter errx(EEXIT, "bad inode number %d to ginode", inumber); 2891558Srgrimes if (startinum == 0 || 2901558Srgrimes inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 2911558Srgrimes iblk = ino_to_fsba(&sblock, inumber); 2921558Srgrimes if (pbp != 0) 2931558Srgrimes pbp->b_flags &= ~B_INUSE; 294249788Smckusick pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES); 2951558Srgrimes startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 2961558Srgrimes } 29798542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 29898542Smckusick return ((union dinode *) 29998542Smckusick &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]); 30098542Smckusick return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]); 3011558Srgrimes} 3021558Srgrimes 3031558Srgrimes/* 3041558Srgrimes * Special purpose version of ginode used to optimize first pass 3051558Srgrimes * over all the inodes in numerical order. 3061558Srgrimes */ 30788413Salfredstatic ino_t nextino, lastinum, lastvalidinum; 308249788Smckusickstatic long readcount, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 309249788Smckusickstatic struct bufarea inobuf; 3101558Srgrimes 31198542Smckusickunion dinode * 312188110Smckusickgetnextinode(ino_t inumber, int rebuildcg) 3131558Srgrimes{ 314188110Smckusick int j; 3151558Srgrimes long size; 316188110Smckusick mode_t mode; 317249788Smckusick ufs2_daddr_t ndb, blk; 31898542Smckusick union dinode *dp; 31998542Smckusick static caddr_t nextinop; 3201558Srgrimes 32163231Smckusick if (inumber != nextino++ || inumber > lastvalidinum) 32223675Speter errx(EEXIT, "bad inode number %d to nextinode", inumber); 3231558Srgrimes if (inumber >= lastinum) { 324249788Smckusick readcount++; 325249788Smckusick blk = ino_to_fsba(&sblock, lastinum); 326249788Smckusick if (readcount % readpercg == 0) { 3271558Srgrimes size = partialsize; 3281558Srgrimes lastinum += partialcnt; 3291558Srgrimes } else { 3301558Srgrimes size = inobufsize; 3311558Srgrimes lastinum += fullcnt; 3321558Srgrimes } 33341474Sjulian /* 334249788Smckusick * If getblk encounters an error, it will already have zeroed 33541474Sjulian * out the buffer, so we do not need to do so here. 33641474Sjulian */ 337249788Smckusick getblk(&inobuf, blk, size); 338249788Smckusick nextinop = inobuf.b_un.b_buf; 3391558Srgrimes } 34098542Smckusick dp = (union dinode *)nextinop; 341249788Smckusick if (rebuildcg && nextinop == inobuf.b_un.b_buf) { 342188110Smckusick /* 343188110Smckusick * Try to determine if we have reached the end of the 344188110Smckusick * allocated inodes. 345188110Smckusick */ 346188110Smckusick mode = DIP(dp, di_mode) & IFMT; 347188110Smckusick if (mode == 0) { 348188110Smckusick if (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 349188110Smckusick NDADDR * sizeof(ufs2_daddr_t)) || 350188110Smckusick memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 351188110Smckusick NIADDR * sizeof(ufs2_daddr_t)) || 352188110Smckusick dp->dp2.di_mode || dp->dp2.di_size) 353188110Smckusick return (NULL); 354188110Smckusick goto inodegood; 355188110Smckusick } 356188110Smckusick if (!ftypeok(dp)) 357188110Smckusick return (NULL); 358188110Smckusick ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 359188110Smckusick if (ndb < 0) 360188110Smckusick return (NULL); 361188110Smckusick if (mode == IFBLK || mode == IFCHR) 362188110Smckusick ndb++; 363188110Smckusick if (mode == IFLNK) { 364188110Smckusick /* 365188110Smckusick * Fake ndb value so direct/indirect block checks below 366188110Smckusick * will detect any garbage after symlink string. 367188110Smckusick */ 368188110Smckusick if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 369188110Smckusick ndb = howmany(DIP(dp, di_size), 370188110Smckusick sizeof(ufs2_daddr_t)); 371188110Smckusick if (ndb > NDADDR) { 372188110Smckusick j = ndb - NDADDR; 373188110Smckusick for (ndb = 1; j > 1; j--) 374188110Smckusick ndb *= NINDIR(&sblock); 375188110Smckusick ndb += NDADDR; 376188110Smckusick } 377188110Smckusick } 378188110Smckusick } 379188110Smckusick for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 380188110Smckusick if (DIP(dp, di_db[j]) != 0) 381188110Smckusick return (NULL); 382188110Smckusick for (j = 0, ndb -= NDADDR; ndb > 0; j++) 383188110Smckusick ndb /= NINDIR(&sblock); 384188110Smckusick for (; j < NIADDR; j++) 385188110Smckusick if (DIP(dp, di_ib[j]) != 0) 386188110Smckusick return (NULL); 387188110Smckusick } 388188110Smckusickinodegood: 38998542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 39098542Smckusick nextinop += sizeof(struct ufs1_dinode); 39198542Smckusick else 39298542Smckusick nextinop += sizeof(struct ufs2_dinode); 39398542Smckusick return (dp); 3941558Srgrimes} 3951558Srgrimes 3967585Sbdevoid 39792839Simpsetinodebuf(ino_t inum) 3981558Srgrimes{ 3991558Srgrimes 40041474Sjulian if (inum % sblock.fs_ipg != 0) 40141474Sjulian errx(EEXIT, "bad inode number %d to setinodebuf", inum); 40263231Smckusick lastvalidinum = inum + sblock.fs_ipg - 1; 4031558Srgrimes startinum = 0; 40441474Sjulian nextino = inum; 40541474Sjulian lastinum = inum; 406249788Smckusick readcount = 0; 407249788Smckusick if (inobuf.b_un.b_buf != NULL) 40841474Sjulian return; 4091558Srgrimes inobufsize = blkroundup(&sblock, INOBUFSIZE); 41098542Smckusick fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ? 41198542Smckusick sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); 4121558Srgrimes readpercg = sblock.fs_ipg / fullcnt; 4131558Srgrimes partialcnt = sblock.fs_ipg % fullcnt; 41498542Smckusick partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ? 41598542Smckusick sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); 4161558Srgrimes if (partialcnt != 0) { 4171558Srgrimes readpercg++; 4181558Srgrimes } else { 4191558Srgrimes partialcnt = fullcnt; 4201558Srgrimes partialsize = inobufsize; 4211558Srgrimes } 422249788Smckusick initbarea(&inobuf, BT_INODES); 423249788Smckusick if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL) 42437000Scharnier errx(EEXIT, "cannot allocate space for inode buffer"); 4251558Srgrimes} 4261558Srgrimes 4277585Sbdevoid 42892839Simpfreeinodebuf(void) 4291558Srgrimes{ 4301558Srgrimes 431249788Smckusick if (inobuf.b_un.b_buf != NULL) 432249788Smckusick free((char *)inobuf.b_un.b_buf); 433249788Smckusick inobuf.b_un.b_buf = NULL; 4341558Srgrimes} 4351558Srgrimes 4361558Srgrimes/* 4371558Srgrimes * Routines to maintain information about directory inodes. 4381558Srgrimes * This is built during the first pass and used during the 4391558Srgrimes * second and third passes. 4401558Srgrimes * 4411558Srgrimes * Enter inodes into the cache. 4421558Srgrimes */ 4437585Sbdevoid 44498542Smckusickcacheino(union dinode *dp, ino_t inumber) 4451558Srgrimes{ 44698542Smckusick struct inoinfo *inp, **inpp; 44798542Smckusick int i, blks; 4481558Srgrimes 44998542Smckusick if (howmany(DIP(dp, di_size), sblock.fs_bsize) > NDADDR) 4501558Srgrimes blks = NDADDR + NIADDR; 45198542Smckusick else 45298542Smckusick blks = howmany(DIP(dp, di_size), sblock.fs_bsize); 4531558Srgrimes inp = (struct inoinfo *) 454249788Smckusick Malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t)); 4551558Srgrimes if (inp == NULL) 45641474Sjulian errx(EEXIT, "cannot increase directory list"); 45757573Smckusick inpp = &inphead[inumber % dirhash]; 4581558Srgrimes inp->i_nexthash = *inpp; 4591558Srgrimes *inpp = inp; 46041474Sjulian inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0; 4611558Srgrimes inp->i_dotdot = (ino_t)0; 4621558Srgrimes inp->i_number = inumber; 46398542Smckusick inp->i_isize = DIP(dp, di_size); 46498542Smckusick inp->i_numblks = blks; 46598542Smckusick for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++) 46698542Smckusick inp->i_blks[i] = DIP(dp, di_db[i]); 46798542Smckusick if (blks > NDADDR) 46898542Smckusick for (i = 0; i < NIADDR; i++) 46998542Smckusick inp->i_blks[NDADDR + i] = DIP(dp, di_ib[i]); 4701558Srgrimes if (inplast == listmax) { 4711558Srgrimes listmax += 100; 4721558Srgrimes inpsort = (struct inoinfo **)realloc((char *)inpsort, 4731558Srgrimes (unsigned)listmax * sizeof(struct inoinfo *)); 4741558Srgrimes if (inpsort == NULL) 47523675Speter errx(EEXIT, "cannot increase directory list"); 4761558Srgrimes } 4771558Srgrimes inpsort[inplast++] = inp; 4781558Srgrimes} 4791558Srgrimes 4801558Srgrimes/* 4811558Srgrimes * Look up an inode cache structure. 4821558Srgrimes */ 4831558Srgrimesstruct inoinfo * 48492839Simpgetinoinfo(ino_t inumber) 4851558Srgrimes{ 48692806Sobrien struct inoinfo *inp; 4871558Srgrimes 48857573Smckusick for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { 4891558Srgrimes if (inp->i_number != inumber) 4901558Srgrimes continue; 4911558Srgrimes return (inp); 4921558Srgrimes } 49323675Speter errx(EEXIT, "cannot find inode %d", inumber); 4941558Srgrimes return ((struct inoinfo *)0); 4951558Srgrimes} 4961558Srgrimes 4971558Srgrimes/* 4981558Srgrimes * Clean up all the inode cache structure. 4991558Srgrimes */ 5007585Sbdevoid 50192839Simpinocleanup(void) 5021558Srgrimes{ 50392806Sobrien struct inoinfo **inpp; 5041558Srgrimes 5051558Srgrimes if (inphead == NULL) 5061558Srgrimes return; 5071558Srgrimes for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 5081558Srgrimes free((char *)(*inpp)); 5091558Srgrimes free((char *)inphead); 5101558Srgrimes free((char *)inpsort); 5111558Srgrimes inphead = inpsort = NULL; 5121558Srgrimes} 5138871Srgrimes 5147585Sbdevoid 51592839Simpinodirty(void) 5161558Srgrimes{ 51723797Sbde 5181558Srgrimes dirty(pbp); 5191558Srgrimes} 5201558Srgrimes 5217585Sbdevoid 522100935Sphkclri(struct inodesc *idesc, const char *type, int flag) 5231558Srgrimes{ 52498542Smckusick union dinode *dp; 5251558Srgrimes 5261558Srgrimes dp = ginode(idesc->id_number); 5271558Srgrimes if (flag == 1) { 5281558Srgrimes pwarn("%s %s", type, 52998542Smckusick (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"); 5301558Srgrimes pinode(idesc->id_number); 5311558Srgrimes } 5321558Srgrimes if (preen || reply("CLEAR") == 1) { 5331558Srgrimes if (preen) 5341558Srgrimes printf(" (CLEARED)\n"); 5351558Srgrimes n_files--; 53674556Smckusick if (bkgrdflag == 0) { 53774556Smckusick (void)ckinode(dp, idesc); 53874556Smckusick inoinfo(idesc->id_number)->ino_state = USTATE; 53974556Smckusick clearinode(dp); 54074556Smckusick inodirty(); 54174556Smckusick } else { 54274556Smckusick cmd.value = idesc->id_number; 54398542Smckusick cmd.size = -DIP(dp, di_nlink); 54474556Smckusick if (debug) 545100935Sphk printf("adjrefcnt ino %ld amt %lld\n", 546100935Sphk (long)cmd.value, (long long)cmd.size); 54774556Smckusick if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 54874556Smckusick &cmd, sizeof cmd) == -1) 54974556Smckusick rwerror("ADJUST INODE", cmd.value); 55074556Smckusick } 5511558Srgrimes } 5521558Srgrimes} 5531558Srgrimes 5547585Sbdeint 55592839Simpfindname(struct inodesc *idesc) 5561558Srgrimes{ 55792806Sobrien struct direct *dirp = idesc->id_dirp; 5581558Srgrimes 55941474Sjulian if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 56041474Sjulian idesc->id_entryno++; 5611558Srgrimes return (KEEPON); 56241474Sjulian } 56323675Speter memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 5641558Srgrimes return (STOP|FOUND); 5651558Srgrimes} 5661558Srgrimes 5677585Sbdeint 56892839Simpfindino(struct inodesc *idesc) 5691558Srgrimes{ 57092806Sobrien struct direct *dirp = idesc->id_dirp; 5711558Srgrimes 5721558Srgrimes if (dirp->d_ino == 0) 5731558Srgrimes return (KEEPON); 5741558Srgrimes if (strcmp(dirp->d_name, idesc->id_name) == 0 && 5751558Srgrimes dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 5761558Srgrimes idesc->id_parent = dirp->d_ino; 5771558Srgrimes return (STOP|FOUND); 5781558Srgrimes } 5791558Srgrimes return (KEEPON); 5801558Srgrimes} 5811558Srgrimes 58241474Sjulianint 58392839Simpclearentry(struct inodesc *idesc) 58441474Sjulian{ 58592806Sobrien struct direct *dirp = idesc->id_dirp; 58641474Sjulian 58741474Sjulian if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 58841474Sjulian idesc->id_entryno++; 58941474Sjulian return (KEEPON); 59041474Sjulian } 59141474Sjulian dirp->d_ino = 0; 59241474Sjulian return (STOP|FOUND|ALTERED); 59341474Sjulian} 59441474Sjulian 5957585Sbdevoid 59692839Simppinode(ino_t ino) 5971558Srgrimes{ 59898542Smckusick union dinode *dp; 59992806Sobrien char *p; 6001558Srgrimes struct passwd *pw; 60124002Speter time_t t; 6021558Srgrimes 60337236Sbde printf(" I=%lu ", (u_long)ino); 6041558Srgrimes if (ino < ROOTINO || ino > maxino) 6051558Srgrimes return; 6061558Srgrimes dp = ginode(ino); 6071558Srgrimes printf(" OWNER="); 60898542Smckusick if ((pw = getpwuid((int)DIP(dp, di_uid))) != 0) 6091558Srgrimes printf("%s ", pw->pw_name); 6101558Srgrimes else 61198542Smckusick printf("%u ", (unsigned)DIP(dp, di_uid)); 61298542Smckusick printf("MODE=%o\n", DIP(dp, di_mode)); 6131558Srgrimes if (preen) 6141558Srgrimes printf("%s: ", cdevname); 615101037Smux printf("SIZE=%ju ", (uintmax_t)DIP(dp, di_size)); 61698542Smckusick t = DIP(dp, di_mtime); 61724002Speter p = ctime(&t); 6181558Srgrimes printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 6191558Srgrimes} 6201558Srgrimes 6217585Sbdevoid 622100935Sphkblkerror(ino_t ino, const char *type, ufs2_daddr_t blk) 6231558Srgrimes{ 6241558Srgrimes 625101037Smux pfatal("%jd %s I=%ju", (intmax_t)blk, type, (uintmax_t)ino); 6261558Srgrimes printf("\n"); 62741474Sjulian switch (inoinfo(ino)->ino_state) { 6281558Srgrimes 6291558Srgrimes case FSTATE: 630136281Struckman case FZLINK: 63141474Sjulian inoinfo(ino)->ino_state = FCLEAR; 6321558Srgrimes return; 6331558Srgrimes 6341558Srgrimes case DSTATE: 635136281Struckman case DZLINK: 63641474Sjulian inoinfo(ino)->ino_state = DCLEAR; 6371558Srgrimes return; 6381558Srgrimes 6391558Srgrimes case FCLEAR: 6401558Srgrimes case DCLEAR: 6411558Srgrimes return; 6421558Srgrimes 6431558Srgrimes default: 64441474Sjulian errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state); 6451558Srgrimes /* NOTREACHED */ 6461558Srgrimes } 6471558Srgrimes} 6481558Srgrimes 6491558Srgrimes/* 6501558Srgrimes * allocate an unused inode 6511558Srgrimes */ 6521558Srgrimesino_t 65392839Simpallocino(ino_t request, int type) 6541558Srgrimes{ 65592806Sobrien ino_t ino; 65698542Smckusick union dinode *dp; 657249788Smckusick struct bufarea *cgbp; 658249788Smckusick struct cg *cgp; 65934266Sjulian int cg; 6601558Srgrimes 6611558Srgrimes if (request == 0) 6621558Srgrimes request = ROOTINO; 66341474Sjulian else if (inoinfo(request)->ino_state != USTATE) 6641558Srgrimes return (0); 6651558Srgrimes for (ino = request; ino < maxino; ino++) 66641474Sjulian if (inoinfo(ino)->ino_state == USTATE) 6671558Srgrimes break; 6681558Srgrimes if (ino == maxino) 6691558Srgrimes return (0); 67034266Sjulian cg = ino_to_cg(&sblock, ino); 671249788Smckusick cgbp = cgget(cg); 672249788Smckusick cgp = cgbp->b_un.b_cg; 673249788Smckusick if (!check_cgmagic(cg, cgbp)) 674188110Smckusick return (0); 67534266Sjulian setbit(cg_inosused(cgp), ino % sblock.fs_ipg); 67634266Sjulian cgp->cg_cs.cs_nifree--; 6771558Srgrimes switch (type & IFMT) { 6781558Srgrimes case IFDIR: 67941474Sjulian inoinfo(ino)->ino_state = DSTATE; 68034266Sjulian cgp->cg_cs.cs_ndir++; 6811558Srgrimes break; 6821558Srgrimes case IFREG: 6831558Srgrimes case IFLNK: 68441474Sjulian inoinfo(ino)->ino_state = FSTATE; 6851558Srgrimes break; 6861558Srgrimes default: 6871558Srgrimes return (0); 6881558Srgrimes } 689249788Smckusick dirty(cgbp); 6901558Srgrimes dp = ginode(ino); 691134589Sscottl DIP_SET(dp, di_db[0], allocblk((long)1)); 69298542Smckusick if (DIP(dp, di_db[0]) == 0) { 69341474Sjulian inoinfo(ino)->ino_state = USTATE; 6941558Srgrimes return (0); 6951558Srgrimes } 696134589Sscottl DIP_SET(dp, di_mode, type); 697134589Sscottl DIP_SET(dp, di_flags, 0); 698134589Sscottl DIP_SET(dp, di_atime, time(NULL)); 699134589Sscottl DIP_SET(dp, di_ctime, DIP(dp, di_atime)); 700134589Sscottl DIP_SET(dp, di_mtime, DIP(dp, di_ctime)); 701134589Sscottl DIP_SET(dp, di_mtimensec, 0); 702134589Sscottl DIP_SET(dp, di_ctimensec, 0); 703134589Sscottl DIP_SET(dp, di_atimensec, 0); 704134589Sscottl DIP_SET(dp, di_size, sblock.fs_fsize); 705134589Sscottl DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize)); 7061558Srgrimes n_files++; 7071558Srgrimes inodirty(); 70896483Sphk inoinfo(ino)->ino_type = IFTODT(type); 7091558Srgrimes return (ino); 7101558Srgrimes} 7111558Srgrimes 7121558Srgrimes/* 7131558Srgrimes * deallocate an inode 7141558Srgrimes */ 7157585Sbdevoid 71692839Simpfreeino(ino_t ino) 7171558Srgrimes{ 7181558Srgrimes struct inodesc idesc; 71998542Smckusick union dinode *dp; 7201558Srgrimes 72123675Speter memset(&idesc, 0, sizeof(struct inodesc)); 7221558Srgrimes idesc.id_type = ADDR; 7231558Srgrimes idesc.id_func = pass4check; 7241558Srgrimes idesc.id_number = ino; 7251558Srgrimes dp = ginode(ino); 7261558Srgrimes (void)ckinode(dp, &idesc); 7271558Srgrimes clearinode(dp); 7281558Srgrimes inodirty(); 72941474Sjulian inoinfo(ino)->ino_state = USTATE; 7301558Srgrimes n_files--; 7311558Srgrimes} 732