10Sstevel@tonic-gate /* 2*6179Smc208700 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 30Sstevel@tonic-gate * Use is subject to license terms. 40Sstevel@tonic-gate */ 50Sstevel@tonic-gate 60Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 70Sstevel@tonic-gate /* All Rights Reserved */ 80Sstevel@tonic-gate 90Sstevel@tonic-gate /* 100Sstevel@tonic-gate * Copyright (c) 1980, 1986, 1990 The Regents of the University of California. 110Sstevel@tonic-gate * All rights reserved. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * Redistribution and use in source and binary forms are permitted 140Sstevel@tonic-gate * provided that: (1) source distributions retain this entire copyright 150Sstevel@tonic-gate * notice and comment, and (2) distributions including binaries display 160Sstevel@tonic-gate * the following acknowledgement: ``This product includes software 170Sstevel@tonic-gate * developed by the University of California, Berkeley and its contributors'' 180Sstevel@tonic-gate * in the documentation or other materials provided with the distribution 190Sstevel@tonic-gate * and in all advertising materials mentioning features or use of this 200Sstevel@tonic-gate * software. Neither the name of the University nor the names of its 210Sstevel@tonic-gate * contributors may be used to endorse or promote products derived 220Sstevel@tonic-gate * from this software without specific prior written permission. 230Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 240Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 250Sstevel@tonic-gate * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 260Sstevel@tonic-gate */ 270Sstevel@tonic-gate 280Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 290Sstevel@tonic-gate 300Sstevel@tonic-gate #include <stdio.h> 310Sstevel@tonic-gate #include <string.h> 320Sstevel@tonic-gate #include <stdlib.h> 330Sstevel@tonic-gate #include <unistd.h> 340Sstevel@tonic-gate #include <time.h> 35392Sswilcox #include <limits.h> 360Sstevel@tonic-gate #include <sys/param.h> 370Sstevel@tonic-gate #include <sys/types.h> 380Sstevel@tonic-gate #include <sys/sysmacros.h> 390Sstevel@tonic-gate #include <sys/mntent.h> 400Sstevel@tonic-gate #include <sys/vnode.h> 410Sstevel@tonic-gate #include <sys/fs/ufs_inode.h> 420Sstevel@tonic-gate #include <sys/fs/ufs_fs.h> 43392Sswilcox #define _KERNEL 440Sstevel@tonic-gate #include <sys/fs/ufs_fsdir.h> 45392Sswilcox #undef _KERNEL 460Sstevel@tonic-gate #include <pwd.h> 470Sstevel@tonic-gate #include "fsck.h" 480Sstevel@tonic-gate 49392Sswilcox static int get_indir_offsets(int, daddr_t, int *, int *); 50392Sswilcox static int clearanentry(struct inodesc *); 51392Sswilcox static void pdinode(struct dinode *); 52392Sswilcox static void inoflush(void); 53392Sswilcox static void mark_delayed_inodes(fsck_ino_t, daddr32_t); 54392Sswilcox static int iblock(struct inodesc *, int, u_offset_t, enum cki_action); 55392Sswilcox static struct inoinfo *search_cache(struct inoinfo *, fsck_ino_t); 56392Sswilcox static int ckinode_common(struct dinode *, struct inodesc *, enum cki_action); 57392Sswilcox static int lookup_dotdot_ino(fsck_ino_t); 580Sstevel@tonic-gate 59392Sswilcox /* 60392Sswilcox * ckinode() essentially traverses the blocklist of the provided 61392Sswilcox * inode. For each block either the caller-supplied callback (id_func 62392Sswilcox * in the provided struct inodesc) or dirscan() is invoked. Which is 63392Sswilcox * chosen is controlled by what type of traversal was requested 64392Sswilcox * (id_type) - if it was for an ADDR or ACL, use the callback, 65392Sswilcox * otherwise it is assumed to be DATA (i.e., a directory) whose 66392Sswilcox * contents need to be scanned. 67392Sswilcox * 68392Sswilcox * Note that a directory inode can get passed in with a type of ADDR; 69392Sswilcox * the type field is orthogonal to the IFMT value. This is so that 70392Sswilcox * the file aspects (no duplicate blocks, etc) of a directory can be 71392Sswilcox * verified just like is done for any other file, or the actual 72392Sswilcox * contents can be scanned so that connectivity and such can be 73392Sswilcox * investigated. 74392Sswilcox * 75392Sswilcox * The traversal is controlled by flags in the return value of 76392Sswilcox * dirscan() or the callback. Five flags are defined, STOP, SKIP, 77392Sswilcox * KEEPON, ALTERED, and FOUND. Their semantics are: 78392Sswilcox * 79392Sswilcox * STOP - no further processing of this inode is desired/possible/ 80392Sswilcox * feasible/etc. This can mean that whatever the scan 81392Sswilcox * was searching for was found, or a serious 82392Sswilcox * inconsistency was encountered, or anything else 83392Sswilcox * appropriate. 84392Sswilcox * 85392Sswilcox * SKIP - something that made it impossible to continue was 86392Sswilcox * encountered, and the caller should go on to the next 87392Sswilcox * inode. This is more for i/o failures than for 88392Sswilcox * logical inconsistencies. Nothing actually looks for 89392Sswilcox * this. 90392Sswilcox * 91392Sswilcox * KEEPON - no more blocks of this inode need to be scanned, but 92392Sswilcox * nothing's wrong, so keep on going with the next 93392Sswilcox * inode. It is similar to STOP, except that 94392Sswilcox * ckinode()'s caller will typically advance to the next 95392Sswilcox * inode for KEEPON, whereas it ceases scanning through 96392Sswilcox * the inodes completely for STOP. 97392Sswilcox * 98392Sswilcox * ALTERED - a change was made to the inode. If the caller sees 99392Sswilcox * this set, it should make sure to flush out the 100392Sswilcox * changes. Note that any data blocks read in by the 101392Sswilcox * function need to be marked dirty by it directly; 102392Sswilcox * flushing of those will happen automatically later. 103392Sswilcox * 104392Sswilcox * FOUND - whatever was being searched for was located. 105392Sswilcox * Typically combined with STOP to avoid wasting time 106392Sswilcox * doing additional looking. 107392Sswilcox * 108392Sswilcox * During a traversal, some state needs to be carried around. At the 109392Sswilcox * least, the callback functions need to know what inode they're 110392Sswilcox * working on, which logical block, and whether or not fixing problems 111392Sswilcox * when they're encountered is desired. Rather than try to guess what 112392Sswilcox * else might be needed (and thus end up passing way more arguments 113392Sswilcox * than is reasonable), all the possibilities have been bundled in 114392Sswilcox * struct inodesc. About half of the fields are specific to directory 115392Sswilcox * traversals, and the rest are pretty much generic to any traversal. 116392Sswilcox * 117392Sswilcox * The general fields are: 118392Sswilcox * 119392Sswilcox * id_fix What to do when an error is found. Generally, this 120392Sswilcox * is set to DONTKNOW before a traversal. If a 121392Sswilcox * problem is encountered, it is changed to either FIX 122392Sswilcox * or NOFIX by the dofix() query function. If id_fix 123392Sswilcox * has already been set to FIX when dofix() is called, then 124392Sswilcox * it includes the ALTERED flag (see above) in its return 125392Sswilcox * value; the net effect is that the inode's buffer 126392Sswilcox * will get marked dirty and written to disk at some 127392Sswilcox * point. If id_fix is DONTKNOW, then dofix() will 128392Sswilcox * query the user. If it is NOFIX, then dofix() 129392Sswilcox * essentially does nothing. A few routines set NOFIX 130392Sswilcox * as the initial value, as they are performing a best- 131392Sswilcox * effort informational task, rather than an actual 132392Sswilcox * repair operation. 133392Sswilcox * 134392Sswilcox * id_func This is the function that will be called for every 135392Sswilcox * logical block in the file (assuming id_type is not 136392Sswilcox * DATA). The logical block may represent a hole, so 137392Sswilcox * the callback needs to be prepared to handle that 138392Sswilcox * case. Its return value is a combination of the flags 139392Sswilcox * described above (SKIP, ALTERED, etc). 140392Sswilcox * 141392Sswilcox * id_number The inode number whose block list or data is being 142392Sswilcox * scanned. 143392Sswilcox * 144392Sswilcox * id_parent When id_type is DATA, this is the inode number for 145392Sswilcox * the parent of id_number. Otherwise, it is 146392Sswilcox * available for use as an extra parameter or return 147392Sswilcox * value between the callback and ckinode()'s caller. 148392Sswilcox * Which, if either, of those is left completely up to 149392Sswilcox * the two routines involved, so nothing can generally 150392Sswilcox * be assumed about the id_parent value for non-DATA 151392Sswilcox * traversals. 152392Sswilcox * 153392Sswilcox * id_lbn This is the current logical block (not fragment) 154392Sswilcox * number being visited by the traversal. 155392Sswilcox * 156392Sswilcox * id_blkno This is the physical block corresponding to id_lbn. 157392Sswilcox * 158392Sswilcox * id_numfrags This defines how large a block is being processed in 159392Sswilcox * this particular invocation of the callback. 160392Sswilcox * Usually, it will be the same as sblock.fs_frag. 161392Sswilcox * However, if a direct block is being processed and 162392Sswilcox * it is less than a full filesystem block, 163392Sswilcox * id_numfrags will indicate just how many fragments 164392Sswilcox * (starting from id_lbn) are actually part of the 165392Sswilcox * file. 166392Sswilcox * 167392Sswilcox * id_truncto The pass 4 callback is used in several places to 168392Sswilcox * free the blocks of a file (the `FILE HAS PROBLEM 169392Sswilcox * FOO; CLEAR?' scenario). This has been generalized 170392Sswilcox * to allow truncating a file to a particular length 171392Sswilcox * rather than always completely discarding it. If 172392Sswilcox * id_truncto is -1, then the entire file is released, 173392Sswilcox * otherwise it is logical block number to truncate 174392Sswilcox * to. This generalized interface was motivated by a 175392Sswilcox * desire to be able to discard everything after a 176392Sswilcox * hole in a directory, rather than the entire 177392Sswilcox * directory. 178392Sswilcox * 179392Sswilcox * id_type Selects the type of traversal. DATA for dirscan(), 180392Sswilcox * ADDR or ACL for using the provided callback. 181392Sswilcox * 182392Sswilcox * There are several more fields used just for dirscan() traversals: 183392Sswilcox * 184392Sswilcox * id_filesize The number of bytes in the overall directory left to 185392Sswilcox * process. 186392Sswilcox * 187392Sswilcox * id_loc Byte position within the directory block. Should always 188392Sswilcox * point to the start of a directory entry. 189392Sswilcox * 190392Sswilcox * id_entryno Which logical directory entry is being processed (0 191392Sswilcox * is `.', 1 is `..', 2 and on are normal entries). 192392Sswilcox * This field is primarily used to enable special 193392Sswilcox * checks when looking at the first two entries. 194392Sswilcox * 195392Sswilcox * The exception (there's always an exception in fsck) 196392Sswilcox * is that in pass 1, it tracks how many fragments are 197392Sswilcox * being used by a particular inode. 198392Sswilcox * 199392Sswilcox * id_firsthole The first logical block number that was found to 200392Sswilcox * be zero. As directories are not supposed to have 201392Sswilcox * holes, this marks where a directory should be 202392Sswilcox * truncated down to. A value of -1 indicates that 203392Sswilcox * no holes were found. 204392Sswilcox * 205392Sswilcox * id_dirp A pointer to the in-memory copy of the current 206392Sswilcox * directory entry (as identified by id_loc). 207392Sswilcox * 208392Sswilcox * id_name This is a directory entry name to either create 209392Sswilcox * (callback is mkentry) or locate (callback is 210392Sswilcox * chgino, findino, or findname). 211392Sswilcox */ 212392Sswilcox int 213392Sswilcox ckinode(struct dinode *dp, struct inodesc *idesc, enum cki_action action) 2140Sstevel@tonic-gate { 215392Sswilcox struct inodesc cleardesc; 216392Sswilcox mode_t mode; 217392Sswilcox 218392Sswilcox if (idesc->id_filesize == 0) 219392Sswilcox idesc->id_filesize = (offset_t)dp->di_size; 2200Sstevel@tonic-gate 221392Sswilcox /* 222392Sswilcox * Our caller should be filtering out completely-free inodes 223392Sswilcox * (mode == zero), so we'll work on the assumption that what 224392Sswilcox * we're given has some basic validity. 225392Sswilcox * 226392Sswilcox * The kernel is inconsistent about MAXPATHLEN including the 227392Sswilcox * trailing \0, so allow the more-generous length for symlinks. 228392Sswilcox */ 229392Sswilcox mode = dp->di_mode & IFMT; 230392Sswilcox if (mode == IFBLK || mode == IFCHR) 2310Sstevel@tonic-gate return (KEEPON); 232392Sswilcox if (mode == IFLNK && dp->di_size > MAXPATHLEN) { 233392Sswilcox pwarn("I=%d Symlink longer than supported maximum", 234392Sswilcox idesc->id_number); 235392Sswilcox init_inodesc(&cleardesc); 236392Sswilcox cleardesc.id_type = ADDR; 237392Sswilcox cleardesc.id_number = idesc->id_number; 238392Sswilcox cleardesc.id_fix = DONTKNOW; 239392Sswilcox clri(&cleardesc, "BAD", CLRI_VERBOSE, CLRI_NOP_CORRUPT); 240392Sswilcox return (STOP); 241392Sswilcox } 242392Sswilcox return (ckinode_common(dp, idesc, action)); 243392Sswilcox } 244392Sswilcox 245392Sswilcox /* 246392Sswilcox * This was split out from ckinode() to allow it to be used 247392Sswilcox * without having to pass in kludge flags to suppress the 248392Sswilcox * wrong-for-deletion initialization and irrelevant checks. 249392Sswilcox * This feature is no longer needed, but is being kept in case 250392Sswilcox * the need comes back. 251392Sswilcox */ 252392Sswilcox static int 253392Sswilcox ckinode_common(struct dinode *dp, struct inodesc *idesc, 254392Sswilcox enum cki_action action) 255392Sswilcox { 256392Sswilcox offset_t offset; 257392Sswilcox struct dinode dino; 258392Sswilcox daddr_t ndb; 259392Sswilcox int indir_data_blks, last_indir_blk; 260392Sswilcox int ret, i, frags; 261392Sswilcox 262392Sswilcox (void) memmove(&dino, dp, sizeof (struct dinode)); 2630Sstevel@tonic-gate ndb = howmany(dino.di_size, (u_offset_t)sblock.fs_bsize); 264392Sswilcox 265392Sswilcox for (i = 0; i < NDADDR; i++) { 266392Sswilcox idesc->id_lbn++; 267392Sswilcox offset = blkoff(&sblock, dino.di_size); 268392Sswilcox if ((--ndb == 0) && (offset != 0)) { 2690Sstevel@tonic-gate idesc->id_numfrags = 2700Sstevel@tonic-gate numfrags(&sblock, fragroundup(&sblock, offset)); 271392Sswilcox } else { 2720Sstevel@tonic-gate idesc->id_numfrags = sblock.fs_frag; 273392Sswilcox } 274392Sswilcox if (dino.di_db[i] == 0) { 275392Sswilcox if ((ndb > 0) && (idesc->id_firsthole < 0)) { 276392Sswilcox idesc->id_firsthole = i; 277392Sswilcox } 2780Sstevel@tonic-gate continue; 279392Sswilcox } 280392Sswilcox idesc->id_blkno = dino.di_db[i]; 2810Sstevel@tonic-gate if (idesc->id_type == ADDR || idesc->id_type == ACL) 2820Sstevel@tonic-gate ret = (*idesc->id_func)(idesc); 2830Sstevel@tonic-gate else 2840Sstevel@tonic-gate ret = dirscan(idesc); 285392Sswilcox 286392Sswilcox /* 287392Sswilcox * Need to clear the entry, now that we're done with 288392Sswilcox * it. We depend on freeblk() ignoring a request to 289392Sswilcox * free already-free fragments to handle the problem of 290392Sswilcox * a partial block. 291392Sswilcox */ 292392Sswilcox if ((action == CKI_TRUNCATE) && 293392Sswilcox (idesc->id_truncto >= 0) && 294392Sswilcox (idesc->id_lbn >= idesc->id_truncto)) { 295392Sswilcox dp = ginode(idesc->id_number); 296392Sswilcox /* 297392Sswilcox * The (int) cast is safe, in that if di_size won't 298392Sswilcox * fit, it'll be a multiple of any legal fs_frag, 299392Sswilcox * thus giving a zero result. That value, in turn 300392Sswilcox * means we're doing an entire block. 301392Sswilcox */ 302392Sswilcox frags = howmany((int)dp->di_size, sblock.fs_fsize) % 303392Sswilcox sblock.fs_frag; 304392Sswilcox if (frags == 0) 305392Sswilcox frags = sblock.fs_frag; 306392Sswilcox freeblk(idesc->id_number, dp->di_db[i], 307392Sswilcox frags); 308392Sswilcox dp = ginode(idesc->id_number); 309392Sswilcox dp->di_db[i] = 0; 310392Sswilcox inodirty(); 311392Sswilcox ret |= ALTERED; 312392Sswilcox } 313392Sswilcox 3140Sstevel@tonic-gate if (ret & STOP) 3150Sstevel@tonic-gate return (ret); 3160Sstevel@tonic-gate } 3170Sstevel@tonic-gate 318392Sswilcox #ifdef lint 319392Sswilcox /* 320392Sswilcox * Cure a lint complaint of ``possible use before set''. 321392Sswilcox * Apparently it can't quite figure out the switch statement. 322392Sswilcox */ 323392Sswilcox indir_data_blks = 0; 324392Sswilcox #endif 3250Sstevel@tonic-gate /* 326392Sswilcox * indir_data_blks contains the number of data blocks in all 327392Sswilcox * the previous levels for this iteration. E.g., for the 328392Sswilcox * single indirect case (i = 0, di_ib[i] != 0), NDADDR's worth 329392Sswilcox * of blocks have already been covered by the direct blocks 330392Sswilcox * (di_db[]). At the triple indirect level (i = NIADDR - 1), 331392Sswilcox * it is all of the number of data blocks that were covered 332392Sswilcox * by the second indirect, single indirect, and direct block 333392Sswilcox * levels. 3340Sstevel@tonic-gate */ 335392Sswilcox idesc->id_numfrags = sblock.fs_frag; 336392Sswilcox ndb = howmany(dino.di_size, (u_offset_t)sblock.fs_bsize); 337392Sswilcox for (i = 0; i < NIADDR; i++) { 338392Sswilcox (void) get_indir_offsets(i, ndb, &indir_data_blks, 339392Sswilcox &last_indir_blk); 340392Sswilcox if (dino.di_ib[i] != 0) { 341392Sswilcox /* 342392Sswilcox * We'll only clear di_ib[i] if the first entry (and 343392Sswilcox * therefore all of them) is to be cleared, since we 344392Sswilcox * only go through this code on the first entry of 345392Sswilcox * each level of indirection. The +1 is to account 346392Sswilcox * for the fact that we don't modify id_lbn until 347392Sswilcox * we actually start processing on a data block. 348392Sswilcox */ 349392Sswilcox idesc->id_blkno = dino.di_ib[i]; 350392Sswilcox ret = iblock(idesc, i + 1, 3510Sstevel@tonic-gate (u_offset_t)howmany(dino.di_size, 352*6179Smc208700 (u_offset_t)sblock.fs_bsize) - indir_data_blks, 353*6179Smc208700 action); 354392Sswilcox if ((action == CKI_TRUNCATE) && 355392Sswilcox (idesc->id_truncto <= indir_data_blks) && 356392Sswilcox ((idesc->id_lbn + 1) >= indir_data_blks) && 357392Sswilcox ((idesc->id_lbn + 1) <= last_indir_blk)) { 358392Sswilcox dp = ginode(idesc->id_number); 359392Sswilcox if (dp->di_ib[i] != 0) { 360392Sswilcox freeblk(idesc->id_number, dp->di_ib[i], 361392Sswilcox sblock.fs_frag); 362392Sswilcox } 363392Sswilcox } 3640Sstevel@tonic-gate if (ret & STOP) 3650Sstevel@tonic-gate return (ret); 3660Sstevel@tonic-gate } else { 367392Sswilcox /* 368392Sswilcox * Need to know which of the file's logical blocks 369392Sswilcox * reside in the missing indirect block. However, the 370392Sswilcox * precise location is only needed for truncating 371392Sswilcox * directories, and level-of-indirection precision is 372392Sswilcox * sufficient for that. 373392Sswilcox */ 374392Sswilcox if ((indir_data_blks < ndb) && 375392Sswilcox (idesc->id_firsthole < 0)) { 376392Sswilcox idesc->id_firsthole = indir_data_blks; 377392Sswilcox } 3780Sstevel@tonic-gate } 3790Sstevel@tonic-gate } 3800Sstevel@tonic-gate return (KEEPON); 3810Sstevel@tonic-gate } 3820Sstevel@tonic-gate 383392Sswilcox static int 384392Sswilcox get_indir_offsets(int ilevel_wanted, daddr_t ndb, int *data_blks, 385392Sswilcox int *last_blk) 3860Sstevel@tonic-gate { 387392Sswilcox int ndb_ilevel = -1; 388392Sswilcox int ilevel; 389392Sswilcox int dblks, lblk; 390392Sswilcox 391392Sswilcox for (ilevel = 0; ilevel < NIADDR; ilevel++) { 392392Sswilcox switch (ilevel) { 393392Sswilcox case 0: /* SINGLE */ 394392Sswilcox dblks = NDADDR; 395392Sswilcox lblk = dblks + NINDIR(&sblock) - 1; 396392Sswilcox break; 397392Sswilcox case 1: /* DOUBLE */ 398392Sswilcox dblks = NDADDR + NINDIR(&sblock); 399392Sswilcox lblk = dblks + (NINDIR(&sblock) * NINDIR(&sblock)) - 1; 400392Sswilcox break; 401392Sswilcox case 2: /* TRIPLE */ 402392Sswilcox dblks = NDADDR + NINDIR(&sblock) + 403392Sswilcox (NINDIR(&sblock) * NINDIR(&sblock)); 404392Sswilcox lblk = dblks + (NINDIR(&sblock) * NINDIR(&sblock) * 405392Sswilcox NINDIR(&sblock)) - 1; 406392Sswilcox break; 407392Sswilcox default: 408392Sswilcox exitstat = EXERRFATAL; 409392Sswilcox /* 410392Sswilcox * Translate from zero-based array to 411392Sswilcox * one-based human-style counting. 412392Sswilcox */ 413392Sswilcox errexit("panic: indirection level %d not 1, 2, or 3", 414392Sswilcox ilevel + 1); 415392Sswilcox /* NOTREACHED */ 416392Sswilcox } 417392Sswilcox 418392Sswilcox if (dblks < ndb && ndb <= lblk) 419392Sswilcox ndb_ilevel = ilevel; 420392Sswilcox 421392Sswilcox if (ilevel == ilevel_wanted) { 422392Sswilcox if (data_blks != NULL) 423392Sswilcox *data_blks = dblks; 424392Sswilcox if (last_blk != NULL) 425392Sswilcox *last_blk = lblk; 426392Sswilcox } 427392Sswilcox } 428392Sswilcox 429392Sswilcox return (ndb_ilevel); 430392Sswilcox } 431392Sswilcox 432392Sswilcox static int 433392Sswilcox iblock(struct inodesc *idesc, int ilevel, u_offset_t iblks, 434392Sswilcox enum cki_action action) 435392Sswilcox { 436392Sswilcox struct bufarea *bp; 437392Sswilcox int i, n; 438392Sswilcox int (*func)(struct inodesc *) = NULL; 4390Sstevel@tonic-gate u_offset_t fsbperindirb; 440392Sswilcox daddr32_t last_lbn; 441392Sswilcox int nif; 4420Sstevel@tonic-gate char buf[BUFSIZ]; 443392Sswilcox 444392Sswilcox n = KEEPON; 4450Sstevel@tonic-gate 446392Sswilcox switch (idesc->id_type) { 447392Sswilcox case ADDR: 4480Sstevel@tonic-gate func = idesc->id_func; 4490Sstevel@tonic-gate if (((n = (*func)(idesc)) & KEEPON) == 0) 450392Sswilcox return (n); 451392Sswilcox break; 452392Sswilcox case ACL: 4530Sstevel@tonic-gate func = idesc->id_func; 454392Sswilcox break; 455392Sswilcox case DATA: 4560Sstevel@tonic-gate func = dirscan; 457392Sswilcox break; 458392Sswilcox default: 459392Sswilcox errexit("unknown inodesc type %d in iblock()", idesc->id_type); 460392Sswilcox /* NOTREACHED */ 461392Sswilcox } 462392Sswilcox if (chkrange(idesc->id_blkno, idesc->id_numfrags)) { 463392Sswilcox return ((idesc->id_type == ACL) ? STOP : SKIP); 4640Sstevel@tonic-gate } 465392Sswilcox 466392Sswilcox bp = getdatablk(idesc->id_blkno, (size_t)sblock.fs_bsize); 467392Sswilcox if (bp->b_errs != 0) { 468392Sswilcox brelse(bp); 469392Sswilcox return (SKIP); 470392Sswilcox } 471392Sswilcox 4720Sstevel@tonic-gate ilevel--; 473392Sswilcox /* 474392Sswilcox * Trivia note: the BSD fsck has the number of bytes remaining 475392Sswilcox * as the third argument to iblock(), so the equivalent of 476392Sswilcox * fsbperindirb starts at fs_bsize instead of one. We're 477392Sswilcox * working in units of filesystem blocks here, not bytes or 478392Sswilcox * fragments. 479392Sswilcox */ 4800Sstevel@tonic-gate for (fsbperindirb = 1, i = 0; i < ilevel; i++) { 4810Sstevel@tonic-gate fsbperindirb *= (u_offset_t)NINDIR(&sblock); 4820Sstevel@tonic-gate } 4830Sstevel@tonic-gate /* 4840Sstevel@tonic-gate * nif indicates the next "free" pointer (as an array index) in this 4850Sstevel@tonic-gate * indirect block, based on counting the blocks remaining in the 4860Sstevel@tonic-gate * file after subtracting all previously processed blocks. 4870Sstevel@tonic-gate * This figure is based on the size field of the inode. 4880Sstevel@tonic-gate * 489392Sswilcox * Note that in normal operation, nif may initially be calculated 490392Sswilcox * as larger than the number of pointers in this block (as when 491392Sswilcox * there are more indirect blocks following); if that is 4920Sstevel@tonic-gate * the case, nif is limited to the max number of pointers per 4930Sstevel@tonic-gate * indirect block. 4940Sstevel@tonic-gate * 495392Sswilcox * Also note that if an inode is inconsistent (has more blocks 4960Sstevel@tonic-gate * allocated to it than the size field would indicate), the sweep 4970Sstevel@tonic-gate * through any indirect blocks directly pointed at by the inode 4980Sstevel@tonic-gate * continues. Since the block offset of any data blocks referenced 4990Sstevel@tonic-gate * by these indirect blocks is greater than the size of the file, 5000Sstevel@tonic-gate * the index nif may be computed as a negative value. 5010Sstevel@tonic-gate * In this case, we reset nif to indicate that all pointers in 5020Sstevel@tonic-gate * this retrieval block should be zeroed and the resulting 503392Sswilcox * unreferenced data and/or retrieval blocks will be recovered 5040Sstevel@tonic-gate * through garbage collection later. 5050Sstevel@tonic-gate */ 5060Sstevel@tonic-gate nif = (offset_t)howmany(iblks, fsbperindirb); 5070Sstevel@tonic-gate if (nif > NINDIR(&sblock)) 5080Sstevel@tonic-gate nif = NINDIR(&sblock); 5090Sstevel@tonic-gate else if (nif < 0) 5100Sstevel@tonic-gate nif = 0; 5110Sstevel@tonic-gate /* 5120Sstevel@tonic-gate * first pass: all "free" retrieval pointers (from [nif] thru 5130Sstevel@tonic-gate * the end of the indirect block) should be zero. (This 5140Sstevel@tonic-gate * assertion does not hold for directories, which may be 5150Sstevel@tonic-gate * truncated without releasing their allocated space) 5160Sstevel@tonic-gate */ 517392Sswilcox if (nif < NINDIR(&sblock) && (idesc->id_func == pass1check || 518392Sswilcox idesc->id_func == pass3bcheck)) { 519392Sswilcox for (i = nif; i < NINDIR(&sblock); i++) { 520392Sswilcox if (bp->b_un.b_indir[i] == 0) 5210Sstevel@tonic-gate continue; 522392Sswilcox (void) sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 523392Sswilcox (ulong_t)idesc->id_number); 524392Sswilcox if (preen) { 525392Sswilcox pfatal(buf); 526392Sswilcox } else if (dofix(idesc, buf)) { 527392Sswilcox freeblk(idesc->id_number, 528392Sswilcox bp->b_un.b_indir[i], 529392Sswilcox sblock.fs_frag); 530392Sswilcox bp->b_un.b_indir[i] = 0; 5310Sstevel@tonic-gate dirty(bp); 5320Sstevel@tonic-gate } 5330Sstevel@tonic-gate } 5340Sstevel@tonic-gate flush(fswritefd, bp); 5350Sstevel@tonic-gate } 5360Sstevel@tonic-gate /* 537392Sswilcox * second pass: all retrieval pointers referring to blocks within 5380Sstevel@tonic-gate * a valid range [0..filesize] (both indirect and data blocks) 539392Sswilcox * are examined in the same manner as ckinode() checks the 540392Sswilcox * direct blocks in the inode. Sweep through from 5410Sstevel@tonic-gate * the first pointer in this retrieval block to [nif-1]. 5420Sstevel@tonic-gate */ 543392Sswilcox last_lbn = howmany(idesc->id_filesize, sblock.fs_bsize); 544392Sswilcox for (i = 0; i < nif; i++) { 545392Sswilcox if (ilevel == 0) 546392Sswilcox idesc->id_lbn++; 547392Sswilcox if (bp->b_un.b_indir[i] != 0) { 548392Sswilcox idesc->id_blkno = bp->b_un.b_indir[i]; 5490Sstevel@tonic-gate if (ilevel > 0) { 550392Sswilcox n = iblock(idesc, ilevel, iblks, action); 5510Sstevel@tonic-gate /* 552392Sswilcox * Each iteration decreases "remaining block 553392Sswilcox * count" by the number of blocks accessible 5540Sstevel@tonic-gate * by a pointer at this indirect block level. 5550Sstevel@tonic-gate */ 5560Sstevel@tonic-gate iblks -= fsbperindirb; 5570Sstevel@tonic-gate } else { 558392Sswilcox /* 559392Sswilcox * If we're truncating, func will discard 560392Sswilcox * the data block for us. 561392Sswilcox */ 5620Sstevel@tonic-gate n = (*func)(idesc); 5630Sstevel@tonic-gate } 564392Sswilcox 565392Sswilcox if ((action == CKI_TRUNCATE) && 566392Sswilcox (idesc->id_truncto >= 0) && 567392Sswilcox (idesc->id_lbn >= idesc->id_truncto)) { 568392Sswilcox freeblk(idesc->id_number, bp->b_un.b_indir[i], 569392Sswilcox sblock.fs_frag); 570392Sswilcox } 571392Sswilcox 572392Sswilcox /* 573392Sswilcox * Note that truncation never gets STOP back 574392Sswilcox * under normal circumstances. Abnormal would 575392Sswilcox * be a bad acl short-circuit in iblock() or 576392Sswilcox * an out-of-range failure in pass4check(). 577392Sswilcox * We still want to keep going when truncating 578392Sswilcox * under those circumstances, since the whole 579392Sswilcox * point of truncating is to get rid of all 580392Sswilcox * that. 581392Sswilcox */ 582392Sswilcox if ((n & STOP) && (action != CKI_TRUNCATE)) { 5830Sstevel@tonic-gate brelse(bp); 5840Sstevel@tonic-gate return (n); 5850Sstevel@tonic-gate } 5860Sstevel@tonic-gate } else { 587392Sswilcox if ((idesc->id_lbn < last_lbn) && 588392Sswilcox (idesc->id_firsthole < 0)) { 589392Sswilcox idesc->id_firsthole = idesc->id_lbn; 590392Sswilcox } 591392Sswilcox if (idesc->id_type == DATA) { 592392Sswilcox /* 593392Sswilcox * No point in continuing in the indirect 594392Sswilcox * blocks of a directory, since they'll just 595392Sswilcox * get freed anyway. 596392Sswilcox */ 597392Sswilcox brelse(bp); 598392Sswilcox return ((n & ~KEEPON) | STOP); 599392Sswilcox } 6000Sstevel@tonic-gate } 6010Sstevel@tonic-gate } 602392Sswilcox 6030Sstevel@tonic-gate brelse(bp); 6040Sstevel@tonic-gate return (KEEPON); 6050Sstevel@tonic-gate } 6060Sstevel@tonic-gate 6070Sstevel@tonic-gate /* 6080Sstevel@tonic-gate * Check that a block is a legal block number. 6090Sstevel@tonic-gate * Return 0 if in range, 1 if out of range. 6100Sstevel@tonic-gate */ 611392Sswilcox int 612392Sswilcox chkrange(daddr32_t blk, int cnt) 6130Sstevel@tonic-gate { 6140Sstevel@tonic-gate int c; 6150Sstevel@tonic-gate 616392Sswilcox if (cnt <= 0 || blk <= 0 || ((unsigned)blk >= (unsigned)maxfsblock) || 617392Sswilcox ((cnt - 1) > (maxfsblock - blk))) { 618392Sswilcox if (debug) 619392Sswilcox (void) printf( 620392Sswilcox "Bad fragment range: should be 1 <= %d..%d < %d\n", 621392Sswilcox blk, blk + cnt, maxfsblock); 6220Sstevel@tonic-gate return (1); 623392Sswilcox } 624392Sswilcox if ((cnt > sblock.fs_frag) || 625392Sswilcox ((fragnum(&sblock, blk) + cnt) > sblock.fs_frag)) { 626392Sswilcox if (debug) 627392Sswilcox (void) printf("Bad fragment size: size %d\n", cnt); 628392Sswilcox return (1); 629392Sswilcox } 6300Sstevel@tonic-gate c = dtog(&sblock, blk); 6310Sstevel@tonic-gate if (blk < cgdmin(&sblock, c)) { 6320Sstevel@tonic-gate if ((unsigned)(blk + cnt) > (unsigned)cgsblock(&sblock, c)) { 633392Sswilcox if (debug) 634392Sswilcox (void) printf( 635392Sswilcox "Bad fragment position: %d..%d spans start of cg metadata\n", 636392Sswilcox blk, blk + cnt); 6370Sstevel@tonic-gate return (1); 6380Sstevel@tonic-gate } 6390Sstevel@tonic-gate } else { 6400Sstevel@tonic-gate if ((unsigned)(blk + cnt) > (unsigned)cgbase(&sblock, c+1)) { 641392Sswilcox if (debug) 642392Sswilcox (void) printf( 643392Sswilcox "Bad frag pos: %d..%d crosses end of cg\n", 644392Sswilcox blk, blk + cnt); 6450Sstevel@tonic-gate return (1); 6460Sstevel@tonic-gate } 6470Sstevel@tonic-gate } 6480Sstevel@tonic-gate return (0); 6490Sstevel@tonic-gate } 6500Sstevel@tonic-gate 6510Sstevel@tonic-gate /* 6520Sstevel@tonic-gate * General purpose interface for reading inodes. 6530Sstevel@tonic-gate */ 654392Sswilcox 655392Sswilcox /* 656392Sswilcox * Note that any call to ginode() can potentially invalidate any 657392Sswilcox * dinode pointers previously acquired from it. To avoid pain, 658392Sswilcox * make sure to always call inodirty() immediately after modifying 659392Sswilcox * an inode, if there's any chance of ginode() being called after 660392Sswilcox * that. Also, always call ginode() right before you need to access 661392Sswilcox * an inode, so that there won't be any surprises from functions 662392Sswilcox * called between the previous ginode() invocation and the dinode 663392Sswilcox * use. 664392Sswilcox * 665392Sswilcox * Despite all that, we aren't doing the amount of i/o that's implied, 666392Sswilcox * as we use the buffer cache that getdatablk() and friends maintain. 667392Sswilcox */ 668392Sswilcox static fsck_ino_t startinum = -1; 669392Sswilcox 6700Sstevel@tonic-gate struct dinode * 671392Sswilcox ginode(fsck_ino_t inum) 6720Sstevel@tonic-gate { 6730Sstevel@tonic-gate daddr32_t iblk; 6740Sstevel@tonic-gate struct dinode *dp; 6750Sstevel@tonic-gate 676392Sswilcox if (inum < UFSROOTINO || inum > maxino) { 677392Sswilcox errexit("bad inode number %d to ginode\n", inum); 678392Sswilcox } 679392Sswilcox if (startinum == -1 || 680392Sswilcox pbp == NULL || 681392Sswilcox inum < startinum || 682392Sswilcox inum >= (fsck_ino_t)(startinum + (fsck_ino_t)INOPB(&sblock))) { 683392Sswilcox iblk = itod(&sblock, inum); 684392Sswilcox if (pbp != NULL) { 6850Sstevel@tonic-gate brelse(pbp); 6860Sstevel@tonic-gate } 687392Sswilcox /* 688392Sswilcox * We don't check for errors here, because we can't 689392Sswilcox * tell our caller about it, and the zeros that will 690392Sswilcox * be in the buffer are just as good as anything we 691392Sswilcox * could fake. 692392Sswilcox */ 693392Sswilcox pbp = getdatablk(iblk, (size_t)sblock.fs_bsize); 6940Sstevel@tonic-gate startinum = 695392Sswilcox (fsck_ino_t)((inum / INOPB(&sblock)) * INOPB(&sblock)); 6960Sstevel@tonic-gate } 697392Sswilcox dp = &pbp->b_un.b_dinode[inum % INOPB(&sblock)]; 698392Sswilcox if (dp->di_suid != UID_LONG) 699392Sswilcox dp->di_uid = dp->di_suid; 700392Sswilcox if (dp->di_sgid != GID_LONG) 701392Sswilcox dp->di_gid = dp->di_sgid; 7020Sstevel@tonic-gate return (dp); 7030Sstevel@tonic-gate } 7040Sstevel@tonic-gate 7050Sstevel@tonic-gate /* 7060Sstevel@tonic-gate * Special purpose version of ginode used to optimize first pass 707392Sswilcox * over all the inodes in numerical order. It bypasses the buffer 708392Sswilcox * system used by ginode(), etc in favour of reading the bulk of a 709392Sswilcox * cg's inodes at one time. 7100Sstevel@tonic-gate */ 711392Sswilcox static fsck_ino_t nextino, lastinum; 712392Sswilcox static int64_t readcnt, readpercg, fullcnt, inobufsize; 713392Sswilcox static int64_t partialcnt, partialsize; 714392Sswilcox static size_t lastsize; 715392Sswilcox static struct dinode *inodebuf; 716392Sswilcox static diskaddr_t currentdblk; 717392Sswilcox static struct dinode *currentinode; 7180Sstevel@tonic-gate 7190Sstevel@tonic-gate struct dinode * 720392Sswilcox getnextinode(fsck_ino_t inum) 7210Sstevel@tonic-gate { 722392Sswilcox size_t size; 7230Sstevel@tonic-gate diskaddr_t dblk; 7240Sstevel@tonic-gate static struct dinode *dp; 7250Sstevel@tonic-gate 726392Sswilcox if (inum != nextino++ || inum > maxino) 727392Sswilcox errexit("bad inode number %d to nextinode\n", inum); 728392Sswilcox 729392Sswilcox /* 730392Sswilcox * Will always go into the if() the first time we're called, 731392Sswilcox * so dp will always be valid. 732392Sswilcox */ 733392Sswilcox if (inum >= lastinum) { 7340Sstevel@tonic-gate readcnt++; 7350Sstevel@tonic-gate dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 736392Sswilcox currentdblk = dblk; 7370Sstevel@tonic-gate if (readcnt % readpercg == 0) { 738392Sswilcox if (partialsize > SIZE_MAX) 739392Sswilcox errexit( 740392Sswilcox "Internal error: partialsize overflow"); 741392Sswilcox size = (size_t)partialsize; 7420Sstevel@tonic-gate lastinum += partialcnt; 7430Sstevel@tonic-gate } else { 744392Sswilcox if (inobufsize > SIZE_MAX) 745392Sswilcox errexit("Internal error: inobufsize overflow"); 746392Sswilcox size = (size_t)inobufsize; 7470Sstevel@tonic-gate lastinum += fullcnt; 7480Sstevel@tonic-gate } 749392Sswilcox /* 750392Sswilcox * If fsck_bread() returns an error, it will already have 751392Sswilcox * zeroed out the buffer, so we do not need to do so here. 752392Sswilcox */ 753392Sswilcox (void) fsck_bread(fsreadfd, (caddr_t)inodebuf, dblk, size); 754392Sswilcox lastsize = size; 7550Sstevel@tonic-gate dp = inodebuf; 7560Sstevel@tonic-gate } 757392Sswilcox currentinode = dp; 7580Sstevel@tonic-gate return (dp++); 7590Sstevel@tonic-gate } 7600Sstevel@tonic-gate 761392Sswilcox /* 762392Sswilcox * Reread the current getnext() buffer. This allows for changing inodes 763392Sswilcox * other than the current one via ginode()/inodirty()/inoflush(). 764392Sswilcox * 765392Sswilcox * Just reuses all the interesting variables that getnextinode() set up 766392Sswilcox * last time it was called. This shouldn't get called often, so we don't 767392Sswilcox * try to figure out if the caller's actually touched an inode in the 768392Sswilcox * range we have cached. There could have been an arbitrary number of 769392Sswilcox * them, after all. 770392Sswilcox */ 771392Sswilcox struct dinode * 772392Sswilcox getnextrefresh(void) 7730Sstevel@tonic-gate { 774392Sswilcox if (inodebuf == NULL) { 775392Sswilcox return (NULL); 776392Sswilcox } 7770Sstevel@tonic-gate 778392Sswilcox inoflush(); 779392Sswilcox (void) fsck_bread(fsreadfd, (caddr_t)inodebuf, currentdblk, lastsize); 780392Sswilcox return (currentinode); 781392Sswilcox } 782392Sswilcox 783392Sswilcox void 784392Sswilcox resetinodebuf(void) 785392Sswilcox { 7860Sstevel@tonic-gate startinum = 0; 7870Sstevel@tonic-gate nextino = 0; 7880Sstevel@tonic-gate lastinum = 0; 7890Sstevel@tonic-gate readcnt = 0; 7900Sstevel@tonic-gate inobufsize = blkroundup(&sblock, INOBUFSIZE); 7910Sstevel@tonic-gate fullcnt = inobufsize / sizeof (struct dinode); 7920Sstevel@tonic-gate readpercg = sblock.fs_ipg / fullcnt; 7930Sstevel@tonic-gate partialcnt = sblock.fs_ipg % fullcnt; 7940Sstevel@tonic-gate partialsize = partialcnt * sizeof (struct dinode); 7950Sstevel@tonic-gate if (partialcnt != 0) { 7960Sstevel@tonic-gate readpercg++; 7970Sstevel@tonic-gate } else { 7980Sstevel@tonic-gate partialcnt = fullcnt; 7990Sstevel@tonic-gate partialsize = inobufsize; 8000Sstevel@tonic-gate } 8010Sstevel@tonic-gate if (inodebuf == NULL && 8020Sstevel@tonic-gate (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 8030Sstevel@tonic-gate errexit("Cannot allocate space for inode buffer\n"); 8040Sstevel@tonic-gate while (nextino < UFSROOTINO) 8050Sstevel@tonic-gate (void) getnextinode(nextino); 8060Sstevel@tonic-gate } 8070Sstevel@tonic-gate 808392Sswilcox void 809392Sswilcox freeinodebuf(void) 8100Sstevel@tonic-gate { 811392Sswilcox if (inodebuf != NULL) { 812392Sswilcox free((void *)inodebuf); 813392Sswilcox } 8140Sstevel@tonic-gate inodebuf = NULL; 8150Sstevel@tonic-gate } 8160Sstevel@tonic-gate 8170Sstevel@tonic-gate /* 8180Sstevel@tonic-gate * Routines to maintain information about directory inodes. 8190Sstevel@tonic-gate * This is built during the first pass and used during the 8200Sstevel@tonic-gate * second and third passes. 8210Sstevel@tonic-gate * 8220Sstevel@tonic-gate * Enter inodes into the cache. 8230Sstevel@tonic-gate */ 824392Sswilcox void 825392Sswilcox cacheino(struct dinode *dp, fsck_ino_t inum) 8260Sstevel@tonic-gate { 8270Sstevel@tonic-gate struct inoinfo *inp; 8280Sstevel@tonic-gate struct inoinfo **inpp; 8290Sstevel@tonic-gate uint_t blks; 8300Sstevel@tonic-gate 8310Sstevel@tonic-gate blks = NDADDR + NIADDR; 8320Sstevel@tonic-gate inp = (struct inoinfo *) 833*6179Smc208700 malloc(sizeof (*inp) + (blks - 1) * sizeof (daddr32_t)); 8340Sstevel@tonic-gate if (inp == NULL) 835392Sswilcox errexit("Cannot increase directory list\n"); 836392Sswilcox init_inoinfo(inp, dp, inum); /* doesn't touch i_nextlist or i_number */ 837392Sswilcox inpp = &inphead[inum % numdirs]; 838392Sswilcox inp->i_nextlist = *inpp; 8390Sstevel@tonic-gate *inpp = inp; 840392Sswilcox inp->i_number = inum; 8410Sstevel@tonic-gate if (inplast == listmax) { 8420Sstevel@tonic-gate listmax += 100; 843392Sswilcox inpsort = (struct inoinfo **)realloc((void *)inpsort, 8440Sstevel@tonic-gate (unsigned)listmax * sizeof (struct inoinfo *)); 8450Sstevel@tonic-gate if (inpsort == NULL) 8460Sstevel@tonic-gate errexit("cannot increase directory list"); 8470Sstevel@tonic-gate } 8480Sstevel@tonic-gate inpsort[inplast++] = inp; 8490Sstevel@tonic-gate } 8500Sstevel@tonic-gate 8510Sstevel@tonic-gate /* 8520Sstevel@tonic-gate * Look up an inode cache structure. 8530Sstevel@tonic-gate */ 8540Sstevel@tonic-gate struct inoinfo * 855392Sswilcox getinoinfo(fsck_ino_t inum) 8560Sstevel@tonic-gate { 8570Sstevel@tonic-gate struct inoinfo *inp; 8580Sstevel@tonic-gate 859392Sswilcox inp = search_cache(inphead[inum % numdirs], inum); 860392Sswilcox return (inp); 8610Sstevel@tonic-gate } 8620Sstevel@tonic-gate 8630Sstevel@tonic-gate /* 8640Sstevel@tonic-gate * Determine whether inode is in cache. 8650Sstevel@tonic-gate */ 866392Sswilcox int 867392Sswilcox inocached(fsck_ino_t inum) 8680Sstevel@tonic-gate { 869392Sswilcox return (search_cache(inphead[inum % numdirs], inum) != NULL); 8700Sstevel@tonic-gate } 8710Sstevel@tonic-gate 8720Sstevel@tonic-gate /* 8730Sstevel@tonic-gate * Clean up all the inode cache structure. 8740Sstevel@tonic-gate */ 875392Sswilcox void 876392Sswilcox inocleanup(void) 8770Sstevel@tonic-gate { 8780Sstevel@tonic-gate struct inoinfo **inpp; 8790Sstevel@tonic-gate 8800Sstevel@tonic-gate if (inphead == NULL) 8810Sstevel@tonic-gate return; 882392Sswilcox for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) { 883392Sswilcox free((void *)(*inpp)); 884392Sswilcox } 885392Sswilcox free((void *)inphead); 886392Sswilcox free((void *)inpsort); 8870Sstevel@tonic-gate inphead = inpsort = NULL; 8880Sstevel@tonic-gate } 8890Sstevel@tonic-gate 8900Sstevel@tonic-gate /* 8910Sstevel@tonic-gate * Routines to maintain information about acl inodes. 8920Sstevel@tonic-gate * This is built during the first pass and used during the 8930Sstevel@tonic-gate * second and third passes. 8940Sstevel@tonic-gate * 8950Sstevel@tonic-gate * Enter acl inodes into the cache. 8960Sstevel@tonic-gate */ 897392Sswilcox void 898392Sswilcox cacheacl(struct dinode *dp, fsck_ino_t inum) 8990Sstevel@tonic-gate { 900392Sswilcox struct inoinfo *aclp; 901392Sswilcox struct inoinfo **aclpp; 9020Sstevel@tonic-gate uint_t blks; 9030Sstevel@tonic-gate 9040Sstevel@tonic-gate blks = NDADDR + NIADDR; 905392Sswilcox aclp = (struct inoinfo *) 906*6179Smc208700 malloc(sizeof (*aclp) + (blks - 1) * sizeof (daddr32_t)); 9070Sstevel@tonic-gate if (aclp == NULL) 9080Sstevel@tonic-gate return; 909392Sswilcox aclpp = &aclphead[inum % numacls]; 910392Sswilcox aclp->i_nextlist = *aclpp; 9110Sstevel@tonic-gate *aclpp = aclp; 912392Sswilcox aclp->i_number = inum; 9130Sstevel@tonic-gate aclp->i_isize = (offset_t)dp->di_size; 914392Sswilcox aclp->i_blkssize = (size_t)(blks * sizeof (daddr32_t)); 915392Sswilcox (void) memmove(&aclp->i_blks[0], &dp->di_db[0], aclp->i_blkssize); 9160Sstevel@tonic-gate if (aclplast == aclmax) { 9170Sstevel@tonic-gate aclmax += 100; 918392Sswilcox aclpsort = (struct inoinfo **)realloc((char *)aclpsort, 919392Sswilcox (unsigned)aclmax * sizeof (struct inoinfo *)); 9200Sstevel@tonic-gate if (aclpsort == NULL) 9210Sstevel@tonic-gate errexit("cannot increase acl list"); 9220Sstevel@tonic-gate } 9230Sstevel@tonic-gate aclpsort[aclplast++] = aclp; 9240Sstevel@tonic-gate } 9250Sstevel@tonic-gate 926392Sswilcox 9270Sstevel@tonic-gate /* 928392Sswilcox * Generic cache search function. 929392Sswilcox * ROOT is the first entry in a hash chain (the caller is expected 930392Sswilcox * to have done the initial bucket lookup). KEY is what's being 931392Sswilcox * searched for. 932392Sswilcox * 933392Sswilcox * Returns a pointer to the entry if it is found, NULL otherwise. 9340Sstevel@tonic-gate */ 935392Sswilcox static struct inoinfo * 936392Sswilcox search_cache(struct inoinfo *element, fsck_ino_t key) 9370Sstevel@tonic-gate { 938392Sswilcox while (element != NULL) { 939392Sswilcox if (element->i_number == key) 940392Sswilcox break; 941392Sswilcox element = element->i_nextlist; 942392Sswilcox } 943392Sswilcox 944392Sswilcox return (element); 945392Sswilcox } 9460Sstevel@tonic-gate 947392Sswilcox void 948392Sswilcox inodirty(void) 949392Sswilcox { 950392Sswilcox dirty(pbp); 951392Sswilcox } 952392Sswilcox 953392Sswilcox static void 954392Sswilcox inoflush(void) 955392Sswilcox { 956392Sswilcox if (pbp != NULL) 957392Sswilcox flush(fswritefd, pbp); 9580Sstevel@tonic-gate } 9590Sstevel@tonic-gate 9600Sstevel@tonic-gate /* 961392Sswilcox * Interactive wrapper for freeino(), for those times when we're 962392Sswilcox * not sure if we should throw something away. 9630Sstevel@tonic-gate */ 964392Sswilcox void 965392Sswilcox clri(struct inodesc *idesc, char *type, int verbose, int corrupting) 9660Sstevel@tonic-gate { 967392Sswilcox int need_parent; 968392Sswilcox struct dinode *dp; 969392Sswilcox 970392Sswilcox if (statemap[idesc->id_number] == USTATE) 971392Sswilcox return; 9720Sstevel@tonic-gate 973392Sswilcox dp = ginode(idesc->id_number); 974392Sswilcox if (verbose == CLRI_VERBOSE) { 975392Sswilcox pwarn("%s %s", type, file_id(idesc->id_number, dp->di_mode)); 976392Sswilcox pinode(idesc->id_number); 9770Sstevel@tonic-gate } 978392Sswilcox if (preen || (reply("CLEAR") == 1)) { 979392Sswilcox need_parent = (corrupting == CLRI_NOP_OK) ? 980*6179Smc208700 TI_NOPARENT : TI_PARENT; 981392Sswilcox freeino(idesc->id_number, need_parent); 982392Sswilcox if (preen) 983392Sswilcox (void) printf(" (CLEARED)\n"); 984392Sswilcox remove_orphan_dir(idesc->id_number); 985392Sswilcox } else if (corrupting == CLRI_NOP_CORRUPT) { 986392Sswilcox iscorrupt = 1; 987392Sswilcox } 988392Sswilcox (void) printf("\n"); 9890Sstevel@tonic-gate } 9900Sstevel@tonic-gate 991392Sswilcox /* 992392Sswilcox * Find the directory entry for the inode noted in id_parent (which is 993392Sswilcox * not necessarily the parent of anything, we're just using a convenient 994392Sswilcox * field. 995392Sswilcox */ 996392Sswilcox int 997392Sswilcox findname(struct inodesc *idesc) 9980Sstevel@tonic-gate { 9990Sstevel@tonic-gate struct direct *dirp = idesc->id_dirp; 10000Sstevel@tonic-gate 10010Sstevel@tonic-gate if (dirp->d_ino != idesc->id_parent) 10020Sstevel@tonic-gate return (KEEPON); 1003392Sswilcox (void) memmove(idesc->id_name, dirp->d_name, 10040Sstevel@tonic-gate MIN(dirp->d_namlen, MAXNAMLEN) + 1); 10050Sstevel@tonic-gate return (STOP|FOUND); 10060Sstevel@tonic-gate } 10070Sstevel@tonic-gate 1008392Sswilcox /* 1009392Sswilcox * Find the inode number associated with the given name. 1010392Sswilcox */ 1011392Sswilcox int 1012392Sswilcox findino(struct inodesc *idesc) 10130Sstevel@tonic-gate { 10140Sstevel@tonic-gate struct direct *dirp = idesc->id_dirp; 10150Sstevel@tonic-gate 10160Sstevel@tonic-gate if (dirp->d_ino == 0) 10170Sstevel@tonic-gate return (KEEPON); 10180Sstevel@tonic-gate if (strcmp(dirp->d_name, idesc->id_name) == 0 && 10190Sstevel@tonic-gate dirp->d_ino >= UFSROOTINO && dirp->d_ino <= maxino) { 10200Sstevel@tonic-gate idesc->id_parent = dirp->d_ino; 10210Sstevel@tonic-gate return (STOP|FOUND); 10220Sstevel@tonic-gate } 10230Sstevel@tonic-gate return (KEEPON); 10240Sstevel@tonic-gate } 10250Sstevel@tonic-gate 1026392Sswilcox int 1027392Sswilcox cleardirentry(fsck_ino_t parentdir, fsck_ino_t target) 1028392Sswilcox { 1029392Sswilcox struct inodesc idesc; 1030392Sswilcox struct dinode *dp; 1031392Sswilcox 1032392Sswilcox dp = ginode(parentdir); 1033392Sswilcox init_inodesc(&idesc); 1034392Sswilcox idesc.id_func = clearanentry; 1035392Sswilcox idesc.id_parent = target; 1036392Sswilcox idesc.id_type = DATA; 1037392Sswilcox idesc.id_fix = NOFIX; 1038392Sswilcox return (ckinode(dp, &idesc, CKI_TRAVERSE)); 1039392Sswilcox } 1040392Sswilcox 1041392Sswilcox static int 1042392Sswilcox clearanentry(struct inodesc *idesc) 1043392Sswilcox { 1044392Sswilcox struct direct *dirp = idesc->id_dirp; 1045392Sswilcox 1046392Sswilcox if (dirp->d_ino != idesc->id_parent || idesc->id_entryno < 2) { 1047392Sswilcox idesc->id_entryno++; 1048392Sswilcox return (KEEPON); 1049392Sswilcox } 1050392Sswilcox dirp->d_ino = 0; 1051392Sswilcox return (STOP|FOUND|ALTERED); 1052392Sswilcox } 1053392Sswilcox 1054392Sswilcox void 1055392Sswilcox pinode(fsck_ino_t ino) 10560Sstevel@tonic-gate { 10570Sstevel@tonic-gate struct dinode *dp; 1058392Sswilcox 1059392Sswilcox (void) printf(" I=%lu ", (ulong_t)ino); 1060392Sswilcox if (ino < UFSROOTINO || ino > maxino) 1061392Sswilcox return; 1062392Sswilcox dp = ginode(ino); 1063392Sswilcox pdinode(dp); 1064392Sswilcox } 1065392Sswilcox 1066392Sswilcox static void 1067392Sswilcox pdinode(struct dinode *dp) 1068392Sswilcox { 10690Sstevel@tonic-gate char *p; 10700Sstevel@tonic-gate struct passwd *pw; 10710Sstevel@tonic-gate time_t t; 10720Sstevel@tonic-gate 1073392Sswilcox (void) printf(" OWNER="); 10740Sstevel@tonic-gate if ((pw = getpwuid((int)dp->di_uid)) != 0) 1075392Sswilcox (void) printf("%s ", pw->pw_name); 10760Sstevel@tonic-gate else 1077392Sswilcox (void) printf("%lu ", (ulong_t)dp->di_uid); 1078392Sswilcox (void) printf("MODE=%o\n", dp->di_mode); 10790Sstevel@tonic-gate if (preen) 1080392Sswilcox (void) printf("%s: ", devname); 1081392Sswilcox (void) printf("SIZE=%lld ", (longlong_t)dp->di_size); 1082392Sswilcox 1083392Sswilcox /* ctime() ignores LOCALE, so this is safe */ 10840Sstevel@tonic-gate t = (time_t)dp->di_mtime; 10850Sstevel@tonic-gate p = ctime(&t); 1086392Sswilcox (void) printf("MTIME=%12.12s %4.4s ", p + 4, p + 20); 10870Sstevel@tonic-gate } 10880Sstevel@tonic-gate 1089392Sswilcox void 1090392Sswilcox blkerror(fsck_ino_t ino, char *type, daddr32_t blk, daddr32_t lbn) 10910Sstevel@tonic-gate { 1092392Sswilcox pfatal("FRAGMENT %d %s I=%u LFN %d", blk, type, ino, lbn); 1093392Sswilcox (void) printf("\n"); 10940Sstevel@tonic-gate 1095392Sswilcox switch (statemap[ino] & ~INDELAYD) { 10960Sstevel@tonic-gate 10970Sstevel@tonic-gate case FSTATE: 1098392Sswilcox case FZLINK: 10990Sstevel@tonic-gate statemap[ino] = FCLEAR; 11000Sstevel@tonic-gate return; 11010Sstevel@tonic-gate 1102392Sswilcox case DFOUND: 11030Sstevel@tonic-gate case DSTATE: 1104392Sswilcox case DZLINK: 11050Sstevel@tonic-gate statemap[ino] = DCLEAR; 1106392Sswilcox add_orphan_dir(ino); 11070Sstevel@tonic-gate return; 11080Sstevel@tonic-gate 11090Sstevel@tonic-gate case SSTATE: 11100Sstevel@tonic-gate statemap[ino] = SCLEAR; 11110Sstevel@tonic-gate return; 11120Sstevel@tonic-gate 11130Sstevel@tonic-gate case FCLEAR: 11140Sstevel@tonic-gate case DCLEAR: 11150Sstevel@tonic-gate case SCLEAR: 11160Sstevel@tonic-gate return; 11170Sstevel@tonic-gate 11180Sstevel@tonic-gate default: 1119392Sswilcox errexit("BAD STATE 0x%x TO BLKERR\n", statemap[ino]); 11200Sstevel@tonic-gate /* NOTREACHED */ 11210Sstevel@tonic-gate } 11220Sstevel@tonic-gate } 11230Sstevel@tonic-gate 11240Sstevel@tonic-gate /* 11250Sstevel@tonic-gate * allocate an unused inode 11260Sstevel@tonic-gate */ 1127392Sswilcox fsck_ino_t 1128392Sswilcox allocino(fsck_ino_t request, int type) 11290Sstevel@tonic-gate { 1130392Sswilcox fsck_ino_t ino; 11310Sstevel@tonic-gate struct dinode *dp; 1132392Sswilcox struct cg *cgp = &cgrp; 11333219Sabalfour int cg; 11340Sstevel@tonic-gate time_t t; 1135392Sswilcox caddr_t err; 11360Sstevel@tonic-gate 1137392Sswilcox if (debug && (request != 0) && (request != UFSROOTINO)) 1138392Sswilcox errexit("assertion failed: allocino() asked for " 1139*6179Smc208700 "inode %d instead of 0 or %d", 1140*6179Smc208700 (int)request, (int)UFSROOTINO); 1141392Sswilcox 1142392Sswilcox /* 1143392Sswilcox * We know that we're only going to get requests for UFSROOTINO 1144392Sswilcox * or 0. If UFSROOTINO is wanted, then it better be available 1145392Sswilcox * because our caller is trying to recreate the root directory. 1146392Sswilcox * If we're asked for 0, then which one we return doesn't matter. 1147392Sswilcox * We know that inodes 0 and 1 are never valid to return, so we 1148392Sswilcox * the start at the lowest-legal inode number. 1149392Sswilcox * 1150392Sswilcox * If we got a request for UFSROOTINO, then request != 0, and 1151392Sswilcox * this pair of conditionals is the only place that treats 1152392Sswilcox * UFSROOTINO specially. 1153392Sswilcox */ 11540Sstevel@tonic-gate if (request == 0) 11550Sstevel@tonic-gate request = UFSROOTINO; 11560Sstevel@tonic-gate else if (statemap[request] != USTATE) 11570Sstevel@tonic-gate return (0); 1158392Sswilcox 1159392Sswilcox /* 1160392Sswilcox * Doesn't do wrapping, since we know we started at 1161392Sswilcox * the smallest inode. 1162392Sswilcox */ 11630Sstevel@tonic-gate for (ino = request; ino < maxino; ino++) 11640Sstevel@tonic-gate if (statemap[ino] == USTATE) 11650Sstevel@tonic-gate break; 11660Sstevel@tonic-gate if (ino == maxino) 11670Sstevel@tonic-gate return (0); 1168392Sswilcox 1169392Sswilcox /* 1170392Sswilcox * In pass5, we'll calculate the bitmaps and counts all again from 1171392Sswilcox * scratch and do a comparison, but for that to work the cg has 1172392Sswilcox * to know what in-memory changes we've made to it. If we have 1173392Sswilcox * trouble reading the cg, cg_sanity() should kick it out so 1174392Sswilcox * we can skip explicit i/o error checking here. 1175392Sswilcox */ 1176392Sswilcox cg = itog(&sblock, ino); 1177392Sswilcox (void) getblk(&cgblk, cgtod(&sblock, cg), (size_t)sblock.fs_cgsize); 11783219Sabalfour err = cg_sanity(cgp, cg); 1179392Sswilcox if (err != NULL) { 1180392Sswilcox pfatal("CG %d: %s\n", cg, err); 1181392Sswilcox free((void *)err); 1182392Sswilcox if (reply("REPAIR") == 0) 1183392Sswilcox errexit("Program terminated."); 1184392Sswilcox fix_cg(cgp, cg); 1185392Sswilcox } 1186392Sswilcox setbit(cg_inosused(cgp), ino % sblock.fs_ipg); 1187392Sswilcox cgp->cg_cs.cs_nifree--; 1188392Sswilcox cgdirty(); 1189392Sswilcox 1190392Sswilcox if (lastino < ino) 1191392Sswilcox lastino = ino; 1192392Sswilcox 1193392Sswilcox /* 1194392Sswilcox * Don't currently support IFATTRDIR or any of the other 1195392Sswilcox * types, as they aren't needed. 1196392Sswilcox */ 11970Sstevel@tonic-gate switch (type & IFMT) { 11980Sstevel@tonic-gate case IFDIR: 11990Sstevel@tonic-gate statemap[ino] = DSTATE; 1200392Sswilcox cgp->cg_cs.cs_ndir++; 12010Sstevel@tonic-gate break; 12020Sstevel@tonic-gate case IFREG: 12030Sstevel@tonic-gate case IFLNK: 12040Sstevel@tonic-gate statemap[ino] = FSTATE; 12050Sstevel@tonic-gate break; 12060Sstevel@tonic-gate default: 1207392Sswilcox /* 1208392Sswilcox * Pretend nothing ever happened. This clears the 1209392Sswilcox * dirty flag, among other things. 1210392Sswilcox */ 1211392Sswilcox initbarea(&cgblk); 1212392Sswilcox if (debug) 1213392Sswilcox (void) printf("allocino: unknown type 0%o\n", 1214392Sswilcox type & IFMT); 12150Sstevel@tonic-gate return (0); 12160Sstevel@tonic-gate } 1217392Sswilcox 1218392Sswilcox /* 1219392Sswilcox * We're allocating what should be a completely-unused inode, 1220392Sswilcox * so make sure we don't inherit anything from any previous 1221392Sswilcox * incarnations. 1222392Sswilcox */ 12230Sstevel@tonic-gate dp = ginode(ino); 1224392Sswilcox (void) memset((void *)dp, 0, sizeof (struct dinode)); 12250Sstevel@tonic-gate dp->di_db[0] = allocblk(1); 12260Sstevel@tonic-gate if (dp->di_db[0] == 0) { 12270Sstevel@tonic-gate statemap[ino] = USTATE; 12280Sstevel@tonic-gate return (0); 12290Sstevel@tonic-gate } 1230392Sswilcox dp->di_mode = (mode_t)type; 1231392Sswilcox (void) time(&t); 12320Sstevel@tonic-gate dp->di_atime = (time32_t)t; 1233392Sswilcox dp->di_ctime = dp->di_atime; 1234392Sswilcox dp->di_mtime = dp->di_ctime; 12350Sstevel@tonic-gate dp->di_size = (u_offset_t)sblock.fs_fsize; 12360Sstevel@tonic-gate dp->di_blocks = btodb(sblock.fs_fsize); 12370Sstevel@tonic-gate n_files++; 12380Sstevel@tonic-gate inodirty(); 12390Sstevel@tonic-gate return (ino); 12400Sstevel@tonic-gate } 12410Sstevel@tonic-gate 12420Sstevel@tonic-gate /* 1243392Sswilcox * Release some or all of the blocks of an inode. 1244392Sswilcox * Only truncates down. Assumes new_length is appropriately aligned 1245392Sswilcox * to a block boundary (or a directory block boundary, if it's a 1246392Sswilcox * directory). 1247392Sswilcox * 1248392Sswilcox * If this is a directory, discard all of its contents first, so 1249392Sswilcox * we don't create a bunch of orphans that would need another fsck 1250392Sswilcox * run to clean up. 1251392Sswilcox * 1252392Sswilcox * Even if truncating to zero length, the inode remains allocated. 12530Sstevel@tonic-gate */ 1254392Sswilcox void 1255392Sswilcox truncino(fsck_ino_t ino, offset_t new_length, int update) 12560Sstevel@tonic-gate { 12570Sstevel@tonic-gate struct inodesc idesc; 1258392Sswilcox struct inoinfo *iip; 12590Sstevel@tonic-gate struct dinode *dp; 1260392Sswilcox fsck_ino_t parent; 1261392Sswilcox mode_t mode; 1262392Sswilcox caddr_t message; 1263392Sswilcox int isdir; 1264392Sswilcox int ilevel, dblk; 12650Sstevel@tonic-gate 1266392Sswilcox dp = ginode(ino); 1267392Sswilcox mode = (dp->di_mode & IFMT); 1268392Sswilcox isdir = (mode == IFDIR) || (mode == IFATTRDIR); 1269392Sswilcox 1270392Sswilcox if (isdir) { 1271392Sswilcox /* 1272392Sswilcox * Go with the parent we found by chasing references, 1273392Sswilcox * if we've gotten that far. Otherwise, use what the 1274392Sswilcox * directory itself claims. If there's no ``..'' entry 1275392Sswilcox * in it, give up trying to get the link counts right. 1276392Sswilcox */ 1277392Sswilcox if (update == TI_NOPARENT) { 1278392Sswilcox parent = -1; 1279392Sswilcox } else { 1280392Sswilcox iip = getinoinfo(ino); 1281392Sswilcox if (iip != NULL) { 1282392Sswilcox parent = iip->i_parent; 1283392Sswilcox } else { 1284392Sswilcox parent = lookup_dotdot_ino(ino); 1285392Sswilcox if (parent != 0) { 1286392Sswilcox /* 1287392Sswilcox * Make sure that the claimed 1288392Sswilcox * parent actually has a 1289392Sswilcox * reference to us. 1290392Sswilcox */ 1291392Sswilcox dp = ginode(parent); 1292392Sswilcox idesc.id_name = lfname; 1293392Sswilcox idesc.id_type = DATA; 1294392Sswilcox idesc.id_func = findino; 1295392Sswilcox idesc.id_number = ino; 1296392Sswilcox idesc.id_fix = DONTKNOW; 1297392Sswilcox if ((ckinode(dp, &idesc, 1298392Sswilcox CKI_TRAVERSE) & FOUND) == 0) 1299392Sswilcox parent = 0; 1300392Sswilcox } 1301392Sswilcox } 1302392Sswilcox } 1303392Sswilcox 1304392Sswilcox mark_delayed_inodes(ino, numfrags(&sblock, new_length)); 1305392Sswilcox if (parent > 0) { 1306392Sswilcox dp = ginode(parent); 1307392Sswilcox LINK_RANGE(message, dp->di_nlink, -1); 1308392Sswilcox if (message != NULL) { 1309392Sswilcox LINK_CLEAR(message, parent, dp->di_mode, 1310392Sswilcox &idesc); 1311392Sswilcox if (statemap[parent] == USTATE) 1312392Sswilcox goto no_parent_update; 1313392Sswilcox } 1314392Sswilcox TRACK_LNCNTP(parent, lncntp[parent]--); 1315392Sswilcox } else if ((mode == IFDIR) && (parent == 0)) { 1316392Sswilcox /* 1317392Sswilcox * Currently don't have a good way to 1318392Sswilcox * handle this, so throw up our hands. 1319392Sswilcox * However, we know that we can still 1320392Sswilcox * do some good if we continue, so 1321392Sswilcox * don't actually exit yet. 1322392Sswilcox * 1323392Sswilcox * We don't do it for attrdirs, 1324392Sswilcox * because there aren't link counts 1325392Sswilcox * between them and their parents. 1326392Sswilcox */ 1327392Sswilcox pwarn("Could not determine former parent of " 1328392Sswilcox "inode %d, link counts are possibly\n" 1329392Sswilcox "incorrect. Please rerun fsck(1M) to " 1330392Sswilcox "correct this.\n", 1331392Sswilcox ino); 1332392Sswilcox iscorrupt = 1; 1333392Sswilcox } 1334392Sswilcox /* 1335392Sswilcox * ...else if it's a directory with parent == -1, then 1336392Sswilcox * we've not gotten far enough to know connectivity, 1337392Sswilcox * and it'll get handled automatically later. 1338392Sswilcox */ 1339392Sswilcox } 1340392Sswilcox 1341392Sswilcox no_parent_update: 1342392Sswilcox init_inodesc(&idesc); 13430Sstevel@tonic-gate idesc.id_type = ADDR; 13440Sstevel@tonic-gate idesc.id_func = pass4check; 13450Sstevel@tonic-gate idesc.id_number = ino; 13460Sstevel@tonic-gate idesc.id_fix = DONTKNOW; 1347392Sswilcox idesc.id_truncto = howmany(new_length, sblock.fs_bsize); 13480Sstevel@tonic-gate dp = ginode(ino); 1349392Sswilcox if (ckinode(dp, &idesc, CKI_TRUNCATE) & ALTERED) 1350392Sswilcox inodirty(); 1351392Sswilcox 1352392Sswilcox /* 1353392Sswilcox * This has to be done after ckinode(), so that all of 1354392Sswilcox * the fragments get visited. Note that we assume we're 1355392Sswilcox * always truncating to a block boundary, rather than a 1356392Sswilcox * fragment boundary. 1357392Sswilcox */ 1358392Sswilcox dp = ginode(ino); 1359392Sswilcox dp->di_size = new_length; 1360392Sswilcox 1361392Sswilcox /* 1362392Sswilcox * Clear now-obsolete pointers. 1363392Sswilcox */ 1364392Sswilcox for (dblk = idesc.id_truncto + 1; dblk < NDADDR; dblk++) { 1365392Sswilcox dp->di_db[dblk] = 0; 1366392Sswilcox } 1367392Sswilcox 1368392Sswilcox ilevel = get_indir_offsets(-1, idesc.id_truncto, NULL, NULL); 1369392Sswilcox for (ilevel++; ilevel < NIADDR; ilevel++) { 1370392Sswilcox dp->di_ib[ilevel] = 0; 1371392Sswilcox } 1372392Sswilcox 1373392Sswilcox inodirty(); 1374392Sswilcox } 1375392Sswilcox 1376392Sswilcox /* 1377392Sswilcox * Release an inode's resources, then release the inode itself. 1378392Sswilcox */ 1379392Sswilcox void 1380392Sswilcox freeino(fsck_ino_t ino, int update_parent) 1381392Sswilcox { 1382392Sswilcox int cg; 1383392Sswilcox struct dinode *dp; 1384392Sswilcox struct cg *cgp; 1385392Sswilcox 1386392Sswilcox n_files--; 1387392Sswilcox dp = ginode(ino); 13883960Sjk201079 /* 13893960Sjk201079 * We need to make sure that the file is really a large file. 13903960Sjk201079 * Everything bigger than UFS_MAXOFFSET_T is treated as a file with 13913960Sjk201079 * negative size, which shall be cleared. (see verify_inode() in 13923960Sjk201079 * pass1.c) 13933960Sjk201079 */ 13943960Sjk201079 if (dp->di_size > (u_offset_t)MAXOFF_T && 1395*6179Smc208700 dp->di_size <= (u_offset_t)UFS_MAXOFFSET_T && 1396*6179Smc208700 ftypeok(dp) && 1397*6179Smc208700 (dp->di_mode & IFMT) != IFBLK && 1398*6179Smc208700 (dp->di_mode & IFMT) != IFCHR) { 1399392Sswilcox largefile_count--; 1400392Sswilcox } 1401392Sswilcox truncino(ino, 0, update_parent); 1402392Sswilcox 1403392Sswilcox dp = ginode(ino); 1404392Sswilcox if ((dp->di_mode & IFMT) == IFATTRDIR) { 1405392Sswilcox clearshadow(ino, &attrclientinfo); 1406392Sswilcox dp = ginode(ino); 1407392Sswilcox } 1408392Sswilcox 14090Sstevel@tonic-gate clearinode(dp); 14100Sstevel@tonic-gate inodirty(); 14110Sstevel@tonic-gate statemap[ino] = USTATE; 1412392Sswilcox 1413392Sswilcox /* 1414392Sswilcox * Keep the disk in sync with us so that pass5 doesn't get 1415392Sswilcox * upset about spurious inconsistencies. 1416392Sswilcox */ 1417392Sswilcox cg = itog(&sblock, ino); 1418392Sswilcox (void) getblk(&cgblk, (diskaddr_t)cgtod(&sblock, cg), 1419392Sswilcox (size_t)sblock.fs_cgsize); 1420392Sswilcox cgp = cgblk.b_un.b_cg; 1421392Sswilcox clrbit(cg_inosused(cgp), ino % sblock.fs_ipg); 1422392Sswilcox cgp->cg_cs.cs_nifree += 1; 1423392Sswilcox cgdirty(); 1424392Sswilcox sblock.fs_cstotal.cs_nifree += 1; 1425392Sswilcox sbdirty(); 1426392Sswilcox } 1427392Sswilcox 1428392Sswilcox void 1429392Sswilcox init_inoinfo(struct inoinfo *inp, struct dinode *dp, fsck_ino_t inum) 1430392Sswilcox { 1431392Sswilcox inp->i_parent = ((inum == UFSROOTINO) ? UFSROOTINO : (fsck_ino_t)0); 1432392Sswilcox inp->i_dotdot = (fsck_ino_t)0; 1433392Sswilcox inp->i_isize = (offset_t)dp->di_size; 1434392Sswilcox inp->i_blkssize = (NDADDR + NIADDR) * sizeof (daddr32_t); 1435392Sswilcox inp->i_extattr = dp->di_oeftflag; 1436392Sswilcox (void) memmove((void *)&inp->i_blks[0], (void *)&dp->di_db[0], 1437392Sswilcox inp->i_blkssize); 1438392Sswilcox } 1439392Sswilcox 1440392Sswilcox /* 1441392Sswilcox * Return the inode number in the ".." entry of the provided 1442392Sswilcox * directory inode. 1443392Sswilcox */ 1444392Sswilcox static int 1445392Sswilcox lookup_dotdot_ino(fsck_ino_t ino) 1446392Sswilcox { 1447392Sswilcox struct inodesc idesc; 1448392Sswilcox 1449392Sswilcox init_inodesc(&idesc); 1450392Sswilcox idesc.id_type = DATA; 1451392Sswilcox idesc.id_func = findino; 1452392Sswilcox idesc.id_name = ".."; 1453392Sswilcox idesc.id_number = ino; 1454392Sswilcox idesc.id_fix = NOFIX; 1455392Sswilcox 1456392Sswilcox if ((ckinode(ginode(ino), &idesc, CKI_TRAVERSE) & FOUND) != 0) { 1457392Sswilcox return (idesc.id_parent); 1458392Sswilcox } 1459392Sswilcox 1460392Sswilcox return (0); 14610Sstevel@tonic-gate } 1462392Sswilcox 1463392Sswilcox /* 1464392Sswilcox * Convenience wrapper around ckinode(findino()). 1465392Sswilcox */ 1466392Sswilcox int 1467392Sswilcox lookup_named_ino(fsck_ino_t dir, caddr_t name) 1468392Sswilcox { 1469392Sswilcox struct inodesc idesc; 1470392Sswilcox 1471392Sswilcox init_inodesc(&idesc); 1472392Sswilcox idesc.id_type = DATA; 1473392Sswilcox idesc.id_func = findino; 1474392Sswilcox idesc.id_name = name; 1475392Sswilcox idesc.id_number = dir; 1476392Sswilcox idesc.id_fix = NOFIX; 1477392Sswilcox 1478392Sswilcox if ((ckinode(ginode(dir), &idesc, CKI_TRAVERSE) & FOUND) != 0) { 1479392Sswilcox return (idesc.id_parent); 1480392Sswilcox } 1481392Sswilcox 1482392Sswilcox return (0); 1483392Sswilcox } 1484392Sswilcox 1485392Sswilcox /* 1486392Sswilcox * Marks inodes that are being orphaned and might need to be reconnected 1487392Sswilcox * by pass4(). The inode we're traversing is the directory whose 1488392Sswilcox * contents will be reconnected later. id_parent is the lfn at which 1489392Sswilcox * to start looking at said contents. 1490392Sswilcox */ 1491392Sswilcox static int 1492392Sswilcox mark_a_delayed_inode(struct inodesc *idesc) 1493392Sswilcox { 1494392Sswilcox struct direct *dirp = idesc->id_dirp; 1495392Sswilcox 1496392Sswilcox if (idesc->id_lbn < idesc->id_parent) { 1497392Sswilcox return (KEEPON); 1498392Sswilcox } 1499392Sswilcox 1500392Sswilcox if (dirp->d_ino != 0 && 1501392Sswilcox strcmp(dirp->d_name, ".") != 0 && 1502392Sswilcox strcmp(dirp->d_name, "..") != 0) { 1503392Sswilcox statemap[dirp->d_ino] &= ~INFOUND; 1504392Sswilcox statemap[dirp->d_ino] |= INDELAYD; 1505392Sswilcox } 1506392Sswilcox 1507392Sswilcox return (KEEPON); 1508392Sswilcox } 1509392Sswilcox 1510392Sswilcox static void 1511392Sswilcox mark_delayed_inodes(fsck_ino_t ino, daddr32_t first_lfn) 1512392Sswilcox { 1513392Sswilcox struct dinode *dp; 1514392Sswilcox struct inodesc idelayed; 1515392Sswilcox 1516392Sswilcox init_inodesc(&idelayed); 1517392Sswilcox idelayed.id_number = ino; 1518392Sswilcox idelayed.id_type = DATA; 1519392Sswilcox idelayed.id_fix = NOFIX; 1520392Sswilcox idelayed.id_func = mark_a_delayed_inode; 1521392Sswilcox idelayed.id_parent = first_lfn; 1522392Sswilcox idelayed.id_entryno = 2; 1523392Sswilcox 1524392Sswilcox dp = ginode(ino); 1525392Sswilcox (void) ckinode(dp, &idelayed, CKI_TRAVERSE); 1526392Sswilcox } 1527392Sswilcox 1528392Sswilcox /* 1529392Sswilcox * Clear the i_oeftflag/extended attribute pointer from INO. 1530392Sswilcox */ 1531392Sswilcox void 1532392Sswilcox clearattrref(fsck_ino_t ino) 1533392Sswilcox { 1534392Sswilcox struct dinode *dp; 1535392Sswilcox 1536392Sswilcox dp = ginode(ino); 1537392Sswilcox if (debug) { 1538392Sswilcox if (dp->di_oeftflag == 0) 1539392Sswilcox (void) printf("clearattref: no attr to clear on %d\n", 1540392Sswilcox ino); 1541392Sswilcox } 1542392Sswilcox 1543392Sswilcox dp->di_oeftflag = 0; 1544392Sswilcox inodirty(); 1545392Sswilcox } 1546