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