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