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.4 1993/06/13 21:09:16 mycroft 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 DFASTLINK(*dp)) 64 return (KEEPON); 65 dino = *dp; 66 ndb = howmany(dino.di_size, sblock.fs_bsize); 67 for (ap = &dino.di_db[0]; ap < &dino.di_db[NDADDR]; ap++) { 68 if (--ndb == 0 && (offset = blkoff(&sblock, dino.di_size)) != 0) 69 idesc->id_numfrags = 70 numfrags(&sblock, fragroundup(&sblock, offset)); 71 else 72 idesc->id_numfrags = sblock.fs_frag; 73 if (*ap == 0) 74 continue; 75 idesc->id_blkno = *ap; 76 if (idesc->id_type == ADDR) 77 ret = (*idesc->id_func)(idesc); 78 else 79 ret = dirscan(idesc); 80 if (ret & STOP) 81 return (ret); 82 } 83 idesc->id_numfrags = sblock.fs_frag; 84 for (ap = &dino.di_ib[0], n = 1; n <= NIADDR; ap++, n++) { 85 if (*ap) { 86 idesc->id_blkno = *ap; 87 ret = iblock(idesc, n, 88 dino.di_size - sblock.fs_bsize * NDADDR); 89 if (ret & STOP) 90 return (ret); 91 } 92 } 93 return (KEEPON); 94 } 95 96 iblock(idesc, ilevel, isize) 97 struct inodesc *idesc; 98 register long ilevel; 99 u_long isize; 100 { 101 register daddr_t *ap; 102 register daddr_t *aplim; 103 int i, n, (*func)(), nif, sizepb; 104 register struct bufarea *bp; 105 char buf[BUFSIZ]; 106 extern int dirscan(), pass1check(); 107 108 if (idesc->id_type == ADDR) { 109 func = idesc->id_func; 110 if (((n = (*func)(idesc)) & KEEPON) == 0) 111 return (n); 112 } else 113 func = dirscan; 114 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 115 return (SKIP); 116 bp = getdatablk(idesc->id_blkno, sblock.fs_bsize); 117 ilevel--; 118 for (sizepb = sblock.fs_bsize, i = 0; i < ilevel; i++) 119 sizepb *= NINDIR(&sblock); 120 nif = isize / sizepb + 1; 121 if (nif > NINDIR(&sblock)) 122 nif = NINDIR(&sblock); 123 if (idesc->id_func == pass1check && nif < NINDIR(&sblock)) { 124 aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 125 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 126 if (*ap == 0) 127 continue; 128 (void)sprintf(buf, "PARTIALLY TRUNCATED INODE I=%lu", 129 idesc->id_number); 130 if (dofix(idesc, buf)) { 131 *ap = 0; 132 dirty(bp); 133 } 134 } 135 flush(fswritefd, bp); 136 } 137 aplim = &bp->b_un.b_indir[nif]; 138 for (ap = bp->b_un.b_indir, i = 1; ap < aplim; ap++, i++) { 139 if (*ap) { 140 idesc->id_blkno = *ap; 141 if (ilevel > 0) 142 n = iblock(idesc, ilevel, isize - i * sizepb); 143 else 144 n = (*func)(idesc); 145 if (n & STOP) { 146 bp->b_flags &= ~B_INUSE; 147 return (n); 148 } 149 } 150 } 151 bp->b_flags &= ~B_INUSE; 152 return (KEEPON); 153 } 154 155 /* 156 * Check that a block in a legal block number. 157 * Return 0 if in range, 1 if out of range. 158 */ 159 chkrange(blk, cnt) 160 daddr_t blk; 161 int cnt; 162 { 163 register int c; 164 165 if ((unsigned)(blk + cnt) > maxfsblock) 166 return (1); 167 c = dtog(&sblock, blk); 168 if (blk < cgdmin(&sblock, c)) { 169 if ((blk + cnt) > cgsblock(&sblock, c)) { 170 if (debug) { 171 printf("blk %ld < cgdmin %ld;", 172 blk, cgdmin(&sblock, c)); 173 printf(" blk + cnt %ld > cgsbase %ld\n", 174 blk + cnt, cgsblock(&sblock, c)); 175 } 176 return (1); 177 } 178 } else { 179 if ((blk + cnt) > cgbase(&sblock, c+1)) { 180 if (debug) { 181 printf("blk %ld >= cgdmin %ld;", 182 blk, cgdmin(&sblock, c)); 183 printf(" blk + cnt %ld > sblock.fs_fpg %ld\n", 184 blk+cnt, sblock.fs_fpg); 185 } 186 return (1); 187 } 188 } 189 return (0); 190 } 191 192 /* 193 * General purpose interface for reading inodes. 194 */ 195 struct dinode * 196 ginode(inumber) 197 ino_t inumber; 198 { 199 daddr_t iblk; 200 201 if (inumber < ROOTINO || inumber > maxino) 202 errexit("bad inode number %d to ginode\n", inumber); 203 if (startinum == 0 || 204 inumber < startinum || inumber >= startinum + INOPB(&sblock)) { 205 iblk = itod(&sblock, inumber); 206 if (pbp != 0) 207 pbp->b_flags &= ~B_INUSE; 208 pbp = getdatablk(iblk, sblock.fs_bsize); 209 startinum = (inumber / INOPB(&sblock)) * INOPB(&sblock); 210 } 211 return (&pbp->b_un.b_dinode[inumber % INOPB(&sblock)]); 212 } 213 214 /* 215 * Special purpose version of ginode used to optimize first pass 216 * over all the inodes in numerical order. 217 */ 218 ino_t nextino, lastinum; 219 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 220 struct dinode *inodebuf; 221 222 struct dinode * 223 getnextinode(inumber) 224 ino_t inumber; 225 { 226 long size; 227 daddr_t dblk; 228 static struct dinode *dp; 229 230 if (inumber != nextino++ || inumber > maxino) 231 errexit("bad inode number %d to nextinode\n", inumber); 232 if (inumber >= lastinum) { 233 readcnt++; 234 dblk = fsbtodb(&sblock, itod(&sblock, lastinum)); 235 if (readcnt % readpercg == 0) { 236 size = partialsize; 237 lastinum += partialcnt; 238 } else { 239 size = inobufsize; 240 lastinum += fullcnt; 241 } 242 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); /* ??? */ 243 dp = inodebuf; 244 } 245 return (dp++); 246 } 247 248 resetinodebuf() 249 { 250 251 startinum = 0; 252 nextino = 0; 253 lastinum = 0; 254 readcnt = 0; 255 inobufsize = blkroundup(&sblock, INOBUFSIZE); 256 fullcnt = inobufsize / sizeof(struct dinode); 257 readpercg = sblock.fs_ipg / fullcnt; 258 partialcnt = sblock.fs_ipg % fullcnt; 259 partialsize = partialcnt * sizeof(struct dinode); 260 if (partialcnt != 0) { 261 readpercg++; 262 } else { 263 partialcnt = fullcnt; 264 partialsize = inobufsize; 265 } 266 if (inodebuf == NULL && 267 (inodebuf = (struct dinode *)malloc((unsigned)inobufsize)) == NULL) 268 errexit("Cannot allocate space for inode buffer\n"); 269 while (nextino < ROOTINO) 270 (void)getnextinode(nextino); 271 } 272 273 freeinodebuf() 274 { 275 276 if (inodebuf != NULL) 277 free((char *)inodebuf); 278 inodebuf = NULL; 279 } 280 281 /* 282 * Routines to maintain information about directory inodes. 283 * This is built during the first pass and used during the 284 * second and third passes. 285 * 286 * Enter inodes into the cache. 287 */ 288 cacheino(dp, inumber) 289 register struct dinode *dp; 290 ino_t inumber; 291 { 292 register struct inoinfo *inp; 293 struct inoinfo **inpp; 294 unsigned int blks; 295 296 blks = howmany(dp->di_size, sblock.fs_bsize); 297 if (blks > NDADDR) 298 blks = NDADDR + NIADDR; 299 inp = (struct inoinfo *) 300 malloc(sizeof(*inp) + (blks - 1) * sizeof(daddr_t)); 301 if (inp == NULL) 302 return; 303 inpp = &inphead[inumber % numdirs]; 304 inp->i_nexthash = *inpp; 305 *inpp = inp; 306 inp->i_parent = (ino_t)0; 307 inp->i_dotdot = (ino_t)0; 308 inp->i_number = inumber; 309 inp->i_isize = dp->di_size; 310 inp->i_numblks = blks * sizeof(daddr_t); 311 bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], 312 (size_t)inp->i_numblks); 313 if (inplast == listmax) { 314 listmax += 100; 315 inpsort = (struct inoinfo **)realloc((char *)inpsort, 316 (unsigned)listmax * sizeof(struct inoinfo *)); 317 if (inpsort == NULL) 318 errexit("cannot increase directory list"); 319 } 320 inpsort[inplast++] = inp; 321 } 322 323 /* 324 * Look up an inode cache structure. 325 */ 326 struct inoinfo * 327 getinoinfo(inumber) 328 ino_t inumber; 329 { 330 register struct inoinfo *inp; 331 332 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 333 if (inp->i_number != inumber) 334 continue; 335 return (inp); 336 } 337 errexit("cannot find inode %d\n", inumber); 338 return ((struct inoinfo *)0); 339 } 340 341 /* 342 * Clean up all the inode cache structure. 343 */ 344 inocleanup() 345 { 346 register struct inoinfo **inpp; 347 348 if (inphead == NULL) 349 return; 350 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 351 free((char *)(*inpp)); 352 free((char *)inphead); 353 free((char *)inpsort); 354 inphead = inpsort = NULL; 355 } 356 357 inodirty() 358 { 359 360 dirty(pbp); 361 } 362 363 clri(idesc, type, flag) 364 register struct inodesc *idesc; 365 char *type; 366 int flag; 367 { 368 register struct dinode *dp; 369 370 dp = ginode(idesc->id_number); 371 if (flag == 1) { 372 pwarn("%s %s", type, 373 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 374 pinode(idesc->id_number); 375 } 376 if (preen || reply("CLEAR") == 1) { 377 if (preen) 378 printf(" (CLEARED)\n"); 379 n_files--; 380 (void)ckinode(dp, idesc); 381 clearinode(dp); 382 statemap[idesc->id_number] = USTATE; 383 inodirty(); 384 } 385 } 386 387 findname(idesc) 388 struct inodesc *idesc; 389 { 390 register struct direct *dirp = idesc->id_dirp; 391 392 if (dirp->d_ino != idesc->id_parent) 393 return (KEEPON); 394 bcopy(dirp->d_name, idesc->id_name, (size_t)dirp->d_namlen + 1); 395 return (STOP|FOUND); 396 } 397 398 findino(idesc) 399 struct inodesc *idesc; 400 { 401 register struct direct *dirp = idesc->id_dirp; 402 403 if (dirp->d_ino == 0) 404 return (KEEPON); 405 if (strcmp(dirp->d_name, idesc->id_name) == 0 && 406 dirp->d_ino >= ROOTINO && dirp->d_ino <= maxino) { 407 idesc->id_parent = dirp->d_ino; 408 return (STOP|FOUND); 409 } 410 return (KEEPON); 411 } 412 413 pinode(ino) 414 ino_t ino; 415 { 416 register struct dinode *dp; 417 register char *p; 418 struct passwd *pw; 419 char *ctime(); 420 421 printf(" I=%lu ", ino); 422 if (ino < ROOTINO || ino > maxino) 423 return; 424 dp = ginode(ino); 425 printf(" OWNER="); 426 if ((pw = getpwuid((int)dp->di_uid)) != 0) 427 printf("%s ", pw->pw_name); 428 else 429 printf("%u ", (unsigned)dp->di_uid); 430 printf("MODE=%o\n", dp->di_mode); 431 if (preen) 432 printf("%s: ", devname); 433 printf("SIZE=%lu ", dp->di_size); 434 p = ctime(&dp->di_mtime); 435 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 436 } 437 438 blkerror(ino, type, blk) 439 ino_t ino; 440 char *type; 441 daddr_t blk; 442 { 443 444 pfatal("%ld %s I=%lu", blk, type, ino); 445 printf("\n"); 446 switch (statemap[ino]) { 447 448 case FSTATE: 449 statemap[ino] = FCLEAR; 450 return; 451 452 case DSTATE: 453 statemap[ino] = DCLEAR; 454 return; 455 456 case FCLEAR: 457 case DCLEAR: 458 return; 459 460 default: 461 errexit("BAD STATE %d TO BLKERR", statemap[ino]); 462 /* NOTREACHED */ 463 } 464 } 465 466 /* 467 * allocate an unused inode 468 */ 469 ino_t 470 allocino(request, type) 471 ino_t request; 472 int type; 473 { 474 register ino_t ino; 475 register struct dinode *dp; 476 477 if (request == 0) 478 request = ROOTINO; 479 else if (statemap[request] != USTATE) 480 return (0); 481 for (ino = request; ino < maxino; ino++) 482 if (statemap[ino] == USTATE) 483 break; 484 if (ino == maxino) 485 return (0); 486 switch (type & IFMT) { 487 case IFDIR: 488 statemap[ino] = DSTATE; 489 break; 490 case IFREG: 491 case IFLNK: 492 statemap[ino] = FSTATE; 493 break; 494 default: 495 return (0); 496 } 497 dp = ginode(ino); 498 dp->di_db[0] = allocblk((long)1); 499 if (dp->di_db[0] == 0) { 500 statemap[ino] = USTATE; 501 return (0); 502 } 503 dp->di_mode = type; 504 (void)time(&dp->di_atime); 505 dp->di_mtime = dp->di_ctime = dp->di_atime; 506 dp->di_size = sblock.fs_fsize; 507 dp->di_blocks = btodb(sblock.fs_fsize); 508 n_files++; 509 inodirty(); 510 return (ino); 511 } 512 513 /* 514 * deallocate an inode 515 */ 516 freeino(ino) 517 ino_t ino; 518 { 519 struct inodesc idesc; 520 extern int pass4check(); 521 struct dinode *dp; 522 523 bzero((char *)&idesc, sizeof(struct inodesc)); 524 idesc.id_type = ADDR; 525 idesc.id_func = pass4check; 526 idesc.id_number = ino; 527 dp = ginode(ino); 528 (void)ckinode(dp, &idesc); 529 clearinode(dp); 530 inodirty(); 531 statemap[ino] = USTATE; 532 n_files--; 533 } 534