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