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