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