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