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