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.7 (Berkeley) 04/27/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 bcopy((char *)&dp->di_db[0], (char *)&inp->i_blks[0], 307 (size_t)inp->i_numblks); 308 if (inplast == listmax) { 309 listmax += 100; 310 inpsort = (struct inoinfo **)realloc((char *)inpsort, 311 (unsigned)listmax * sizeof(struct inoinfo *)); 312 if (inpsort == NULL) 313 errx(EEXIT, "cannot increase directory list"); 314 } 315 inpsort[inplast++] = inp; 316 } 317 318 /* 319 * Look up an inode cache structure. 320 */ 321 struct inoinfo * 322 getinoinfo(inumber) 323 ino_t inumber; 324 { 325 register struct inoinfo *inp; 326 327 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 328 if (inp->i_number != inumber) 329 continue; 330 return (inp); 331 } 332 errx(EEXIT, "cannot find inode %d", inumber); 333 return ((struct inoinfo *)0); 334 } 335 336 /* 337 * Clean up all the inode cache structure. 338 */ 339 void 340 inocleanup() 341 { 342 register struct inoinfo **inpp; 343 344 if (inphead == NULL) 345 return; 346 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 347 free((char *)(*inpp)); 348 free((char *)inphead); 349 free((char *)inpsort); 350 inphead = inpsort = NULL; 351 } 352 353 void 354 inodirty() 355 { 356 357 dirty(pbp); 358 } 359 360 void 361 clri(idesc, type, flag) 362 register struct inodesc *idesc; 363 char *type; 364 int flag; 365 { 366 register struct dinode *dp; 367 368 dp = ginode(idesc->id_number); 369 if (flag == 1) { 370 pwarn("%s %s", type, 371 (dp->di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 372 pinode(idesc->id_number); 373 } 374 if (preen || reply("CLEAR") == 1) { 375 if (preen) 376 printf(" (CLEARED)\n"); 377 n_files--; 378 (void)ckinode(dp, idesc); 379 clearinode(dp); 380 statemap[idesc->id_number] = USTATE; 381 inodirty(); 382 } 383 } 384 385 int 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 int 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 void 414 pinode(ino) 415 ino_t ino; 416 { 417 register struct dinode *dp; 418 register char *p; 419 struct passwd *pw; 420 char *ctime(); 421 422 printf(" I=%lu ", ino); 423 if (ino < ROOTINO || ino > maxino) 424 return; 425 dp = ginode(ino); 426 printf(" OWNER="); 427 if ((pw = getpwuid((int)dp->di_uid)) != 0) 428 printf("%s ", pw->pw_name); 429 else 430 printf("%u ", (unsigned)dp->di_uid); 431 printf("MODE=%o\n", dp->di_mode); 432 if (preen) 433 printf("%s: ", cdevname); 434 printf("SIZE=%qu ", dp->di_size); 435 p = ctime(&dp->di_mtime); 436 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 437 } 438 439 void 440 blkerror(ino, type, blk) 441 ino_t ino; 442 char *type; 443 ufs_daddr_t blk; 444 { 445 446 pfatal("%ld %s I=%lu", blk, type, ino); 447 printf("\n"); 448 switch (statemap[ino]) { 449 450 case FSTATE: 451 statemap[ino] = FCLEAR; 452 return; 453 454 case DSTATE: 455 statemap[ino] = DCLEAR; 456 return; 457 458 case FCLEAR: 459 case DCLEAR: 460 return; 461 462 default: 463 errx(EEXIT, "BAD STATE %d TO BLKERR", statemap[ino]); 464 /* NOTREACHED */ 465 } 466 } 467 468 /* 469 * allocate an unused inode 470 */ 471 ino_t 472 allocino(request, type) 473 ino_t request; 474 int type; 475 { 476 register ino_t ino; 477 register struct dinode *dp; 478 479 if (request == 0) 480 request = ROOTINO; 481 else if (statemap[request] != USTATE) 482 return (0); 483 for (ino = request; ino < maxino; ino++) 484 if (statemap[ino] == USTATE) 485 break; 486 if (ino == maxino) 487 return (0); 488 switch (type & IFMT) { 489 case IFDIR: 490 statemap[ino] = DSTATE; 491 break; 492 case IFREG: 493 case IFLNK: 494 statemap[ino] = FSTATE; 495 break; 496 default: 497 return (0); 498 } 499 dp = ginode(ino); 500 dp->di_db[0] = allocblk((long)1); 501 if (dp->di_db[0] == 0) { 502 statemap[ino] = USTATE; 503 return (0); 504 } 505 dp->di_mode = type; 506 (void)time(&dp->di_atime); 507 dp->di_mtime = dp->di_ctime = dp->di_atime; 508 dp->di_size = sblock.fs_fsize; 509 dp->di_blocks = btodb(sblock.fs_fsize); 510 n_files++; 511 inodirty(); 512 if (newinofmt) 513 typemap[ino] = IFTODT(type); 514 return (ino); 515 } 516 517 /* 518 * deallocate an inode 519 */ 520 void 521 freeino(ino) 522 ino_t ino; 523 { 524 struct inodesc idesc; 525 struct dinode *dp; 526 527 bzero((char *)&idesc, sizeof(struct inodesc)); 528 idesc.id_type = ADDR; 529 idesc.id_func = pass4check; 530 idesc.id_number = ino; 531 dp = ginode(ino); 532 (void)ckinode(dp, &idesc); 533 clearinode(dp); 534 inodirty(); 535 statemap[ino] = USTATE; 536 n_files--; 537 } 538