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