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