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