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