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