1 /* $NetBSD: inode.c,v 1.11 2003/08/07 10:04:16 agc Exp $ */ 2 3 /* 4 * Copyright (c) 1980, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1997 Manuel Bouyer. 34 * 35 * Redistribution and use in source and binary forms, with or without 36 * modification, are permitted provided that the following conditions 37 * are met: 38 * 1. Redistributions of source code must retain the above copyright 39 * notice, this list of conditions and the following disclaimer. 40 * 2. Redistributions in binary form must reproduce the above copyright 41 * notice, this list of conditions and the following disclaimer in the 42 * documentation and/or other materials provided with the distribution. 43 * 3. All advertising materials mentioning features or use of this software 44 * must display the following acknowledgement: 45 * This product includes software developed by the University of 46 * California, Berkeley and its contributors. 47 * 4. Neither the name of the University nor the names of its contributors 48 * may be used to endorse or promote products derived from this software 49 * without specific prior written permission. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 */ 63 64 #include <sys/cdefs.h> 65 #ifndef lint 66 #if 0 67 static char sccsid[] = "@(#)inode.c 8.5 (Berkeley) 2/8/95"; 68 #else 69 __RCSID("$NetBSD: inode.c,v 1.11 2003/08/07 10:04:16 agc Exp $"); 70 #endif 71 #endif /* not lint */ 72 73 #include <sys/param.h> 74 #include <sys/time.h> 75 #include <ufs/ext2fs/ext2fs_dinode.h> 76 #include <ufs/ext2fs/ext2fs_dir.h> 77 #include <ufs/ext2fs/ext2fs.h> 78 79 #include <ufs/ufs/dinode.h> /* for IFMT & friends */ 80 #ifndef SMALL 81 #include <pwd.h> 82 #endif 83 #include <stdio.h> 84 #include <stdlib.h> 85 #include <string.h> 86 #include <time.h> 87 88 #include "fsck.h" 89 #include "fsutil.h" 90 #include "extern.h" 91 92 /* 93 * CG is stored in fs byte order in memory, so we can't use ino_to_fsba 94 * here. 95 */ 96 97 #define fsck_ino_to_fsba(fs, x) \ 98 (fs2h32((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables) + \ 99 (((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb) 100 101 102 static ino_t startinum; 103 104 static int iblock __P((struct inodesc *, long, u_int64_t)); 105 106 int 107 ckinode(dp, idesc) 108 struct ext2fs_dinode *dp; 109 struct inodesc *idesc; 110 { 111 u_int32_t *ap; 112 long ret, n, ndb; 113 struct ext2fs_dinode dino; 114 u_int64_t remsize, sizepb; 115 mode_t mode; 116 char pathbuf[MAXPATHLEN + 1]; 117 118 if (idesc->id_fix != IGNORE) 119 idesc->id_fix = DONTKNOW; 120 idesc->id_entryno = 0; 121 idesc->id_filesize = fs2h32(dp->e2di_size); 122 mode = fs2h16(dp->e2di_mode) & IFMT; 123 if (mode == IFBLK || mode == IFCHR || mode == IFIFO || 124 (mode == IFLNK && (fs2h32(dp->e2di_size) < EXT2_MAXSYMLINKLEN))) 125 return (KEEPON); 126 dino = *dp; 127 ndb = howmany(fs2h32(dino.e2di_size), sblock.e2fs_bsize); 128 for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[NDADDR]; 129 ap++,ndb--) { 130 idesc->id_numfrags = 1; 131 if (*ap == 0) { 132 if (idesc->id_type == DATA && ndb > 0) { 133 /* An empty block in a directory XXX */ 134 getpathname(pathbuf, sizeof(pathbuf), 135 idesc->id_number, idesc->id_number); 136 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 137 pathbuf); 138 if (reply("ADJUST LENGTH") == 1) { 139 dp = ginode(idesc->id_number); 140 dp->e2di_size = h2fs32((ap - &dino.e2di_blocks[0]) * 141 sblock.e2fs_bsize); 142 printf( 143 "YOU MUST RERUN FSCK AFTERWARDS\n"); 144 rerun = 1; 145 inodirty(); 146 } 147 } 148 continue; 149 } 150 idesc->id_blkno = fs2h32(*ap); 151 if (idesc->id_type == ADDR) 152 ret = (*idesc->id_func)(idesc); 153 else 154 ret = dirscan(idesc); 155 if (ret & STOP) 156 return (ret); 157 } 158 idesc->id_numfrags = 1; 159 remsize = fs2h32(dino.e2di_size) - sblock.e2fs_bsize * NDADDR; 160 sizepb = sblock.e2fs_bsize; 161 for (ap = &dino.e2di_blocks[NDADDR], n = 1; n <= NIADDR; ap++, n++) { 162 if (*ap) { 163 idesc->id_blkno = fs2h32(*ap); 164 ret = iblock(idesc, n, remsize); 165 if (ret & STOP) 166 return (ret); 167 } else { 168 if (idesc->id_type == DATA && remsize > 0) { 169 /* An empty block in a directory XXX */ 170 getpathname(pathbuf, sizeof(pathbuf), 171 idesc->id_number, idesc->id_number); 172 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 173 pathbuf); 174 if (reply("ADJUST LENGTH") == 1) { 175 dp = ginode(idesc->id_number); 176 dp->e2di_size = h2fs32(fs2h32(dp->e2di_size) - remsize); 177 remsize = 0; 178 printf( 179 "YOU MUST RERUN FSCK AFTERWARDS\n"); 180 rerun = 1; 181 inodirty(); 182 break; 183 } 184 } 185 } 186 sizepb *= NINDIR(&sblock); 187 remsize -= sizepb; 188 } 189 return (KEEPON); 190 } 191 192 static int 193 iblock(idesc, ilevel, isize) 194 struct inodesc *idesc; 195 long ilevel; 196 u_int64_t isize; 197 { 198 /* XXX ondisk32 */ 199 int32_t *ap; 200 int32_t *aplim; 201 struct bufarea *bp; 202 int i, n, (*func) __P((struct inodesc *)), nif; 203 u_int64_t sizepb; 204 char buf[BUFSIZ]; 205 char pathbuf[MAXPATHLEN + 1]; 206 struct ext2fs_dinode *dp; 207 208 if (idesc->id_type == ADDR) { 209 func = idesc->id_func; 210 if (((n = (*func)(idesc)) & KEEPON) == 0) 211 return (n); 212 } else 213 func = dirscan; 214 if (chkrange(idesc->id_blkno, idesc->id_numfrags)) 215 return (SKIP); 216 bp = getdatablk(idesc->id_blkno, sblock.e2fs_bsize); 217 ilevel--; 218 for (sizepb = sblock.e2fs_bsize, i = 0; i < ilevel; i++) 219 sizepb *= NINDIR(&sblock); 220 if (isize > sizepb * NINDIR(&sblock)) 221 nif = NINDIR(&sblock); 222 else 223 nif = howmany(isize, sizepb); 224 if (idesc->id_func == pass1check && 225 nif < NINDIR(&sblock)) { 226 aplim = &bp->b_un.b_indir[NINDIR(&sblock)]; 227 for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) { 228 if (*ap == 0) 229 continue; 230 (void)snprintf(buf, sizeof(buf), 231 "PARTIALLY TRUNCATED INODE I=%u", idesc->id_number); 232 if (dofix(idesc, buf)) { 233 *ap = 0; 234 dirty(bp); 235 } 236 } 237 flush(fswritefd, bp); 238 } 239 aplim = &bp->b_un.b_indir[nif]; 240 for (ap = bp->b_un.b_indir; ap < aplim; ap++) { 241 if (*ap) { 242 idesc->id_blkno = fs2h32(*ap); 243 if (ilevel == 0) 244 n = (*func)(idesc); 245 else 246 n = iblock(idesc, ilevel, isize); 247 if (n & STOP) { 248 bp->b_flags &= ~B_INUSE; 249 return (n); 250 } 251 } else { 252 if (idesc->id_type == DATA && isize > 0) { 253 /* An empty block in a directory XXX */ 254 getpathname(pathbuf, sizeof(pathbuf), 255 idesc->id_number, idesc->id_number); 256 pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS", 257 pathbuf); 258 if (reply("ADJUST LENGTH") == 1) { 259 dp = ginode(idesc->id_number); 260 dp->e2di_size = h2fs32(fs2h32(dp->e2di_size) - isize); 261 isize = 0; 262 printf( 263 "YOU MUST RERUN FSCK AFTERWARDS\n"); 264 rerun = 1; 265 inodirty(); 266 bp->b_flags &= ~B_INUSE; 267 return(STOP); 268 } 269 } 270 } 271 isize -= sizepb; 272 } 273 bp->b_flags &= ~B_INUSE; 274 return (KEEPON); 275 } 276 277 /* 278 * Check that a block in a legal block number. 279 * Return 0 if in range, 1 if out of range. 280 */ 281 int 282 chkrange(blk, cnt) 283 daddr_t blk; 284 int cnt; 285 { 286 int c, overh; 287 288 if ((unsigned)(blk + cnt) > maxfsblock) 289 return (1); 290 c = dtog(&sblock, blk); 291 overh = cgoverhead(c); 292 if (blk < sblock.e2fs.e2fs_bpg * c + overh + 293 sblock.e2fs.e2fs_first_dblock) { 294 if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + overh + 295 sblock.e2fs.e2fs_first_dblock) { 296 if (debug) { 297 printf("blk %lld < cgdmin %d;", 298 (long long)blk, 299 sblock.e2fs.e2fs_bpg * c + overh + 300 sblock.e2fs.e2fs_first_dblock); 301 printf(" blk + cnt %lld > cgsbase %d\n", 302 (long long)(blk + cnt), 303 sblock.e2fs.e2fs_bpg * c + 304 overh + sblock.e2fs.e2fs_first_dblock); 305 } 306 return (1); 307 } 308 } else { 309 if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + overh + 310 sblock.e2fs.e2fs_first_dblock) { 311 if (debug) { 312 printf("blk %lld >= cgdmin %d;", 313 (long long)blk, 314 sblock.e2fs.e2fs_bpg * c + overh + 315 sblock.e2fs.e2fs_first_dblock); 316 printf(" blk + cnt %lld > cgdmax %d\n", 317 (long long)(blk+cnt), 318 sblock.e2fs.e2fs_bpg * (c + 1) + 319 overh + sblock.e2fs.e2fs_first_dblock); 320 } 321 return (1); 322 } 323 } 324 return (0); 325 } 326 327 /* 328 * General purpose interface for reading inodes. 329 */ 330 struct ext2fs_dinode * 331 ginode(inumber) 332 ino_t inumber; 333 { 334 daddr_t iblk; 335 336 if ((inumber < EXT2_FIRSTINO && inumber != EXT2_ROOTINO) 337 || inumber > maxino) 338 errexit("bad inode number %d to ginode\n", inumber); 339 if (startinum == 0 || 340 inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) { 341 iblk = fsck_ino_to_fsba(&sblock, inumber); 342 if (pbp != 0) 343 pbp->b_flags &= ~B_INUSE; 344 pbp = getdatablk(iblk, sblock.e2fs_bsize); 345 startinum = ((inumber -1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1; 346 } 347 return (&pbp->b_un.b_dinode[(inumber-1) % sblock.e2fs_ipb]); 348 } 349 350 /* 351 * Special purpose version of ginode used to optimize first pass 352 * over all the inodes in numerical order. 353 */ 354 ino_t nextino, lastinum; 355 long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize; 356 struct ext2fs_dinode *inodebuf; 357 358 struct ext2fs_dinode * 359 getnextinode(inumber) 360 ino_t inumber; 361 { 362 long size; 363 daddr_t dblk; 364 static struct ext2fs_dinode *dp; 365 366 if (inumber != nextino++ || inumber > maxino) 367 errexit("bad inode number %d to nextinode\n", inumber); 368 if (inumber >= lastinum) { 369 readcnt++; 370 dblk = fsbtodb(&sblock, fsck_ino_to_fsba(&sblock, lastinum)); 371 if (readcnt % readpercg == 0) { 372 size = partialsize; 373 lastinum += partialcnt; 374 } else { 375 size = inobufsize; 376 lastinum += fullcnt; 377 } 378 (void)bread(fsreadfd, (char *)inodebuf, dblk, size); 379 dp = inodebuf; 380 } 381 return (dp++); 382 } 383 384 void 385 resetinodebuf() 386 { 387 388 startinum = 0; 389 nextino = 1; 390 lastinum = 1; 391 readcnt = 0; 392 inobufsize = blkroundup(&sblock, INOBUFSIZE); 393 fullcnt = inobufsize / sizeof(struct ext2fs_dinode); 394 readpercg = sblock.e2fs.e2fs_ipg / fullcnt; 395 partialcnt = sblock.e2fs.e2fs_ipg % fullcnt; 396 partialsize = partialcnt * sizeof(struct ext2fs_dinode); 397 if (partialcnt != 0) { 398 readpercg++; 399 } else { 400 partialcnt = fullcnt; 401 partialsize = inobufsize; 402 } 403 if (inodebuf == NULL && 404 (inodebuf = (struct ext2fs_dinode *)malloc((unsigned)inobufsize)) == 405 NULL) 406 errexit("Cannot allocate space for inode buffer\n"); 407 while (nextino < EXT2_ROOTINO) 408 (void)getnextinode(nextino); 409 } 410 411 void 412 freeinodebuf() 413 { 414 415 if (inodebuf != NULL) 416 free((char *)inodebuf); 417 inodebuf = NULL; 418 } 419 420 /* 421 * Routines to maintain information about directory inodes. 422 * This is built during the first pass and used during the 423 * second and third passes. 424 * 425 * Enter inodes into the cache. 426 */ 427 void 428 cacheino(dp, inumber) 429 struct ext2fs_dinode *dp; 430 ino_t inumber; 431 { 432 struct inoinfo *inp; 433 struct inoinfo **inpp; 434 unsigned int blks; 435 436 blks = howmany(fs2h32(dp->e2di_size), sblock.e2fs_bsize); 437 if (blks > NDADDR) 438 blks = NDADDR + NIADDR; 439 /* XXX ondisk32 */ 440 inp = (struct inoinfo *) 441 malloc(sizeof(*inp) + (blks - 1) * sizeof(int32_t)); 442 if (inp == NULL) 443 return; 444 inpp = &inphead[inumber % numdirs]; 445 inp->i_nexthash = *inpp; 446 *inpp = inp; 447 inp->i_child = inp->i_sibling = inp->i_parentp = 0; 448 if (inumber == EXT2_ROOTINO) 449 inp->i_parent = EXT2_ROOTINO; 450 else 451 inp->i_parent = (ino_t)0; 452 inp->i_dotdot = (ino_t)0; 453 inp->i_number = inumber; 454 inp->i_isize = fs2h32(dp->e2di_size); 455 /* XXX ondisk32 */ 456 inp->i_numblks = blks * sizeof(int32_t); 457 memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks); 458 if (inplast == listmax) { 459 listmax += 100; 460 inpsort = (struct inoinfo **)realloc((char *)inpsort, 461 (unsigned)listmax * sizeof(struct inoinfo *)); 462 if (inpsort == NULL) 463 errexit("cannot increase directory list\n"); 464 } 465 inpsort[inplast++] = inp; 466 } 467 468 /* 469 * Look up an inode cache structure. 470 */ 471 struct inoinfo * 472 getinoinfo(inumber) 473 ino_t inumber; 474 { 475 struct inoinfo *inp; 476 477 for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) { 478 if (inp->i_number != inumber) 479 continue; 480 return (inp); 481 } 482 errexit("cannot find inode %d\n", inumber); 483 return ((struct inoinfo *)0); 484 } 485 486 /* 487 * Clean up all the inode cache structure. 488 */ 489 void 490 inocleanup() 491 { 492 struct inoinfo **inpp; 493 494 if (inphead == NULL) 495 return; 496 for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--) 497 free((char *)(*inpp)); 498 free((char *)inphead); 499 free((char *)inpsort); 500 inphead = inpsort = NULL; 501 } 502 503 void 504 inodirty() 505 { 506 507 dirty(pbp); 508 } 509 510 void 511 clri(idesc, type, flag) 512 struct inodesc *idesc; 513 char *type; 514 int flag; 515 { 516 struct ext2fs_dinode *dp; 517 518 dp = ginode(idesc->id_number); 519 if (flag == 1) { 520 pwarn("%s %s", type, 521 (dp->e2di_mode & IFMT) == IFDIR ? "DIR" : "FILE"); 522 pinode(idesc->id_number); 523 } 524 if (preen || reply("CLEAR") == 1) { 525 if (preen) 526 printf(" (CLEARED)\n"); 527 n_files--; 528 (void)ckinode(dp, idesc); 529 clearinode(dp); 530 statemap[idesc->id_number] = USTATE; 531 inodirty(); 532 } 533 } 534 535 int 536 findname(idesc) 537 struct inodesc *idesc; 538 { 539 struct ext2fs_direct *dirp = idesc->id_dirp; 540 u_int16_t namlen = dirp->e2d_namlen; 541 542 if (fs2h32(dirp->e2d_ino) != idesc->id_parent) 543 return (KEEPON); 544 memcpy(idesc->id_name, dirp->e2d_name, (size_t)namlen); 545 idesc->id_name[namlen] = '\0'; 546 return (STOP|FOUND); 547 } 548 549 int 550 findino(idesc) 551 struct inodesc *idesc; 552 { 553 struct ext2fs_direct *dirp = idesc->id_dirp; 554 u_int32_t ino = fs2h32(dirp->e2d_ino); 555 556 if (ino == 0) 557 return (KEEPON); 558 if (strcmp(dirp->e2d_name, idesc->id_name) == 0 && 559 (ino == EXT2_ROOTINO || ino >= EXT2_FIRSTINO) 560 && ino <= maxino) { 561 idesc->id_parent = ino; 562 return (STOP|FOUND); 563 } 564 return (KEEPON); 565 } 566 567 void 568 pinode(ino) 569 ino_t ino; 570 { 571 struct ext2fs_dinode *dp; 572 char *p; 573 struct passwd *pw; 574 time_t t; 575 576 printf(" I=%u ", ino); 577 if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino) 578 return; 579 dp = ginode(ino); 580 printf(" OWNER="); 581 #ifndef SMALL 582 if ((pw = getpwuid((int)dp->e2di_uid)) != 0) 583 printf("%s ", pw->pw_name); 584 else 585 #endif 586 printf("%u ", (unsigned)fs2h16(dp->e2di_uid)); 587 printf("MODE=%o\n", fs2h16(dp->e2di_mode)); 588 if (preen) 589 printf("%s: ", cdevname()); 590 printf("SIZE=%u ", fs2h32(dp->e2di_size)); 591 t = fs2h32(dp->e2di_mtime); 592 p = ctime(&t); 593 printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); 594 } 595 596 void 597 blkerror(ino, type, blk) 598 ino_t ino; 599 char *type; 600 daddr_t blk; 601 { 602 603 pfatal("%lld %s I=%u", (long long)blk, type, ino); 604 printf("\n"); 605 switch (statemap[ino]) { 606 607 case FSTATE: 608 statemap[ino] = FCLEAR; 609 return; 610 611 case DSTATE: 612 statemap[ino] = DCLEAR; 613 return; 614 615 case FCLEAR: 616 case DCLEAR: 617 return; 618 619 default: 620 errexit("BAD STATE %d TO BLKERR\n", statemap[ino]); 621 /* NOTREACHED */ 622 } 623 } 624 625 /* 626 * allocate an unused inode 627 */ 628 ino_t 629 allocino(request, type) 630 ino_t request; 631 int type; 632 { 633 ino_t ino; 634 struct ext2fs_dinode *dp; 635 time_t t; 636 637 if (request == 0) 638 request = EXT2_ROOTINO; 639 else if (statemap[request] != USTATE) 640 return (0); 641 for (ino = request; ino < maxino; ino++) { 642 if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO)) 643 continue; 644 if (statemap[ino] == USTATE) 645 break; 646 } 647 if (ino == maxino) 648 return (0); 649 switch (type & IFMT) { 650 case IFDIR: 651 statemap[ino] = DSTATE; 652 break; 653 case IFREG: 654 case IFLNK: 655 statemap[ino] = FSTATE; 656 break; 657 default: 658 return (0); 659 } 660 dp = ginode(ino); 661 dp->e2di_blocks[0] = h2fs32(allocblk()); 662 if (dp->e2di_blocks[0] == 0) { 663 statemap[ino] = USTATE; 664 return (0); 665 } 666 dp->e2di_mode = h2fs16(type); 667 (void)time(&t); 668 dp->e2di_atime = h2fs32(t); 669 dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime; 670 dp->e2di_dtime = 0; 671 dp->e2di_size = h2fs32(sblock.e2fs_bsize); 672 dp->e2di_nblock = h2fs32(btodb(sblock.e2fs_bsize)); 673 n_files++; 674 inodirty(); 675 typemap[ino] = E2IFTODT(type); 676 return (ino); 677 } 678 679 /* 680 * deallocate an inode 681 */ 682 void 683 freeino(ino) 684 ino_t ino; 685 { 686 struct inodesc idesc; 687 struct ext2fs_dinode *dp; 688 689 memset(&idesc, 0, sizeof(struct inodesc)); 690 idesc.id_type = ADDR; 691 idesc.id_func = pass4check; 692 idesc.id_number = ino; 693 dp = ginode(ino); 694 (void)ckinode(dp, &idesc); 695 clearinode(dp); 696 inodirty(); 697 statemap[ino] = USTATE; 698 n_files--; 699 } 700