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