From e723898372517d7a195b4eb18912751f9316ae2e Mon Sep 17 00:00:00 2001 From: Niall O'Higgins Date: Sat, 30 Apr 2005 13:56:17 +0000 Subject: Support checking filesystems which have or once had large files (>4 GB) on them. From NetBSD --- sbin/fsck_ext2fs/dir.c | 16 +++++------ sbin/fsck_ext2fs/extern.h | 5 ++-- sbin/fsck_ext2fs/fsck.h | 4 +-- sbin/fsck_ext2fs/inode.c | 72 +++++++++++++++++++++++++++++++++++++++-------- sbin/fsck_ext2fs/pass1.c | 24 ++++++++-------- sbin/fsck_ext2fs/pass2.c | 8 +++--- sbin/fsck_ext2fs/pass4.c | 4 +-- sbin/fsck_ext2fs/setup.c | 5 +++- 8 files changed, 94 insertions(+), 44 deletions(-) diff --git a/sbin/fsck_ext2fs/dir.c b/sbin/fsck_ext2fs/dir.c index b67261ba0ec..d6790e5dfdf 100644 --- a/sbin/fsck_ext2fs/dir.c +++ b/sbin/fsck_ext2fs/dir.c @@ -1,4 +1,4 @@ -/* $OpenBSD: dir.c,v 1.12 2003/07/29 18:38:35 deraadt Exp $ */ +/* $OpenBSD: dir.c,v 1.13 2005/04/30 13:56:15 niallo Exp $ */ /* $NetBSD: dir.c,v 1.5 2000/01/28 16:01:46 bouyer Exp $ */ /* @@ -363,7 +363,7 @@ linkup(ino_t orphan, ino_t parentdir) lostdir = (fs2h16(dp->e2di_mode) & IFMT) == IFDIR; pwarn("UNREF %s ", lostdir ? "DIR" : "FILE"); pinode(orphan); - if (preen && fs2h32(dp->e2di_size) == 0) + if (preen && inosize(dp) == 0) return (0); if (preen) printf(" (RECONNECTED)\n"); @@ -491,9 +491,8 @@ makeentry(ino_t parent, ino_t ino, char *name) idesc.id_fix = DONTKNOW; idesc.id_name = name; dp = ginode(parent); - if (fs2h32(dp->e2di_size) % sblock.e2fs_bsize) { - dp->e2di_size = - h2fs32(roundup(fs2h32(dp->e2di_size), sblock.e2fs_bsize)); + if (inosize(dp) % sblock.e2fs_bsize) { + inossize(dp, roundup(inosize(dp), sblock.e2fs_bsize)); inodirty(); } if ((ckinode(dp, &idesc) & ALTERED) != 0) @@ -520,15 +519,15 @@ expanddir(struct ext2fs_dinode *dp, char *name) exit(8); } - lastbn = lblkno(&sblock, fs2h32(dp->e2di_size)); + lastbn = lblkno(&sblock, inosize(dp)); if (lastbn >= NDADDR - 1 || fs2h32(dp->e2di_blocks[lastbn]) == 0 || - fs2h32(dp->e2di_size) == 0) + inosize(dp) == 0) return (0); if ((newblk = allocblk()) == 0) return (0); dp->e2di_blocks[lastbn + 1] = dp->e2di_blocks[lastbn]; dp->e2di_blocks[lastbn] = h2fs32(newblk); - dp->e2di_size = h2fs32(fs2h32(dp->e2di_size) + sblock.e2fs_bsize); + inossize(dp, inosize(dp) + sblock.e2fs_bsize); dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) + 1); bp = getdirblk(fs2h32(dp->e2di_blocks[lastbn + 1]), sblock.e2fs_bsize); @@ -558,6 +557,7 @@ bad: dp->e2di_blocks[lastbn] = dp->e2di_blocks[lastbn + 1]; dp->e2di_blocks[lastbn + 1] = 0; dp->e2di_size = h2fs32(fs2h32(dp->e2di_size) - sblock.e2fs_bsize); + inossize(dp, inosize(dp) - sblock.e2fs_bsize); dp->e2di_nblock = h2fs32(fs2h32(dp->e2di_nblock) - 1); freeblk(newblk); return (0); diff --git a/sbin/fsck_ext2fs/extern.h b/sbin/fsck_ext2fs/extern.h index 82f4f70f855..091af9875d7 100644 --- a/sbin/fsck_ext2fs/extern.h +++ b/sbin/fsck_ext2fs/extern.h @@ -1,4 +1,4 @@ -/* $OpenBSD: extern.h,v 1.5 2003/04/17 06:48:47 tedu Exp $ */ +/* $OpenBSD: extern.h,v 1.6 2005/04/30 13:56:16 niallo Exp $ */ /* $NetBSD: extern.h,v 1.1 1997/06/11 11:21:46 bouyer Exp $ */ /* @@ -35,7 +35,6 @@ void bufinit(void); void bwrite(int, char *, daddr_t, long); void cacheino(struct ext2fs_dinode *, ino_t); int changeino(ino_t, char *, ino_t); -struct fstab; int chkrange(daddr_t, int); void ckfini(int); int ckinode(struct ext2fs_dinode *, struct inodesc *); @@ -55,6 +54,8 @@ int ftypeok(struct ext2fs_dinode *); void getpathname(char *, size_t, ino_t, ino_t); void inocleanup(void); void inodirty(void); +u_int64_t inosize(struct ext2fs_dinode *); +void inossize(struct ext2fs_dinode *, u_int64_t); int linkup(ino_t, ino_t); int makeentry(ino_t, ino_t, char *); void pass1(void); diff --git a/sbin/fsck_ext2fs/fsck.h b/sbin/fsck_ext2fs/fsck.h index f01bb88b8d9..88a54cd1f6c 100644 --- a/sbin/fsck_ext2fs/fsck.h +++ b/sbin/fsck_ext2fs/fsck.h @@ -1,4 +1,4 @@ -/* $OpenBSD: fsck.h,v 1.8 2003/06/02 20:06:15 millert Exp $ */ +/* $OpenBSD: fsck.h,v 1.9 2005/04/30 13:56:16 niallo Exp $ */ /* $NetBSD: fsck.h,v 1.1 1997/06/11 11:21:47 bouyer Exp $ */ /* @@ -155,7 +155,7 @@ struct inoinfo { ino_t i_number; /* inode number of this entry */ ino_t i_parent; /* inode number of parent */ ino_t i_dotdot; /* inode number of `..' */ - size_t i_isize; /* size of inode */ + u_int64_t i_isize; /* size of inode */ u_int i_numblks; /* size of block array in bytes */ daddr_t i_blks[1]; /* actually longer */ } **inphead, **inpsort; diff --git a/sbin/fsck_ext2fs/inode.c b/sbin/fsck_ext2fs/inode.c index 1b6fa1ac251..69c34bcfbc2 100644 --- a/sbin/fsck_ext2fs/inode.c +++ b/sbin/fsck_ext2fs/inode.c @@ -1,4 +1,4 @@ -/* $OpenBSD: inode.c,v 1.14 2003/07/29 18:38:35 deraadt Exp $ */ +/* $OpenBSD: inode.c,v 1.15 2005/04/30 13:56:16 niallo Exp $ */ /* $NetBSD: inode.c,v 1.8 2000/01/28 16:01:46 bouyer Exp $ */ /* @@ -62,6 +62,53 @@ static ino_t startinum; static int iblock(struct inodesc *, long, u_int64_t); +static int setlarge(void); + +static int +setlarge(void) +{ + if (sblock.e2fs.e2fs_rev < E2FS_REV1) { + pfatal("LARGE FILES UNSUPPORTED ON REVISION 0 FILESYSTEMS"); + return 0; + } + if (!(sblock.e2fs.e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE)) { + if (preen) + pwarn("SETTING LARGE FILE INDICATOR\n"); + else if (!reply("SET LARGE FILE INDICATOR")) + return 0; + sblock.e2fs.e2fs_features_rocompat |= EXT2F_ROCOMPAT_LARGEFILE; + sbdirty(); + } + return 1; +} + +u_int64_t +inosize(struct ext2fs_dinode *dp) +{ + u_int64_t size = fs2h32(dp->e2di_size); + + if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG) + size |= (u_int64_t)fs2h32(dp->e2di_dacl) << 32; + if (size >= 0x80000000U) + (void)setlarge(); + return size; +} + +void +inossize(struct ext2fs_dinode *dp, u_int64_t size) +{ + if ((fs2h16(dp->e2di_mode) & IFMT) == IFREG) { + dp->e2di_dacl = h2fs32(size >> 32); + if (size >= 0x80000000U) + if (!setlarge()) + return; + } else if (size >= 0x80000000U) { + pfatal("TRYING TO SET FILESIZE TO %llu ON MODE %x FILE\n", + (unsigned long long)size, fs2h16(dp->e2di_mode) & IFMT); + return; + } + dp->e2di_size = h2fs32(size); +} int ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc) @@ -76,13 +123,13 @@ ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc) if (idesc->id_fix != IGNORE) idesc->id_fix = DONTKNOW; idesc->id_entryno = 0; - idesc->id_filesize = fs2h32(dp->e2di_size); + idesc->id_filesize = inosize(dp); mode = fs2h16(dp->e2di_mode) & IFMT; if (mode == IFBLK || mode == IFCHR || mode == IFIFO || - (mode == IFLNK && (fs2h32(dp->e2di_size) < EXT2_MAXSYMLINKLEN))) + (mode == IFLNK && (inosize(dp) < EXT2_MAXSYMLINKLEN))) return (KEEPON); dino = *dp; - ndb = howmany(fs2h32(dino.e2di_size), sblock.e2fs_bsize); + ndb = howmany(inosize(&dino), sblock.e2fs_bsize); for (ap = &dino.e2di_blocks[0]; ap < &dino.e2di_blocks[NDADDR]; ap++,ndb--) { idesc->id_numfrags = 1; @@ -95,7 +142,8 @@ ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc) pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); - dp->e2di_size = h2fs32((ap - &dino.e2di_blocks[0]) * + inossize(dp, + (ap - &dino.e2di_blocks[0]) * sblock.e2fs_bsize); printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); @@ -114,7 +162,7 @@ ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc) return (ret); } idesc->id_numfrags = 1; - remsize = fs2h32(dino.e2di_size) - sblock.e2fs_bsize * NDADDR; + remsize = inosize(&dino) - sblock.e2fs_bsize * NDADDR; sizepb = sblock.e2fs_bsize; for (ap = &dino.e2di_blocks[NDADDR], n = 1; n <= NIADDR; ap++, n++) { if (*ap) { @@ -131,7 +179,7 @@ ckinode(struct ext2fs_dinode *dp, struct inodesc *idesc) pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); - dp->e2di_size = h2fs32(fs2h32(dp->e2di_size) - remsize); + inossize(dp, inosize(dp) - remsize); remsize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); @@ -211,7 +259,7 @@ iblock(struct inodesc *idesc, long ilevel, u_int64_t isize) pathbuf); if (reply("ADJUST LENGTH") == 1) { dp = ginode(idesc->id_number); - dp->e2di_size = h2fs32(fs2h32(dp->e2di_size) - isize); + inossize(dp, inosize(dp) - isize); isize = 0; printf( "YOU MUST RERUN FSCK AFTERWARDS\n"); @@ -377,7 +425,7 @@ cacheino(struct ext2fs_dinode *dp, ino_t inumber) struct inoinfo **inpp; unsigned int blks; - blks = howmany(fs2h32(dp->e2di_size), sblock.e2fs_bsize); + blks = howmany(inosize(dp), sblock.e2fs_bsize); if (blks > NDADDR) blks = NDADDR + NIADDR; inp = (struct inoinfo *) @@ -394,7 +442,7 @@ cacheino(struct ext2fs_dinode *dp, ino_t inumber) inp->i_parent = (ino_t)0; inp->i_dotdot = (ino_t)0; inp->i_number = inumber; - inp->i_isize = fs2h32(dp->e2di_size); + inp->i_isize = inosize(dp); inp->i_numblks = blks * sizeof(daddr_t); memcpy(&inp->i_blks[0], &dp->e2di_blocks[0], (size_t)inp->i_numblks); if (inplast == listmax) { @@ -522,7 +570,7 @@ pinode(ino_t ino) printf("MODE=%o\n", fs2h16(dp->e2di_mode)); if (preen) printf("%s: ", cdevname()); - printf("SIZE=%u ", fs2h32(dp->e2di_size)); + printf("SIZE=%llu ", (long long)inosize(dp)); t = fs2h32(dp->e2di_mtime); p = ctime(&t); printf("MTIME=%12.12s %4.4s ", &p[4], &p[20]); @@ -598,7 +646,7 @@ allocino(ino_t request, int type) dp->e2di_atime = h2fs32(t); dp->e2di_mtime = dp->e2di_ctime = dp->e2di_atime; dp->e2di_dtime = 0; - dp->e2di_size = h2fs32(sblock.e2fs_bsize); + inossize(dp, sblock.e2fs_bsize); dp->e2di_nblock = h2fs32(btodb(sblock.e2fs_bsize)); n_files++; inodirty(); diff --git a/sbin/fsck_ext2fs/pass1.c b/sbin/fsck_ext2fs/pass1.c index 15805efc916..e32a79030eb 100644 --- a/sbin/fsck_ext2fs/pass1.c +++ b/sbin/fsck_ext2fs/pass1.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pass1.c,v 1.10 2003/06/11 06:22:13 deraadt Exp $ */ +/* $OpenBSD: pass1.c,v 1.11 2005/04/30 13:56:16 niallo Exp $ */ /* $NetBSD: pass1.c,v 1.9 2000/01/31 11:40:12 bouyer Exp $ */ /* @@ -135,7 +135,7 @@ checkinode(ino_t inumber, struct inodesc *idesc) if (mode == 0 && ( memcmp(dp->e2di_blocks, zino.e2di_blocks, (NDADDR + NIADDR) * sizeof(u_int32_t)) || - dp->e2di_mode || dp->e2di_size)) { + dp->e2di_mode || inosize(dp))) { pfatal("PARTIALLY ALLOCATED INODE I=%u", inumber); if (reply("CLEAR") == 1) { dp = ginode(inumber); @@ -175,24 +175,22 @@ checkinode(ino_t inumber, struct inodesc *idesc) inodirty(); } } - if (/* dp->di_size < 0 || */ - fs2h32(dp->e2di_size) + sblock.e2fs_bsize - 1 < - fs2h32(dp->e2di_size)) { + if (inosize(dp) + sblock.e2fs_bsize - 1 < inosize(dp)) { if (debug) - printf("bad size %lu:", (u_long)fs2h32(dp->e2di_size)); + printf("bad size %llu:", (unsigned long long)inosize(dp)); goto unknown; } if (!preen && mode == IFMT && reply("HOLD BAD BLOCK") == 1) { dp = ginode(inumber); - dp->e2di_size = h2fs32(sblock.e2fs_bsize); dp->e2di_mode = h2fs16(IFREG|0600); + inossize(dp, sblock.e2fs_bsize); inodirty(); } - ndb = howmany(fs2h32(dp->e2di_size), sblock.e2fs_bsize); + ndb = howmany(inosize(dp), sblock.e2fs_bsize); if (ndb < 0) { if (debug) - printf("bad size %lu ndb %d:", - (u_long)fs2h32(dp->e2di_size), ndb); + printf("bad size %llu ndb %d:", + (unsigned long long)inosize(dp), ndb); goto unknown; } if (mode == IFBLK || mode == IFCHR) @@ -202,9 +200,9 @@ checkinode(ino_t inumber, struct inodesc *idesc) * Fake ndb value so direct/indirect block checks below * will detect any garbage after symlink string. */ - if (fs2h32(dp->e2di_size) < EXT2_MAXSYMLINKLEN || + if (inosize(dp) < EXT2_MAXSYMLINKLEN || (EXT2_MAXSYMLINKLEN == 0 && dp->e2di_blocks == 0)) { - ndb = howmany(fs2h32(dp->e2di_size), sizeof(u_int32_t)); + ndb = howmany(inosize(dp), sizeof(u_int32_t)); if (ndb > NDADDR) { j = ndb - NDADDR; for (ndb = 1; j > 1; j--) @@ -250,7 +248,7 @@ checkinode(ino_t inumber, struct inodesc *idesc) } } if (mode == IFDIR) { - if (dp->e2di_size == 0) + if (inosize(dp) == 0) statemap[inumber] = DCLEAR; else statemap[inumber] = DSTATE; diff --git a/sbin/fsck_ext2fs/pass2.c b/sbin/fsck_ext2fs/pass2.c index 5dc7fcd5892..828726978f1 100644 --- a/sbin/fsck_ext2fs/pass2.c +++ b/sbin/fsck_ext2fs/pass2.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pass2.c,v 1.10 2003/06/11 06:22:13 deraadt Exp $ */ +/* $OpenBSD: pass2.c,v 1.11 2005/04/30 13:56:16 niallo Exp $ */ /* $NetBSD: pass2.c,v 1.6 2000/01/28 16:01:46 bouyer Exp $ */ /* @@ -127,7 +127,7 @@ pass2(void) inp->i_isize = roundup(MINDIRSIZE, sblock.e2fs_bsize); if (reply("FIX") == 1) { dp = ginode(inp->i_number); - dp->e2di_size = h2fs32(inp->i_isize); + inossize(dp, inp->i_isize); inodirty(); } } else if ((inp->i_isize & (sblock.e2fs_bsize - 1)) != 0) { @@ -140,13 +140,13 @@ pass2(void) inp->i_isize = roundup(inp->i_isize, sblock.e2fs_bsize); if (preen || reply("ADJUST") == 1) { dp = ginode(inp->i_number); - dp->e2di_size = h2fs32(inp->i_isize); + inossize(dp, inp->i_isize); inodirty(); } } memset(&dino, 0, sizeof(struct ext2fs_dinode)); dino.e2di_mode = h2fs16(IFDIR); - dino.e2di_size = h2fs32(inp->i_isize); + inossize(&dino, inp->i_isize); memcpy(&dino.e2di_blocks[0], &inp->i_blks[0], (size_t)inp->i_numblks); curino.id_number = inp->i_number; curino.id_parent = inp->i_parent; diff --git a/sbin/fsck_ext2fs/pass4.c b/sbin/fsck_ext2fs/pass4.c index 8cb0edff0ba..6c363d268c9 100644 --- a/sbin/fsck_ext2fs/pass4.c +++ b/sbin/fsck_ext2fs/pass4.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pass4.c,v 1.6 2003/06/11 06:22:13 deraadt Exp $ */ +/* $OpenBSD: pass4.c,v 1.7 2005/04/30 13:56:16 niallo Exp $ */ /* $NetBSD: pass4.c,v 1.2 1997/09/14 14:27:29 lukem Exp $ */ /* @@ -84,7 +84,7 @@ pass4(void) case DCLEAR: dp = ginode(inumber); - if (dp->e2di_size == 0) { + if (inosize(dp) == 0) { clri(&idesc, "ZERO LENGTH", 1); break; } diff --git a/sbin/fsck_ext2fs/setup.c b/sbin/fsck_ext2fs/setup.c index 5156cdf29d6..7a3767982bf 100644 --- a/sbin/fsck_ext2fs/setup.c +++ b/sbin/fsck_ext2fs/setup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: setup.c,v 1.12 2003/07/29 18:38:35 deraadt Exp $ */ +/* $OpenBSD: setup.c,v 1.13 2005/04/30 13:56:16 niallo Exp $ */ /* $NetBSD: setup.c,v 1.1 1997/06/11 11:22:01 bouyer Exp $ */ /* @@ -326,6 +326,9 @@ readsb(int listerr) asblk.b_un.b_fs->e2fs_rgid = sblk.b_un.b_fs->e2fs_rgid; asblk.b_un.b_fs->e2fs_block_group_nr = sblk.b_un.b_fs->e2fs_block_group_nr; + asblk.b_un.b_fs->e2fs_features_rocompat &= ~EXT2F_ROCOMPAT_LARGEFILE; + asblk.b_un.b_fs->e2fs_features_rocompat |= + sblk.b_un.b_fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE; if (sblock.e2fs.e2fs_rev > E2FS_REV0 && ((sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP) || (sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP))) { -- cgit v1.2.3