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