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