xref: /minix3/sbin/fsck_ext2fs/inode.c (revision 84d9c625bfea59e274550651111ae9edfdc40fbd)
1*84d9c625SLionel Sambuc /*	$NetBSD: inode.c,v 1.36 2013/06/23 07:28:36 dholland Exp $	*/
294715d8eSBen Gras 
394715d8eSBen Gras /*
494715d8eSBen Gras  * Copyright (c) 1980, 1986, 1993
594715d8eSBen Gras  *	The Regents of the University of California.  All rights reserved.
694715d8eSBen Gras  *
794715d8eSBen Gras  * Redistribution and use in source and binary forms, with or without
894715d8eSBen Gras  * modification, are permitted provided that the following conditions
994715d8eSBen Gras  * are met:
1094715d8eSBen Gras  * 1. Redistributions of source code must retain the above copyright
1194715d8eSBen Gras  *    notice, this list of conditions and the following disclaimer.
1294715d8eSBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
1394715d8eSBen Gras  *    notice, this list of conditions and the following disclaimer in the
1494715d8eSBen Gras  *    documentation and/or other materials provided with the distribution.
1594715d8eSBen Gras  * 3. Neither the name of the University nor the names of its contributors
1694715d8eSBen Gras  *    may be used to endorse or promote products derived from this software
1794715d8eSBen Gras  *    without specific prior written permission.
1894715d8eSBen Gras  *
1994715d8eSBen Gras  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2094715d8eSBen Gras  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2194715d8eSBen Gras  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2294715d8eSBen Gras  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2394715d8eSBen Gras  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2494715d8eSBen Gras  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2594715d8eSBen Gras  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2694715d8eSBen Gras  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2794715d8eSBen Gras  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2894715d8eSBen Gras  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2994715d8eSBen Gras  * SUCH DAMAGE.
3094715d8eSBen Gras  */
3194715d8eSBen Gras 
3294715d8eSBen Gras /*
3394715d8eSBen Gras  * Copyright (c) 1997 Manuel Bouyer.
3494715d8eSBen Gras  *
3594715d8eSBen Gras  * Redistribution and use in source and binary forms, with or without
3694715d8eSBen Gras  * modification, are permitted provided that the following conditions
3794715d8eSBen Gras  * are met:
3894715d8eSBen Gras  * 1. Redistributions of source code must retain the above copyright
3994715d8eSBen Gras  *    notice, this list of conditions and the following disclaimer.
4094715d8eSBen Gras  * 2. Redistributions in binary form must reproduce the above copyright
4194715d8eSBen Gras  *    notice, this list of conditions and the following disclaimer in the
4294715d8eSBen Gras  *    documentation and/or other materials provided with the distribution.
4394715d8eSBen Gras  *
4494715d8eSBen Gras  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
4594715d8eSBen Gras  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
4694715d8eSBen Gras  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
4794715d8eSBen Gras  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
4894715d8eSBen Gras  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
4994715d8eSBen Gras  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
5094715d8eSBen Gras  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
5194715d8eSBen Gras  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
5294715d8eSBen Gras  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
5394715d8eSBen Gras  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
5494715d8eSBen Gras  */
5594715d8eSBen Gras 
5694715d8eSBen Gras #include <sys/cdefs.h>
5794715d8eSBen Gras #ifndef lint
5894715d8eSBen Gras #if 0
5994715d8eSBen Gras static char sccsid[] = "@(#)inode.c	8.5 (Berkeley) 2/8/95";
6094715d8eSBen Gras #else
61*84d9c625SLionel Sambuc __RCSID("$NetBSD: inode.c,v 1.36 2013/06/23 07:28:36 dholland Exp $");
6294715d8eSBen Gras #endif
6394715d8eSBen Gras #endif /* not lint */
6494715d8eSBen Gras 
6594715d8eSBen Gras #include <sys/param.h>
6694715d8eSBen Gras #include <sys/time.h>
6794715d8eSBen Gras #include <ufs/ext2fs/ext2fs_dinode.h>
6894715d8eSBen Gras #include <ufs/ext2fs/ext2fs_dir.h>
6994715d8eSBen Gras #include <ufs/ext2fs/ext2fs.h>
7094715d8eSBen Gras 
7194715d8eSBen Gras #include <ufs/ufs/dinode.h> /* for IFMT & friends */
7294715d8eSBen Gras #ifndef SMALL
7394715d8eSBen Gras #include <pwd.h>
7494715d8eSBen Gras #endif
7594715d8eSBen Gras #include <stdio.h>
7694715d8eSBen Gras #include <stdlib.h>
7794715d8eSBen Gras #include <string.h>
7894715d8eSBen Gras #include <time.h>
7994715d8eSBen Gras 
8094715d8eSBen Gras #include "fsck.h"
8194715d8eSBen Gras #include "fsutil.h"
8294715d8eSBen Gras #include "extern.h"
8394715d8eSBen Gras 
8494715d8eSBen Gras /*
8594715d8eSBen Gras  * CG is stored in fs byte order in memory, so we can't use ino_to_fsba
8694715d8eSBen Gras  * here.
8794715d8eSBen Gras  */
8894715d8eSBen Gras 
8994715d8eSBen Gras #define fsck_ino_to_fsba(fs, x)                      \
9094715d8eSBen Gras 	(fs2h32((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables) + \
9194715d8eSBen Gras 	(((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb)
9294715d8eSBen Gras 
9394715d8eSBen Gras 
9494715d8eSBen Gras static ino_t startinum;
9594715d8eSBen Gras 
9694715d8eSBen Gras static int iblock(struct inodesc *, long, u_int64_t);
9794715d8eSBen Gras 
9894715d8eSBen Gras static int setlarge(void);
9994715d8eSBen Gras 
100*84d9c625SLionel Sambuc static int sethuge(void);
101*84d9c625SLionel Sambuc 
10294715d8eSBen Gras static int
setlarge(void)10394715d8eSBen Gras setlarge(void)
10494715d8eSBen Gras {
10594715d8eSBen Gras 	if (sblock.e2fs.e2fs_rev < E2FS_REV1) {
10694715d8eSBen Gras 		pfatal("LARGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS");
10794715d8eSBen Gras 		return 0;
10894715d8eSBen Gras 	}
10994715d8eSBen Gras 	if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE)) {
11094715d8eSBen Gras 		if (preen)
11194715d8eSBen Gras 			pwarn("SETTING LARGE FILE INDICATOR\n");
11294715d8eSBen Gras 		else if (!reply("SET LARGE FILE INDICATOR"))
11394715d8eSBen Gras 			return 0;
11494715d8eSBen Gras 		sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGEFILE;
11594715d8eSBen Gras 		sbdirty();
11694715d8eSBen Gras 	}
11794715d8eSBen Gras 	return 1;
11894715d8eSBen Gras }
11994715d8eSBen Gras 
120*84d9c625SLionel Sambuc static int
sethuge(void)121*84d9c625SLionel Sambuc sethuge(void)
122*84d9c625SLionel Sambuc {
123*84d9c625SLionel Sambuc 	if (sblock.e2fs.e2fs_rev < E2FS_REV1) {
124*84d9c625SLionel Sambuc 		pfatal("HUGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS");
125*84d9c625SLionel Sambuc 		return 0;
126*84d9c625SLionel Sambuc 	}
127*84d9c625SLionel Sambuc 	if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_HUGE_FILE)) {
128*84d9c625SLionel Sambuc 		if (preen)
129*84d9c625SLionel Sambuc 			pwarn("SETTING HUGE FILE FEATURE\n");
130*84d9c625SLionel Sambuc 		else if (!reply("SET HUGE FILE FEATURE"))
131*84d9c625SLionel Sambuc 			return 0;
132*84d9c625SLionel Sambuc 		sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_HUGE_FILE;
133*84d9c625SLionel Sambuc 		sbdirty();
134*84d9c625SLionel Sambuc 	}
135*84d9c625SLionel Sambuc 	return 1;
136*84d9c625SLionel Sambuc }
137*84d9c625SLionel Sambuc 
13894715d8eSBen Gras u_int64_t
inosize(struct ext2fs_dinode * dp)13994715d8eSBen Gras inosize(struct ext2fs_dinode *dp)
14094715d8eSBen Gras {
14194715d8eSBen Gras 	u_int64_t size = fs2h32(dp->e2di_size);
14294715d8eSBen Gras 
14394715d8eSBen Gras 	if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG)
14494715d8eSBen Gras 		size |= (u_int64_t)fs2h32(dp->e2di_dacl) << 32;
14594715d8eSBen Gras 	if (size > INT32_MAX)
14694715d8eSBen Gras 		(void)setlarge();
14794715d8eSBen Gras 	return size;
14894715d8eSBen Gras }
14994715d8eSBen Gras 
15094715d8eSBen Gras void
inossize(struct ext2fs_dinode * dp,u_int64_t size)15194715d8eSBen Gras inossize(struct ext2fs_dinode *dp, u_int64_t size)
15294715d8eSBen Gras {
15394715d8eSBen Gras 	if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG) {
15494715d8eSBen Gras 		dp->e2di_dacl = h2fs32(size >> 32);
15594715d8eSBen Gras 		if (size > INT32_MAX)
15694715d8eSBen Gras 			if (!setlarge())
15794715d8eSBen Gras 				return;
15894715d8eSBen Gras 	} else if (size > INT32_MAX) {
15994715d8eSBen Gras 		pfatal("TRYING TO SET FILESIZE TO %llu ON MODE %x FILE\n",
16094715d8eSBen Gras 		    (unsigned long long)size, fs2h16(dp->e2di_mode) & IFMT);
16194715d8eSBen Gras 		return;
16294715d8eSBen Gras 	}
16394715d8eSBen Gras 	dp->e2di_size = h2fs32(size);
16494715d8eSBen Gras }
16594715d8eSBen Gras 
16694715d8eSBen Gras int
ckinode(struct ext2fs_dinode * dp,struct inodesc * idesc)16794715d8eSBen Gras ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc)
16894715d8eSBen Gras {
16994715d8eSBen Gras 	u_int32_t *ap;
17094715d8eSBen Gras 	long ret, n, ndb;
17194715d8eSBen Gras 	struct ext2fs_dinode dino;
17294715d8eSBen Gras 	u_int64_t remsize, sizepb;
17394715d8eSBen Gras 	mode_t mode;
17494715d8eSBen Gras 	char pathbuf[MAXPATHLEN + 1];
17594715d8eSBen Gras 
17694715d8eSBen Gras 	if (idesc->id_fix != IGNORE)
17794715d8eSBen Gras 		idesc->id_fix = DONTKNOW;
17894715d8eSBen Gras 	idesc->id_entryno = 0;
17994715d8eSBen Gras 	idesc->id_filesize = inosize(dp);
18094715d8eSBen Gras 	mode = fs2h16(dp->e2di_mode) & IFMT;
18194715d8eSBen Gras 	if (mode == IFBLK || mode == IFCHR || mode == IFIFO ||
18294715d8eSBen Gras 	    (mode == IFLNK && (inosize(dp) < EXT2_MAXSYMLINKLEN)))
18394715d8eSBen Gras 		return (KEEPON);
18494715d8eSBen Gras 	dino = *dp;
18594715d8eSBen Gras 	ndb = howmany(inosize(&dino), sblock.e2fs_bsize);
186*84d9c625SLionel Sambuc 	for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[EXT2FS_NDADDR];
18794715d8eSBen Gras 	    ap++,ndb--) {
18894715d8eSBen Gras 		idesc->id_numfrags = 1;
18994715d8eSBen Gras 		if (*ap == 0) {
19094715d8eSBen Gras 			if (idesc->id_type == DATA && ndb > 0) {
19194715d8eSBen Gras 				/* An empty block in a directory XXX */
19294715d8eSBen Gras 				getpathname(pathbuf, sizeof(pathbuf),
19394715d8eSBen Gras 				    idesc->id_number, idesc->id_number);
19494715d8eSBen Gras 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
19594715d8eSBen Gras 				    pathbuf);
19694715d8eSBen Gras 				if (reply("ADJUST LENGTH") == 1) {
19794715d8eSBen Gras 					dp = ginode(idesc->id_number);
19894715d8eSBen Gras 					inossize(dp,
19994715d8eSBen Gras 					    (ap - &dino.e2di_blocks[0]) *
20094715d8eSBen Gras 					    sblock.e2fs_bsize);
20194715d8eSBen Gras 					printf(
20294715d8eSBen Gras 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
20394715d8eSBen Gras 					rerun = 1;
20494715d8eSBen Gras 					inodirty();
20594715d8eSBen Gras 				}
20694715d8eSBen Gras 			}
20794715d8eSBen Gras 			continue;
20894715d8eSBen Gras 		}
20994715d8eSBen Gras 		idesc->id_blkno = fs2h32(*ap);
21094715d8eSBen Gras 		if (idesc->id_type == ADDR)
21194715d8eSBen Gras 			ret = (*idesc->id_func)(idesc);
21294715d8eSBen Gras 		else
21394715d8eSBen Gras 			ret = dirscan(idesc);
21494715d8eSBen Gras 		if (ret & STOP)
21594715d8eSBen Gras 			return (ret);
21694715d8eSBen Gras 	}
21794715d8eSBen Gras 	idesc->id_numfrags = 1;
218*84d9c625SLionel Sambuc 	remsize = inosize(&dino) - sblock.e2fs_bsize * EXT2FS_NDADDR;
21994715d8eSBen Gras 	sizepb = sblock.e2fs_bsize;
220*84d9c625SLionel Sambuc 	for (ap = &dino.e2di_blocks[EXT2FS_NDADDR], n = 1; n <= EXT2FS_NIADDR; ap++, n++) {
22194715d8eSBen Gras 		if (*ap) {
22294715d8eSBen Gras 			idesc->id_blkno = fs2h32(*ap);
22394715d8eSBen Gras 			ret = iblock(idesc, n, remsize);
22494715d8eSBen Gras 			if (ret & STOP)
22594715d8eSBen Gras 				return (ret);
22694715d8eSBen Gras 		} else {
22794715d8eSBen Gras 			if (idesc->id_type == DATA && remsize > 0) {
22894715d8eSBen Gras 				/* An empty block in a directory XXX */
22994715d8eSBen Gras 				getpathname(pathbuf, sizeof(pathbuf),
23094715d8eSBen Gras 				    idesc->id_number, idesc->id_number);
23194715d8eSBen Gras 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
23294715d8eSBen Gras 				    pathbuf);
23394715d8eSBen Gras 				if (reply("ADJUST LENGTH") == 1) {
23494715d8eSBen Gras 					dp = ginode(idesc->id_number);
23594715d8eSBen Gras 					inossize(dp, inosize(dp) - remsize);
23694715d8eSBen Gras 					remsize = 0;
23794715d8eSBen Gras 					printf(
23894715d8eSBen Gras 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
23994715d8eSBen Gras 					rerun = 1;
24094715d8eSBen Gras 					inodirty();
24194715d8eSBen Gras 					break;
24294715d8eSBen Gras 				}
24394715d8eSBen Gras 			}
24494715d8eSBen Gras 		}
245*84d9c625SLionel Sambuc 		sizepb *= EXT2_NINDIR(&sblock);
24694715d8eSBen Gras 		remsize -= sizepb;
24794715d8eSBen Gras 	}
24894715d8eSBen Gras 	return (KEEPON);
24994715d8eSBen Gras }
25094715d8eSBen Gras 
25194715d8eSBen Gras static int
iblock(struct inodesc * idesc,long ilevel,u_int64_t isize)25294715d8eSBen Gras iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
25394715d8eSBen Gras {
25494715d8eSBen Gras 	/* XXX ondisk32 */
25594715d8eSBen Gras 	int32_t *ap;
25694715d8eSBen Gras 	int32_t *aplim;
25794715d8eSBen Gras 	struct bufarea *bp;
25894715d8eSBen Gras 	int i, n, (*func)(struct inodesc *);
25994715d8eSBen Gras 	size_t nif;
26094715d8eSBen Gras 	u_int64_t sizepb;
26194715d8eSBen Gras 	char buf[BUFSIZ];
26294715d8eSBen Gras 	char pathbuf[MAXPATHLEN + 1];
26394715d8eSBen Gras 	struct ext2fs_dinode *dp;
26494715d8eSBen Gras 
26594715d8eSBen Gras 	if (idesc->id_type == ADDR) {
26694715d8eSBen Gras 		func = idesc->id_func;
26794715d8eSBen Gras 		if (((n = (*func)(idesc)) & KEEPON) == 0)
26894715d8eSBen Gras 			return (n);
26994715d8eSBen Gras 	} else
27094715d8eSBen Gras 		func = dirscan;
27194715d8eSBen Gras 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
27294715d8eSBen Gras 		return (SKIP);
27394715d8eSBen Gras 	bp = getdatablk(idesc->id_blkno, sblock.e2fs_bsize);
27494715d8eSBen Gras 	ilevel--;
27594715d8eSBen Gras 	for (sizepb = sblock.e2fs_bsize, i = 0; i < ilevel; i++)
276*84d9c625SLionel Sambuc 		sizepb *= EXT2_NINDIR(&sblock);
277*84d9c625SLionel Sambuc 	if (isize > sizepb * EXT2_NINDIR(&sblock))
278*84d9c625SLionel Sambuc 		nif = EXT2_NINDIR(&sblock);
27994715d8eSBen Gras 	else
28094715d8eSBen Gras 		nif = howmany(isize, sizepb);
28194715d8eSBen Gras 	if (idesc->id_func == pass1check &&
282*84d9c625SLionel Sambuc 		nif < EXT2_NINDIR(&sblock)) {
283*84d9c625SLionel Sambuc 		aplim = &bp->b_un.b_indir[EXT2_NINDIR(&sblock)];
28494715d8eSBen Gras 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
28594715d8eSBen Gras 			if (*ap == 0)
28694715d8eSBen Gras 				continue;
28794715d8eSBen Gras 			(void)snprintf(buf, sizeof(buf),
28894715d8eSBen Gras 			    "PARTIALLY TRUNCATED INODE I=%llu",
28994715d8eSBen Gras 			    (unsigned long long)idesc->id_number);
29094715d8eSBen Gras 			if (dofix(idesc, buf)) {
29194715d8eSBen Gras 				*ap = 0;
29294715d8eSBen Gras 				dirty(bp);
29394715d8eSBen Gras 			}
29494715d8eSBen Gras 		}
29594715d8eSBen Gras 		flush(fswritefd, bp);
29694715d8eSBen Gras 	}
29794715d8eSBen Gras 	aplim = &bp->b_un.b_indir[nif];
29894715d8eSBen Gras 	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
29994715d8eSBen Gras 		if (*ap) {
30094715d8eSBen Gras 			idesc->id_blkno = fs2h32(*ap);
30194715d8eSBen Gras 			if (ilevel == 0)
30294715d8eSBen Gras 				n = (*func)(idesc);
30394715d8eSBen Gras 			else
30494715d8eSBen Gras 				n = iblock(idesc, ilevel, isize);
30594715d8eSBen Gras 			if (n & STOP) {
30694715d8eSBen Gras 				bp->b_flags &= ~B_INUSE;
30794715d8eSBen Gras 				return (n);
30894715d8eSBen Gras 			}
30994715d8eSBen Gras 		} else {
31094715d8eSBen Gras 			if (idesc->id_type == DATA && isize > 0) {
31194715d8eSBen Gras 				/* An empty block in a directory XXX */
31294715d8eSBen Gras 				getpathname(pathbuf, sizeof(pathbuf),
31394715d8eSBen Gras 				    idesc->id_number, idesc->id_number);
31494715d8eSBen Gras 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
31594715d8eSBen Gras 				    pathbuf);
31694715d8eSBen Gras 				if (reply("ADJUST LENGTH") == 1) {
31794715d8eSBen Gras 					dp = ginode(idesc->id_number);
31894715d8eSBen Gras 					inossize(dp, inosize(dp) - isize);
31994715d8eSBen Gras 					isize = 0;
32094715d8eSBen Gras 					printf(
32194715d8eSBen Gras 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
32294715d8eSBen Gras 					rerun = 1;
32394715d8eSBen Gras 					inodirty();
32494715d8eSBen Gras 					bp->b_flags &= ~B_INUSE;
32594715d8eSBen Gras 					return(STOP);
32694715d8eSBen Gras 				}
32794715d8eSBen Gras 			}
32894715d8eSBen Gras 		}
32994715d8eSBen Gras 		isize -= sizepb;
33094715d8eSBen Gras 	}
33194715d8eSBen Gras 	bp->b_flags &= ~B_INUSE;
33294715d8eSBen Gras 	return (KEEPON);
33394715d8eSBen Gras }
33494715d8eSBen Gras 
33594715d8eSBen Gras /*
33694715d8eSBen Gras  * Check that a block in a legal block number.
33794715d8eSBen Gras  * Return 0 if in range, 1 if out of range.
33894715d8eSBen Gras  */
33994715d8eSBen Gras int
chkrange(daddr_t blk,int cnt)34094715d8eSBen Gras chkrange(daddr_t blk, int cnt)
34194715d8eSBen Gras {
34294715d8eSBen Gras 	int c, overh;
34394715d8eSBen Gras 
34494715d8eSBen Gras 	if ((unsigned int)(blk + cnt) > maxfsblock)
34594715d8eSBen Gras 		return (1);
34694715d8eSBen Gras 	c = dtog(&sblock, blk);
34794715d8eSBen Gras 	overh = cgoverhead(c);
34894715d8eSBen Gras 	if (blk < sblock.e2fs.e2fs_bpg * c + overh +
34994715d8eSBen Gras 	    sblock.e2fs.e2fs_first_dblock) {
35094715d8eSBen Gras 		if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + overh +
35194715d8eSBen Gras 		    sblock.e2fs.e2fs_first_dblock) {
35294715d8eSBen Gras 			if (debug) {
35394715d8eSBen Gras 				printf("blk %lld < cgdmin %d;",
35494715d8eSBen Gras 				    (long long)blk,
35594715d8eSBen Gras 				    sblock.e2fs.e2fs_bpg * c + overh +
35694715d8eSBen Gras 				    sblock.e2fs.e2fs_first_dblock);
35794715d8eSBen Gras 				printf(" blk + cnt %lld > cgsbase %d\n",
35894715d8eSBen Gras 				    (long long)(blk + cnt),
35994715d8eSBen Gras 				    sblock.e2fs.e2fs_bpg * c +
36094715d8eSBen Gras 				    overh + sblock.e2fs.e2fs_first_dblock);
36194715d8eSBen Gras 			}
36294715d8eSBen Gras 			return (1);
36394715d8eSBen Gras 		}
36494715d8eSBen Gras 	} else {
36594715d8eSBen Gras 		if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + overh +
36694715d8eSBen Gras 		    sblock.e2fs.e2fs_first_dblock) {
36794715d8eSBen Gras 			if (debug)  {
36894715d8eSBen Gras 				printf("blk %lld >= cgdmin %d;",
36994715d8eSBen Gras 				    (long long)blk,
37094715d8eSBen Gras 				    sblock.e2fs.e2fs_bpg * c + overh +
37194715d8eSBen Gras 				    sblock.e2fs.e2fs_first_dblock);
37294715d8eSBen Gras 				printf(" blk + cnt %lld > cgdmax %d\n",
37394715d8eSBen Gras 				    (long long)(blk+cnt),
37494715d8eSBen Gras 				    sblock.e2fs.e2fs_bpg * (c + 1) +
37594715d8eSBen Gras 				    overh + sblock.e2fs.e2fs_first_dblock);
37694715d8eSBen Gras 			}
37794715d8eSBen Gras 			return (1);
37894715d8eSBen Gras 		}
37994715d8eSBen Gras 	}
38094715d8eSBen Gras 	return (0);
38194715d8eSBen Gras }
38294715d8eSBen Gras 
38394715d8eSBen Gras /*
38494715d8eSBen Gras  * General purpose interface for reading inodes.
38594715d8eSBen Gras  */
38694715d8eSBen Gras struct ext2fs_dinode *
ginode(ino_t inumber)38794715d8eSBen Gras ginode(ino_t inumber)
38894715d8eSBen Gras {
38994715d8eSBen Gras 	daddr_t iblk;
39094715d8eSBen Gras 	struct ext2fs_dinode *dp;
39194715d8eSBen Gras 
39294715d8eSBen Gras 	if ((inumber < EXT2_FIRSTINO &&
39394715d8eSBen Gras 	     inumber != EXT2_ROOTINO &&
39494715d8eSBen Gras 	     !(inumber == EXT2_RESIZEINO &&
39594715d8eSBen Gras 	       (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0))
39694715d8eSBen Gras 		|| inumber > maxino)
39794715d8eSBen Gras 		errexit("bad inode number %llu to ginode",
39894715d8eSBen Gras 		    (unsigned long long)inumber);
39994715d8eSBen Gras 	if (startinum == 0 ||
40094715d8eSBen Gras 	    inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) {
40194715d8eSBen Gras 		iblk = fsck_ino_to_fsba(&sblock, inumber);
40294715d8eSBen Gras 		if (pbp != 0)
40394715d8eSBen Gras 			pbp->b_flags &= ~B_INUSE;
40494715d8eSBen Gras 		pbp = getdatablk(iblk, sblock.e2fs_bsize);
40594715d8eSBen Gras 		startinum =
40694715d8eSBen Gras 		    ((inumber - 1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1;
40794715d8eSBen Gras 	}
40894715d8eSBen Gras 	dp = (struct ext2fs_dinode *)(pbp->b_un.b_buf +
40994715d8eSBen Gras 	    EXT2_DINODE_SIZE(&sblock) * ino_to_fsbo(&sblock, inumber));
41094715d8eSBen Gras 
41194715d8eSBen Gras 	return dp;
41294715d8eSBen Gras }
41394715d8eSBen Gras 
41494715d8eSBen Gras /*
41594715d8eSBen Gras  * Special purpose version of ginode used to optimize first pass
41694715d8eSBen Gras  * over all the inodes in numerical order.
41794715d8eSBen Gras  */
41894715d8eSBen Gras ino_t nextino, lastinum;
41994715d8eSBen Gras long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
42094715d8eSBen Gras char *inodebuf;
42194715d8eSBen Gras 
42294715d8eSBen Gras struct ext2fs_dinode *
getnextinode(ino_t inumber)42394715d8eSBen Gras getnextinode(ino_t inumber)
42494715d8eSBen Gras {
42594715d8eSBen Gras 	long size;
42694715d8eSBen Gras 	daddr_t dblk;
42794715d8eSBen Gras 	struct ext2fs_dinode *dp;
42894715d8eSBen Gras 	static char *bp;
42994715d8eSBen Gras 
43094715d8eSBen Gras 	if (inumber != nextino++ || inumber > maxino)
43194715d8eSBen Gras 		errexit("bad inode number %llu to nextinode",
43294715d8eSBen Gras 		    (unsigned long long)inumber);
43394715d8eSBen Gras 	if (inumber >= lastinum) {
43494715d8eSBen Gras 		readcnt++;
435*84d9c625SLionel Sambuc 		dblk = EXT2_FSBTODB(&sblock, fsck_ino_to_fsba(&sblock, lastinum));
43694715d8eSBen Gras 		if (readcnt % readpercg == 0) {
43794715d8eSBen Gras 			size = partialsize;
43894715d8eSBen Gras 			lastinum += partialcnt;
43994715d8eSBen Gras 		} else {
44094715d8eSBen Gras 			size = inobufsize;
44194715d8eSBen Gras 			lastinum += fullcnt;
44294715d8eSBen Gras 		}
44394715d8eSBen Gras 		(void)bread(fsreadfd, inodebuf, dblk, size);
44494715d8eSBen Gras 		bp = inodebuf;
44594715d8eSBen Gras 	}
44694715d8eSBen Gras 	dp = (struct ext2fs_dinode *)bp;
44794715d8eSBen Gras 	bp += EXT2_DINODE_SIZE(&sblock);
44894715d8eSBen Gras 
44994715d8eSBen Gras 	return dp;
45094715d8eSBen Gras }
45194715d8eSBen Gras 
45294715d8eSBen Gras void
resetinodebuf(void)45394715d8eSBen Gras resetinodebuf(void)
45494715d8eSBen Gras {
45594715d8eSBen Gras 
45694715d8eSBen Gras 	startinum = 0;
45794715d8eSBen Gras 	nextino = 1;
45894715d8eSBen Gras 	lastinum = 1;
45994715d8eSBen Gras 	readcnt = 0;
460*84d9c625SLionel Sambuc 	inobufsize = ext2_blkroundup(&sblock, INOBUFSIZE);
46194715d8eSBen Gras 	fullcnt = inobufsize / EXT2_DINODE_SIZE(&sblock);
46294715d8eSBen Gras 	readpercg = sblock.e2fs.e2fs_ipg / fullcnt;
46394715d8eSBen Gras 	partialcnt = sblock.e2fs.e2fs_ipg % fullcnt;
46494715d8eSBen Gras 	partialsize = partialcnt * EXT2_DINODE_SIZE(&sblock);
46594715d8eSBen Gras 	if (partialcnt != 0) {
46694715d8eSBen Gras 		readpercg++;
46794715d8eSBen Gras 	} else {
46894715d8eSBen Gras 		partialcnt = fullcnt;
46994715d8eSBen Gras 		partialsize = inobufsize;
47094715d8eSBen Gras 	}
47194715d8eSBen Gras 	if (inodebuf == NULL &&
47294715d8eSBen Gras 	    (inodebuf = malloc((unsigned int)inobufsize)) == NULL)
47394715d8eSBen Gras 		errexit("Cannot allocate space for inode buffer");
47494715d8eSBen Gras 	while (nextino < EXT2_ROOTINO)
47594715d8eSBen Gras 		(void)getnextinode(nextino);
47694715d8eSBen Gras }
47794715d8eSBen Gras 
47894715d8eSBen Gras void
freeinodebuf(void)47994715d8eSBen Gras freeinodebuf(void)
48094715d8eSBen Gras {
48194715d8eSBen Gras 
48294715d8eSBen Gras 	if (inodebuf != NULL)
48394715d8eSBen Gras 		free(inodebuf);
48494715d8eSBen Gras 	inodebuf = NULL;
48594715d8eSBen Gras }
48694715d8eSBen Gras 
48794715d8eSBen Gras /*
48894715d8eSBen Gras  * Routines to maintain information about directory inodes.
48994715d8eSBen Gras  * This is built during the first pass and used during the
49094715d8eSBen Gras  * second and third passes.
49194715d8eSBen Gras  *
49294715d8eSBen Gras  * Enter inodes into the cache.
49394715d8eSBen Gras  */
49494715d8eSBen Gras void
cacheino(struct ext2fs_dinode * dp,ino_t inumber)49594715d8eSBen Gras cacheino(struct ext2fs_dinode *dp, ino_t inumber)
49694715d8eSBen Gras {
49794715d8eSBen Gras 	struct inoinfo *inp;
49894715d8eSBen Gras 	struct inoinfo **inpp;
49994715d8eSBen Gras 	unsigned int blks;
50094715d8eSBen Gras 
50194715d8eSBen Gras 	blks = howmany(inosize(dp), sblock.e2fs_bsize);
502*84d9c625SLionel Sambuc 	if (blks > EXT2FS_NDADDR)
503*84d9c625SLionel Sambuc 		blks = EXT2FS_NDADDR + EXT2FS_NIADDR;
50494715d8eSBen Gras 	/* XXX ondisk32 */
50594715d8eSBen Gras 	inp = malloc(sizeof(*inp) + (blks - 1) * sizeof(int32_t));
50694715d8eSBen Gras 	if (inp == NULL)
50794715d8eSBen Gras 		return;
50894715d8eSBen Gras 	inpp = &inphead[inumber % numdirs];
50994715d8eSBen Gras 	inp->i_nexthash = *inpp;
51094715d8eSBen Gras 	*inpp = inp;
51194715d8eSBen Gras 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
51294715d8eSBen Gras 	if (inumber == EXT2_ROOTINO)
51394715d8eSBen Gras 		inp->i_parent = EXT2_ROOTINO;
51494715d8eSBen Gras 	else
51594715d8eSBen Gras 		inp->i_parent = (ino_t)0;
51694715d8eSBen Gras 	inp->i_dotdot = (ino_t)0;
51794715d8eSBen Gras 	inp->i_number = inumber;
51894715d8eSBen Gras 	inp->i_isize = inosize(dp);
51994715d8eSBen Gras 	/* XXX ondisk32 */
52094715d8eSBen Gras 	inp->i_numblks = blks * sizeof(int32_t);
52194715d8eSBen Gras 	memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks);
52294715d8eSBen Gras 	if (inplast == listmax) {
52394715d8eSBen Gras 		listmax += 100;
52494715d8eSBen Gras 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
52594715d8eSBen Gras 		    (unsigned int)listmax * sizeof(struct inoinfo *));
52694715d8eSBen Gras 		if (inpsort == NULL)
52794715d8eSBen Gras 			errexit("cannot increase directory list");
52894715d8eSBen Gras 	}
52994715d8eSBen Gras 	inpsort[inplast++] = inp;
53094715d8eSBen Gras }
53194715d8eSBen Gras 
53294715d8eSBen Gras /*
53394715d8eSBen Gras  * Look up an inode cache structure.
53494715d8eSBen Gras  */
53594715d8eSBen Gras struct inoinfo *
getinoinfo(ino_t inumber)53694715d8eSBen Gras getinoinfo(ino_t inumber)
53794715d8eSBen Gras {
53894715d8eSBen Gras 	struct inoinfo *inp;
53994715d8eSBen Gras 
54094715d8eSBen Gras 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
54194715d8eSBen Gras 		if (inp->i_number != inumber)
54294715d8eSBen Gras 			continue;
54394715d8eSBen Gras 		return (inp);
54494715d8eSBen Gras 	}
54594715d8eSBen Gras 	errexit("cannot find inode %llu", (unsigned long long)inumber);
54694715d8eSBen Gras 	return ((struct inoinfo *)0);
54794715d8eSBen Gras }
54894715d8eSBen Gras 
54994715d8eSBen Gras /*
55094715d8eSBen Gras  * Clean up all the inode cache structure.
55194715d8eSBen Gras  */
55294715d8eSBen Gras void
inocleanup(void)55394715d8eSBen Gras inocleanup(void)
55494715d8eSBen Gras {
55594715d8eSBen Gras 	struct inoinfo **inpp;
55694715d8eSBen Gras 
55794715d8eSBen Gras 	if (inphead == NULL)
55894715d8eSBen Gras 		return;
55994715d8eSBen Gras 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
56094715d8eSBen Gras 		free(*inpp);
56194715d8eSBen Gras 	free(inphead);
56294715d8eSBen Gras 	free(inpsort);
56394715d8eSBen Gras 	inphead = inpsort = NULL;
56494715d8eSBen Gras }
56594715d8eSBen Gras 
56694715d8eSBen Gras void
inodirty(void)56794715d8eSBen Gras inodirty(void)
56894715d8eSBen Gras {
56994715d8eSBen Gras 
57094715d8eSBen Gras 	dirty(pbp);
57194715d8eSBen Gras }
57294715d8eSBen Gras 
57394715d8eSBen Gras void
clri(struct inodesc * idesc,const char * type,int flag)57494715d8eSBen Gras clri(struct inodesc *idesc, const char *type, int flag)
57594715d8eSBen Gras {
57694715d8eSBen Gras 	struct ext2fs_dinode *dp;
57794715d8eSBen Gras 
57894715d8eSBen Gras 	dp = ginode(idesc->id_number);
57994715d8eSBen Gras 	if (flag == 1) {
58094715d8eSBen Gras 		pwarn("%s %s", type,
58194715d8eSBen Gras 		    (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
58294715d8eSBen Gras 		pinode(idesc->id_number);
58394715d8eSBen Gras 	}
58494715d8eSBen Gras 	if (preen || reply("CLEAR") == 1) {
58594715d8eSBen Gras 		if (preen)
58694715d8eSBen Gras 			printf(" (CLEARED)\n");
58794715d8eSBen Gras 		n_files--;
58894715d8eSBen Gras 		(void)ckinode(dp, idesc);
58994715d8eSBen Gras 		clearinode(dp);
59094715d8eSBen Gras 		statemap[idesc->id_number] = USTATE;
59194715d8eSBen Gras 		inodirty();
59294715d8eSBen Gras 	}
59394715d8eSBen Gras }
59494715d8eSBen Gras 
59594715d8eSBen Gras int
findname(struct inodesc * idesc)59694715d8eSBen Gras findname(struct inodesc *idesc)
59794715d8eSBen Gras {
59894715d8eSBen Gras 	struct ext2fs_direct *dirp = idesc->id_dirp;
59994715d8eSBen Gras 	u_int16_t namlen = dirp->e2d_namlen;
60094715d8eSBen Gras 	/* from utilities.c namebuf[] variable */
60194715d8eSBen Gras 	char *buf = __UNCONST(idesc->id_name);
60294715d8eSBen Gras 	if (namlen > MAXPATHLEN) {
60394715d8eSBen Gras 		/* XXX: Prevent overflow but don't fix */
60494715d8eSBen Gras 		namlen = MAXPATHLEN;
60594715d8eSBen Gras 	}
60694715d8eSBen Gras 
60794715d8eSBen Gras 	if (fs2h32(dirp->e2d_ino) != idesc->id_parent)
60894715d8eSBen Gras 		return (KEEPON);
60994715d8eSBen Gras 	(void)memcpy(buf, dirp->e2d_name, (size_t)namlen);
61094715d8eSBen Gras 	buf[namlen] = '\0';
61194715d8eSBen Gras 	return (STOP|FOUND);
61294715d8eSBen Gras }
61394715d8eSBen Gras 
61494715d8eSBen Gras int
findino(struct inodesc * idesc)61594715d8eSBen Gras findino(struct inodesc *idesc)
61694715d8eSBen Gras {
61794715d8eSBen Gras 	struct ext2fs_direct *dirp = idesc->id_dirp;
61894715d8eSBen Gras 	u_int32_t ino = fs2h32(dirp->e2d_ino);
61994715d8eSBen Gras 
62094715d8eSBen Gras 	if (ino == 0)
62194715d8eSBen Gras 		return (KEEPON);
62294715d8eSBen Gras 	if (strcmp(dirp->e2d_name, idesc->id_name) == 0 &&
62394715d8eSBen Gras 	    (ino == EXT2_ROOTINO || ino >= EXT2_FIRSTINO)
62494715d8eSBen Gras 		&& ino <= maxino) {
62594715d8eSBen Gras 		idesc->id_parent = ino;
62694715d8eSBen Gras 		return (STOP|FOUND);
62794715d8eSBen Gras 	}
62894715d8eSBen Gras 	return (KEEPON);
62994715d8eSBen Gras }
63094715d8eSBen Gras 
63194715d8eSBen Gras void
pinode(ino_t ino)63294715d8eSBen Gras pinode(ino_t ino)
63394715d8eSBen Gras {
63494715d8eSBen Gras 	struct ext2fs_dinode *dp;
63594715d8eSBen Gras 	struct passwd *pw;
63694715d8eSBen Gras 	uid_t uid;
63794715d8eSBen Gras 
63894715d8eSBen Gras 	printf(" I=%llu ", (unsigned long long)ino);
63994715d8eSBen Gras 	if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino)
64094715d8eSBen Gras 		return;
64194715d8eSBen Gras 	dp = ginode(ino);
64294715d8eSBen Gras 	uid = fs2h16(dp->e2di_uid);
64394715d8eSBen Gras 	if (sblock.e2fs.e2fs_rev > E2FS_REV0)
64494715d8eSBen Gras 		uid |= fs2h16(dp->e2di_uid_high) << 16;
64594715d8eSBen Gras 	printf(" OWNER=");
64694715d8eSBen Gras #ifndef SMALL
64794715d8eSBen Gras 	if (Uflag && (pw = getpwuid(uid)) != 0)
64894715d8eSBen Gras 		printf("%s ", pw->pw_name);
64994715d8eSBen Gras 	else
65094715d8eSBen Gras #endif
65194715d8eSBen Gras 		printf("%u ", (unsigned int)uid);
65294715d8eSBen Gras 	printf("MODE=%o\n", fs2h16(dp->e2di_mode));
65394715d8eSBen Gras 	if (preen)
65494715d8eSBen Gras 		printf("%s: ", cdevname());
65594715d8eSBen Gras 	printf("SIZE=%llu ", (long long)inosize(dp));
65694715d8eSBen Gras 	printf("MTIME=%s ", print_mtime(fs2h32(dp->e2di_mtime)));
65794715d8eSBen Gras }
65894715d8eSBen Gras 
65994715d8eSBen Gras void
blkerror(ino_t ino,const char * type,daddr_t blk)66094715d8eSBen Gras blkerror(ino_t ino, const char *type, daddr_t blk)
66194715d8eSBen Gras {
66294715d8eSBen Gras 
66394715d8eSBen Gras 	pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino);
66494715d8eSBen Gras 	printf("\n");
66594715d8eSBen Gras 	switch (statemap[ino]) {
66694715d8eSBen Gras 
66794715d8eSBen Gras 	case FSTATE:
66894715d8eSBen Gras 		statemap[ino] = FCLEAR;
66994715d8eSBen Gras 		return;
67094715d8eSBen Gras 
67194715d8eSBen Gras 	case DSTATE:
67294715d8eSBen Gras 		statemap[ino] = DCLEAR;
67394715d8eSBen Gras 		return;
67494715d8eSBen Gras 
67594715d8eSBen Gras 	case FCLEAR:
67694715d8eSBen Gras 	case DCLEAR:
67794715d8eSBen Gras 		return;
67894715d8eSBen Gras 
67994715d8eSBen Gras 	default:
68094715d8eSBen Gras 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
68194715d8eSBen Gras 		/* NOTREACHED */
68294715d8eSBen Gras 	}
68394715d8eSBen Gras }
68494715d8eSBen Gras 
68594715d8eSBen Gras /*
68694715d8eSBen Gras  * allocate an unused inode
68794715d8eSBen Gras  */
68894715d8eSBen Gras ino_t
allocino(ino_t request,int type)68994715d8eSBen Gras allocino(ino_t request, int type)
69094715d8eSBen Gras {
69194715d8eSBen Gras 	ino_t ino;
69294715d8eSBen Gras 	struct ext2fs_dinode *dp;
69394715d8eSBen Gras 	time_t t;
69494715d8eSBen Gras 
69594715d8eSBen Gras 	if (request == 0)
69694715d8eSBen Gras 		request = EXT2_ROOTINO;
69794715d8eSBen Gras 	else if (statemap[request] != USTATE)
69894715d8eSBen Gras 		return (0);
69994715d8eSBen Gras 	for (ino = request; ino < maxino; ino++) {
70094715d8eSBen Gras 		if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO))
70194715d8eSBen Gras 			continue;
70294715d8eSBen Gras 		if (statemap[ino] == USTATE)
70394715d8eSBen Gras 			break;
70494715d8eSBen Gras 	}
70594715d8eSBen Gras 	if (ino == maxino)
70694715d8eSBen Gras 		return (0);
70794715d8eSBen Gras 	switch (type & IFMT) {
70894715d8eSBen Gras 	case IFDIR:
70994715d8eSBen Gras 		statemap[ino] = DSTATE;
71094715d8eSBen Gras 		break;
71194715d8eSBen Gras 	case IFREG:
71294715d8eSBen Gras 	case IFLNK:
71394715d8eSBen Gras 		statemap[ino] = FSTATE;
71494715d8eSBen Gras 		break;
71594715d8eSBen Gras 	default:
71694715d8eSBen Gras 		return (0);
71794715d8eSBen Gras 	}
71894715d8eSBen Gras 	dp = ginode(ino);
71994715d8eSBen Gras 	dp->e2di_blocks[0] = h2fs32(allocblk());
72094715d8eSBen Gras 	if (dp->e2di_blocks[0] == 0) {
72194715d8eSBen Gras 		statemap[ino] = USTATE;
72294715d8eSBen Gras 		return (0);
72394715d8eSBen Gras 	}
72494715d8eSBen Gras 	dp->e2di_mode = h2fs16(type);
72594715d8eSBen Gras 	(void)time(&t);
72694715d8eSBen Gras 	dp->e2di_atime = h2fs32(t);
72794715d8eSBen Gras 	dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime;
72894715d8eSBen Gras 	dp->e2di_dtime = 0;
72994715d8eSBen Gras 	inossize(dp, sblock.e2fs_bsize);
730*84d9c625SLionel Sambuc 	inosnblock(dp, btodb(sblock.e2fs_bsize));
73194715d8eSBen Gras 	n_files++;
73294715d8eSBen Gras 	inodirty();
73394715d8eSBen Gras 	typemap[ino] = E2IFTODT(type);
73494715d8eSBen Gras 	return (ino);
73594715d8eSBen Gras }
73694715d8eSBen Gras 
73794715d8eSBen Gras /*
73894715d8eSBen Gras  * deallocate an inode
73994715d8eSBen Gras  */
74094715d8eSBen Gras void
freeino(ino_t ino)74194715d8eSBen Gras freeino(ino_t ino)
74294715d8eSBen Gras {
74394715d8eSBen Gras 	struct inodesc idesc;
74494715d8eSBen Gras 	struct ext2fs_dinode *dp;
74594715d8eSBen Gras 
74694715d8eSBen Gras 	memset(&idesc, 0, sizeof(struct inodesc));
74794715d8eSBen Gras 	idesc.id_type = ADDR;
74894715d8eSBen Gras 	idesc.id_func = pass4check;
74994715d8eSBen Gras 	idesc.id_number = ino;
75094715d8eSBen Gras 	dp = ginode(ino);
75194715d8eSBen Gras 	(void)ckinode(dp, &idesc);
75294715d8eSBen Gras 	clearinode(dp);
75394715d8eSBen Gras 	inodirty();
75494715d8eSBen Gras 	statemap[ino] = USTATE;
75594715d8eSBen Gras 	n_files--;
75694715d8eSBen Gras }
757*84d9c625SLionel Sambuc 
758*84d9c625SLionel Sambuc uint64_t
inonblock(struct ext2fs_dinode * dp)759*84d9c625SLionel Sambuc inonblock(struct ext2fs_dinode *dp)
760*84d9c625SLionel Sambuc {
761*84d9c625SLionel Sambuc 	uint64_t nblock;
762*84d9c625SLionel Sambuc 
763*84d9c625SLionel Sambuc 	/* XXX check for EXT2_HUGE_FILE without EXT2F_ROCOMPAT_HUGE_FILE? */
764*84d9c625SLionel Sambuc 
765*84d9c625SLionel Sambuc 	nblock = fs2h32(dp->e2di_nblock);
766*84d9c625SLionel Sambuc 
767*84d9c625SLionel Sambuc 	if ((sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_HUGE_FILE)) {
768*84d9c625SLionel Sambuc 		nblock |= (uint64_t)fs2h16(dp->e2di_nblock_high) << 32;
769*84d9c625SLionel Sambuc 		if (fs2h32(dp->e2di_flags) & EXT2_HUGE_FILE) {
770*84d9c625SLionel Sambuc 			nblock = EXT2_FSBTODB(&sblock, nblock);
771*84d9c625SLionel Sambuc 		}
772*84d9c625SLionel Sambuc 	}
773*84d9c625SLionel Sambuc 
774*84d9c625SLionel Sambuc 	return nblock;
775*84d9c625SLionel Sambuc }
776*84d9c625SLionel Sambuc 
777*84d9c625SLionel Sambuc void
inosnblock(struct ext2fs_dinode * dp,uint64_t nblock)778*84d9c625SLionel Sambuc inosnblock(struct ext2fs_dinode *dp, uint64_t nblock)
779*84d9c625SLionel Sambuc {
780*84d9c625SLionel Sambuc 	uint32_t flags;
781*84d9c625SLionel Sambuc 
782*84d9c625SLionel Sambuc 	flags = fs2h32(dp->e2di_flags);
783*84d9c625SLionel Sambuc 
784*84d9c625SLionel Sambuc 	if (nblock <= 0xffffffffULL) {
785*84d9c625SLionel Sambuc 		flags &= ~EXT2_HUGE_FILE;
786*84d9c625SLionel Sambuc 		dp->e2di_flags = h2fs32(flags);
787*84d9c625SLionel Sambuc 		dp->e2di_nblock = h2fs32(nblock);
788*84d9c625SLionel Sambuc 		return;
789*84d9c625SLionel Sambuc 	}
790*84d9c625SLionel Sambuc 
791*84d9c625SLionel Sambuc 	sethuge();
792*84d9c625SLionel Sambuc 
793*84d9c625SLionel Sambuc 	if (nblock <= 0xffffffffffffULL) {
794*84d9c625SLionel Sambuc 		flags &= ~EXT2_HUGE_FILE;
795*84d9c625SLionel Sambuc 		dp->e2di_flags = h2fs32(flags);
796*84d9c625SLionel Sambuc 		dp->e2di_nblock = h2fs32(nblock);
797*84d9c625SLionel Sambuc 		dp->e2di_nblock_high = h2fs16((nblock >> 32));
798*84d9c625SLionel Sambuc 		return;
799*84d9c625SLionel Sambuc 	}
800*84d9c625SLionel Sambuc 
801*84d9c625SLionel Sambuc 	if (EXT2_DBTOFSB(&sblock, nblock) <= 0xffffffffffffULL) {
802*84d9c625SLionel Sambuc 		flags |= EXT2_HUGE_FILE;
803*84d9c625SLionel Sambuc 		dp->e2di_flags = h2fs32(flags);
804*84d9c625SLionel Sambuc 		dp->e2di_nblock = h2fs32(EXT2_DBTOFSB(&sblock, nblock));
805*84d9c625SLionel Sambuc 		dp->e2di_nblock_high = h2fs16((EXT2_DBTOFSB(&sblock, nblock) >> 32));
806*84d9c625SLionel Sambuc 		return;
807*84d9c625SLionel Sambuc 	}
808*84d9c625SLionel Sambuc 
809*84d9c625SLionel Sambuc 	pfatal("trying to set nblocks higher than representable");
810*84d9c625SLionel Sambuc 
811*84d9c625SLionel Sambuc 	return;
812*84d9c625SLionel Sambuc }
813