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