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