inode.c revision 302408
157416Smarkm/* 257416Smarkm * Copyright (c) 1980, 1986, 1993 357416Smarkm * The Regents of the University of California. All rights reserved. 457416Smarkm * 557416Smarkm * Redistribution and use in source and binary forms, with or without 657416Smarkm * modification, are permitted provided that the following conditions 757416Smarkm * are met: 857416Smarkm * 1. Redistributions of source code must retain the above copyright 957416Smarkm * notice, this list of conditions and the following disclaimer. 1057416Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1157416Smarkm * notice, this list of conditions and the following disclaimer in the 1257416Smarkm * documentation and/or other materials provided with the distribution. 1357416Smarkm * 4. Neither the name of the University nor the names of its contributors 1457416Smarkm * may be used to endorse or promote products derived from this software 1557416Smarkm * without specific prior written permission. 1657416Smarkm * 1757416Smarkm * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1857416Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1957416Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2057416Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2157416Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2257416Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2357416Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2457416Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2557416Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2657416Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2757416Smarkm * SUCH DAMAGE. 2857416Smarkm */ 2957416Smarkm 3057416Smarkm#if 0 3157416Smarkm#ifndef lint 3257416Smarkmstatic const char sccsid[] = "@(#)inode.c 8.8 (Berkeley) 4/28/95"; 3357416Smarkm#endif /* not lint */ 3457416Smarkm#endif 3557416Smarkm#include <sys/cdefs.h> 3657416Smarkm__FBSDID("$FreeBSD: stable/11/sbin/fsck_ffs/inode.c 298907 2016-05-02 01:28:21Z araujo $"); 3757416Smarkm 3857416Smarkm#include <sys/param.h> 3957416Smarkm#include <sys/stdint.h> 40233294Sstas#include <sys/sysctl.h> 4157416Smarkm 4257416Smarkm#include <ufs/ufs/dinode.h> 4357416Smarkm#include <ufs/ufs/dir.h> 4457416Smarkm#include <ufs/ffs/fs.h> 4557416Smarkm 4657416Smarkm#include <err.h> 4757416Smarkm#include <pwd.h> 4857416Smarkm#include <string.h> 4957416Smarkm#include <time.h> 5057416Smarkm 5157416Smarkm#include "fsck.h" 5257416Smarkm 5357416Smarkmstatic ino_t startinum; 5457416Smarkm 5557416Smarkmstatic int iblock(struct inodesc *, long ilevel, off_t isize, int type); 5657416Smarkm 5757416Smarkmint 5857416Smarkmckinode(union dinode *dp, struct inodesc *idesc) 5957416Smarkm{ 6057416Smarkm off_t remsize, sizepb; 6157416Smarkm int i, offset, ret; 6257416Smarkm union dinode dino; 6357416Smarkm ufs2_daddr_t ndb; 6457416Smarkm mode_t mode; 6557416Smarkm char pathbuf[MAXPATHLEN + 1]; 6657416Smarkm 6757416Smarkm if (idesc->id_fix != IGNORE) 6857416Smarkm idesc->id_fix = DONTKNOW; 6957416Smarkm idesc->id_lbn = -1; 7057416Smarkm idesc->id_entryno = 0; 7157416Smarkm idesc->id_filesize = DIP(dp, di_size); 7257416Smarkm mode = DIP(dp, di_mode) & IFMT; 7357416Smarkm if (mode == IFBLK || mode == IFCHR || (mode == IFLNK && 7457416Smarkm DIP(dp, di_size) < (unsigned)sblock.fs_maxsymlinklen)) 7557416Smarkm return (KEEPON); 7657416Smarkm if (sblock.fs_magic == FS_UFS1_MAGIC) 7757416Smarkm dino.dp1 = dp->dp1; 7857416Smarkm else 7957416Smarkm dino.dp2 = dp->dp2; 8057416Smarkm ndb = howmany(DIP(&dino, di_size), sblock.fs_bsize); 8157416Smarkm for (i = 0; i < NDADDR; i++) { 8257416Smarkm idesc->id_lbn++; 8357416Smarkm if (--ndb == 0 && 8457416Smarkm (offset = blkoff(&sblock, DIP(&dino, di_size))) != 0) 8557416Smarkm idesc->id_numfrags = 8657416Smarkm numfrags(&sblock, fragroundup(&sblock, offset)); 8757416Smarkm else 8857416Smarkm idesc->id_numfrags = sblock.fs_frag; 8957416Smarkm if (DIP(&dino, di_db[i]) == 0) { 9057416Smarkm if (idesc->id_type == DATA && ndb >= 0) { 9157416Smarkm /* An empty block in a directory XXX */ 9257416Smarkm getpathname(pathbuf, idesc->id_number, 9357416Smarkm idesc->id_number); 9457416Smarkm pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 9557416Smarkm pathbuf); 9657416Smarkm if (reply("ADJUST LENGTH") == 1) { 9757416Smarkm dp = ginode(idesc->id_number); 9857416Smarkm DIP_SET(dp, di_size, 9957416Smarkm i * sblock.fs_bsize); 10057416Smarkm printf( 10157416Smarkm "YOU MUST RERUN FSCK AFTERWARDS\n"); 10257416Smarkm rerun = 1; 10357416Smarkm inodirty(); 10457416Smarkm 10557416Smarkm } 10657416Smarkm } 10757416Smarkm continue; 10857416Smarkm } 10957416Smarkm idesc->id_blkno = DIP(&dino, di_db[i]); 11057416Smarkm if (idesc->id_type != DATA) 11157416Smarkm ret = (*idesc->id_func)(idesc); 11257416Smarkm else 11357416Smarkm ret = dirscan(idesc); 11457416Smarkm if (ret & STOP) 11557416Smarkm return (ret); 11657416Smarkm } 11757416Smarkm idesc->id_numfrags = sblock.fs_frag; 11857416Smarkm remsize = DIP(&dino, di_size) - sblock.fs_bsize * NDADDR; 11957416Smarkm sizepb = sblock.fs_bsize; 12057416Smarkm for (i = 0; i < NIADDR; i++) { 12157416Smarkm sizepb *= NINDIR(&sblock); 12257416Smarkm if (DIP(&dino, di_ib[i])) { 12357416Smarkm idesc->id_blkno = DIP(&dino, di_ib[i]); 12457416Smarkm ret = iblock(idesc, i + 1, remsize, BT_LEVEL1 + i); 12557416Smarkm if (ret & STOP) 12657416Smarkm return (ret); 12757416Smarkm } else { 12857416Smarkm idesc->id_lbn += sizepb / sblock.fs_bsize; 12957416Smarkm if (idesc->id_type == DATA && remsize > 0) { 13057416Smarkm /* An empty block in a directory XXX */ 13157416Smarkm getpathname(pathbuf, idesc->id_number, 13257416Smarkm idesc->id_number); 13357416Smarkm pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 13457416Smarkm pathbuf); 13557416Smarkm if (reply("ADJUST LENGTH") == 1) { 13657416Smarkm dp = ginode(idesc->id_number); 13757416Smarkm DIP_SET(dp, di_size, 13857416Smarkm DIP(dp, di_size) - remsize); 13957416Smarkm remsize = 0; 14057416Smarkm printf( 14157416Smarkm "YOU MUST RERUN FSCK AFTERWARDS\n"); 14257416Smarkm rerun = 1; 14357416Smarkm inodirty(); 14457416Smarkm break; 14557416Smarkm } 14657416Smarkm } 14757416Smarkm } 14857416Smarkm remsize -= sizepb; 14957416Smarkm } 15057416Smarkm return (KEEPON); 15157416Smarkm} 15257416Smarkm 15357416Smarkmstatic int 15457416Smarkmiblock(struct inodesc *idesc, long ilevel, off_t isize, int type) 15557416Smarkm{ 15657416Smarkm struct bufarea *bp; 15757416Smarkm int i, n, (*func)(struct inodesc *), nif; 15857416Smarkm off_t sizepb; 15957416Smarkm char buf[BUFSIZ]; 16057416Smarkm char pathbuf[MAXPATHLEN + 1]; 16157416Smarkm union dinode *dp; 16257416Smarkm 16357416Smarkm if (idesc->id_type != DATA) { 16457416Smarkm func = idesc->id_func; 16557416Smarkm if (((n = (*func)(idesc)) & KEEPON) == 0) 16657416Smarkm return (n); 16757416Smarkm } else 16857416Smarkm func = dirscan; 16957416Smarkm if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 17057416Smarkm return (SKIP); 17157416Smarkm bp = getdatablk(idesc->id_blkno, sblock.fs_bsize, type); 17257416Smarkm ilevel--; 17357416Smarkm for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 17457416Smarkm sizepb *= NINDIR(&sblock); 17557416Smarkm if (howmany(isize, sizepb) > NINDIR(&sblock)) 17657416Smarkm nif = NINDIR(&sblock); 17757416Smarkm else 17857416Smarkm nif = howmany(isize, sizepb); 17957416Smarkm if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 18057416Smarkm for (i = nif; i < NINDIR(&sblock); i++) { 18157416Smarkm if (IBLK(bp, i) == 0) 18257416Smarkm continue; 18357416Smarkm (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 18457416Smarkm (u_long)idesc->id_number); 18557416Smarkm if (preen) { 18657416Smarkm pfatal("%s", buf); 18757416Smarkm } else if (dofix(idesc, buf)) { 18857416Smarkm IBLK_SET(bp, i, 0); 18957416Smarkm dirty(bp); 19057416Smarkm } 19157416Smarkm } 19257416Smarkm flush(fswritefd, bp); 19357416Smarkm } 19457416Smarkm for (i = 0; i < nif; i++) { 19557416Smarkm if (ilevel == 0) 19657416Smarkm idesc->id_lbn++; 19757416Smarkm if (IBLK(bp, i)) { 19857416Smarkm idesc->id_blkno = IBLK(bp, i); 19957416Smarkm if (ilevel == 0) 20057416Smarkm n = (*func)(idesc); 20157416Smarkm else 20257416Smarkm n = iblock(idesc, ilevel, isize, type); 20357416Smarkm if (n & STOP) { 20457416Smarkm bp->b_flags &= ~B_INUSE; 20557416Smarkm return (n); 20657416Smarkm } 20757416Smarkm } else { 20857416Smarkm if (idesc->id_type == DATA && isize > 0) { 20957416Smarkm /* An empty block in a directory XXX */ 21057416Smarkm getpathname(pathbuf, idesc->id_number, 21157416Smarkm idesc->id_number); 21257416Smarkm pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 21357416Smarkm pathbuf); 21457416Smarkm if (reply("ADJUST LENGTH") == 1) { 21557416Smarkm dp = ginode(idesc->id_number); 21657416Smarkm DIP_SET(dp, di_size, 21757416Smarkm DIP(dp, di_size) - isize); 21857416Smarkm isize = 0; 21957416Smarkm printf( 22057416Smarkm "YOU MUST RERUN FSCK AFTERWARDS\n"); 22157416Smarkm rerun = 1; 22257416Smarkm inodirty(); 22357416Smarkm bp->b_flags &= ~B_INUSE; 22457416Smarkm return(STOP); 22557416Smarkm } 22657416Smarkm } 22757416Smarkm } 22857416Smarkm isize -= sizepb; 22957416Smarkm } 23057416Smarkm bp->b_flags &= ~B_INUSE; 23157416Smarkm return (KEEPON); 23257416Smarkm} 23357416Smarkm 23457416Smarkm/* 23557416Smarkm * Check that a block in a legal block number. 23657416Smarkm * Return 0 if in range, 1 if out of range. 23757416Smarkm */ 23857416Smarkmint 23957416Smarkmchkrange(ufs2_daddr_t blk, int cnt) 24057416Smarkm{ 24157416Smarkm int c; 24257416Smarkm 24357416Smarkm if (cnt <= 0 || blk <= 0 || blk > maxfsblock || 24457416Smarkm cnt - 1 > maxfsblock - blk) 24557416Smarkm return (1); 24657416Smarkm if (cnt > sblock.fs_frag || 24757416Smarkm fragnum(&sblock, blk) + cnt > sblock.fs_frag) { 24857416Smarkm if (debug) 24957416Smarkm printf("bad size: blk %ld, offset %i, size %d\n", 25057416Smarkm (long)blk, (int)fragnum(&sblock, blk), cnt); 251233294Sstas return (1); 252233294Sstas } 253233294Sstas c = dtog(&sblock, blk); 254233294Sstas if (blk < cgdmin(&sblock, c)) { 255233294Sstas if ((blk + cnt) > cgsblock(&sblock, c)) { 256233294Sstas if (debug) { 257233294Sstas printf("blk %ld < cgdmin %ld;", 258233294Sstas (long)blk, (long)cgdmin(&sblock, c)); 259233294Sstas printf(" blk + cnt %ld > cgsbase %ld\n", 260233294Sstas (long)(blk + cnt), 261233294Sstas (long)cgsblock(&sblock, c)); 262233294Sstas } 26357416Smarkm return (1); 264233294Sstas } 26557416Smarkm } else { 26657416Smarkm if ((blk + cnt) > cgbase(&sblock, c+1)) { 26757416Smarkm if (debug) { 26857416Smarkm printf("blk %ld >= cgdmin %ld;", 26957416Smarkm (long)blk, (long)cgdmin(&sblock, c)); 27057416Smarkm printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 27157416Smarkm (long)(blk + cnt), (long)sblock.fs_fpg); 27257416Smarkm } 27357416Smarkm return (1); 27457416Smarkm } 27557416Smarkm } 27657416Smarkm return (0); 27757416Smarkm} 27857416Smarkm 27957416Smarkm/* 28057416Smarkm * General purpose interface for reading inodes. 28157416Smarkm */ 28257416Smarkmunion dinode * 28357416Smarkmginode(ino_t inumber) 28457416Smarkm{ 28557416Smarkm ufs2_daddr_t iblk; 28657416Smarkm 28757416Smarkm if (inumber < ROOTINO || inumber > maxino) 28857416Smarkm errx(EEXIT, "bad inode number %ju to ginode", 28957416Smarkm (uintmax_t)inumber); 29057416Smarkm if (startinum == 0 || 29157416Smarkm inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 29257416Smarkm iblk = ino_to_fsba(&sblock, inumber); 29357416Smarkm if (pbp != NULL) 29457416Smarkm pbp->b_flags &= ~B_INUSE; 29557416Smarkm pbp = getdatablk(iblk, sblock.fs_bsize, BT_INODES); 29657416Smarkm startinum = rounddown(inumber, INOPB(&sblock)); 29757416Smarkm } 29857416Smarkm if (sblock.fs_magic == FS_UFS1_MAGIC) 29957416Smarkm return ((union dinode *) 30057416Smarkm &pbp->b_un.b_dinode1[inumber % INOPB(&sblock)]); 30157416Smarkm return ((union dinode *)&pbp->b_un.b_dinode2[inumber % INOPB(&sblock)]); 30257416Smarkm} 30357416Smarkm 30457416Smarkm/* 30557416Smarkm * Special purpose version of ginode used to optimize first pass 30657416Smarkm * over all the inodes in numerical order. 30757416Smarkm */ 30857416Smarkmstatic ino_t nextino, lastinum, lastvalidinum; 30957416Smarkmstatic long readcount, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 310233294Sstasstatic struct bufarea inobuf; 311233294Sstas 312233294Sstasunion dinode * 31357416Smarkmgetnextinode(ino_t inumber, int rebuildcg) 31457416Smarkm{ 31557416Smarkm int j; 31657416Smarkm long size; 31757416Smarkm mode_t mode; 31857416Smarkm ufs2_daddr_t ndb, blk; 31957416Smarkm union dinode *dp; 32057416Smarkm static caddr_t nextinop; 32157416Smarkm 32257416Smarkm if (inumber != nextino++ || inumber > lastvalidinum) 32357416Smarkm errx(EEXIT, "bad inode number %ju to nextinode", 32457416Smarkm (uintmax_t)inumber); 32557416Smarkm if (inumber >= lastinum) { 32657416Smarkm readcount++; 32757416Smarkm blk = ino_to_fsba(&sblock, lastinum); 32857416Smarkm if (readcount % readpercg == 0) { 32957416Smarkm size = partialsize; 33057416Smarkm lastinum += partialcnt; 33157416Smarkm } else { 332233294Sstas size = inobufsize; 33357416Smarkm lastinum += fullcnt; 33457416Smarkm } 33557416Smarkm /* 33657416Smarkm * If getblk encounters an error, it will already have zeroed 33757416Smarkm * out the buffer, so we do not need to do so here. 33857416Smarkm */ 33957416Smarkm getblk(&inobuf, blk, size); 34057416Smarkm nextinop = inobuf.b_un.b_buf; 34157416Smarkm } 34257416Smarkm dp = (union dinode *)nextinop; 34357416Smarkm if (rebuildcg && nextinop == inobuf.b_un.b_buf) { 34457416Smarkm /* 34557416Smarkm * Try to determine if we have reached the end of the 34657416Smarkm * allocated inodes. 34757416Smarkm */ 34857416Smarkm mode = DIP(dp, di_mode) & IFMT; 34957416Smarkm if (mode == 0) { 35057416Smarkm if (memcmp(dp->dp2.di_db, ufs2_zino.di_db, 35157416Smarkm NDADDR * sizeof(ufs2_daddr_t)) || 35257416Smarkm memcmp(dp->dp2.di_ib, ufs2_zino.di_ib, 35357416Smarkm NIADDR * sizeof(ufs2_daddr_t)) || 35457416Smarkm dp->dp2.di_mode || dp->dp2.di_size) 35557416Smarkm return (NULL); 35657416Smarkm goto inodegood; 35757416Smarkm } 35857416Smarkm if (!ftypeok(dp)) 35957416Smarkm return (NULL); 36057416Smarkm ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 36157416Smarkm if (ndb < 0) 36257416Smarkm return (NULL); 36357416Smarkm if (mode == IFBLK || mode == IFCHR) 36457416Smarkm ndb++; 36557416Smarkm if (mode == IFLNK) { 36657416Smarkm /* 36757416Smarkm * Fake ndb value so direct/indirect block checks below 36857416Smarkm * will detect any garbage after symlink string. 36957416Smarkm */ 37057416Smarkm if (DIP(dp, di_size) < (off_t)sblock.fs_maxsymlinklen) { 37157416Smarkm ndb = howmany(DIP(dp, di_size), 37257416Smarkm sizeof(ufs2_daddr_t)); 37357416Smarkm if (ndb > NDADDR) { 37457416Smarkm j = ndb - NDADDR; 37557416Smarkm for (ndb = 1; j > 1; j--) 37657416Smarkm ndb *= NINDIR(&sblock); 37757416Smarkm ndb += NDADDR; 37857416Smarkm } 37957416Smarkm } 38057416Smarkm } 38157416Smarkm for (j = ndb; ndb < NDADDR && j < NDADDR; j++) 38257416Smarkm if (DIP(dp, di_db[j]) != 0) 38357416Smarkm return (NULL); 38457416Smarkm for (j = 0, ndb -= NDADDR; ndb > 0; j++) 38557416Smarkm ndb /= NINDIR(&sblock); 38657416Smarkm for (; j < NIADDR; j++) 38757416Smarkm if (DIP(dp, di_ib[j]) != 0) 38857416Smarkm return (NULL); 38957416Smarkm } 39057416Smarkminodegood: 39157416Smarkm if (sblock.fs_magic == FS_UFS1_MAGIC) 39257416Smarkm nextinop += sizeof(struct ufs1_dinode); 39357416Smarkm else 39457416Smarkm nextinop += sizeof(struct ufs2_dinode); 39557416Smarkm return (dp); 39657416Smarkm} 39757416Smarkm 39857416Smarkmvoid 39957416Smarkmsetinodebuf(ino_t inum) 40057416Smarkm{ 40157416Smarkm 40257416Smarkm if (inum % sblock.fs_ipg != 0) 40357416Smarkm errx(EEXIT, "bad inode number %ju to setinodebuf", 40457416Smarkm (uintmax_t)inum); 40557416Smarkm lastvalidinum = inum + sblock.fs_ipg - 1; 40657416Smarkm startinum = 0; 40757416Smarkm nextino = inum; 40857416Smarkm lastinum = inum; 40957416Smarkm readcount = 0; 41057416Smarkm if (inobuf.b_un.b_buf != NULL) 41157416Smarkm return; 41257416Smarkm inobufsize = blkroundup(&sblock, INOBUFSIZE); 41357416Smarkm fullcnt = inobufsize / ((sblock.fs_magic == FS_UFS1_MAGIC) ? 41457416Smarkm sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); 41557416Smarkm readpercg = sblock.fs_ipg / fullcnt; 41657416Smarkm partialcnt = sblock.fs_ipg % fullcnt; 41757416Smarkm partialsize = partialcnt * ((sblock.fs_magic == FS_UFS1_MAGIC) ? 41857416Smarkm sizeof(struct ufs1_dinode) : sizeof(struct ufs2_dinode)); 41957416Smarkm if (partialcnt != 0) { 42057416Smarkm readpercg++; 42157416Smarkm } else { 42257416Smarkm partialcnt = fullcnt; 42357416Smarkm partialsize = inobufsize; 42457416Smarkm } 42557416Smarkm initbarea(&inobuf, BT_INODES); 42657416Smarkm if ((inobuf.b_un.b_buf = Malloc((unsigned)inobufsize)) == NULL) 42757416Smarkm errx(EEXIT, "cannot allocate space for inode buffer"); 42857416Smarkm} 42957416Smarkm 43057416Smarkmvoid 43157416Smarkmfreeinodebuf(void) 43257416Smarkm{ 43357416Smarkm 43457416Smarkm if (inobuf.b_un.b_buf != NULL) 43557416Smarkm free((char *)inobuf.b_un.b_buf); 43657416Smarkm inobuf.b_un.b_buf = NULL; 43757416Smarkm} 43857416Smarkm 43957416Smarkm/* 44057416Smarkm * Routines to maintain information about directory inodes. 44157416Smarkm * This is built during the first pass and used during the 44257416Smarkm * second and third passes. 44357416Smarkm * 44457416Smarkm * Enter inodes into the cache. 44557416Smarkm */ 44657416Smarkmvoid 44757416Smarkmcacheino(union dinode *dp, ino_t inumber) 44857416Smarkm{ 44957416Smarkm struct inoinfo *inp, **inpp; 45057416Smarkm int i, blks; 45157416Smarkm 45257416Smarkm if (howmany(DIP(dp, di_size), sblock.fs_bsize) > NDADDR) 45357416Smarkm blks = NDADDR + NIADDR; 45457416Smarkm else 45557416Smarkm blks = howmany(DIP(dp, di_size), sblock.fs_bsize); 45657416Smarkm inp = (struct inoinfo *) 45757416Smarkm Malloc(sizeof(*inp) + (blks - 1) * sizeof(ufs2_daddr_t)); 45857416Smarkm if (inp == NULL) 45957416Smarkm errx(EEXIT, "cannot increase directory list"); 46057416Smarkm inpp = &inphead[inumber % dirhash]; 46157416Smarkm inp->i_nexthash = *inpp; 46257416Smarkm *inpp = inp; 46357416Smarkm inp->i_parent = inumber == ROOTINO ? ROOTINO : (ino_t)0; 46457416Smarkm inp->i_dotdot = (ino_t)0; 46557416Smarkm inp->i_number = inumber; 46657416Smarkm inp->i_isize = DIP(dp, di_size); 46757416Smarkm inp->i_numblks = blks; 46857416Smarkm for (i = 0; i < MIN(blks, NDADDR); i++) 46957416Smarkm inp->i_blks[i] = DIP(dp, di_db[i]); 47057416Smarkm if (blks > NDADDR) 47157416Smarkm for (i = 0; i < NIADDR; i++) 47257416Smarkm inp->i_blks[NDADDR + i] = DIP(dp, di_ib[i]); 47357416Smarkm if (inplast == listmax) { 47457416Smarkm listmax += 100; 47557416Smarkm inpsort = (struct inoinfo **)realloc((char *)inpsort, 47657416Smarkm (unsigned)listmax * sizeof(struct inoinfo *)); 47757416Smarkm if (inpsort == NULL) 47857416Smarkm errx(EEXIT, "cannot increase directory list"); 47957416Smarkm } 48057416Smarkm inpsort[inplast++] = inp; 48157416Smarkm} 48257416Smarkm 48357416Smarkm/* 48457416Smarkm * Look up an inode cache structure. 48557416Smarkm */ 48657416Smarkmstruct inoinfo * 48757416Smarkmgetinoinfo(ino_t inumber) 48857416Smarkm{ 48957416Smarkm struct inoinfo *inp; 49057416Smarkm 49157416Smarkm for (inp = inphead[inumber % dirhash]; inp; inp = inp->i_nexthash) { 49257416Smarkm if (inp->i_number != inumber) 49357416Smarkm continue; 49457416Smarkm return (inp); 49557416Smarkm } 49657416Smarkm errx(EEXIT, "cannot find inode %ju", (uintmax_t)inumber); 49757416Smarkm return ((struct inoinfo *)0); 49857416Smarkm} 49957416Smarkm 50057416Smarkm/* 50157416Smarkm * Clean up all the inode cache structure. 50257416Smarkm */ 50357416Smarkmvoid 50457416Smarkminocleanup(void) 50557416Smarkm{ 50657416Smarkm struct inoinfo **inpp; 50757416Smarkm 50857416Smarkm if (inphead == NULL) 50957416Smarkm return; 51057416Smarkm for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 51157416Smarkm free((char *)(*inpp)); 51257416Smarkm free((char *)inphead); 51357416Smarkm free((char *)inpsort); 51457416Smarkm inphead = inpsort = NULL; 51557416Smarkm} 51657416Smarkm 51757416Smarkmvoid 51857416Smarkminodirty(void) 51957416Smarkm{ 52057416Smarkm 52157416Smarkm dirty(pbp); 52257416Smarkm} 52357416Smarkm 52457416Smarkmvoid 52557416Smarkmclri(struct inodesc *idesc, const char *type, int flag) 52657416Smarkm{ 52757416Smarkm union dinode *dp; 52857416Smarkm 52957416Smarkm dp = ginode(idesc->id_number); 53057416Smarkm if (flag == 1) { 53157416Smarkm pwarn("%s %s", type, 53257416Smarkm (DIP(dp, di_mode) & IFMT) == IFDIR ? "DIR" : "FILE"); 53357416Smarkm pinode(idesc->id_number); 53457416Smarkm } 53557416Smarkm if (preen || reply("CLEAR") == 1) { 53657416Smarkm if (preen) 53757416Smarkm printf(" (CLEARED)\n"); 53857416Smarkm n_files--; 53957416Smarkm if (bkgrdflag == 0) { 54057416Smarkm (void)ckinode(dp, idesc); 54157416Smarkm inoinfo(idesc->id_number)->ino_state = USTATE; 54257416Smarkm clearinode(dp); 54357416Smarkm inodirty(); 54457416Smarkm } else { 54557416Smarkm cmd.value = idesc->id_number; 54657416Smarkm cmd.size = -DIP(dp, di_nlink); 54757416Smarkm if (debug) 54857416Smarkm printf("adjrefcnt ino %ld amt %lld\n", 54957416Smarkm (long)cmd.value, (long long)cmd.size); 55057416Smarkm if (sysctl(adjrefcnt, MIBSIZE, 0, 0, 55157416Smarkm &cmd, sizeof cmd) == -1) 55257416Smarkm rwerror("ADJUST INODE", cmd.value); 55357416Smarkm } 55457416Smarkm } 55557416Smarkm} 55657416Smarkm 55757416Smarkmint 55857416Smarkmfindname(struct inodesc *idesc) 55957416Smarkm{ 56057416Smarkm struct direct *dirp = idesc->id_dirp; 56157416Smarkm 56257416Smarkm if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 56357416Smarkm idesc->id_entryno++; 56457416Smarkm return (KEEPON); 56557416Smarkm } 56657416Smarkm memmove(idesc->id_name, dirp->d_name, (size_t)dirp->d_namlen + 1); 56757416Smarkm return (STOP|FOUND); 56857416Smarkm} 56957416Smarkm 57057416Smarkmint 57157416Smarkmfindino(struct inodesc *idesc) 57257416Smarkm{ 57357416Smarkm struct direct *dirp = idesc->id_dirp; 57457416Smarkm 57557416Smarkm if (dirp->d_ino == 0) 57657416Smarkm return (KEEPON); 57757416Smarkm if (strcmp(dirp->d_name, idesc->id_name) == 0 && 57857416Smarkm dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 57957416Smarkm idesc->id_parent = dirp->d_ino; 58057416Smarkm return (STOP|FOUND); 58157416Smarkm } 58257416Smarkm return (KEEPON); 58357416Smarkm} 58457416Smarkm 58557416Smarkmint 58657416Smarkmclearentry(struct inodesc *idesc) 58757416Smarkm{ 58857416Smarkm struct direct *dirp = idesc->id_dirp; 58957416Smarkm 59057416Smarkm if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 59157416Smarkm idesc->id_entryno++; 59257416Smarkm return (KEEPON); 59357416Smarkm } 59457416Smarkm dirp->d_ino = 0; 59557416Smarkm return (STOP|FOUND|ALTERED); 59657416Smarkm} 59757416Smarkm 59857416Smarkmvoid 59957416Smarkmpinode(ino_t ino) 60057416Smarkm{ 60157416Smarkm union dinode *dp; 60257416Smarkm char *p; 60357416Smarkm struct passwd *pw; 60457416Smarkm time_t t; 60557416Smarkm 60657416Smarkm printf(" I=%lu ", (u_long)ino); 60757416Smarkm if (ino < ROOTINO || ino > maxino) 60857416Smarkm return; 60957416Smarkm dp = ginode(ino); 61057416Smarkm printf(" OWNER="); 61157416Smarkm if ((pw = getpwuid((int)DIP(dp, di_uid))) != NULL) 61257416Smarkm printf("%s ", pw->pw_name); 61357416Smarkm else 61457416Smarkm printf("%u ", (unsigned)DIP(dp, di_uid)); 61557416Smarkm printf("MODE=%o\n", DIP(dp, di_mode)); 61657416Smarkm if (preen) 61757416Smarkm printf("%s: ", cdevname); 61857416Smarkm printf("SIZE=%ju ", (uintmax_t)DIP(dp, di_size)); 61957416Smarkm t = DIP(dp, di_mtime); 62057416Smarkm p = ctime(&t); 62157416Smarkm printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 62257416Smarkm} 62357416Smarkm 62457416Smarkmvoid 62557416Smarkmblkerror(ino_t ino, const char *type, ufs2_daddr_t blk) 62657416Smarkm{ 62757416Smarkm 62857416Smarkm pfatal("%jd %s I=%ju", (intmax_t)blk, type, (uintmax_t)ino); 62957416Smarkm printf("\n"); 63057416Smarkm switch (inoinfo(ino)->ino_state) { 63157416Smarkm 63257416Smarkm case FSTATE: 63357416Smarkm case FZLINK: 63457416Smarkm inoinfo(ino)->ino_state = FCLEAR; 63557416Smarkm return; 63657416Smarkm 63757416Smarkm case DSTATE: 63857416Smarkm case DZLINK: 63957416Smarkm inoinfo(ino)->ino_state = DCLEAR; 64057416Smarkm return; 64157416Smarkm 64257416Smarkm case FCLEAR: 64357416Smarkm case DCLEAR: 64457416Smarkm return; 64557416Smarkm 64657416Smarkm default: 64757416Smarkm errx(EEXIT, "BAD STATE %d TO BLKERR", inoinfo(ino)->ino_state); 64857416Smarkm /* NOTREACHED */ 64957416Smarkm } 65057416Smarkm} 65157416Smarkm 65257416Smarkm/* 65357416Smarkm * allocate an unused inode 65457416Smarkm */ 65557416Smarkmino_t 65657416Smarkmallocino(ino_t request, int type) 65757416Smarkm{ 65857416Smarkm ino_t ino; 65957416Smarkm union dinode *dp; 66057416Smarkm struct bufarea *cgbp; 66157416Smarkm struct cg *cgp; 66257416Smarkm int cg; 66357416Smarkm 66457416Smarkm if (request == 0) 66557416Smarkm request = ROOTINO; 66657416Smarkm else if (inoinfo(request)->ino_state != USTATE) 66757416Smarkm return (0); 66857416Smarkm for (ino = request; ino < maxino; ino++) 66957416Smarkm if (inoinfo(ino)->ino_state == USTATE) 67057416Smarkm break; 67157416Smarkm if (ino == maxino) 67257416Smarkm return (0); 67357416Smarkm cg = ino_to_cg(&sblock, ino); 67457416Smarkm cgbp = cgget(cg); 67557416Smarkm cgp = cgbp->b_un.b_cg; 67657416Smarkm if (!check_cgmagic(cg, cgbp)) 67757416Smarkm return (0); 67857416Smarkm setbit(cg_inosused(cgp), ino % sblock.fs_ipg); 67957416Smarkm cgp->cg_cs.cs_nifree--; 68057416Smarkm switch (type & IFMT) { 68157416Smarkm case IFDIR: 68257416Smarkm inoinfo(ino)->ino_state = DSTATE; 68357416Smarkm cgp->cg_cs.cs_ndir++; 68457416Smarkm break; 68557416Smarkm case IFREG: 68657416Smarkm case IFLNK: 68757416Smarkm inoinfo(ino)->ino_state = FSTATE; 68857416Smarkm break; 68957416Smarkm default: 69057416Smarkm return (0); 69157416Smarkm } 69257416Smarkm dirty(cgbp); 69357416Smarkm dp = ginode(ino); 69457416Smarkm DIP_SET(dp, di_db[0], allocblk((long)1)); 69557416Smarkm if (DIP(dp, di_db[0]) == 0) { 69657416Smarkm inoinfo(ino)->ino_state = USTATE; 69757416Smarkm return (0); 69857416Smarkm } 69957416Smarkm DIP_SET(dp, di_mode, type); 70057416Smarkm DIP_SET(dp, di_flags, 0); 70157416Smarkm DIP_SET(dp, di_atime, time(NULL)); 70257416Smarkm DIP_SET(dp, di_ctime, DIP(dp, di_atime)); 70357416Smarkm DIP_SET(dp, di_mtime, DIP(dp, di_ctime)); 70457416Smarkm DIP_SET(dp, di_mtimensec, 0); 70557416Smarkm DIP_SET(dp, di_ctimensec, 0); 70657416Smarkm DIP_SET(dp, di_atimensec, 0); 70757416Smarkm DIP_SET(dp, di_size, sblock.fs_fsize); 70857416Smarkm DIP_SET(dp, di_blocks, btodb(sblock.fs_fsize)); 70957416Smarkm n_files++; 71057416Smarkm inodirty(); 71157416Smarkm inoinfo(ino)->ino_type = IFTODT(type); 71257416Smarkm return (ino); 713233294Sstas} 71457416Smarkm 71557416Smarkm/* 71657416Smarkm * deallocate an inode 71757416Smarkm */ 71857416Smarkmvoid 71957416Smarkmfreeino(ino_t ino) 72057416Smarkm{ 72157416Smarkm struct inodesc idesc; 72257416Smarkm union dinode *dp; 72357416Smarkm 72457416Smarkm memset(&idesc, 0, sizeof(struct inodesc)); 72557416Smarkm idesc.id_type = ADDR; 72657416Smarkm idesc.id_func = pass4check; 72757416Smarkm idesc.id_number = ino; 72857416Smarkm dp = ginode(ino); 72957416Smarkm (void)ckinode(dp, &idesc); 73057416Smarkm clearinode(dp); 73157416Smarkm inodirty(); 73257416Smarkm inoinfo(ino)->ino_state = USTATE; 73357416Smarkm n_files--; 73457416Smarkm} 73557416Smarkm