xref: /netbsd-src/sbin/fsck_ext2fs/inode.c (revision 249e8f5f7e6a579b651a95f028a9dc26d1fb2af4)
1*249e8f5fSjdolecek /*	$NetBSD: inode.c,v 1.37 2016/08/04 17:43:47 jdolecek Exp $	*/
2bf07c871Sagc 
3bf07c871Sagc /*
4bf07c871Sagc  * Copyright (c) 1980, 1986, 1993
5bf07c871Sagc  *	The Regents of the University of California.  All rights reserved.
6bf07c871Sagc  *
7bf07c871Sagc  * Redistribution and use in source and binary forms, with or without
8bf07c871Sagc  * modification, are permitted provided that the following conditions
9bf07c871Sagc  * are met:
10bf07c871Sagc  * 1. Redistributions of source code must retain the above copyright
11bf07c871Sagc  *    notice, this list of conditions and the following disclaimer.
12bf07c871Sagc  * 2. Redistributions in binary form must reproduce the above copyright
13bf07c871Sagc  *    notice, this list of conditions and the following disclaimer in the
14bf07c871Sagc  *    documentation and/or other materials provided with the distribution.
15bf07c871Sagc  * 3. Neither the name of the University nor the names of its contributors
16bf07c871Sagc  *    may be used to endorse or promote products derived from this software
17bf07c871Sagc  *    without specific prior written permission.
18bf07c871Sagc  *
19bf07c871Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20bf07c871Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21bf07c871Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22bf07c871Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23bf07c871Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24bf07c871Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25bf07c871Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26bf07c871Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27bf07c871Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28bf07c871Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29bf07c871Sagc  * SUCH DAMAGE.
30bf07c871Sagc  */
318f7c2b37Sbouyer 
328f7c2b37Sbouyer /*
338f7c2b37Sbouyer  * Copyright (c) 1997 Manuel Bouyer.
348f7c2b37Sbouyer  *
358f7c2b37Sbouyer  * Redistribution and use in source and binary forms, with or without
368f7c2b37Sbouyer  * modification, are permitted provided that the following conditions
378f7c2b37Sbouyer  * are met:
388f7c2b37Sbouyer  * 1. Redistributions of source code must retain the above copyright
398f7c2b37Sbouyer  *    notice, this list of conditions and the following disclaimer.
408f7c2b37Sbouyer  * 2. Redistributions in binary form must reproduce the above copyright
418f7c2b37Sbouyer  *    notice, this list of conditions and the following disclaimer in the
428f7c2b37Sbouyer  *    documentation and/or other materials provided with the distribution.
438f7c2b37Sbouyer  *
442f853da9Sbouyer  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
452f853da9Sbouyer  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
462f853da9Sbouyer  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
472f853da9Sbouyer  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
482f853da9Sbouyer  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
492f853da9Sbouyer  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
502f853da9Sbouyer  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
512f853da9Sbouyer  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
522f853da9Sbouyer  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
532f853da9Sbouyer  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
548f7c2b37Sbouyer  */
558f7c2b37Sbouyer 
564b836889Slukem #include <sys/cdefs.h>
578f7c2b37Sbouyer #ifndef lint
588f7c2b37Sbouyer #if 0
598f7c2b37Sbouyer static char sccsid[] = "@(#)inode.c	8.5 (Berkeley) 2/8/95";
608f7c2b37Sbouyer #else
61*249e8f5fSjdolecek __RCSID("$NetBSD: inode.c,v 1.37 2016/08/04 17:43:47 jdolecek Exp $");
628f7c2b37Sbouyer #endif
638f7c2b37Sbouyer #endif /* not lint */
648f7c2b37Sbouyer 
658f7c2b37Sbouyer #include <sys/param.h>
668f7c2b37Sbouyer #include <sys/time.h>
678f7c2b37Sbouyer #include <ufs/ext2fs/ext2fs_dinode.h>
688f7c2b37Sbouyer #include <ufs/ext2fs/ext2fs_dir.h>
698f7c2b37Sbouyer #include <ufs/ext2fs/ext2fs.h>
708f7c2b37Sbouyer 
718f7c2b37Sbouyer #include <ufs/ufs/dinode.h> /* for IFMT & friends */
728f7c2b37Sbouyer #ifndef SMALL
738f7c2b37Sbouyer #include <pwd.h>
748f7c2b37Sbouyer #endif
758f7c2b37Sbouyer #include <stdio.h>
768f7c2b37Sbouyer #include <stdlib.h>
778f7c2b37Sbouyer #include <string.h>
784212e564Skleink #include <time.h>
798f7c2b37Sbouyer 
808f7c2b37Sbouyer #include "fsck.h"
818f7c2b37Sbouyer #include "fsutil.h"
828f7c2b37Sbouyer #include "extern.h"
838f7c2b37Sbouyer 
847052d78bSbouyer /*
857052d78bSbouyer  * CG is stored in fs byte order in memory, so we can't use ino_to_fsba
867052d78bSbouyer  * here.
877052d78bSbouyer  */
887052d78bSbouyer 
897052d78bSbouyer #define fsck_ino_to_fsba(fs, x)                      \
907052d78bSbouyer 	(fs2h32((fs)->e2fs_gd[ino_to_cg(fs, x)].ext2bgd_i_tables) + \
917052d78bSbouyer 	(((x)-1) % (fs)->e2fs.e2fs_ipg)/(fs)->e2fs_ipb)
927052d78bSbouyer 
937052d78bSbouyer 
948f7c2b37Sbouyer static ino_t startinum;
958f7c2b37Sbouyer 
96ccde05f0Sxtraeme static int iblock(struct inodesc *, long, u_int64_t);
978f7c2b37Sbouyer 
98d53c382dSws static int setlarge(void);
99d53c382dSws 
100a3904b0bSjakllsch static int sethuge(void);
101a3904b0bSjakllsch 
102d53c382dSws static int
setlarge(void)103d53c382dSws setlarge(void)
104d53c382dSws {
105d53c382dSws 	if (sblock.e2fs.e2fs_rev < E2FS_REV1) {
106d53c382dSws 		pfatal("LARGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS");
107d53c382dSws 		return 0;
108d53c382dSws 	}
109d53c382dSws 	if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE)) {
110d53c382dSws 		if (preen)
111d53c382dSws 			pwarn("SETTING LARGE FILE INDICATOR\n");
112d53c382dSws 		else if (!reply("SET LARGE FILE INDICATOR"))
113d53c382dSws 			return 0;
114d53c382dSws 		sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGEFILE;
115d53c382dSws 		sbdirty();
116d53c382dSws 	}
117d53c382dSws 	return 1;
118d53c382dSws }
119d53c382dSws 
120a3904b0bSjakllsch static int
sethuge(void)121a3904b0bSjakllsch sethuge(void)
122a3904b0bSjakllsch {
123a3904b0bSjakllsch 	if (sblock.e2fs.e2fs_rev < E2FS_REV1) {
124a3904b0bSjakllsch 		pfatal("HUGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS");
125a3904b0bSjakllsch 		return 0;
126a3904b0bSjakllsch 	}
127a3904b0bSjakllsch 	if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_HUGE_FILE)) {
128a3904b0bSjakllsch 		if (preen)
129a3904b0bSjakllsch 			pwarn("SETTING HUGE FILE FEATURE\n");
130a3904b0bSjakllsch 		else if (!reply("SET HUGE FILE FEATURE"))
131a3904b0bSjakllsch 			return 0;
132a3904b0bSjakllsch 		sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_HUGE_FILE;
133a3904b0bSjakllsch 		sbdirty();
134a3904b0bSjakllsch 	}
135a3904b0bSjakllsch 	return 1;
136a3904b0bSjakllsch }
137a3904b0bSjakllsch 
138d53c382dSws u_int64_t
inosize(struct ext2fs_dinode * dp)139d53c382dSws inosize(struct ext2fs_dinode *dp)
140d53c382dSws {
141d53c382dSws 	u_int64_t size = fs2h32(dp->e2di_size);
142d53c382dSws 
143d53c382dSws 	if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG)
144*249e8f5fSjdolecek 		size |= (u_int64_t)fs2h32(dp->e2di_size_high) << 32;
145ee70a0c9Stsutsui 	if (size > INT32_MAX)
146d53c382dSws 		(void)setlarge();
147d53c382dSws 	return size;
148d53c382dSws }
149d53c382dSws 
150d53c382dSws void
inossize(struct ext2fs_dinode * dp,u_int64_t size)151d53c382dSws inossize(struct ext2fs_dinode *dp, u_int64_t size)
152d53c382dSws {
153d53c382dSws 	if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG) {
154*249e8f5fSjdolecek 		dp->e2di_size_high = h2fs32(size >> 32);
155ee70a0c9Stsutsui 		if (size > INT32_MAX)
156d53c382dSws 			if (!setlarge())
157d53c382dSws 				return;
158ee70a0c9Stsutsui 	} else if (size > INT32_MAX) {
159d53c382dSws 		pfatal("TRYING TO SET FILESIZE TO %llu ON MODE %x FILE\n",
160d53c382dSws 		    (unsigned long long)size, fs2h16(dp->e2di_mode) & IFMT);
161d53c382dSws 		return;
162d53c382dSws 	}
163d53c382dSws 	dp->e2di_size = h2fs32(size);
164d53c382dSws }
165d53c382dSws 
1668f7c2b37Sbouyer int
ckinode(struct ext2fs_dinode * dp,struct inodesc * idesc)167ccde05f0Sxtraeme ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc)
1688f7c2b37Sbouyer {
1694b836889Slukem 	u_int32_t *ap;
1704b836889Slukem 	long ret, n, ndb;
1718f7c2b37Sbouyer 	struct ext2fs_dinode dino;
1728f7c2b37Sbouyer 	u_int64_t remsize, sizepb;
1738f7c2b37Sbouyer 	mode_t mode;
1748f7c2b37Sbouyer 	char pathbuf[MAXPATHLEN + 1];
1758f7c2b37Sbouyer 
1768f7c2b37Sbouyer 	if (idesc->id_fix != IGNORE)
1778f7c2b37Sbouyer 		idesc->id_fix = DONTKNOW;
1788f7c2b37Sbouyer 	idesc->id_entryno = 0;
179d53c382dSws 	idesc->id_filesize = inosize(dp);
1807052d78bSbouyer 	mode = fs2h16(dp->e2di_mode) & IFMT;
1811bb2b4ddSbouyer 	if (mode == IFBLK || mode == IFCHR || mode == IFIFO ||
182d53c382dSws 	    (mode == IFLNK && (inosize(dp) < EXT2_MAXSYMLINKLEN)))
1838f7c2b37Sbouyer 		return (KEEPON);
1848f7c2b37Sbouyer 	dino = *dp;
185d53c382dSws 	ndb = howmany(inosize(&dino), sblock.e2fs_bsize);
186dcd34a91Sdholland 	for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[EXT2FS_NDADDR];
1878f7c2b37Sbouyer 	    ap++,ndb--) {
1888f7c2b37Sbouyer 		idesc->id_numfrags = 1;
1898f7c2b37Sbouyer 		if (*ap == 0) {
1908f7c2b37Sbouyer 			if (idesc->id_type == DATA && ndb > 0) {
1918f7c2b37Sbouyer 				/* An empty block in a directory XXX */
19249fbaf53Sitojun 				getpathname(pathbuf, sizeof(pathbuf),
19349fbaf53Sitojun 				    idesc->id_number, idesc->id_number);
1948f7c2b37Sbouyer 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
1958f7c2b37Sbouyer 				    pathbuf);
1968f7c2b37Sbouyer 				if (reply("ADJUST LENGTH") == 1) {
1978f7c2b37Sbouyer 					dp = ginode(idesc->id_number);
198d53c382dSws 					inossize(dp,
199d53c382dSws 					    (ap - &dino.e2di_blocks[0]) *
2007052d78bSbouyer 					    sblock.e2fs_bsize);
2018f7c2b37Sbouyer 					printf(
2028f7c2b37Sbouyer 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
2038f7c2b37Sbouyer 					rerun = 1;
2048f7c2b37Sbouyer 					inodirty();
2058f7c2b37Sbouyer 				}
2068f7c2b37Sbouyer 			}
2078f7c2b37Sbouyer 			continue;
2088f7c2b37Sbouyer 		}
2097052d78bSbouyer 		idesc->id_blkno = fs2h32(*ap);
2108f7c2b37Sbouyer 		if (idesc->id_type == ADDR)
2118f7c2b37Sbouyer 			ret = (*idesc->id_func)(idesc);
2128f7c2b37Sbouyer 		else
2138f7c2b37Sbouyer 			ret = dirscan(idesc);
2148f7c2b37Sbouyer 		if (ret & STOP)
2158f7c2b37Sbouyer 			return (ret);
2168f7c2b37Sbouyer 	}
2178f7c2b37Sbouyer 	idesc->id_numfrags = 1;
218dcd34a91Sdholland 	remsize = inosize(&dino) - sblock.e2fs_bsize * EXT2FS_NDADDR;
2198f7c2b37Sbouyer 	sizepb = sblock.e2fs_bsize;
220dcd34a91Sdholland 	for (ap = &dino.e2di_blocks[EXT2FS_NDADDR], n = 1; n <= EXT2FS_NIADDR; ap++, n++) {
2218f7c2b37Sbouyer 		if (*ap) {
2227052d78bSbouyer 			idesc->id_blkno = fs2h32(*ap);
2238f7c2b37Sbouyer 			ret = iblock(idesc, n, remsize);
2248f7c2b37Sbouyer 			if (ret & STOP)
2258f7c2b37Sbouyer 				return (ret);
2268f7c2b37Sbouyer 		} else {
2278f7c2b37Sbouyer 			if (idesc->id_type == DATA && remsize > 0) {
2288f7c2b37Sbouyer 				/* An empty block in a directory XXX */
22949fbaf53Sitojun 				getpathname(pathbuf, sizeof(pathbuf),
23049fbaf53Sitojun 				    idesc->id_number, idesc->id_number);
2318f7c2b37Sbouyer 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
2328f7c2b37Sbouyer 				    pathbuf);
2338f7c2b37Sbouyer 				if (reply("ADJUST LENGTH") == 1) {
2348f7c2b37Sbouyer 					dp = ginode(idesc->id_number);
235d53c382dSws 					inossize(dp, inosize(dp) - remsize);
2368f7c2b37Sbouyer 					remsize = 0;
2378f7c2b37Sbouyer 					printf(
2388f7c2b37Sbouyer 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
2398f7c2b37Sbouyer 					rerun = 1;
2408f7c2b37Sbouyer 					inodirty();
2418f7c2b37Sbouyer 					break;
2428f7c2b37Sbouyer 				}
2438f7c2b37Sbouyer 			}
2448f7c2b37Sbouyer 		}
245f1333577Sdholland 		sizepb *= EXT2_NINDIR(&sblock);
2468f7c2b37Sbouyer 		remsize -= sizepb;
2478f7c2b37Sbouyer 	}
2488f7c2b37Sbouyer 	return (KEEPON);
2498f7c2b37Sbouyer }
2508f7c2b37Sbouyer 
2518f7c2b37Sbouyer static int
iblock(struct inodesc * idesc,long ilevel,u_int64_t isize)252ccde05f0Sxtraeme iblock(struct inodesc *idesc, long ilevel, u_int64_t isize)
2538f7c2b37Sbouyer {
254a3ff3a30Sfvdl 	/* XXX ondisk32 */
255a3ff3a30Sfvdl 	int32_t *ap;
256a3ff3a30Sfvdl 	int32_t *aplim;
2574b836889Slukem 	struct bufarea *bp;
2585bd52bbaSlukem 	int i, n, (*func)(struct inodesc *);
2595bd52bbaSlukem 	size_t nif;
2608f7c2b37Sbouyer 	u_int64_t sizepb;
2618f7c2b37Sbouyer 	char buf[BUFSIZ];
2628f7c2b37Sbouyer 	char pathbuf[MAXPATHLEN + 1];
2638f7c2b37Sbouyer 	struct ext2fs_dinode *dp;
2648f7c2b37Sbouyer 
2658f7c2b37Sbouyer 	if (idesc->id_type == ADDR) {
2668f7c2b37Sbouyer 		func = idesc->id_func;
2678f7c2b37Sbouyer 		if (((n = (*func)(idesc)) & KEEPON) == 0)
2688f7c2b37Sbouyer 			return (n);
2698f7c2b37Sbouyer 	} else
2708f7c2b37Sbouyer 		func = dirscan;
2718f7c2b37Sbouyer 	if (chkrange(idesc->id_blkno, idesc->id_numfrags))
2728f7c2b37Sbouyer 		return (SKIP);
2738f7c2b37Sbouyer 	bp = getdatablk(idesc->id_blkno, sblock.e2fs_bsize);
2748f7c2b37Sbouyer 	ilevel--;
2758f7c2b37Sbouyer 	for (sizepb = sblock.e2fs_bsize, i = 0; i < ilevel; i++)
276f1333577Sdholland 		sizepb *= EXT2_NINDIR(&sblock);
277f1333577Sdholland 	if (isize > sizepb * EXT2_NINDIR(&sblock))
278f1333577Sdholland 		nif = EXT2_NINDIR(&sblock);
2798f7c2b37Sbouyer 	else
2808f7c2b37Sbouyer 		nif = howmany(isize, sizepb);
2818f7c2b37Sbouyer 	if (idesc->id_func == pass1check &&
282f1333577Sdholland 		nif < EXT2_NINDIR(&sblock)) {
283f1333577Sdholland 		aplim = &bp->b_un.b_indir[EXT2_NINDIR(&sblock)];
2848f7c2b37Sbouyer 		for (ap = &bp->b_un.b_indir[nif]; ap < aplim; ap++) {
2858f7c2b37Sbouyer 			if (*ap == 0)
2868f7c2b37Sbouyer 				continue;
287519d8585Smycroft 			(void)snprintf(buf, sizeof(buf),
288c4ee9f6dSchristos 			    "PARTIALLY TRUNCATED INODE I=%llu",
289c4ee9f6dSchristos 			    (unsigned long long)idesc->id_number);
2908f7c2b37Sbouyer 			if (dofix(idesc, buf)) {
2918f7c2b37Sbouyer 				*ap = 0;
2928f7c2b37Sbouyer 				dirty(bp);
2938f7c2b37Sbouyer 			}
2948f7c2b37Sbouyer 		}
2958f7c2b37Sbouyer 		flush(fswritefd, bp);
2968f7c2b37Sbouyer 	}
2978f7c2b37Sbouyer 	aplim = &bp->b_un.b_indir[nif];
2988f7c2b37Sbouyer 	for (ap = bp->b_un.b_indir; ap < aplim; ap++) {
2998f7c2b37Sbouyer 		if (*ap) {
3007052d78bSbouyer 			idesc->id_blkno = fs2h32(*ap);
3018f7c2b37Sbouyer 			if (ilevel == 0)
3028f7c2b37Sbouyer 				n = (*func)(idesc);
3038f7c2b37Sbouyer 			else
3048f7c2b37Sbouyer 				n = iblock(idesc, ilevel, isize);
3058f7c2b37Sbouyer 			if (n & STOP) {
3068f7c2b37Sbouyer 				bp->b_flags &= ~B_INUSE;
3078f7c2b37Sbouyer 				return (n);
3088f7c2b37Sbouyer 			}
3098f7c2b37Sbouyer 		} else {
3108f7c2b37Sbouyer 			if (idesc->id_type == DATA && isize > 0) {
3118f7c2b37Sbouyer 				/* An empty block in a directory XXX */
31249fbaf53Sitojun 				getpathname(pathbuf, sizeof(pathbuf),
31349fbaf53Sitojun 				    idesc->id_number, idesc->id_number);
3148f7c2b37Sbouyer 				pfatal("DIRECTORY %s: CONTAINS EMPTY BLOCKS",
3158f7c2b37Sbouyer 				    pathbuf);
3168f7c2b37Sbouyer 				if (reply("ADJUST LENGTH") == 1) {
3178f7c2b37Sbouyer 					dp = ginode(idesc->id_number);
318d53c382dSws 					inossize(dp, inosize(dp) - isize);
3198f7c2b37Sbouyer 					isize = 0;
3208f7c2b37Sbouyer 					printf(
3218f7c2b37Sbouyer 					    "YOU MUST RERUN FSCK AFTERWARDS\n");
3228f7c2b37Sbouyer 					rerun = 1;
3238f7c2b37Sbouyer 					inodirty();
3248f7c2b37Sbouyer 					bp->b_flags &= ~B_INUSE;
3258f7c2b37Sbouyer 					return(STOP);
3268f7c2b37Sbouyer 				}
3278f7c2b37Sbouyer 			}
3288f7c2b37Sbouyer 		}
3298f7c2b37Sbouyer 		isize -= sizepb;
3308f7c2b37Sbouyer 	}
3318f7c2b37Sbouyer 	bp->b_flags &= ~B_INUSE;
3328f7c2b37Sbouyer 	return (KEEPON);
3338f7c2b37Sbouyer }
3348f7c2b37Sbouyer 
3358f7c2b37Sbouyer /*
3368f7c2b37Sbouyer  * Check that a block in a legal block number.
3378f7c2b37Sbouyer  * Return 0 if in range, 1 if out of range.
3388f7c2b37Sbouyer  */
3398f7c2b37Sbouyer int
chkrange(daddr_t blk,int cnt)340ccde05f0Sxtraeme chkrange(daddr_t blk, int cnt)
3418f7c2b37Sbouyer {
34209d4663fSbouyer 	int c, overh;
3438f7c2b37Sbouyer 
344a43d077cStsutsui 	if ((unsigned int)(blk + cnt) > maxfsblock)
3458f7c2b37Sbouyer 		return (1);
3468f7c2b37Sbouyer 	c = dtog(&sblock, blk);
34709d4663fSbouyer 	overh = cgoverhead(c);
34809d4663fSbouyer 	if (blk < sblock.e2fs.e2fs_bpg * c + overh +
3498f7c2b37Sbouyer 	    sblock.e2fs.e2fs_first_dblock) {
35009d4663fSbouyer 		if ((blk + cnt) > sblock.e2fs.e2fs_bpg * c + overh +
3518f7c2b37Sbouyer 		    sblock.e2fs.e2fs_first_dblock) {
3528f7c2b37Sbouyer 			if (debug) {
353a3ff3a30Sfvdl 				printf("blk %lld < cgdmin %d;",
354a3ff3a30Sfvdl 				    (long long)blk,
355a3ff3a30Sfvdl 				    sblock.e2fs.e2fs_bpg * c + overh +
3568f7c2b37Sbouyer 				    sblock.e2fs.e2fs_first_dblock);
357a3ff3a30Sfvdl 				printf(" blk + cnt %lld > cgsbase %d\n",
358a3ff3a30Sfvdl 				    (long long)(blk + cnt),
359a3ff3a30Sfvdl 				    sblock.e2fs.e2fs_bpg * c +
36009d4663fSbouyer 				    overh + sblock.e2fs.e2fs_first_dblock);
3618f7c2b37Sbouyer 			}
3628f7c2b37Sbouyer 			return (1);
3638f7c2b37Sbouyer 		}
3648f7c2b37Sbouyer 	} else {
36509d4663fSbouyer 		if ((blk + cnt) > sblock.e2fs.e2fs_bpg * (c + 1) + overh +
3668f7c2b37Sbouyer 		    sblock.e2fs.e2fs_first_dblock) {
3678f7c2b37Sbouyer 			if (debug)  {
368a3ff3a30Sfvdl 				printf("blk %lld >= cgdmin %d;",
369a3ff3a30Sfvdl 				    (long long)blk,
370a3ff3a30Sfvdl 				    sblock.e2fs.e2fs_bpg * c + overh +
3718f7c2b37Sbouyer 				    sblock.e2fs.e2fs_first_dblock);
372a3ff3a30Sfvdl 				printf(" blk + cnt %lld > cgdmax %d\n",
373a3ff3a30Sfvdl 				    (long long)(blk+cnt),
374a3ff3a30Sfvdl 				    sblock.e2fs.e2fs_bpg * (c + 1) +
37509d4663fSbouyer 				    overh + sblock.e2fs.e2fs_first_dblock);
3768f7c2b37Sbouyer 			}
3778f7c2b37Sbouyer 			return (1);
3788f7c2b37Sbouyer 		}
3798f7c2b37Sbouyer 	}
3808f7c2b37Sbouyer 	return (0);
3818f7c2b37Sbouyer }
3828f7c2b37Sbouyer 
3838f7c2b37Sbouyer /*
3848f7c2b37Sbouyer  * General purpose interface for reading inodes.
3858f7c2b37Sbouyer  */
3868f7c2b37Sbouyer struct ext2fs_dinode *
ginode(ino_t inumber)387ccde05f0Sxtraeme ginode(ino_t inumber)
3888f7c2b37Sbouyer {
3898f7c2b37Sbouyer 	daddr_t iblk;
390f5925335Stsutsui 	struct ext2fs_dinode *dp;
3918f7c2b37Sbouyer 
3921e795b03Stsutsui 	if ((inumber < EXT2_FIRSTINO &&
3931e795b03Stsutsui 	     inumber != EXT2_ROOTINO &&
3941e795b03Stsutsui 	     !(inumber == EXT2_RESIZEINO &&
3951e795b03Stsutsui 	       (sblock.e2fs.e2fs_features_compat & EXT2F_COMPAT_RESIZE) != 0))
3968f7c2b37Sbouyer 		|| inumber > maxino)
397481ad7b0Slukem 		errexit("bad inode number %llu to ginode",
398c4ee9f6dSchristos 		    (unsigned long long)inumber);
3998f7c2b37Sbouyer 	if (startinum == 0 ||
4008f7c2b37Sbouyer 	    inumber < startinum || inumber >= startinum + sblock.e2fs_ipb) {
4017052d78bSbouyer 		iblk = fsck_ino_to_fsba(&sblock, inumber);
4028f7c2b37Sbouyer 		if (pbp != 0)
4038f7c2b37Sbouyer 			pbp->b_flags &= ~B_INUSE;
4048f7c2b37Sbouyer 		pbp = getdatablk(iblk, sblock.e2fs_bsize);
405f5925335Stsutsui 		startinum =
406f5925335Stsutsui 		    ((inumber - 1) / sblock.e2fs_ipb) * sblock.e2fs_ipb + 1;
4078f7c2b37Sbouyer 	}
408f5925335Stsutsui 	dp = (struct ext2fs_dinode *)(pbp->b_un.b_buf +
409f5925335Stsutsui 	    EXT2_DINODE_SIZE(&sblock) * ino_to_fsbo(&sblock, inumber));
410f5925335Stsutsui 
411f5925335Stsutsui 	return dp;
4128f7c2b37Sbouyer }
4138f7c2b37Sbouyer 
4148f7c2b37Sbouyer /*
4158f7c2b37Sbouyer  * Special purpose version of ginode used to optimize first pass
4168f7c2b37Sbouyer  * over all the inodes in numerical order.
4178f7c2b37Sbouyer  */
4188f7c2b37Sbouyer ino_t nextino, lastinum;
4198f7c2b37Sbouyer long readcnt, readpercg, fullcnt, inobufsize, partialcnt, partialsize;
420f5925335Stsutsui char *inodebuf;
4218f7c2b37Sbouyer 
4228f7c2b37Sbouyer struct ext2fs_dinode *
getnextinode(ino_t inumber)423ccde05f0Sxtraeme getnextinode(ino_t inumber)
4248f7c2b37Sbouyer {
4258f7c2b37Sbouyer 	long size;
4268f7c2b37Sbouyer 	daddr_t dblk;
427f5925335Stsutsui 	struct ext2fs_dinode *dp;
428f5925335Stsutsui 	static char *bp;
4298f7c2b37Sbouyer 
4308f7c2b37Sbouyer 	if (inumber != nextino++ || inumber > maxino)
431481ad7b0Slukem 		errexit("bad inode number %llu to nextinode",
432c4ee9f6dSchristos 		    (unsigned long long)inumber);
4338f7c2b37Sbouyer 	if (inumber >= lastinum) {
4348f7c2b37Sbouyer 		readcnt++;
4352737439dSdholland 		dblk = EXT2_FSBTODB(&sblock, fsck_ino_to_fsba(&sblock, lastinum));
4368f7c2b37Sbouyer 		if (readcnt % readpercg == 0) {
4378f7c2b37Sbouyer 			size = partialsize;
4388f7c2b37Sbouyer 			lastinum += partialcnt;
4398f7c2b37Sbouyer 		} else {
4408f7c2b37Sbouyer 			size = inobufsize;
4418f7c2b37Sbouyer 			lastinum += fullcnt;
4428f7c2b37Sbouyer 		}
443f5925335Stsutsui 		(void)bread(fsreadfd, inodebuf, dblk, size);
444f5925335Stsutsui 		bp = inodebuf;
4458f7c2b37Sbouyer 	}
446f5925335Stsutsui 	dp = (struct ext2fs_dinode *)bp;
447f5925335Stsutsui 	bp += EXT2_DINODE_SIZE(&sblock);
448f5925335Stsutsui 
449f5925335Stsutsui 	return dp;
4508f7c2b37Sbouyer }
4518f7c2b37Sbouyer 
4528f7c2b37Sbouyer void
resetinodebuf(void)453ccde05f0Sxtraeme resetinodebuf(void)
4548f7c2b37Sbouyer {
4558f7c2b37Sbouyer 
4568f7c2b37Sbouyer 	startinum = 0;
4578f7c2b37Sbouyer 	nextino = 1;
4588f7c2b37Sbouyer 	lastinum = 1;
4598f7c2b37Sbouyer 	readcnt = 0;
460e1610ba4Sdholland 	inobufsize = ext2_blkroundup(&sblock, INOBUFSIZE);
461f5925335Stsutsui 	fullcnt = inobufsize / EXT2_DINODE_SIZE(&sblock);
4628f7c2b37Sbouyer 	readpercg = sblock.e2fs.e2fs_ipg / fullcnt;
4638f7c2b37Sbouyer 	partialcnt = sblock.e2fs.e2fs_ipg % fullcnt;
464f5925335Stsutsui 	partialsize = partialcnt * EXT2_DINODE_SIZE(&sblock);
4658f7c2b37Sbouyer 	if (partialcnt != 0) {
4668f7c2b37Sbouyer 		readpercg++;
4678f7c2b37Sbouyer 	} else {
4688f7c2b37Sbouyer 		partialcnt = fullcnt;
4698f7c2b37Sbouyer 		partialsize = inobufsize;
4708f7c2b37Sbouyer 	}
4718f7c2b37Sbouyer 	if (inodebuf == NULL &&
472a43d077cStsutsui 	    (inodebuf = malloc((unsigned int)inobufsize)) == NULL)
473481ad7b0Slukem 		errexit("Cannot allocate space for inode buffer");
4748f7c2b37Sbouyer 	while (nextino < EXT2_ROOTINO)
4758f7c2b37Sbouyer 		(void)getnextinode(nextino);
4768f7c2b37Sbouyer }
4778f7c2b37Sbouyer 
4788f7c2b37Sbouyer void
freeinodebuf(void)479ccde05f0Sxtraeme freeinodebuf(void)
4808f7c2b37Sbouyer {
4818f7c2b37Sbouyer 
4828f7c2b37Sbouyer 	if (inodebuf != NULL)
483a43d077cStsutsui 		free(inodebuf);
4848f7c2b37Sbouyer 	inodebuf = NULL;
4858f7c2b37Sbouyer }
4868f7c2b37Sbouyer 
4878f7c2b37Sbouyer /*
4888f7c2b37Sbouyer  * Routines to maintain information about directory inodes.
4898f7c2b37Sbouyer  * This is built during the first pass and used during the
4908f7c2b37Sbouyer  * second and third passes.
4918f7c2b37Sbouyer  *
4928f7c2b37Sbouyer  * Enter inodes into the cache.
4938f7c2b37Sbouyer  */
4948f7c2b37Sbouyer void
cacheino(struct ext2fs_dinode * dp,ino_t inumber)495ccde05f0Sxtraeme cacheino(struct ext2fs_dinode *dp, ino_t inumber)
4968f7c2b37Sbouyer {
4974b836889Slukem 	struct inoinfo *inp;
4988f7c2b37Sbouyer 	struct inoinfo **inpp;
4998f7c2b37Sbouyer 	unsigned int blks;
5008f7c2b37Sbouyer 
501d53c382dSws 	blks = howmany(inosize(dp), sblock.e2fs_bsize);
502dcd34a91Sdholland 	if (blks > EXT2FS_NDADDR)
503dcd34a91Sdholland 		blks = EXT2FS_NDADDR + EXT2FS_NIADDR;
504a3ff3a30Sfvdl 	/* XXX ondisk32 */
505a43d077cStsutsui 	inp = malloc(sizeof(*inp) + (blks - 1) * sizeof(int32_t));
5068f7c2b37Sbouyer 	if (inp == NULL)
5078f7c2b37Sbouyer 		return;
5088f7c2b37Sbouyer 	inpp = &inphead[inumber % numdirs];
5098f7c2b37Sbouyer 	inp->i_nexthash = *inpp;
5108f7c2b37Sbouyer 	*inpp = inp;
5118f7c2b37Sbouyer 	inp->i_child = inp->i_sibling = inp->i_parentp = 0;
5128f7c2b37Sbouyer 	if (inumber == EXT2_ROOTINO)
5138f7c2b37Sbouyer 		inp->i_parent = EXT2_ROOTINO;
5148f7c2b37Sbouyer 	else
5158f7c2b37Sbouyer 		inp->i_parent = (ino_t)0;
5168f7c2b37Sbouyer 	inp->i_dotdot = (ino_t)0;
5178f7c2b37Sbouyer 	inp->i_number = inumber;
518d53c382dSws 	inp->i_isize = inosize(dp);
519a3ff3a30Sfvdl 	/* XXX ondisk32 */
520a3ff3a30Sfvdl 	inp->i_numblks = blks * sizeof(int32_t);
5218f7c2b37Sbouyer 	memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks);
5228f7c2b37Sbouyer 	if (inplast == listmax) {
5238f7c2b37Sbouyer 		listmax += 100;
5248f7c2b37Sbouyer 		inpsort = (struct inoinfo **)realloc((char *)inpsort,
525a43d077cStsutsui 		    (unsigned int)listmax * sizeof(struct inoinfo *));
5268f7c2b37Sbouyer 		if (inpsort == NULL)
527481ad7b0Slukem 			errexit("cannot increase directory list");
5288f7c2b37Sbouyer 	}
5298f7c2b37Sbouyer 	inpsort[inplast++] = inp;
5308f7c2b37Sbouyer }
5318f7c2b37Sbouyer 
5328f7c2b37Sbouyer /*
5338f7c2b37Sbouyer  * Look up an inode cache structure.
5348f7c2b37Sbouyer  */
5358f7c2b37Sbouyer struct inoinfo *
getinoinfo(ino_t inumber)536ccde05f0Sxtraeme getinoinfo(ino_t inumber)
5378f7c2b37Sbouyer {
5384b836889Slukem 	struct inoinfo *inp;
5398f7c2b37Sbouyer 
5408f7c2b37Sbouyer 	for (inp = inphead[inumber % numdirs]; inp; inp = inp->i_nexthash) {
5418f7c2b37Sbouyer 		if (inp->i_number != inumber)
5428f7c2b37Sbouyer 			continue;
5438f7c2b37Sbouyer 		return (inp);
5448f7c2b37Sbouyer 	}
545481ad7b0Slukem 	errexit("cannot find inode %llu", (unsigned long long)inumber);
5468f7c2b37Sbouyer 	return ((struct inoinfo *)0);
5478f7c2b37Sbouyer }
5488f7c2b37Sbouyer 
5498f7c2b37Sbouyer /*
5508f7c2b37Sbouyer  * Clean up all the inode cache structure.
5518f7c2b37Sbouyer  */
5528f7c2b37Sbouyer void
inocleanup(void)553ccde05f0Sxtraeme inocleanup(void)
5548f7c2b37Sbouyer {
5554b836889Slukem 	struct inoinfo **inpp;
5568f7c2b37Sbouyer 
5578f7c2b37Sbouyer 	if (inphead == NULL)
5588f7c2b37Sbouyer 		return;
5598f7c2b37Sbouyer 	for (inpp = &inpsort[inplast - 1]; inpp >= inpsort; inpp--)
560a43d077cStsutsui 		free(*inpp);
561a43d077cStsutsui 	free(inphead);
562a43d077cStsutsui 	free(inpsort);
5638f7c2b37Sbouyer 	inphead = inpsort = NULL;
5648f7c2b37Sbouyer }
5658f7c2b37Sbouyer 
5668f7c2b37Sbouyer void
inodirty(void)567ccde05f0Sxtraeme inodirty(void)
5688f7c2b37Sbouyer {
5698f7c2b37Sbouyer 
5708f7c2b37Sbouyer 	dirty(pbp);
5718f7c2b37Sbouyer }
5728f7c2b37Sbouyer 
5738f7c2b37Sbouyer void
clri(struct inodesc * idesc,const char * type,int flag)57497880e96Schristos clri(struct inodesc *idesc, const char *type, int flag)
5758f7c2b37Sbouyer {
5764b836889Slukem 	struct ext2fs_dinode *dp;
5778f7c2b37Sbouyer 
5788f7c2b37Sbouyer 	dp = ginode(idesc->id_number);
5798f7c2b37Sbouyer 	if (flag == 1) {
5808f7c2b37Sbouyer 		pwarn("%s %s", type,
5816189d5e3Stsutsui 		    (fs2h16(dp->e2di_mode) & IFMT) == IFDIR ? "DIR" : "FILE");
5828f7c2b37Sbouyer 		pinode(idesc->id_number);
5838f7c2b37Sbouyer 	}
5848f7c2b37Sbouyer 	if (preen || reply("CLEAR") == 1) {
5858f7c2b37Sbouyer 		if (preen)
5868f7c2b37Sbouyer 			printf(" (CLEARED)\n");
5878f7c2b37Sbouyer 		n_files--;
5888f7c2b37Sbouyer 		(void)ckinode(dp, idesc);
5898f7c2b37Sbouyer 		clearinode(dp);
5908f7c2b37Sbouyer 		statemap[idesc->id_number] = USTATE;
5918f7c2b37Sbouyer 		inodirty();
5928f7c2b37Sbouyer 	}
5938f7c2b37Sbouyer }
5948f7c2b37Sbouyer 
5958f7c2b37Sbouyer int
findname(struct inodesc * idesc)596ccde05f0Sxtraeme findname(struct inodesc *idesc)
5978f7c2b37Sbouyer {
5984b836889Slukem 	struct ext2fs_direct *dirp = idesc->id_dirp;
5995fb6bc4eSbouyer 	u_int16_t namlen = dirp->e2d_namlen;
60097880e96Schristos 	/* from utilities.c namebuf[] variable */
60197880e96Schristos 	char *buf = __UNCONST(idesc->id_name);
60297880e96Schristos 	if (namlen > MAXPATHLEN) {
60397880e96Schristos 		/* XXX: Prevent overflow but don't fix */
60497880e96Schristos 		namlen = MAXPATHLEN;
60597880e96Schristos 	}
6068f7c2b37Sbouyer 
6077052d78bSbouyer 	if (fs2h32(dirp->e2d_ino) != idesc->id_parent)
6088f7c2b37Sbouyer 		return (KEEPON);
60997880e96Schristos 	(void)memcpy(buf, dirp->e2d_name, (size_t)namlen);
61097880e96Schristos 	buf[namlen] = '\0';
6118f7c2b37Sbouyer 	return (STOP|FOUND);
6128f7c2b37Sbouyer }
6138f7c2b37Sbouyer 
6148f7c2b37Sbouyer int
findino(struct inodesc * idesc)615ccde05f0Sxtraeme findino(struct inodesc *idesc)
6168f7c2b37Sbouyer {
6174b836889Slukem 	struct ext2fs_direct *dirp = idesc->id_dirp;
6187052d78bSbouyer 	u_int32_t ino = fs2h32(dirp->e2d_ino);
6198f7c2b37Sbouyer 
6207052d78bSbouyer 	if (ino == 0)
6218f7c2b37Sbouyer 		return (KEEPON);
6228f7c2b37Sbouyer 	if (strcmp(dirp->e2d_name, idesc->id_name) == 0 &&
6237052d78bSbouyer 	    (ino == EXT2_ROOTINO || ino >= EXT2_FIRSTINO)
6247052d78bSbouyer 		&& ino <= maxino) {
6257052d78bSbouyer 		idesc->id_parent = ino;
6268f7c2b37Sbouyer 		return (STOP|FOUND);
6278f7c2b37Sbouyer 	}
6288f7c2b37Sbouyer 	return (KEEPON);
6298f7c2b37Sbouyer }
6308f7c2b37Sbouyer 
6318f7c2b37Sbouyer void
pinode(ino_t ino)632ccde05f0Sxtraeme pinode(ino_t ino)
6338f7c2b37Sbouyer {
6344b836889Slukem 	struct ext2fs_dinode *dp;
6358f7c2b37Sbouyer 	struct passwd *pw;
6366189d5e3Stsutsui 	uid_t uid;
6378f7c2b37Sbouyer 
638c4ee9f6dSchristos 	printf(" I=%llu ", (unsigned long long)ino);
6398f7c2b37Sbouyer 	if ((ino < EXT2_FIRSTINO && ino != EXT2_ROOTINO) || ino > maxino)
6408f7c2b37Sbouyer 		return;
6418f7c2b37Sbouyer 	dp = ginode(ino);
6426189d5e3Stsutsui 	uid = fs2h16(dp->e2di_uid);
6430c5d0100Stsutsui 	if (sblock.e2fs.e2fs_rev > E2FS_REV0)
6440c5d0100Stsutsui 		uid |= fs2h16(dp->e2di_uid_high) << 16;
6458f7c2b37Sbouyer 	printf(" OWNER=");
6468f7c2b37Sbouyer #ifndef SMALL
6476189d5e3Stsutsui 	if (Uflag && (pw = getpwuid(uid)) != 0)
6488f7c2b37Sbouyer 		printf("%s ", pw->pw_name);
6498f7c2b37Sbouyer 	else
6508f7c2b37Sbouyer #endif
6516189d5e3Stsutsui 		printf("%u ", (unsigned int)uid);
6527052d78bSbouyer 	printf("MODE=%o\n", fs2h16(dp->e2di_mode));
6538f7c2b37Sbouyer 	if (preen)
6548f7c2b37Sbouyer 		printf("%s: ", cdevname());
655d53c382dSws 	printf("SIZE=%llu ", (long long)inosize(dp));
656c68c36a5Schristos 	printf("MTIME=%s ", print_mtime(fs2h32(dp->e2di_mtime)));
6578f7c2b37Sbouyer }
6588f7c2b37Sbouyer 
6598f7c2b37Sbouyer void
blkerror(ino_t ino,const char * type,daddr_t blk)660042582c1Schristos blkerror(ino_t ino, const char *type, daddr_t blk)
6618f7c2b37Sbouyer {
6628f7c2b37Sbouyer 
663c4ee9f6dSchristos 	pfatal("%lld %s I=%llu", (long long)blk, type, (unsigned long long)ino);
6648f7c2b37Sbouyer 	printf("\n");
6658f7c2b37Sbouyer 	switch (statemap[ino]) {
6668f7c2b37Sbouyer 
6678f7c2b37Sbouyer 	case FSTATE:
6688f7c2b37Sbouyer 		statemap[ino] = FCLEAR;
6698f7c2b37Sbouyer 		return;
6708f7c2b37Sbouyer 
6718f7c2b37Sbouyer 	case DSTATE:
6728f7c2b37Sbouyer 		statemap[ino] = DCLEAR;
6738f7c2b37Sbouyer 		return;
6748f7c2b37Sbouyer 
6758f7c2b37Sbouyer 	case FCLEAR:
6768f7c2b37Sbouyer 	case DCLEAR:
6778f7c2b37Sbouyer 		return;
6788f7c2b37Sbouyer 
6798f7c2b37Sbouyer 	default:
680481ad7b0Slukem 		errexit("BAD STATE %d TO BLKERR", statemap[ino]);
6818f7c2b37Sbouyer 		/* NOTREACHED */
6828f7c2b37Sbouyer 	}
6838f7c2b37Sbouyer }
6848f7c2b37Sbouyer 
6858f7c2b37Sbouyer /*
6868f7c2b37Sbouyer  * allocate an unused inode
6878f7c2b37Sbouyer  */
6888f7c2b37Sbouyer ino_t
allocino(ino_t request,int type)689ccde05f0Sxtraeme allocino(ino_t request, int type)
6908f7c2b37Sbouyer {
6914b836889Slukem 	ino_t ino;
6924b836889Slukem 	struct ext2fs_dinode *dp;
6938f7c2b37Sbouyer 	time_t t;
6948f7c2b37Sbouyer 
6958f7c2b37Sbouyer 	if (request == 0)
6968f7c2b37Sbouyer 		request = EXT2_ROOTINO;
6978f7c2b37Sbouyer 	else if (statemap[request] != USTATE)
6988f7c2b37Sbouyer 		return (0);
6998f7c2b37Sbouyer 	for (ino = request; ino < maxino; ino++) {
7008f7c2b37Sbouyer 		if ((ino > EXT2_ROOTINO) && (ino < EXT2_FIRSTINO))
7018f7c2b37Sbouyer 			continue;
7028f7c2b37Sbouyer 		if (statemap[ino] == USTATE)
7038f7c2b37Sbouyer 			break;
7048f7c2b37Sbouyer 	}
7058f7c2b37Sbouyer 	if (ino == maxino)
7068f7c2b37Sbouyer 		return (0);
7078f7c2b37Sbouyer 	switch (type & IFMT) {
7088f7c2b37Sbouyer 	case IFDIR:
7098f7c2b37Sbouyer 		statemap[ino] = DSTATE;
7108f7c2b37Sbouyer 		break;
7118f7c2b37Sbouyer 	case IFREG:
7128f7c2b37Sbouyer 	case IFLNK:
7138f7c2b37Sbouyer 		statemap[ino] = FSTATE;
7148f7c2b37Sbouyer 		break;
7158f7c2b37Sbouyer 	default:
7168f7c2b37Sbouyer 		return (0);
7178f7c2b37Sbouyer 	}
7188f7c2b37Sbouyer 	dp = ginode(ino);
7197052d78bSbouyer 	dp->e2di_blocks[0] = h2fs32(allocblk());
7208f7c2b37Sbouyer 	if (dp->e2di_blocks[0] == 0) {
7218f7c2b37Sbouyer 		statemap[ino] = USTATE;
7228f7c2b37Sbouyer 		return (0);
7238f7c2b37Sbouyer 	}
7247052d78bSbouyer 	dp->e2di_mode = h2fs16(type);
7258f7c2b37Sbouyer 	(void)time(&t);
7267052d78bSbouyer 	dp->e2di_atime = h2fs32(t);
7278f7c2b37Sbouyer 	dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime;
7288f7c2b37Sbouyer 	dp->e2di_dtime = 0;
729d53c382dSws 	inossize(dp, sblock.e2fs_bsize);
730a3904b0bSjakllsch 	inosnblock(dp, btodb(sblock.e2fs_bsize));
7318f7c2b37Sbouyer 	n_files++;
7328f7c2b37Sbouyer 	inodirty();
73309d4663fSbouyer 	typemap[ino] = E2IFTODT(type);
7348f7c2b37Sbouyer 	return (ino);
7358f7c2b37Sbouyer }
7368f7c2b37Sbouyer 
7378f7c2b37Sbouyer /*
7388f7c2b37Sbouyer  * deallocate an inode
7398f7c2b37Sbouyer  */
7408f7c2b37Sbouyer void
freeino(ino_t ino)741ccde05f0Sxtraeme freeino(ino_t ino)
7428f7c2b37Sbouyer {
7438f7c2b37Sbouyer 	struct inodesc idesc;
7448f7c2b37Sbouyer 	struct ext2fs_dinode *dp;
7458f7c2b37Sbouyer 
7468f7c2b37Sbouyer 	memset(&idesc, 0, sizeof(struct inodesc));
7478f7c2b37Sbouyer 	idesc.id_type = ADDR;
7488f7c2b37Sbouyer 	idesc.id_func = pass4check;
7498f7c2b37Sbouyer 	idesc.id_number = ino;
7508f7c2b37Sbouyer 	dp = ginode(ino);
7518f7c2b37Sbouyer 	(void)ckinode(dp, &idesc);
7528f7c2b37Sbouyer 	clearinode(dp);
7538f7c2b37Sbouyer 	inodirty();
7548f7c2b37Sbouyer 	statemap[ino] = USTATE;
7558f7c2b37Sbouyer 	n_files--;
7568f7c2b37Sbouyer }
757a3904b0bSjakllsch 
758a3904b0bSjakllsch uint64_t
inonblock(struct ext2fs_dinode * dp)759a3904b0bSjakllsch inonblock(struct ext2fs_dinode *dp)
760a3904b0bSjakllsch {
761a3904b0bSjakllsch 	uint64_t nblock;
762a3904b0bSjakllsch 
763a3904b0bSjakllsch 	/* XXX check for EXT2_HUGE_FILE without EXT2F_ROCOMPAT_HUGE_FILE? */
764a3904b0bSjakllsch 
765a3904b0bSjakllsch 	nblock = fs2h32(dp->e2di_nblock);
766a3904b0bSjakllsch 
767a3904b0bSjakllsch 	if ((sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_HUGE_FILE)) {
768a3904b0bSjakllsch 		nblock |= (uint64_t)fs2h16(dp->e2di_nblock_high) << 32;
769a3904b0bSjakllsch 		if (fs2h32(dp->e2di_flags) & EXT2_HUGE_FILE) {
7702737439dSdholland 			nblock = EXT2_FSBTODB(&sblock, nblock);
771a3904b0bSjakllsch 		}
772a3904b0bSjakllsch 	}
773a3904b0bSjakllsch 
774a3904b0bSjakllsch 	return nblock;
775a3904b0bSjakllsch }
776a3904b0bSjakllsch 
777a3904b0bSjakllsch void
inosnblock(struct ext2fs_dinode * dp,uint64_t nblock)778a3904b0bSjakllsch inosnblock(struct ext2fs_dinode *dp, uint64_t nblock)
779a3904b0bSjakllsch {
780a3904b0bSjakllsch 	uint32_t flags;
781a3904b0bSjakllsch 
782a3904b0bSjakllsch 	flags = fs2h32(dp->e2di_flags);
783a3904b0bSjakllsch 
784a3904b0bSjakllsch 	if (nblock <= 0xffffffffULL) {
785a3904b0bSjakllsch 		flags &= ~EXT2_HUGE_FILE;
786a3904b0bSjakllsch 		dp->e2di_flags = h2fs32(flags);
787a3904b0bSjakllsch 		dp->e2di_nblock = h2fs32(nblock);
788a3904b0bSjakllsch 		return;
789a3904b0bSjakllsch 	}
790a3904b0bSjakllsch 
791a3904b0bSjakllsch 	sethuge();
792a3904b0bSjakllsch 
793a3904b0bSjakllsch 	if (nblock <= 0xffffffffffffULL) {
794a3904b0bSjakllsch 		flags &= ~EXT2_HUGE_FILE;
795a3904b0bSjakllsch 		dp->e2di_flags = h2fs32(flags);
796a3904b0bSjakllsch 		dp->e2di_nblock = h2fs32(nblock);
797a3904b0bSjakllsch 		dp->e2di_nblock_high = h2fs16((nblock >> 32));
798a3904b0bSjakllsch 		return;
799a3904b0bSjakllsch 	}
800a3904b0bSjakllsch 
8012737439dSdholland 	if (EXT2_DBTOFSB(&sblock, nblock) <= 0xffffffffffffULL) {
802a3904b0bSjakllsch 		flags |= EXT2_HUGE_FILE;
803a3904b0bSjakllsch 		dp->e2di_flags = h2fs32(flags);
8042737439dSdholland 		dp->e2di_nblock = h2fs32(EXT2_DBTOFSB(&sblock, nblock));
8052737439dSdholland 		dp->e2di_nblock_high = h2fs16((EXT2_DBTOFSB(&sblock, nblock) >> 32));
806a3904b0bSjakllsch 		return;
807a3904b0bSjakllsch 	}
808a3904b0bSjakllsch 
809a3904b0bSjakllsch 	pfatal("trying to set nblocks higher than representable");
810a3904b0bSjakllsch 
811a3904b0bSjakllsch 	return;
812a3904b0bSjakllsch }
813