1 /* 2 * Copyright (c) 1980, 1986 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #ifndef lint 35 static char sccsid[] = "@(#)inode.c 5.18 (Berkeley) 3/19/91"; 36 static char rcsid[] = "$Header: /cvsroot/src/sbin/fsck_ffs/inode.c,v 1.3 1993/03/23 00:27:53 cgd Exp $"; 37 #endif /* not lint */ 38 39 #include <sys/param.h> 40 #include <ufs/dinode.h> 41 #include <ufs/fs.h> 42 #include <ufs/dir.h> 43 #include <pwd.h> 44 #include <stdlib.h> 45 #include <string.h> 46 #include "fsck.h" 47 48 static ino_t startinum; 49 50 ckinode(dp, idesc) 51 struct dinode *dp; 52 register struct inodesc *idesc; 53 { 54 register daddr_t *ap; 55 long ret, n, ndb, offset; 56 struct dinode dino; 57 58 if (idesc->id_fix != IGNORE) 59 idesc->id_fix = DONTKNOW; 60 idesc->id_entryno = 0; 61 idesc->id_filesize = dp->di_size; 62 if ((dp->di_mode & IFMT) == IFBLK || (dp->di_mode & IFMT) == IFCHR) 63 return (KEEPON); 64 dino = *dp; 65 ndb = howmany(dino.di_size, sblock.fs_bsize); 66 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 67 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 68 idesc->id_numfrags = 69 numfrags(&sblock, fragroundup(&sblock, offset)); 70 else 71 idesc->id_numfrags = sblock.fs_frag; 72 if (*ap == 0) 73 continue; 74 idesc->id_blkno = *ap; 75 if (idesc->id_type == ADDR) 76 ret = (*idesc->id_func)(idesc); 77 else 78 ret = dirscan(idesc); 79 if (ret & STOP) 80 return (ret); 81 } 82 idesc->id_numfrags = sblock.fs_frag; 83 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 84 if (*ap) { 85 idesc->id_blkno = *ap; 86 ret = iblock(idesc, n, 87 dino.di_size - sblock.fs_bsize * NDADDR); 88 if (ret & STOP) 89 return (ret); 90 } 91 } 92 return (KEEPON); 93 } 94 95 iblock(idesc, ilevel, isize) 96 struct inodesc *idesc; 97 register long ilevel; 98 u_long isize; 99 { 100 register daddr_t *ap; 101 register daddr_t *aplim; 102 int i, n, (*func)(), nif, sizepb; 103 register struct bufarea *bp; 104 char buf[BUFSIZ]; 105 extern int dirscan(), pass1check(); 106 107 if (idesc->id_type == ADDR) { 108 func = idesc->id_func; 109 if (((n = (*func)(idesc)) & KEEPON) == 0) 110 return (n); 111 } else 112 func = dirscan; 113 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 114 return (SKIP); 115 bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 116 ilevel--; 117 for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 118 sizepb *= NINDIR(&sblock); 119 nif = isize / sizepb + 1; 120 if (nif > NINDIR(&sblock)) 121 nif = NINDIR(&sblock); 122 if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 123 aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 124 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 125 if (*ap == 0) 126 continue; 127 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 128 idesc->id_number); 129 if (dofix(idesc, buf)) { 130 *ap = 0; 131 dirty(bp); 132 } 133 } 134 flush(fswritefd, bp); 135 } 136 aplim = &bp->b_un.b_indir[nif]; 137 for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) { 138 if (*ap) { 139 idesc->id_blkno = *ap; 140 if (ilevel > 0) 141 n = iblock(idesc, ilevel, isize - i * sizepb); 142 else 143 n = (*func)(idesc); 144 if (n & STOP) { 145 bp->b_flags &= ~B_INUSE; 146 return (n); 147 } 148 } 149 } 150 bp->b_flags &= ~B_INUSE; 151 return (KEEPON); 152 } 153 154 /* 155 * Check that a block in a legal block number. 156 * Return 0 if in range, 1 if out of range. 157 */ 158 chkrange(blk, cnt) 159 daddr_t blk; 160 int cnt; 161 { 162 register int c; 163 164 if ((unsigned)(blk + cnt) > maxfsblock) 165 return (1); 166 c = dtog(&sblock, blk); 167 if (blk < cgdmin(&sblock, c)) { 168 if ((blk + cnt) > cgsblock(&sblock, c)) { 169 if (debug) { 170 printf("blk %ld < cgdmin %ld;", 171 blk, cgdmin(&sblock, c)); 172 printf(" blk + cnt %ld > cgsbase %ld\n", 173 blk + cnt, cgsblock(&sblock, c)); 174 } 175 return (1); 176 } 177 } else { 178 if ((blk + cnt) > cgbase(&sblock, c+1)) { 179 if (debug) { 180 printf("blk %ld >= cgdmin %ld;", 181 blk, cgdmin(&sblock, c)); 182 printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 183 blk+cnt, sblock.fs_fpg); 184 } 185 return (1); 186 } 187 } 188 return (0); 189 } 190 191 /* 192 * General purpose interface for reading inodes. 193 */ 194 struct dinode * 195 ginode(inumber) 196 ino_t inumber; 197 { 198 daddr_t iblk; 199 200 if (inumber < ROOTINO || inumber > maxino) 201 errexit("bad inode number %d to ginode\n", inumber); 202 if (startinum == 0 || 203 inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 204 iblk = itod(&sblock, inumber); 205 if (pbp != 0) 206 pbp->b_flags &= ~B_INUSE; 207 pbp = getdatablk(iblk, sblock.fs_bsize); 208 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 209 } 210 return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 211 } 212 213 /* 214 * Special purpose version of ginode used to optimize first pass 215 * over all the inodes in numerical order. 216 */ 217 ino_t nextino, lastinum; 218 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 219 struct dinode *inodebuf; 220 221 struct dinode * 222 getnextinode(inumber) 223 ino_t inumber; 224 { 225 long size; 226 daddr_t dblk; 227 static struct dinode *dp; 228 229 if (inumber != nextino++ || inumber > maxino) 230 errexit("bad inode number %d to nextinode\n", inumber); 231 if (inumber >= lastinum) { 232 readcnt++; 233 dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 234 if (readcnt % readpercg == 0) { 235 size = partialsize; 236 lastinum += partialcnt; 237 } else { 238 size = inobufsize; 239 lastinum += fullcnt; 240 } 241 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ 242 dp = inodebuf; 243 } 244 return (dp++); 245 } 246 247 resetinodebuf() 248 { 249 250 startinum = 0; 251 nextino = 0; 252 lastinum = 0; 253 readcnt = 0; 254 inobufsize = blkroundup(&sblock, INOBUFSIZE); 255 fullcnt = inobufsize / sizeof(struct dinode); 256 readpercg = sblock.fs_ipg / fullcnt; 257 partialcnt = sblock.fs_ipg % fullcnt; 258 partialsize = partialcnt * sizeof(struct dinode); 259 if (partialcnt != 0) { 260 readpercg++; 261 } else { 262 partialcnt = fullcnt; 263 partialsize = inobufsize; 264 } 265 if (inodebuf == NULL && 266 (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 267 errexit("Cannot allocate space for inode buffer\n"); 268 while (nextino < ROOTINO) 269 (void)getnextinode(nextino); 270 } 271 272 freeinodebuf() 273 { 274 275 if (inodebuf != NULL) 276 free((char *)inodebuf); 277 inodebuf = NULL; 278 } 279 280 /* 281 * Routines to maintain information about directory inodes. 282 * This is built during the first pass and used during the 283 * second and third passes. 284 * 285 * Enter inodes into the cache. 286 */ 287 cacheino(dp, inumber) 288 register struct dinode *dp; 289 ino_t inumber; 290 { 291 register struct inoinfo *inp; 292 struct inoinfo **inpp; 293 unsigned int blks; 294 295 blks = howmany(dp->di_size, sblock.fs_bsize); 296 if (blks > NDADDR) 297 blks = NDADDR + NIADDR; 298 inp = (struct inoinfo *) 299 malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); 300 if (inp == NULL) 301 return; 302 inpp = &inphead[inumber % numdirs]; 303 inp->i_nexthash = *inpp; 304 *inpp = inp; 305 inp->i_parent = (ino_t)0; 306 inp->i_dotdot = (ino_t)0; 307 inp->i_number = inumber; 308 inp->i_isize = dp->di_size; 309 inp->i_numblks = blks * sizeof(daddr_t); 310 bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], 311 (size_t)inp->i_numblks); 312 if (inplast == listmax) { 313 listmax += 100; 314 inpsort = (struct inoinfo **)realloc((char *)inpsort, 315 (unsigned)listmax * sizeof(struct inoinfo *)); 316 if (inpsort == NULL) 317 errexit("cannot increase directory list"); 318 } 319 inpsort[inplast++] = inp; 320 } 321 322 /* 323 * Look up an inode cache structure. 324 */ 325 struct inoinfo * 326 getinoinfo(inumber) 327 ino_t inumber; 328 { 329 register struct inoinfo *inp; 330 331 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 332 if (inp->i_number != inumber) 333 continue; 334 return (inp); 335 } 336 errexit("cannot find inode %d\n", inumber); 337 return ((struct inoinfo *)0); 338 } 339 340 /* 341 * Clean up all the inode cache structure. 342 */ 343 inocleanup() 344 { 345 register struct inoinfo **inpp; 346 347 if (inphead == NULL) 348 return; 349 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 350 free((char *)(*inpp)); 351 free((char *)inphead); 352 free((char *)inpsort); 353 inphead = inpsort = NULL; 354 } 355 356 inodirty() 357 { 358 359 dirty(pbp); 360 } 361 362 clri(idesc, type, flag) 363 register struct inodesc *idesc; 364 char *type; 365 int flag; 366 { 367 register struct dinode *dp; 368 369 dp = ginode(idesc->id_number); 370 if (flag == 1) { 371 pwarn("%s %s", type, 372 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 373 pinode(idesc->id_number); 374 } 375 if (preen || reply("CLEAR") == 1) { 376 if (preen) 377 printf(" (CLEARED)\n"); 378 n_files--; 379 (void)ckinode(dp, idesc); 380 clearinode(dp); 381 statemap[idesc->id_number] = USTATE; 382 inodirty(); 383 } 384 } 385 386 findname(idesc) 387 struct inodesc *idesc; 388 { 389 register struct direct *dirp = idesc->id_dirp; 390 391 if (dirp->d_ino != idesc->id_parent) 392 return (KEEPON); 393 bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); 394 return (STOP|FOUND); 395 } 396 397 findino(idesc) 398 struct inodesc *idesc; 399 { 400 register struct direct *dirp = idesc->id_dirp; 401 402 if (dirp->d_ino == 0) 403 return (KEEPON); 404 if (strcmp(dirp->d_name, idesc->id_name) == 0 && 405 dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 406 idesc->id_parent = dirp->d_ino; 407 return (STOP|FOUND); 408 } 409 return (KEEPON); 410 } 411 412 pinode(ino) 413 ino_t ino; 414 { 415 register struct dinode *dp; 416 register char *p; 417 struct passwd *pw; 418 char *ctime(); 419 420 printf(" I=%lu ", ino); 421 if (ino < ROOTINO || ino > maxino) 422 return; 423 dp = ginode(ino); 424 printf(" OWNER="); 425 if ((pw = getpwuid((int)dp->di_uid)) != 0) 426 printf("%s ", pw->pw_name); 427 else 428 printf("%u ", (unsigned)dp->di_uid); 429 printf("MODE=%o\n", dp->di_mode); 430 if (preen) 431 printf("%s: ", devname); 432 printf("SIZE=%lu ", dp->di_size); 433 p = ctime(&dp->di_mtime); 434 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 435 } 436 437 blkerror(ino, type, blk) 438 ino_t ino; 439 char *type; 440 daddr_t blk; 441 { 442 443 pfatal("%ld %s I=%lu", blk, type, ino); 444 printf("\n"); 445 switch (statemap[ino]) { 446 447 case FSTATE: 448 statemap[ino] = FCLEAR; 449 return; 450 451 case DSTATE: 452 statemap[ino] = DCLEAR; 453 return; 454 455 case FCLEAR: 456 case DCLEAR: 457 return; 458 459 default: 460 errexit("BAD STATE %d TO BLKERR", statemap[ino]); 461 /* NOTREACHED */ 462 } 463 } 464 465 /* 466 * allocate an unused inode 467 */ 468 ino_t 469 allocino(request, type) 470 ino_t request; 471 int type; 472 { 473 register ino_t ino; 474 register struct dinode *dp; 475 476 if (request == 0) 477 request = ROOTINO; 478 else if (statemap[request] != USTATE) 479 return (0); 480 for (ino = request; ino < maxino; ino++) 481 if (statemap[ino] == USTATE) 482 break; 483 if (ino == maxino) 484 return (0); 485 switch (type & IFMT) { 486 case IFDIR: 487 statemap[ino] = DSTATE; 488 break; 489 case IFREG: 490 case IFLNK: 491 statemap[ino] = FSTATE; 492 break; 493 default: 494 return (0); 495 } 496 dp = ginode(ino); 497 dp->di_db[0] = allocblk((long)1); 498 if (dp->di_db[0] == 0) { 499 statemap[ino] = USTATE; 500 return (0); 501 } 502 dp->di_mode = type; 503 (void)time(&dp->di_atime); 504 dp->di_mtime = dp->di_ctime = dp->di_atime; 505 dp->di_size = sblock.fs_fsize; 506 dp->di_blocks = btodb(sblock.fs_fsize); 507 n_files++; 508 inodirty(); 509 return (ino); 510 } 511 512 /* 513 * deallocate an inode 514 */ 515 freeino(ino) 516 ino_t ino; 517 { 518 struct inodesc idesc; 519 extern int pass4check(); 520 struct dinode *dp; 521 522 bzero((char *)&idesc, sizeof(struct inodesc)); 523 idesc.id_type = ADDR; 524 idesc.id_func = pass4check; 525 idesc.id_number = ino; 526 dp = ginode(ino); 527 (void)ckinode(dp, &idesc); 528 clearinode(dp); 529 inodirty(); 530 statemap[ino] = USTATE; 531 n_files--; 532 } 533