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