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 55247212Smckusickstatic 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]); 124247212Smckusick 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 154247212Smckusickiblock(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); 171247212Smckusick 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 202247212Smckusick 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) 288241012Smdf errx(EEXIT, "bad inode number %ju to ginode", 289241012Smdf (uintmax_t)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; 295247212Smckusick pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES); 2961558Srgrimes startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 2971558Srgrimes } 29898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 29998542Smckusick return ((union dinode *) 30098542Smckusick &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]); 30198542Smckusick return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]); 3021558Srgrimes} 3031558Srgrimes 3041558Srgrimes/* 3051558Srgrimes * Special purpose version of ginode used to optimize first pass 3061558Srgrimes * over all the inodes in numerical order. 3071558Srgrimes */ 30888413Salfredstatic ino_t nextino, lastinum, lastvalidinum; 309247212Smckusickstatic long readcount, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 310247212Smckusickstatic struct bufarea inobuf; 3111558Srgrimes 31298542Smckusickunion dinode * 313188110Smckusickgetnextinode(ino_t inumber, int rebuildcg) 3141558Srgrimes{ 315188110Smckusick int j; 3161558Srgrimes long size; 317188110Smckusick mode_t mode; 318247212Smckusick ufs2_daddr_t ndb, blk; 31998542Smckusick union dinode *dp; 32098542Smckusick static caddr_t nextinop; 3211558Srgrimes 32263231Smckusick if (inumber != nextino++ || inumber > lastvalidinum) 323241012Smdf errx(EEXIT, "bad inode number %ju to nextinode", 324241012Smdf (uintmax_t)inumber); 3251558Srgrimes if (inumber >= lastinum) { 326247212Smckusick readcount++; 327247212Smckusick blk = ino_to_fsba(&sblock, lastinum); 328247212Smckusick if (readcount % readpercg == 0) { 3291558Srgrimes size = partialsize; 3301558Srgrimes lastinum += partialcnt; 3311558Srgrimes } else { 3321558Srgrimes size = inobufsize; 3331558Srgrimes lastinum += fullcnt; 3341558Srgrimes } 33541474Sjulian /* 336247212Smckusick * If getblk encounters an error, it will already have zeroed 33741474Sjulian * out the buffer, so we do not need to do so here. 33841474Sjulian */ 339247212Smckusick getblk(&inobuf, blk, size); 340247212Smckusick nextinop = inobuf.b_un.b_buf; 3411558Srgrimes } 34298542Smckusick dp = (union dinode *)nextinop; 343247212Smckusick if (rebuildcg && nextinop == inobuf.b_un.b_buf) { 344188110Smckusick /* 345188110Smckusick * Try to determine if we have reached the end of the 346188110Smckusick * allocated inodes. 347188110Smckusick */ 348188110Smckusick mode = DIP(dp, di_mode) & IFMT; 349188110Smckusick if (mode == 0) { 350188110Smckusick if (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 351188110Smckusick NDADDR * sizeof(ufs2_daddr_t)) || 352188110Smckusick memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 353188110Smckusick NIADDR * sizeof(ufs2_daddr_t)) || 354188110Smckusick dp->dp2.di_mode || dp->dp2.di_size) 355188110Smckusick return (NULL); 356188110Smckusick goto inodegood; 357188110Smckusick } 358188110Smckusick if (!ftypeok(dp)) 359188110Smckusick return (NULL); 360188110Smckusick ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 361188110Smckusick if (ndb < 0) 362188110Smckusick return (NULL); 363188110Smckusick if (mode == IFBLK || mode == IFCHR) 364188110Smckusick ndb++; 365188110Smckusick if (mode == IFLNK) { 366188110Smckusick /* 367188110Smckusick * Fake ndb value so direct/indirect block checks below 368188110Smckusick * will detect any garbage after symlink string. 369188110Smckusick */ 370188110Smckusick if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 371188110Smckusick ndb = howmany(DIP(dp, di_size), 372188110Smckusick sizeof(ufs2_daddr_t)); 373188110Smckusick if (ndb > NDADDR) { 374188110Smckusick j = ndb - NDADDR; 375188110Smckusick for (ndb = 1; j > 1; j--) 376188110Smckusick ndb *= NINDIR(&sblock); 377188110Smckusick ndb += NDADDR; 378188110Smckusick } 379188110Smckusick } 380188110Smckusick } 381188110Smckusick for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 382188110Smckusick if (DIP(dp, di_db[j]) != 0) 383188110Smckusick return (NULL); 384188110Smckusick for (j = 0, ndb -= NDADDR; ndb > 0; j++) 385188110Smckusick ndb /= NINDIR(&sblock); 386188110Smckusick for (; j < NIADDR; j++) 387188110Smckusick if (DIP(dp, di_ib[j]) != 0) 388188110Smckusick return (NULL); 389188110Smckusick } 390188110Smckusickinodegood: 39198542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 39298542Smckusick nextinop += sizeof(struct ufs1_dinode); 39398542Smckusick else 39498542Smckusick nextinop += sizeof(struct ufs2_dinode); 39598542Smckusick return (dp); 3961558Srgrimes} 3971558Srgrimes 3987585Sbdevoid 39992839Simpsetinodebuf(ino_t inum) 4001558Srgrimes{ 4011558Srgrimes 40241474Sjulian if (inum % sblock.fs_ipg != 0) 403241012Smdf errx(EEXIT, "bad inode number %ju to setinodebuf", 404241012Smdf (uintmax_t)inum); 40563231Smckusick lastvalidinum = inum + sblock.fs_ipg - 1; 4061558Srgrimes startinum = 0; 40741474Sjulian nextino = inum; 40841474Sjulian lastinum = inum; 409247212Smckusick readcount = 0; 410247212Smckusick if (inobuf.b_un.b_buf != NULL) 41141474Sjulian return; 4121558Srgrimes inobufsize = blkroundup(&sblock, INOBUFSIZE); 41398542Smckusick fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ? 41498542Smckusick sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); 4151558Srgrimes readpercg = sblock.fs_ipg / fullcnt; 4161558Srgrimes partialcnt = sblock.fs_ipg % fullcnt; 41798542Smckusick partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ? 41898542Smckusick sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); 4191558Srgrimes if (partialcnt != 0) { 4201558Srgrimes readpercg++; 4211558Srgrimes } else { 4221558Srgrimes partialcnt = fullcnt; 4231558Srgrimes partialsize = inobufsize; 4241558Srgrimes } 425247212Smckusick initbarea(&inobuf, BT_INODES); 426248658Smckusick if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL) 42737000Scharnier errx(EEXIT, "cannot allocate space for inode buffer"); 4281558Srgrimes} 4291558Srgrimes 4307585Sbdevoid 43192839Simpfreeinodebuf(void) 4321558Srgrimes{ 4331558Srgrimes 434247212Smckusick if (inobuf.b_un.b_buf != NULL) 435247212Smckusick free((char *)inobuf.b_un.b_buf); 436247212Smckusick inobuf.b_un.b_buf = NULL; 4371558Srgrimes} 4381558Srgrimes 4391558Srgrimes/* 4401558Srgrimes * Routines to maintain information about directory inodes. 4411558Srgrimes * This is built during the first pass and used during the 4421558Srgrimes * second and third passes. 4431558Srgrimes * 4441558Srgrimes * Enter inodes into the cache. 4451558Srgrimes */ 4467585Sbdevoid 44798542Smckusickcacheino(union dinode *dp, ino_t inumber) 4481558Srgrimes{ 44998542Smckusick struct inoinfo *inp, **inpp; 45098542Smckusick int i, blks; 4511558Srgrimes 45298542Smckusick if (howmany(DIP(dp, di_size), sblock.fs_bsize) > NDADDR) 4531558Srgrimes blks = NDADDR + NIADDR; 45498542Smckusick else 45598542Smckusick blks = howmany(DIP(dp, di_size), sblock.fs_bsize); 4561558Srgrimes inp = (struct inoinfo *) 457248658Smckusick Malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t)); 4581558Srgrimes if (inp == NULL) 45941474Sjulian errx(EEXIT, "cannot increase directory list"); 46057573Smckusick inpp = &inphead[inumber % dirhash]; 4611558Srgrimes inp->i_nexthash = *inpp; 4621558Srgrimes *inpp = inp; 46341474Sjulian inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0; 4641558Srgrimes inp->i_dotdot = (ino_t)0; 4651558Srgrimes inp->i_number = inumber; 46698542Smckusick inp->i_isize = DIP(dp, di_size); 46798542Smckusick inp->i_numblks = blks; 46898542Smckusick for (i = 0; i < (blks < NDADDR ? blks : NDADDR); i++) 46998542Smckusick inp->i_blks[i] = DIP(dp, di_db[i]); 47098542Smckusick if (blks > NDADDR) 47198542Smckusick for (i = 0; i < NIADDR; i++) 47298542Smckusick inp->i_blks[NDADDR + i] = DIP(dp, di_ib[i]); 4731558Srgrimes if (inplast == listmax) { 4741558Srgrimes listmax += 100; 4751558Srgrimes inpsort = (struct inoinfo **)realloc((char *)inpsort, 4761558Srgrimes (unsigned)listmax * sizeof(struct inoinfo *)); 4771558Srgrimes if (inpsort == NULL) 47823675Speter errx(EEXIT, "cannot increase directory list"); 4791558Srgrimes } 4801558Srgrimes inpsort[inplast++] = inp; 4811558Srgrimes} 4821558Srgrimes 4831558Srgrimes/* 4841558Srgrimes * Look up an inode cache structure. 4851558Srgrimes */ 4861558Srgrimesstruct inoinfo * 48792839Simpgetinoinfo(ino_t inumber) 4881558Srgrimes{ 48992806Sobrien struct inoinfo *inp; 4901558Srgrimes 49157573Smckusick for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { 4921558Srgrimes if (inp->i_number != inumber) 4931558Srgrimes continue; 4941558Srgrimes return (inp); 4951558Srgrimes } 496241012Smdf errx(EEXIT, "cannot find inode %ju", (uintmax_t)inumber); 4971558Srgrimes return ((struct inoinfo *)0); 4981558Srgrimes} 4991558Srgrimes 5001558Srgrimes/* 5011558Srgrimes * Clean up all the inode cache structure. 5021558Srgrimes */ 5037585Sbdevoid 50492839Simpinocleanup(void) 5051558Srgrimes{ 50692806Sobrien struct inoinfo **inpp; 5071558Srgrimes 5081558Srgrimes if (inphead == NULL) 5091558Srgrimes return; 5101558Srgrimes for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 5111558Srgrimes free((char *)(*inpp)); 5121558Srgrimes free((char *)inphead); 5131558Srgrimes free((char *)inpsort); 5141558Srgrimes inphead = inpsort = NULL; 5151558Srgrimes} 5168871Srgrimes 5177585Sbdevoid 51892839Simpinodirty(void) 5191558Srgrimes{ 52023797Sbde 5211558Srgrimes dirty(pbp); 5221558Srgrimes} 5231558Srgrimes 5247585Sbdevoid 525100935Sphkclri(struct inodesc *idesc, const char *type, int flag) 5261558Srgrimes{ 52798542Smckusick union dinode *dp; 5281558Srgrimes 5291558Srgrimes dp = ginode(idesc->id_number); 5301558Srgrimes if (flag == 1) { 5311558Srgrimes pwarn("%s %s", type, 53298542Smckusick (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"); 5331558Srgrimes pinode(idesc->id_number); 5341558Srgrimes } 5351558Srgrimes if (preen || reply("CLEAR") == 1) { 5361558Srgrimes if (preen) 5371558Srgrimes printf(" (CLEARED)\n"); 5381558Srgrimes n_files--; 53974556Smckusick if (bkgrdflag == 0) { 54074556Smckusick (void)ckinode(dp, idesc); 54174556Smckusick inoinfo(idesc->id_number)->ino_state = USTATE; 54274556Smckusick clearinode(dp); 54374556Smckusick inodirty(); 54474556Smckusick } else { 54574556Smckusick cmd.value = idesc->id_number; 54698542Smckusick cmd.size = -DIP(dp, di_nlink); 54774556Smckusick if (debug) 548100935Sphk printf("adjrefcnt ino %ld amt %lld\n", 549100935Sphk (long)cmd.value, (long long)cmd.size); 55074556Smckusick if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 55174556Smckusick &cmd, sizeof cmd) == -1) 55274556Smckusick rwerror("ADJUST INODE", cmd.value); 55374556Smckusick } 5541558Srgrimes } 5551558Srgrimes} 5561558Srgrimes 5577585Sbdeint 55892839Simpfindname(struct inodesc *idesc) 5591558Srgrimes{ 56092806Sobrien struct direct *dirp = idesc->id_dirp; 5611558Srgrimes 56241474Sjulian if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 56341474Sjulian idesc->id_entryno++; 5641558Srgrimes return (KEEPON); 56541474Sjulian } 56623675Speter memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 5671558Srgrimes return (STOP|FOUND); 5681558Srgrimes} 5691558Srgrimes 5707585Sbdeint 57192839Simpfindino(struct inodesc *idesc) 5721558Srgrimes{ 57392806Sobrien struct direct *dirp = idesc->id_dirp; 5741558Srgrimes 5751558Srgrimes if (dirp->d_ino == 0) 5761558Srgrimes return (KEEPON); 5771558Srgrimes if (strcmp(dirp->d_name, idesc->id_name) == 0 && 5781558Srgrimes dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 5791558Srgrimes idesc->id_parent = dirp->d_ino; 5801558Srgrimes return (STOP|FOUND); 5811558Srgrimes } 5821558Srgrimes return (KEEPON); 5831558Srgrimes} 5841558Srgrimes 58541474Sjulianint 58692839Simpclearentry(struct inodesc *idesc) 58741474Sjulian{ 58892806Sobrien struct direct *dirp = idesc->id_dirp; 58941474Sjulian 59041474Sjulian if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 59141474Sjulian idesc->id_entryno++; 59241474Sjulian return (KEEPON); 59341474Sjulian } 59441474Sjulian dirp->d_ino = 0; 59541474Sjulian return (STOP|FOUND|ALTERED); 59641474Sjulian} 59741474Sjulian 5987585Sbdevoid 59992839Simppinode(ino_t ino) 6001558Srgrimes{ 60198542Smckusick union dinode *dp; 60292806Sobrien char *p; 6031558Srgrimes struct passwd *pw; 60424002Speter time_t t; 6051558Srgrimes 60637236Sbde printf(" I=%lu ", (u_long)ino); 6071558Srgrimes if (ino < ROOTINO || ino > maxino) 6081558Srgrimes return; 6091558Srgrimes dp = ginode(ino); 6101558Srgrimes printf(" OWNER="); 61198542Smckusick if ((pw = getpwuid((int)DIP(dp, di_uid))) != 0) 6121558Srgrimes printf("%s ", pw->pw_name); 6131558Srgrimes else 61498542Smckusick printf("%u ", (unsigned)DIP(dp, di_uid)); 61598542Smckusick printf("MODE=%o\n", DIP(dp, di_mode)); 6161558Srgrimes if (preen) 6171558Srgrimes printf("%s: ", cdevname); 618101037Smux printf("SIZE=%ju ", (uintmax_t)DIP(dp, di_size)); 61998542Smckusick t = DIP(dp, di_mtime); 62024002Speter p = ctime(&t); 6211558Srgrimes printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 6221558Srgrimes} 6231558Srgrimes 6247585Sbdevoid 625100935Sphkblkerror(ino_t ino, const char *type, ufs2_daddr_t blk) 6261558Srgrimes{ 6271558Srgrimes 628101037Smux pfatal("%jd %s I=%ju", (intmax_t)blk, type, (uintmax_t)ino); 6291558Srgrimes printf("\n"); 63041474Sjulian switch (inoinfo(ino)->ino_state) { 6311558Srgrimes 6321558Srgrimes case FSTATE: 633136281Struckman case FZLINK: 63441474Sjulian inoinfo(ino)->ino_state = FCLEAR; 6351558Srgrimes return; 6361558Srgrimes 6371558Srgrimes case DSTATE: 638136281Struckman case DZLINK: 63941474Sjulian inoinfo(ino)->ino_state = DCLEAR; 6401558Srgrimes return; 6411558Srgrimes 6421558Srgrimes case FCLEAR: 6431558Srgrimes case DCLEAR: 6441558Srgrimes return; 6451558Srgrimes 6461558Srgrimes default: 64741474Sjulian errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state); 6481558Srgrimes /* NOTREACHED */ 6491558Srgrimes } 6501558Srgrimes} 6511558Srgrimes 6521558Srgrimes/* 6531558Srgrimes * allocate an unused inode 6541558Srgrimes */ 6551558Srgrimesino_t 65692839Simpallocino(ino_t request, int type) 6571558Srgrimes{ 65892806Sobrien ino_t ino; 65998542Smckusick union dinode *dp; 660248658Smckusick struct bufarea *cgbp; 661248658Smckusick struct cg *cgp; 66234266Sjulian int cg; 6631558Srgrimes 6641558Srgrimes if (request == 0) 6651558Srgrimes request = ROOTINO; 66641474Sjulian else if (inoinfo(request)->ino_state != USTATE) 6671558Srgrimes return (0); 6681558Srgrimes for (ino = request; ino < maxino; ino++) 66941474Sjulian if (inoinfo(ino)->ino_state == USTATE) 6701558Srgrimes break; 6711558Srgrimes if (ino == maxino) 6721558Srgrimes return (0); 67334266Sjulian cg = ino_to_cg(&sblock, ino); 674248658Smckusick cgbp = cgget(cg); 675248658Smckusick cgp = cgbp->b_un.b_cg; 676248658Smckusick if (!check_cgmagic(cg, cgbp)) 677188110Smckusick return (0); 67834266Sjulian setbit(cg_inosused(cgp), ino % sblock.fs_ipg); 67934266Sjulian cgp->cg_cs.cs_nifree--; 6801558Srgrimes switch (type & IFMT) { 6811558Srgrimes case IFDIR: 68241474Sjulian inoinfo(ino)->ino_state = DSTATE; 68334266Sjulian cgp->cg_cs.cs_ndir++; 6841558Srgrimes break; 6851558Srgrimes case IFREG: 6861558Srgrimes case IFLNK: 68741474Sjulian inoinfo(ino)->ino_state = FSTATE; 6881558Srgrimes break; 6891558Srgrimes default: 6901558Srgrimes return (0); 6911558Srgrimes } 692248658Smckusick dirty(cgbp); 6931558Srgrimes dp = ginode(ino); 694134589Sscottl DIP_SET(dp, di_db[0], allocblk((long)1)); 69598542Smckusick if (DIP(dp, di_db[0]) == 0) { 69641474Sjulian inoinfo(ino)->ino_state = USTATE; 6971558Srgrimes return (0); 6981558Srgrimes } 699134589Sscottl DIP_SET(dp, di_mode, type); 700134589Sscottl DIP_SET(dp, di_flags, 0); 701134589Sscottl DIP_SET(dp, di_atime, time(NULL)); 702134589Sscottl DIP_SET(dp, di_ctime, DIP(dp, di_atime)); 703134589Sscottl DIP_SET(dp, di_mtime, DIP(dp, di_ctime)); 704134589Sscottl DIP_SET(dp, di_mtimensec, 0); 705134589Sscottl DIP_SET(dp, di_ctimensec, 0); 706134589Sscottl DIP_SET(dp, di_atimensec, 0); 707134589Sscottl DIP_SET(dp, di_size, sblock.fs_fsize); 708134589Sscottl DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize)); 7091558Srgrimes n_files++; 7101558Srgrimes inodirty(); 71196483Sphk inoinfo(ino)->ino_type = IFTODT(type); 7121558Srgrimes return (ino); 7131558Srgrimes} 7141558Srgrimes 7151558Srgrimes/* 7161558Srgrimes * deallocate an inode 7171558Srgrimes */ 7187585Sbdevoid 71992839Simpfreeino(ino_t ino) 7201558Srgrimes{ 7211558Srgrimes struct inodesc idesc; 72298542Smckusick union dinode *dp; 7231558Srgrimes 72423675Speter memset(&idesc, 0, sizeof(struct inodesc)); 7251558Srgrimes idesc.id_type = ADDR; 7261558Srgrimes idesc.id_func = pass4check; 7271558Srgrimes idesc.id_number = ino; 7281558Srgrimes dp = ginode(ino); 7291558Srgrimes (void)ckinode(dp, &idesc); 7301558Srgrimes clearinode(dp); 7311558Srgrimes inodirty(); 73241474Sjulian inoinfo(ino)->ino_state = USTATE; 7331558Srgrimes n_files--; 7341558Srgrimes} 735