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