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