From 3056d54cc1c1b18a91aa50088819cb0d350b3aca Mon Sep 17 00:00:00 2001 From: Pete Batard Date: Sat, 9 Jan 2021 16:14:14 +0000 Subject: [PATCH] [ext2fs] update ext2fs to latest * Also drop nt_io_manager() as a function call and just use a direct ref to the manager. --- .vs/ext2fs.vcxproj | 1 + .vs/ext2fs.vcxproj.filters | 3 + src/ext2fs/Makefile.am | 6 +- src/ext2fs/Makefile.in | 14 +- src/ext2fs/blknum.c | 53 +++- src/ext2fs/closefs.c | 29 +- src/ext2fs/csum.c | 76 +++-- src/ext2fs/dirhash.c | 307 +++++++++++++++++++++ src/ext2fs/ext2_err.h | 1 + src/ext2fs/ext2_fs.h | 36 +-- src/ext2fs/ext2fs.h | 67 ++++- src/ext2fs/ext2fsP.h | 14 + src/ext2fs/ext_attr.c | 5 +- src/ext2fs/fallocate.c | 28 +- src/ext2fs/gen_bitmap64.c | 54 +++- src/ext2fs/hashmap.c | 16 ++ src/ext2fs/hashmap.h | 30 +- src/ext2fs/initialize.c | 3 + src/ext2fs/inode.c | 11 +- src/ext2fs/jfs_compat.h | 16 +- src/ext2fs/kernel-jbd.h | 245 ++++++++--------- src/ext2fs/link.c | 550 +++++++++++++++++++++++++++++++++---- src/ext2fs/mkdir.c | 22 +- src/ext2fs/mkjournal.c | 16 +- src/ext2fs/mmp.c | 15 +- src/ext2fs/nt_io.c | 9 +- src/ext2fs/openfs.c | 21 +- src/ext2fs/rw_bitmaps.c | 46 +++- src/ext2fs/symlink.c | 22 +- src/format_ext.c | 8 +- src/rufus.rc | 10 +- 31 files changed, 1365 insertions(+), 369 deletions(-) create mode 100644 src/ext2fs/dirhash.c diff --git a/.vs/ext2fs.vcxproj b/.vs/ext2fs.vcxproj index ebe693a4..2d7a4565 100644 --- a/.vs/ext2fs.vcxproj +++ b/.vs/ext2fs.vcxproj @@ -53,6 +53,7 @@ + diff --git a/.vs/ext2fs.vcxproj.filters b/.vs/ext2fs.vcxproj.filters index 19ec661e..3175862a 100644 --- a/.vs/ext2fs.vcxproj.filters +++ b/.vs/ext2fs.vcxproj.filters @@ -162,6 +162,9 @@ Source Files + + Source Files + diff --git a/src/ext2fs/Makefile.am b/src/ext2fs/Makefile.am index 3730e481..27a628d9 100644 --- a/src/ext2fs/Makefile.am +++ b/src/ext2fs/Makefile.am @@ -1,8 +1,8 @@ noinst_LIBRARIES = libext2fs.a -libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c \ - bitmaps.c bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c \ - crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c \ +libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c bitmaps.c \ + bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c crc32c.c \ + csum.c dirblock.c dirhash.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c \ freefs.c gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c \ inline.c inline_data.c inode.c io_manager.c link.c lookup.c mkdir.c mkjournal.c namei.c mmp.c \ newdir.c nt_io.c openfs.c punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c diff --git a/src/ext2fs/Makefile.in b/src/ext2fs/Makefile.in index 52b00dc4..e9e7270e 100644 --- a/src/ext2fs/Makefile.in +++ b/src/ext2fs/Makefile.in @@ -104,7 +104,7 @@ am_libext2fs_a_OBJECTS = libext2fs_a-alloc.$(OBJEXT) \ libext2fs_a-block.$(OBJEXT) libext2fs_a-bmap.$(OBJEXT) \ libext2fs_a-closefs.$(OBJEXT) libext2fs_a-crc16.$(OBJEXT) \ libext2fs_a-crc32c.$(OBJEXT) libext2fs_a-csum.$(OBJEXT) \ - libext2fs_a-dirblock.$(OBJEXT) \ + libext2fs_a-dirblock.$(OBJEXT) libext2fs_a-dirhash.$(OBJEXT) \ libext2fs_a-dir_iterate.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \ libext2fs_a-ext_attr.$(OBJEXT) libext2fs_a-extent.$(OBJEXT) \ libext2fs_a-fallocate.$(OBJEXT) libext2fs_a-fileio.$(OBJEXT) \ @@ -271,9 +271,9 @@ top_build_prefix = @top_build_prefix@ top_builddir = @top_builddir@ top_srcdir = @top_srcdir@ noinst_LIBRARIES = libext2fs.a -libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c \ - bitmaps.c bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c \ - crc32c.c csum.c dirblock.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c \ +libext2fs_a_SOURCES = alloc.c alloc_sb.c alloc_stats.c alloc_tables.c badblocks.c bb_inode.c bitmaps.c \ + bitops.c blkmap64_ba.c blkmap64_rb.c blknum.c block.c bmap.c closefs.c crc16.c crc32c.c \ + csum.c dirblock.c dirhash.c dir_iterate.c extent.c ext_attr.c extent.c fallocate.c fileio.c \ freefs.c gen_bitmap.c gen_bitmap64.c get_num_dirs.c hashmap.c i_block.c ind_block.c initialize.c \ inline.c inline_data.c inode.c io_manager.c link.c lookup.c mkdir.c mkjournal.c namei.c mmp.c \ newdir.c nt_io.c openfs.c punch.c rbtree.c read_bb.c rw_bitmaps.c sha512.c symlink.c valid_blk.c @@ -442,6 +442,12 @@ libext2fs_a-dirblock.o: dirblock.c libext2fs_a-dirblock.obj: dirblock.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-dirblock.obj `if test -f 'dirblock.c'; then $(CYGPATH_W) 'dirblock.c'; else $(CYGPATH_W) '$(srcdir)/dirblock.c'; fi` +libext2fs_a-dirhash.o: dirhash.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-dirhash.o `test -f 'dirhash.c' || echo '$(srcdir)/'`dirhash.c + +libext2fs_a-dirhash.obj: dirhash.c + $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-dirhash.obj `if test -f 'dirhash.c'; then $(CYGPATH_W) 'dirhash.c'; else $(CYGPATH_W) '$(srcdir)/dirhash.c'; fi` + libext2fs_a-dir_iterate.o: dir_iterate.c $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libext2fs_a_CFLAGS) $(CFLAGS) -c -o libext2fs_a-dir_iterate.o `test -f 'dir_iterate.c' || echo '$(srcdir)/'`dir_iterate.c diff --git a/src/ext2fs/blknum.c b/src/ext2fs/blknum.c index 9ee5c66e..30440dd5 100644 --- a/src/ext2fs/blknum.c +++ b/src/ext2fs/blknum.c @@ -85,6 +85,22 @@ blk64_t ext2fs_inode_i_blocks(ext2_filsys fs, (__u64)inode->osd2.linux2.l_i_blocks_hi << 32 : 0)); } +/* + * Return the inode i_blocks in stat (512 byte) units + */ +blk64_t ext2fs_get_stat_i_blocks(ext2_filsys fs, + struct ext2_inode *inode) +{ + blk64_t ret = inode->i_blocks; + + if (ext2fs_has_feature_huge_file(fs->super)) { + ret += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32; + if (inode->i_flags & EXT4_HUGE_FILE_FL) + ret *= (fs->blocksize / 512); + } + return ret; +} + /* * Return the fs block count */ @@ -185,9 +201,42 @@ struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs, struct opaque_ext2_group_desc *gdp, dgrp_t group) { - int desc_size = EXT2_DESC_SIZE(fs->super) & ~7; + struct ext2_group_desc *ret_gdp; + errcode_t retval; + static char *buf = 0; + static int bufsize = 0; + blk64_t blk; + int desc_size = EXT2_DESC_SIZE(fs->super) & ~7; + int desc_per_blk = EXT2_DESC_PER_BLOCK(fs->super); - return (struct ext2_group_desc *)((char *)gdp + group * desc_size); + if (group > fs->group_desc_count) + return NULL; + if (gdp) + return (struct ext2_group_desc *)((char *)gdp + + group * desc_size); + /* + * If fs->group_desc wasn't read in when the file system was + * opened, then read it on demand here. + */ + if (bufsize < fs->blocksize) + ext2fs_free_mem(&buf); + if (!buf) { + retval = ext2fs_get_mem(fs->blocksize, &buf); + if (retval) + return NULL; + bufsize = fs->blocksize; + } + blk = ext2fs_descriptor_block_loc2(fs, fs->super->s_first_data_block, + group / desc_per_blk); + retval = io_channel_read_blk(fs->io, blk, 1, buf); + if (retval) + return NULL; + ret_gdp = (struct ext2_group_desc *) + (buf + ((group % desc_per_blk) * desc_size)); +#ifdef WORDS_BIGENDIAN + ext2fs_swap_group_desc2(fs, ret_gdp); +#endif + return ret_gdp; } /* Do the same but as an ext4 group desc for internal use here */ diff --git a/src/ext2fs/closefs.c b/src/ext2fs/closefs.c index 997be80b..971a8fc0 100644 --- a/src/ext2fs/closefs.c +++ b/src/ext2fs/closefs.c @@ -293,6 +293,11 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags) EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); + if ((fs->flags & EXT2_FLAG_SUPER_ONLY) == 0 && + !ext2fs_has_feature_journal_dev(fs->super) && + fs->group_desc == NULL) + return EXT2_ET_NO_GDESC; + fs_state = fs->super->s_state; feature_incompat = fs->super->s_feature_incompat; @@ -326,20 +331,24 @@ errcode_t ext2fs_flush2(ext2_filsys fs, int flags) #ifdef WORDS_BIGENDIAN retval = EXT2_ET_NO_MEMORY; retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow); - if (retval) - goto errout; - retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, - &group_shadow); if (retval) goto errout; memcpy(super_shadow, fs->super, sizeof(struct ext2_super_block)); - memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize * - fs->desc_blocks); - ext2fs_swap_super(super_shadow); - for (j = 0; j < fs->group_desc_count; j++) { - gdp = ext2fs_group_desc(fs, group_shadow, j); - ext2fs_swap_group_desc2(fs, gdp); + + if (((fs->flags & EXT2_FLAG_SUPER_ONLY) == 0) && + !ext2fs_has_feature_journal_dev(fs->super)) { + retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, + &group_shadow); + if (retval) + goto errout; + memcpy(group_shadow, fs->group_desc, (size_t) fs->blocksize * + fs->desc_blocks); + + for (j = 0; j < fs->group_desc_count; j++) { + gdp = ext2fs_group_desc(fs, group_shadow, j); + ext2fs_swap_group_desc2(fs, gdp); + } } #else super_shadow = fs->super; diff --git a/src/ext2fs/csum.c b/src/ext2fs/csum.c index 98236137..86184b68 100644 --- a/src/ext2fs/csum.c +++ b/src/ext2fs/csum.c @@ -266,14 +266,15 @@ static errcode_t __get_dirent_tail(ext2_filsys fs, d = dirent; top = EXT2_DIRENT_TAIL(dirent, fs->blocksize); - rec_len = translate(d->rec_len); - while (rec_len && !(rec_len & 0x3)) { - d = (struct ext2_dir_entry *)(((char *)d) + rec_len); - if ((void *)d >= top) - break; + while ((void *) d < top) { rec_len = translate(d->rec_len); + if ((rec_len < 8) || (rec_len & 0x03)) + return EXT2_ET_DIR_CORRUPTED; + d = (struct ext2_dir_entry *)(((char *)d) + rec_len); } + if ((char *)d > ((char *)dirent + fs->blocksize)) + return EXT2_ET_DIR_CORRUPTED; if (d != top) return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; @@ -290,7 +291,8 @@ static errcode_t __get_dirent_tail(ext2_filsys fs, int ext2fs_dirent_has_tail(ext2_filsys fs, struct ext2_dir_entry *dirent) { - return __get_dirent_tail(fs, dirent, NULL, 0) == 0; + return __get_dirent_tail(fs, dirent, NULL, 0) != + EXT2_ET_DIR_NO_SPACE_FOR_CSUM; } static errcode_t ext2fs_dirent_csum(ext2_filsys fs, ext2_ino_t inum, @@ -358,20 +360,31 @@ static errcode_t ext2fs_dirent_csum_set(ext2_filsys fs, ext2_ino_t inum, return 0; } -static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum, - struct ext2_dir_entry *dirent, - __u32 *crc, int count_offset, int count, - struct ext2_dx_tail *t) +errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent, + __u32 *crc, struct ext2_dx_tail **ret_t) { errcode_t retval; char *buf = (char *)dirent; int size; - __u32 old_csum, gen; + __u32 gen, dummy_csum = 0; struct ext2_inode inode; + struct ext2_dx_tail *t; + struct ext2_dx_countlimit *c; + int count_offset, limit, count; + + retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1); + if (retval) + return retval; + limit = ext2fs_le16_to_cpu(c->limit); + count = ext2fs_le16_to_cpu(c->count); + if (count_offset + (limit * sizeof(struct ext2_dx_entry)) > + fs->blocksize - sizeof(struct ext2_dx_tail)) + return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; + /* htree structs are accessed in LE order */ + t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit); size = count_offset + (count * sizeof(struct ext2_dx_entry)); - old_csum = t->dt_checksum; - t->dt_checksum = 0; retval = ext2fs_read_inode(fs, inum, &inode); if (retval) @@ -383,10 +396,11 @@ static errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum, sizeof(inum)); *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&gen, sizeof(gen)); *crc = ext2fs_crc32c_le(*crc, (unsigned char *)buf, size); - *crc = ext2fs_crc32c_le(*crc, (unsigned char *)t, - sizeof(struct ext2_dx_tail)); - t->dt_checksum = old_csum; + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)t, 4); + *crc = ext2fs_crc32c_le(*crc, (unsigned char *)&dummy_csum, 4); + if (ret_t) + *ret_t = t; return 0; } @@ -395,22 +409,9 @@ static int ext2fs_dx_csum_verify(ext2_filsys fs, ext2_ino_t inum, { __u32 calculated; errcode_t retval; - struct ext2_dx_countlimit *c; struct ext2_dx_tail *t; - int count_offset, limit, count; - retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1); - if (retval) - return 1; - limit = ext2fs_le16_to_cpu(c->limit); - count = ext2fs_le16_to_cpu(c->count); - if (count_offset + (limit * sizeof(struct ext2_dx_entry)) > - fs->blocksize - sizeof(struct ext2_dx_tail)) - return 0; - /* htree structs are accessed in LE order */ - t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit); - retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, count_offset, - count, t); + retval = ext2fs_dx_csum(fs, inum, dirent, &calculated, &t); if (retval) return 0; @@ -422,22 +423,9 @@ static errcode_t ext2fs_dx_csum_set(ext2_filsys fs, ext2_ino_t inum, { __u32 crc; errcode_t retval = 0; - struct ext2_dx_countlimit *c; struct ext2_dx_tail *t; - int count_offset, limit, count; - retval = __get_dx_countlimit(fs, dirent, &c, &count_offset, 1); - if (retval) - return retval; - limit = ext2fs_le16_to_cpu(c->limit); - count = ext2fs_le16_to_cpu(c->count); - if (count_offset + (limit * sizeof(struct ext2_dx_entry)) > - fs->blocksize - sizeof(struct ext2_dx_tail)) - return EXT2_ET_DIR_NO_SPACE_FOR_CSUM; - t = (struct ext2_dx_tail *)(((struct ext2_dx_entry *)c) + limit); - - /* htree structs are accessed in LE order */ - retval = ext2fs_dx_csum(fs, inum, dirent, &crc, count_offset, count, t); + retval = ext2fs_dx_csum(fs, inum, dirent, &crc, &t); if (retval) return retval; t->dt_checksum = ext2fs_cpu_to_le32(crc); diff --git a/src/ext2fs/dirhash.c b/src/ext2fs/dirhash.c new file mode 100644 index 00000000..42fe98bb --- /dev/null +++ b/src/ext2fs/dirhash.c @@ -0,0 +1,307 @@ +/* + * dirhash.c -- Calculate the hash of a directory entry + * + * Copyright (c) 2001 Daniel Phillips + * + * Copyright (c) 2002 Theodore Ts'o. + * + * %Begin-Header% + * This file may be redistributed under the terms of the GNU Library + * General Public License, version 2. + * %End-Header% + */ + +#include "config.h" +#include +#include +#include + +#include "ext2_fs.h" +#include "ext2fs.h" +#include "ext2fsP.h" + +#ifndef PATH_MAX +#define PATH_MAX 4096 +#endif + +/* + * Keyed 32-bit hash function using TEA in a Davis-Meyer function + * H0 = Key + * Hi = E Mi(Hi-1) + Hi-1 + * + * (see Applied Cryptography, 2nd edition, p448). + * + * Jeremy Fitzhardinge 1998 + * + * This code is made available under the terms of the GPL + */ +#define DELTA 0x9E3779B9 + +static void TEA_transform(__u32 buf[4], __u32 const in[]) +{ + __u32 sum = 0; + __u32 b0 = buf[0], b1 = buf[1]; + __u32 a = in[0], b = in[1], c = in[2], d = in[3]; + int n = 16; + + do { + sum += DELTA; + b0 += ((b1 << 4)+a) ^ (b1+sum) ^ ((b1 >> 5)+b); + b1 += ((b0 << 4)+c) ^ (b0+sum) ^ ((b0 >> 5)+d); + } while(--n); + + buf[0] += b0; + buf[1] += b1; +} + +/* F, G and H are basic MD4 functions: selection, majority, parity */ +#define F(x, y, z) ((z) ^ ((x) & ((y) ^ (z)))) +#define G(x, y, z) (((x) & (y)) + (((x) ^ (y)) & (z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) + +/* + * The generic round function. The application is so specific that + * we don't bother protecting all the arguments with parens, as is generally + * good macro practice, in favor of extra legibility. + * Rotation is separate from addition to prevent recomputation + */ +#define ROUND(f, a, b, c, d, x, s) \ + (a += f(b, c, d) + x, a = (a << s) | (a >> (32-s))) +#define K1 0 +#define K2 013240474631UL +#define K3 015666365641UL + +/* + * Basic cut-down MD4 transform. Returns only 32 bits of result. + */ +static void halfMD4Transform (__u32 buf[4], __u32 const in[]) +{ + __u32 a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + + /* Round 1 */ + ROUND(F, a, b, c, d, in[0] + K1, 3); + ROUND(F, d, a, b, c, in[1] + K1, 7); + ROUND(F, c, d, a, b, in[2] + K1, 11); + ROUND(F, b, c, d, a, in[3] + K1, 19); + ROUND(F, a, b, c, d, in[4] + K1, 3); + ROUND(F, d, a, b, c, in[5] + K1, 7); + ROUND(F, c, d, a, b, in[6] + K1, 11); + ROUND(F, b, c, d, a, in[7] + K1, 19); + + /* Round 2 */ + ROUND(G, a, b, c, d, in[1] + K2, 3); + ROUND(G, d, a, b, c, in[3] + K2, 5); + ROUND(G, c, d, a, b, in[5] + K2, 9); + ROUND(G, b, c, d, a, in[7] + K2, 13); + ROUND(G, a, b, c, d, in[0] + K2, 3); + ROUND(G, d, a, b, c, in[2] + K2, 5); + ROUND(G, c, d, a, b, in[4] + K2, 9); + ROUND(G, b, c, d, a, in[6] + K2, 13); + + /* Round 3 */ + ROUND(H, a, b, c, d, in[3] + K3, 3); + ROUND(H, d, a, b, c, in[7] + K3, 9); + ROUND(H, c, d, a, b, in[2] + K3, 11); + ROUND(H, b, c, d, a, in[6] + K3, 15); + ROUND(H, a, b, c, d, in[1] + K3, 3); + ROUND(H, d, a, b, c, in[5] + K3, 9); + ROUND(H, c, d, a, b, in[0] + K3, 11); + ROUND(H, b, c, d, a, in[4] + K3, 15); + + buf[0] += a; + buf[1] += b; + buf[2] += c; + buf[3] += d; +} + +#undef ROUND +#undef F +#undef G +#undef H +#undef K1 +#undef K2 +#undef K3 + +/* The old legacy hash */ +static ext2_dirhash_t dx_hack_hash (const char *name, int len, + int unsigned_flag) +{ + __u32 hash, hash0 = 0x12a3fe2d, hash1 = 0x37abe8f9; + const unsigned char *ucp = (const unsigned char *) name; + const signed char *scp = (const signed char *) name; + int c; + + while (len--) { + if (unsigned_flag) + c = (int) *ucp++; + else + c = (int) *scp++; + hash = hash1 + (hash0 ^ (c * 7152373)); + + if (hash & 0x80000000) hash -= 0x7fffffff; + hash1 = hash0; + hash0 = hash; + } + return (hash0 << 1); +} + +static void str2hashbuf(const char *msg, int len, __u32 *buf, int num, + int unsigned_flag) +{ + __u32 pad, val; + int i, c; + const unsigned char *ucp = (const unsigned char *) msg; + const signed char *scp = (const signed char *) msg; + + pad = (__u32)len | ((__u32)len << 8); + pad |= pad << 16; + + val = pad; + if (len > num*4) + len = num * 4; + for (i=0; i < len; i++) { + if (unsigned_flag) + c = (int) ucp[i]; + else + c = (int) scp[i]; + + val = c + (val << 8); + if ((i % 4) == 3) { + *buf++ = val; + val = pad; + num--; + } + } + if (--num >= 0) + *buf++ = val; + while (--num >= 0) + *buf++ = pad; +} + +/* + * Returns the hash of a filename. If len is 0 and name is NULL, then + * this function can be used to test whether or not a hash version is + * supported. + * + * The seed is an 4 longword (32 bits) "secret" which can be used to + * uniquify a hash. If the seed is all zero's, then some default seed + * may be used. + * + * A particular hash version specifies whether or not the seed is + * represented, and whether or not the returned hash is 32 bits or 64 + * bits. 32 bit hashes will return 0 for the minor hash. + * + * This function doesn't do any normalization or casefolding of the + * input string. To take charset encoding into account, use + * ext2fs_dirhash2. + * + */ +errcode_t ext2fs_dirhash(int version, const char *name, int len, + const __u32 *seed, + ext2_dirhash_t *ret_hash, + ext2_dirhash_t *ret_minor_hash) +{ + __u32 hash; + __u32 minor_hash = 0; + const char *p; + int i; + __u32 in[8], buf[4]; + int unsigned_flag = 0; + + /* Initialize the default seed for the hash checksum functions */ + buf[0] = 0x67452301; + buf[1] = 0xefcdab89; + buf[2] = 0x98badcfe; + buf[3] = 0x10325476; + + /* Check to see if the seed is all zero's */ + if (seed) { + for (i=0; i < 4; i++) { + if (seed[i]) + break; + } + if (i < 4) + memcpy(buf, seed, sizeof(buf)); + } + + switch (version) { + case EXT2_HASH_LEGACY_UNSIGNED: + unsigned_flag++; + /* fallthrough */ + case EXT2_HASH_LEGACY: + hash = dx_hack_hash(name, len, unsigned_flag); + break; + case EXT2_HASH_HALF_MD4_UNSIGNED: + unsigned_flag++; + /* fallthrough */ + case EXT2_HASH_HALF_MD4: + p = name; + while (len > 0) { + str2hashbuf(p, len, in, 8, unsigned_flag); + halfMD4Transform(buf, in); + len -= 32; + p += 32; + } + minor_hash = buf[2]; + hash = buf[1]; + break; + case EXT2_HASH_TEA_UNSIGNED: + unsigned_flag++; + /* fallthrough */ + case EXT2_HASH_TEA: + p = name; + while (len > 0) { + str2hashbuf(p, len, in, 4, unsigned_flag); + TEA_transform(buf, in); + len -= 16; + p += 16; + } + hash = buf[0]; + minor_hash = buf[1]; + break; + default: + *ret_hash = 0; + return EXT2_ET_DIRHASH_UNSUPP; + } + *ret_hash = hash & ~1; + if (ret_minor_hash) + *ret_minor_hash = minor_hash; + return 0; +} + +/* + * Returns the hash of a filename considering normalization and + * casefolding. This is a wrapper around ext2fs_dirhash with string + * encoding support based on the nls_table and the flags. Check + * ext2fs_dirhash for documentation on the input and output parameters. + */ +errcode_t ext2fs_dirhash2(int version, const char *name, int len, + const struct ext2fs_nls_table *charset, + int hash_flags, const __u32 *seed, + ext2_dirhash_t *ret_hash, + ext2_dirhash_t *ret_minor_hash) +{ + errcode_t r; + int dlen; + + if (len && charset && (hash_flags & EXT4_CASEFOLD_FL)) { + char buff[PATH_MAX]; + + dlen = charset->ops->casefold(charset, + (const unsigned char *) name, len, + (unsigned char *) buff, sizeof(buff)); + if (dlen < 0) { + if (dlen == -EINVAL) + goto opaque_seq; + + return dlen; + } + r = ext2fs_dirhash(version, buff, dlen, seed, ret_hash, + ret_minor_hash); + return r; + } + +opaque_seq: + return ext2fs_dirhash(version, name, len, seed, ret_hash, + ret_minor_hash); +} diff --git a/src/ext2fs/ext2_err.h b/src/ext2fs/ext2_err.h index 6547a039..4fbfd11e 100644 --- a/src/ext2fs/ext2_err.h +++ b/src/ext2fs/ext2_err.h @@ -184,6 +184,7 @@ #define EXT2_ET_CORRUPT_JOURNAL_SB (2133571504L) #define EXT2_ET_INODE_CORRUPTED (2133571505L) #define EXT2_ET_EA_INODE_CORRUPTED (2133571506L) +#define EXT2_ET_NO_GDESC (2133571507L) extern const struct error_table et_ext2_error_table; extern void initialize_ext2_error_table(void); diff --git a/src/ext2fs/ext2_fs.h b/src/ext2fs/ext2_fs.h index e9b2994e..6d8d24bf 100644 --- a/src/ext2fs/ext2_fs.h +++ b/src/ext2fs/ext2_fs.h @@ -351,6 +351,7 @@ struct ext2_dx_tail { /* EXT4_EOFBLOCKS_FL 0x00400000 was here */ #define FS_NOCOW_FL 0x00800000 /* Do not cow file */ #define EXT4_SNAPFILE_FL 0x01000000 /* Inode is a snapshot */ +#define FS_DAX_FL 0x02000000 /* Inode is DAX */ #define EXT4_SNAPFILE_DELETED_FL 0x04000000 /* Snapshot is being deleted */ #define EXT4_SNAPFILE_SHRUNK_FL 0x08000000 /* Snapshot shrink has completed */ #define EXT4_INLINE_DATA_FL 0x10000000 /* Inode has inline data */ @@ -698,8 +699,8 @@ struct ext2_super_block { /*060*/ __u32 s_feature_incompat; /* incompatible feature set */ __u32 s_feature_ro_compat; /* readonly-compatible feature set */ /*068*/ __u8 s_uuid[16]; /* 128-bit uuid for volume */ -/*078*/ char s_volume_name[EXT2_LABEL_LEN]; /* volume name */ -/*088*/ char s_last_mounted[64]; /* directory where last mounted */ +/*078*/ __u8 s_volume_name[EXT2_LABEL_LEN]; /* volume name, no NUL? */ +/*088*/ __u8 s_last_mounted[64]; /* directory last mounted on, no NUL? */ /*0c8*/ __u32 s_algorithm_usage_bitmap; /* For compression */ /* * Performance hints. Directory preallocation should only @@ -747,18 +748,18 @@ struct ext2_super_block { __u32 s_first_error_time; /* first time an error happened */ __u32 s_first_error_ino; /* inode involved in first error */ /*1a0*/ __u64 s_first_error_block; /* block involved in first error */ - __u8 s_first_error_func[32]; /* function where the error happened */ + __u8 s_first_error_func[32]; /* function where error hit, no NUL? */ /*1c8*/ __u32 s_first_error_line; /* line number where error happened */ __u32 s_last_error_time; /* most recent time of an error */ /*1d0*/ __u32 s_last_error_ino; /* inode involved in last error */ __u32 s_last_error_line; /* line number where error happened */ __u64 s_last_error_block; /* block involved of last error */ -/*1e0*/ __u8 s_last_error_func[32]; /* function where the error happened */ +/*1e0*/ __u8 s_last_error_func[32]; /* function where error hit, no NUL? */ #define EXT4_S_ERR_END ext4_offsetof(struct ext2_super_block, s_mount_opts) -/*200*/ __u8 s_mount_opts[64]; +/*200*/ __u8 s_mount_opts[64]; /* default mount options, no NUL? */ /*240*/ __u32 s_usr_quota_inum; /* inode number of user quota file */ __u32 s_grp_quota_inum; /* inode number of group quota file */ - __u32 s_overhead_blocks; /* overhead blocks/clusters in fs */ + __u32 s_overhead_clusters; /* overhead blocks/clusters in fs */ /*24c*/ __u32 s_backup_bgs[2]; /* If sparse_super2 enabled */ /*254*/ __u8 s_encrypt_algos[4]; /* Encryption algorithms in use */ /*258*/ __u8 s_encrypt_pw_salt[16]; /* Salt used for string2key algorithm */ @@ -771,7 +772,8 @@ struct ext2_super_block { __u8 s_lastcheck_hi; __u8 s_first_error_time_hi; __u8 s_last_error_time_hi; - __u8 s_pad[2]; + __u8 s_first_error_errcode; + __u8 s_last_error_errcode; /*27c*/ __le16 s_encoding; /* Filename charset encoding */ __le16 s_encoding_flags; /* Filename charset encoding flags */ __le32 s_reserved[95]; /* Padding to the end of the block */ @@ -779,6 +781,7 @@ struct ext2_super_block { }; #define EXT4_S_ERR_LEN (EXT4_S_ERR_END - EXT4_S_ERR_START) +#define EXT2_LEN_STR(buf) (int)sizeof(buf), (char *)buf /* * Codes for operating systems @@ -828,6 +831,8 @@ struct ext2_super_block { /* #define EXT2_FEATURE_COMPAT_EXCLUDE_INODE 0x0080 not used, legacy */ #define EXT2_FEATURE_COMPAT_EXCLUDE_BITMAP 0x0100 #define EXT4_FEATURE_COMPAT_SPARSE_SUPER2 0x0200 +#define EXT4_FEATURE_COMPAT_FAST_COMMIT 0x0400 +#define EXT4_FEATURE_COMPAT_STABLE_INODES 0x0800 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 @@ -867,7 +872,7 @@ struct ext2_super_block { #define EXT4_FEATURE_INCOMPAT_LARGEDIR 0x4000 /* >2GB or 3-lvl htree */ #define EXT4_FEATURE_INCOMPAT_INLINE_DATA 0x8000 /* data in inode */ #define EXT4_FEATURE_INCOMPAT_ENCRYPT 0x10000 -#define EXT4_FEATURE_INCOMPAT_FNAME_ENCODING 0x20000 +#define EXT4_FEATURE_INCOMPAT_CASEFOLD 0x20000 #define EXT4_FEATURE_COMPAT_FUNCS(name, ver, flagname) \ static inline int ext2fs_has_feature_##name(struct ext2_super_block *sb) \ @@ -929,6 +934,8 @@ EXT4_FEATURE_COMPAT_FUNCS(dir_index, 2, DIR_INDEX) EXT4_FEATURE_COMPAT_FUNCS(lazy_bg, 2, LAZY_BG) EXT4_FEATURE_COMPAT_FUNCS(exclude_bitmap, 2, EXCLUDE_BITMAP) EXT4_FEATURE_COMPAT_FUNCS(sparse_super2, 4, SPARSE_SUPER2) +EXT4_FEATURE_COMPAT_FUNCS(fast_commit, 4, FAST_COMMIT) +EXT4_FEATURE_COMPAT_FUNCS(stable_inodes, 4, STABLE_INODES) EXT4_FEATURE_RO_COMPAT_FUNCS(sparse_super, 2, SPARSE_SUPER) EXT4_FEATURE_RO_COMPAT_FUNCS(large_file, 2, LARGE_FILE) @@ -961,7 +968,7 @@ EXT4_FEATURE_INCOMPAT_FUNCS(csum_seed, 4, CSUM_SEED) EXT4_FEATURE_INCOMPAT_FUNCS(largedir, 4, LARGEDIR) EXT4_FEATURE_INCOMPAT_FUNCS(inline_data, 4, INLINE_DATA) EXT4_FEATURE_INCOMPAT_FUNCS(encrypt, 4, ENCRYPT) -EXT4_FEATURE_INCOMPAT_FUNCS(fname_encoding, 4, FNAME_ENCODING) +EXT4_FEATURE_INCOMPAT_FUNCS(casefold, 4, CASEFOLD) #define EXT2_FEATURE_COMPAT_SUPP 0 #define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ @@ -1112,9 +1119,9 @@ struct ext2_dir_entry_tail { struct mmp_struct { __u32 mmp_magic; /* Magic number for MMP */ __u32 mmp_seq; /* Sequence no. updated periodically */ - __u64 mmp_time; /* Time last updated */ - char mmp_nodename[64]; /* Node which last updated MMP block */ - char mmp_bdevname[32]; /* Bdev which last updated MMP block */ + __u64 mmp_time; /* Time last updated (seconds) */ + __u8 mmp_nodename[64]; /* Node updating MMP block, no NUL? */ + __u8 mmp_bdevname[32]; /* Bdev updating MMP block, no NUL? */ __u16 mmp_check_interval; /* Changed mmp_check_interval */ __u16 mmp_pad1; __u32 mmp_pad2[226]; @@ -1146,11 +1153,8 @@ struct mmp_struct { */ #define EXT4_INLINE_DATA_DOTDOT_SIZE (4) -#define EXT4_ENC_ASCII 0 -#define EXT4_ENC_UTF8_11_0 1 +#define EXT4_ENC_UTF8_12_1 1 #define EXT4_ENC_STRICT_MODE_FL (1 << 0) /* Reject invalid sequences */ -#define EXT4_UTF8_NORMALIZATION_TYPE_NFKD (1 << 1) -#define EXT4_UTF8_CASEFOLD_TYPE_NFKDCF (1 << 4) #endif /* _LINUX_EXT2_FS_H */ diff --git a/src/ext2fs/ext2fs.h b/src/ext2fs/ext2fs.h index a866a1d7..dd2be7af 100644 --- a/src/ext2fs/ext2fs.h +++ b/src/ext2fs/ext2fs.h @@ -198,6 +198,8 @@ typedef struct ext2_file *ext2_file_t; #define EXT2_FLAG_IGNORE_CSUM_ERRORS 0x200000 #define EXT2_FLAG_SHARE_DUP 0x400000 #define EXT2_FLAG_IGNORE_SB_ERRORS 0x800000 +#define EXT2_FLAG_BBITMAP_TAIL_PROBLEM 0x1000000 +#define EXT2_FLAG_IBITMAP_TAIL_PROBLEM 0x2000000 /* * Special flag in the ext2 inode i_flag field that means that this is @@ -302,7 +304,7 @@ struct struct_ext2_filsys { /* hashmap for SHA of data blocks */ struct ext2fs_hashmap* block_sha_map; - const struct nls_table *encoding; + const struct ext2fs_nls_table *encoding; }; #if EXT2_FLAT_INCLUDES @@ -603,7 +605,9 @@ typedef struct ext2_icount *ext2_icount_t; EXT2_FEATURE_COMPAT_RESIZE_INODE|\ EXT2_FEATURE_COMPAT_DIR_INDEX|\ EXT2_FEATURE_COMPAT_EXT_ATTR|\ - EXT4_FEATURE_COMPAT_SPARSE_SUPER2) + EXT4_FEATURE_COMPAT_SPARSE_SUPER2|\ + EXT4_FEATURE_COMPAT_FAST_COMMIT|\ + EXT4_FEATURE_COMPAT_STABLE_INODES) #ifdef CONFIG_MMP #define EXT4_LIB_INCOMPAT_MMP EXT4_FEATURE_INCOMPAT_MMP @@ -622,7 +626,7 @@ typedef struct ext2_icount *ext2_icount_t; EXT4_FEATURE_INCOMPAT_64BIT|\ EXT4_FEATURE_INCOMPAT_INLINE_DATA|\ EXT4_FEATURE_INCOMPAT_ENCRYPT|\ - EXT4_FEATURE_INCOMPAT_FNAME_ENCODING|\ + EXT4_FEATURE_INCOMPAT_CASEFOLD|\ EXT4_FEATURE_INCOMPAT_CSUM_SEED|\ EXT4_FEATURE_INCOMPAT_LARGEDIR) @@ -900,7 +904,9 @@ extern int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group); extern blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs, struct ext2_inode *inode); extern blk64_t ext2fs_inode_i_blocks(ext2_filsys fs, - struct ext2_inode *inode); + struct ext2_inode *inode); +extern blk64_t ext2fs_get_stat_i_blocks(ext2_filsys fs, + struct ext2_inode *inode); extern blk64_t ext2fs_blocks_count(struct ext2_super_block *super); extern void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk); @@ -1072,6 +1078,9 @@ extern errcode_t ext2fs_get_dx_countlimit(ext2_filsys fs, struct ext2_dir_entry *dirent, struct ext2_dx_countlimit **cc, int *offset); +extern errcode_t ext2fs_dx_csum(ext2_filsys fs, ext2_ino_t inum, + struct ext2_dir_entry *dirent, + __u32 *crc, struct ext2_dx_tail **ret_t); extern errcode_t ext2fs_extent_block_csum_set(ext2_filsys fs, ext2_ino_t inum, struct ext3_extent_header *eh); @@ -1181,7 +1190,7 @@ extern errcode_t ext2fs_dirhash(int version, const char *name, int len, ext2_dirhash_t *ret_minor_hash); extern errcode_t ext2fs_dirhash2(int version, const char *name, int len, - const struct nls_table *charset, + const struct ext2fs_nls_table *charset, int hash_flags, const __u32 *seed, ext2_dirhash_t *ret_hash, @@ -1429,6 +1438,8 @@ errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap bmap, void *in); errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, ext2fs_block_bitmap *bitmap); +errcode_t ext2fs_count_used_clusters(ext2_filsys fs, blk64_t start, + blk64_t end, blk64_t *out); /* get_num_dirs.c */ extern errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs); @@ -1594,6 +1605,9 @@ extern errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, extern errcode_t ext2fs_new_dir_inline_data(ext2_filsys fs, ext2_ino_t dir_ino, ext2_ino_t parent_ino, __u32 *iblock); +/* nls_utf8.c */ +extern const struct ext2fs_nls_table *ext2fs_load_nls_table(int encoding); + /* mkdir.c */ extern errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, const char *name); @@ -1751,6 +1765,8 @@ extern errcode_t ext2fs_get_arrayzero(unsigned long count, extern errcode_t ext2fs_free_mem(void *ptr); extern errcode_t ext2fs_resize_mem(unsigned long old_size, unsigned long size, void *ptr); +extern errcode_t ext2fs_resize_array(unsigned long old_count, unsigned long count, + unsigned long size, void *ptr); extern void ext2fs_mark_super_dirty(ext2_filsys fs); extern void ext2fs_mark_changed(ext2_filsys fs); extern int ext2fs_test_changed(ext2_filsys fs); @@ -1834,7 +1850,8 @@ _INLINE_ errcode_t ext2fs_get_memzero(unsigned long size, void *ptr) return 0; } -_INLINE_ errcode_t ext2fs_get_array(unsigned long count, unsigned long size, void *ptr) +_INLINE_ errcode_t ext2fs_get_array(unsigned long count, unsigned long size, + void *ptr) { if (count && (~0UL)/count < size) return EXT2_ET_NO_MEMORY; @@ -1889,6 +1906,36 @@ _INLINE_ errcode_t ext2fs_resize_mem(unsigned long EXT2FS_ATTR((unused)) old_siz memcpy(ptr, &p, sizeof(p)); return 0; } + +/* + * Resize array. The 'ptr' arg must point to a pointer. + */ +_INLINE_ errcode_t ext2fs_resize_array(unsigned long size, + unsigned long old_count, + unsigned long count, void *ptr) +{ + unsigned long old_size; + errcode_t retval; + + if (count && (~0UL)/count < size) + return EXT2_ET_NO_MEMORY; + + size *= count; + old_size = size * old_count; + retval = ext2fs_resize_mem(old_size, size, ptr); + if (retval) + return retval; + + if (size > old_size) { + void *p; + + memcpy(&p, ptr, sizeof(p)); + memset((char *)p + old_size, 0, size - old_size); + memcpy(ptr, &p, sizeof(p)); + } + + return 0; +} #endif /* Custom memory routines */ /* @@ -2010,7 +2057,13 @@ _INLINE_ blk_t ext2fs_inode_data_blocks(ext2_filsys fs, _INLINE_ int ext2fs_htree_intnode_maxrecs(ext2_filsys fs, int blocks) { - return blocks * ((fs->blocksize - 8) / sizeof(struct ext2_dx_entry)); + int csum_size = 0; + + if ((EXT2_SB(fs->super)->s_feature_ro_compat & + EXT4_FEATURE_RO_COMPAT_METADATA_CSUM) != 0) + csum_size = sizeof(struct ext2_dx_tail); + return blocks * ((fs->blocksize - (8 + csum_size)) / + sizeof(struct ext2_dx_entry)); } /* diff --git a/src/ext2fs/ext2fsP.h b/src/ext2fs/ext2fsP.h index fd5b4b1a..ad8b7d52 100644 --- a/src/ext2fs/ext2fsP.h +++ b/src/ext2fs/ext2fsP.h @@ -92,6 +92,20 @@ struct ext2_inode_cache_ent { struct ext2_inode *inode; }; +/* + * NLS defintions + */ +struct ext2fs_nls_table { + int version; + const struct ext2fs_nls_ops *ops; +}; + +struct ext2fs_nls_ops { + int (*casefold)(const struct ext2fs_nls_table *charset, + const unsigned char *str, size_t len, + unsigned char *dest, size_t dlen); +}; + /* Function prototypes */ extern int ext2fs_process_dir_block(ext2_filsys fs, diff --git a/src/ext2fs/ext_attr.c b/src/ext2fs/ext_attr.c index 78a823a9..affc1a8f 100644 --- a/src/ext2fs/ext_attr.c +++ b/src/ext2fs/ext_attr.c @@ -1550,14 +1550,15 @@ errcode_t ext2fs_xattr_set(struct ext2_xattr_handle *h, new_value, &value_len); if (ret) goto out; - } else + } else if (value_len) memcpy(new_value, value, value_len); /* Imitate kernel behavior by skipping update if value is the same. */ for (x = h->attrs; x < h->attrs + h->count; x++) { if (!strcmp(x->name, name)) { if (!x->ea_ino && x->value_len == value_len && - !memcmp(x->value, new_value, value_len)) { + (!value_len || + !memcmp(x->value, new_value, value_len))) { ret = 0; goto out; } diff --git a/src/ext2fs/fallocate.c b/src/ext2fs/fallocate.c index 19737c19..0c05597c 100644 --- a/src/ext2fs/fallocate.c +++ b/src/ext2fs/fallocate.c @@ -808,7 +808,8 @@ errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, blk64_t start, blk64_t len) { struct ext2_inode inode_buf; - blk64_t blk, x; + blk64_t blk, x, zero_blk = 0, last = 0; + int zero_len = 0; errcode_t err = 0; if (((flags & EXT2_FALLOCATE_FORCE_INIT) && @@ -848,15 +849,32 @@ errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino, if (x) continue; - err = ext2fs_bmap2(fs, ino, inode, NULL, - BMAP_ALLOC | BMAP_UNINIT | BMAP_ZERO, blk, - 0, &x); + err = ext2fs_bmap2(fs, ino, inode, NULL, BMAP_ALLOC, + blk, 0, &x); if (err) - return err; + goto errout; + if ((zero_len && (x != last+1)) || + (zero_len >= 65536)) { + err = ext2fs_zero_blocks2(fs, zero_blk, zero_len, + NULL, NULL); + zero_len = 0; + if (err) + goto errout; + } + if (zero_len == 0) { + zero_blk = x; + zero_len = 1; + } else { + zero_len++; + } + last = x; } out: if (inode == &inode_buf) ext2fs_write_inode(fs, ino, inode); +errout: + if (zero_len) + ext2fs_zero_blocks2(fs, zero_blk, zero_len, NULL, NULL); return err; } diff --git a/src/ext2fs/gen_bitmap64.c b/src/ext2fs/gen_bitmap64.c index 87fb8ca7..2b01a395 100644 --- a/src/ext2fs/gen_bitmap64.c +++ b/src/ext2fs/gen_bitmap64.c @@ -799,7 +799,7 @@ errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, ext2fs_generic_bitmap_64 bmap, cmap; ext2fs_block_bitmap gen_bmap = *bitmap, gen_cmap; errcode_t retval; - blk64_t i, b_end, c_end, n, ratio; + blk64_t i, next, b_end, c_end; bmap = (ext2fs_generic_bitmap_64) gen_bmap; if (fs->cluster_ratio_bits == ext2fs_get_bitmap_granularity(gen_bmap)) @@ -816,18 +816,13 @@ errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs, bmap->end = bmap->real_end; c_end = cmap->end; cmap->end = cmap->real_end; - n = 0; - ratio = 1ULL << fs->cluster_ratio_bits; while (i < bmap->real_end) { - if (ext2fs_test_block_bitmap2(gen_bmap, i)) { - ext2fs_mark_block_bitmap2(gen_cmap, i); - i += ratio - n; - n = 0; - continue; - } - i++; n++; - if (n >= ratio) - n = 0; + retval = ext2fs_find_first_set_block_bitmap2(gen_bmap, + i, bmap->real_end, &next); + if (retval) + break; + ext2fs_mark_block_bitmap2(gen_cmap, next); + i = EXT2FS_C2B(fs, EXT2FS_B2C(fs, next) + 1); } bmap->end = b_end; cmap->end = c_end; @@ -945,3 +940,38 @@ errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap, return ENOENT; } + +errcode_t ext2fs_count_used_clusters(ext2_filsys fs, blk64_t start, + blk64_t end, blk64_t *out) +{ + blk64_t next; + blk64_t tot_set = 0; + errcode_t retval; + + while (start < end) { + retval = ext2fs_find_first_set_block_bitmap2(fs->block_map, + start, end, &next); + if (retval) { + if (retval == ENOENT) + retval = 0; + break; + } + start = next; + + retval = ext2fs_find_first_zero_block_bitmap2(fs->block_map, + start, end, &next); + if (retval == 0) { + tot_set += next - start; + start = next + 1; + } else if (retval == ENOENT) { + retval = 0; + tot_set += end - start + 1; + break; + } else + break; + } + + if (!retval) + *out = EXT2FS_NUM_B2C(fs, tot_set); + return retval; +} diff --git a/src/ext2fs/hashmap.c b/src/ext2fs/hashmap.c index eca9edc6..3dd6eada 100644 --- a/src/ext2fs/hashmap.c +++ b/src/ext2fs/hashmap.c @@ -1,6 +1,22 @@ #include "hashmap.h" #include +struct ext2fs_hashmap { + uint32_t size; + uint32_t(*hash)(const void *key, size_t len); + void(*free)(void*); + struct ext2fs_hashmap_entry *first; + struct ext2fs_hashmap_entry *last; +#if __GNUC_PREREQ (4, 8) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + struct ext2fs_hashmap_entry *entries[0]; +#if __GNUC_PREREQ (4, 8) +#pragma GCC diagnostic pop +#endif +}; + uint32_t ext2fs_djb2_hash(const void *str, size_t size) { int c; diff --git a/src/ext2fs/hashmap.h b/src/ext2fs/hashmap.h index 656d3d90..dcfa7455 100644 --- a/src/ext2fs/hashmap.h +++ b/src/ext2fs/hashmap.h @@ -13,27 +13,15 @@ #endif #endif -struct ext2fs_hashmap { - uint32_t size; - uint32_t(*hash)(const void *key, size_t len); - void(*free)(void*); - struct ext2fs_hashmap_entry *first; - struct ext2fs_hashmap_entry *last; - struct ext2fs_hashmap_entry { - void *data; - const void *key; - size_t key_len; - struct ext2fs_hashmap_entry *next; - struct ext2fs_hashmap_entry *list_next; - struct ext2fs_hashmap_entry *list_prev; -#if __GNUC_PREREQ (4, 8) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -#endif - } *entries[0]; -#if __GNUC_PREREQ (4, 8) -#pragma GCC diagnostic pop -#endif +struct ext2fs_hashmap; + +struct ext2fs_hashmap_entry { + void *data; + const void *key; + size_t key_len; + struct ext2fs_hashmap_entry *next; + struct ext2fs_hashmap_entry *list_next; + struct ext2fs_hashmap_entry *list_prev; }; struct ext2fs_hashmap *ext2fs_hashmap_create( diff --git a/src/ext2fs/initialize.c b/src/ext2fs/initialize.c index b887cc85..afe7d6e9 100644 --- a/src/ext2fs/initialize.c +++ b/src/ext2fs/initialize.c @@ -190,6 +190,9 @@ errcode_t ext2fs_initialize(const char *name, int flags, assign_field(s_encoding); assign_field(s_encoding_flags); +// if (ext2fs_has_feature_casefold(param)) +// fs->encoding = ext2fs_load_nls_table(param->s_encoding); + if (super->s_feature_incompat & ~EXT2_LIB_FEATURE_INCOMPAT_SUPP) { retval = EXT2_ET_UNSUPP_FEATURE; goto cleanup; diff --git a/src/ext2fs/inode.c b/src/ext2fs/inode.c index fbb97ae4..c4377eeb 100644 --- a/src/ext2fs/inode.c +++ b/src/ext2fs/inode.c @@ -309,6 +309,7 @@ errcode_t ext2fs_inode_scan_goto_blockgroup(ext2_inode_scan scan, { scan->current_group = group - 1; scan->groups_left = scan->fs->group_desc_count - group; + scan->bad_block_ptr = 0; return get_next_blockgroup(scan); } @@ -332,6 +333,12 @@ static errcode_t check_for_inode_bad_blocks(ext2_inode_scan scan, if (blk == 0) return 0; + /* Make sure bad_block_ptr is still valid */ + if (scan->bad_block_ptr >= bb->num) { + scan->scan_flags &= ~EXT2_SF_CHK_BADBLOCKS; + return 0; + } + /* * If the current block is greater than the bad block listed * in the bad block list, then advance the pointer until this @@ -967,10 +974,6 @@ errcode_t ext2fs_write_inode2(ext2_filsys fs, ext2_ino_t ino, if ((offset + length) > fs->blocksize) clen = fs->blocksize - offset; - if (!fs->icache) { - retval = EXT2_ET_GDESC_READ; - goto errout; - } if (fs->icache->buffer_blk != block_nr) { retval = io_channel_read_blk64(fs->io, block_nr, 1, fs->icache->buffer); diff --git a/src/ext2fs/jfs_compat.h b/src/ext2fs/jfs_compat.h index 8df9acb3..f8ad2e83 100644 --- a/src/ext2fs/jfs_compat.h +++ b/src/ext2fs/jfs_compat.h @@ -22,8 +22,8 @@ #define KERN_ERR "" #define KERN_DEBUG "" -#define READ 0 -#define WRITE 1 +#define REQ_OP_READ 0 +#define REQ_OP_WRITE 1 #define cpu_to_be32(n) htonl(n) #define be32_to_cpu(n) ntohl(n) @@ -37,14 +37,14 @@ typedef struct kdev_s *kdev_t; struct buffer_head; struct inode; +typedef unsigned int gfp_t; #define GFP_KERNEL 0 -#define JFS_TAG_SIZE32 JBD_TAG_SIZE32 -#define JFS_BARRIER 0 +#define GFP_NOFS 0 +#define __GFP_NOFAIL 0 +#define JBD2_TAG_SIZE32 JBD_TAG_SIZE32 +#define JBD2_BARRIER 0 typedef __u64 u64; -#define JFS_CRC32_CHKSUM JBD2_CRC32_CHKSUM -#define JFS_CRC32_CHKSUM_SIZE JBD2_CRC32_CHKSUM_SIZE #define put_bh(x) brelse(x) -#define be64_to_cpu(x) ext2fs_be64_to_cpu(x) static inline __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)), __u32 crc, const void *address, @@ -56,7 +56,6 @@ static inline __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)), #define spin_lock_init(x) #define spin_lock(x) #define spin_unlock(x) -#define yield() #define SLAB_HWCACHE_ALIGN 0 #define SLAB_TEMPORARY 0 #define KMEM_CACHE(__struct, __flags) kmem_cache_create(#__struct,\ @@ -65,6 +64,7 @@ static inline __u32 jbd2_chksum(journal_t *j EXT2FS_ATTR((unused)), #define blkdev_issue_flush(kdev, a, b) sync_blockdev(kdev) #define is_power_of_2(x) ((x) != 0 && (((x) & ((x) - 1)) == 0)) +#define pr_emerg(fmt) struct journal_s { diff --git a/src/ext2fs/kernel-jbd.h b/src/ext2fs/kernel-jbd.h index 19c78b21..82f293f8 100644 --- a/src/ext2fs/kernel-jbd.h +++ b/src/ext2fs/kernel-jbd.h @@ -24,7 +24,7 @@ #define __FUNCTION__ "" #endif -#define journal_oom_retry 1 +#define journal_oom_retry 0 #ifdef __STDC__ #ifdef CONFIG_JBD_DEBUG @@ -73,13 +73,13 @@ extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry); #define jbd_rep_kmalloc(size, flags) \ __jbd_kmalloc(__FUNCTION__, (size), (flags), 1) -#define JFS_MIN_JOURNAL_BLOCKS 1024 +#define JBD2_MIN_JOURNAL_BLOCKS 1024 /* * Internal structures used by the logging mechanism: */ -#define JFS_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ +#define JBD2_MAGIC_NUMBER 0xc03b3998U /* The first 4 bytes of /dev/random! */ /* * On-disk structures @@ -89,20 +89,20 @@ extern void * __jbd_kmalloc (char *where, size_t size, int flags, int retry); * Descriptor block types: */ -#define JFS_DESCRIPTOR_BLOCK 1 -#define JFS_COMMIT_BLOCK 2 -#define JFS_SUPERBLOCK_V1 3 -#define JFS_SUPERBLOCK_V2 4 -#define JFS_REVOKE_BLOCK 5 +#define JBD2_DESCRIPTOR_BLOCK 1 +#define JBD2_COMMIT_BLOCK 2 +#define JBD2_SUPERBLOCK_V1 3 +#define JBD2_SUPERBLOCK_V2 4 +#define JBD2_REVOKE_BLOCK 5 /* * Standard header for all descriptor blocks: */ typedef struct journal_header_s { - __u32 h_magic; - __u32 h_blocktype; - __u32 h_sequence; + __be32 h_magic; + __be32 h_blocktype; + __be32 h_sequence; } journal_header_t; /* @@ -135,15 +135,15 @@ typedef struct journal_header_s * Checksum v1, v2, and v3 are mutually exclusive features. */ struct commit_header { - __u32 h_magic; - __u32 h_blocktype; - __u32 h_sequence; + __be32 h_magic; + __be32 h_blocktype; + __be32 h_sequence; unsigned char h_chksum_type; unsigned char h_chksum_size; unsigned char h_padding[2]; - __u32 h_chksum[JBD2_CHECKSUM_BYTES]; - __u64 h_commit_sec; - __u32 h_commit_nsec; + __be32 h_chksum[JBD2_CHECKSUM_BYTES]; + __be64 h_commit_sec; + __be32 h_commit_nsec; }; /* @@ -151,22 +151,22 @@ struct commit_header { */ typedef struct journal_block_tag3_s { - __u32 t_blocknr; /* The on-disk block number */ - __u32 t_flags; /* See below */ - __u32 t_blocknr_high; /* most-significant high 32bits. */ - __u32 t_checksum; /* crc32c(uuid+seq+block) */ + __be32 t_blocknr; /* The on-disk block number */ + __be32 t_flags; /* See below */ + __be32 t_blocknr_high; /* most-significant high 32bits. */ + __be32 t_checksum; /* crc32c(uuid+seq+block) */ } journal_block_tag3_t; typedef struct journal_block_tag_s { - __u32 t_blocknr; /* The on-disk block number */ - __u16 t_checksum; /* truncated crc32c(uuid+seq+block) */ - __u16 t_flags; /* See below */ - __u32 t_blocknr_high; /* most-significant high 32bits. */ + __be32 t_blocknr; /* The on-disk block number */ + __be16 t_checksum; /* truncated crc32c(uuid+seq+block) */ + __be16 t_flags; /* See below */ + __be32 t_blocknr_high; /* most-significant high 32bits. */ } journal_block_tag_t; -/* Tail of descriptor block, for checksumming */ -struct journal_block_tail { +/* Tail of descriptor or revoke block, for checksumming */ +struct jbd2_journal_block_tail { __be32 t_checksum; }; @@ -177,24 +177,19 @@ struct journal_block_tail { typedef struct journal_revoke_header_s { journal_header_t r_header; - int r_count; /* Count of bytes used in the block */ -} journal_revoke_header_t; - -/* Tail of revoke block, for checksumming */ -struct journal_revoke_tail { - __be32 r_checksum; -}; + __be32 r_count; /* Count of bytes used in the block */ +} jbd2_journal_revoke_header_t; /* Definitions for the journal tag flags word: */ -#define JFS_FLAG_ESCAPE 1 /* on-disk block is escaped */ -#define JFS_FLAG_SAME_UUID 2 /* block has same uuid as previous */ -#define JFS_FLAG_DELETED 4 /* block deleted by this transaction */ -#define JFS_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ +#define JBD2_FLAG_ESCAPE 1 /* on-disk block is escaped */ +#define JBD2_FLAG_SAME_UUID 2 /* block has same uuid as previous */ +#define JBD2_FLAG_DELETED 4 /* block deleted by this transaction */ +#define JBD2_FLAG_LAST_TAG 8 /* last tag in this descriptor block */ #define UUID_SIZE 16 -#define JFS_USERS_MAX 48 -#define JFS_USERS_SIZE (UUID_SIZE * JFS_USERS_MAX) +#define JBD2_USERS_MAX 48 +#define JBD2_USERS_SIZE (UUID_SIZE * JBD2_USERS_MAX) /* * The journal superblock. All fields are in big-endian byte order. */ @@ -205,14 +200,14 @@ typedef struct journal_superblock_s /* 0x000C */ /* Static information describing the journal */ - __u32 s_blocksize; /* journal device blocksize */ - __u32 s_maxlen; /* total blocks in journal file */ - __u32 s_first; /* first block of log information */ + __be32 s_blocksize; /* journal device blocksize */ + __be32 s_maxlen; /* total blocks in journal file */ + __be32 s_first; /* first block of log information */ /* 0x0018 */ /* Dynamic information describing the current state of the log */ - __u32 s_sequence; /* first commit ID expected in log */ - __u32 s_start; /* blocknr of start of log */ + __be32 s_sequence; /* first commit ID expected in log */ + __be32 s_start; /* blocknr of start of log */ /* 0x0020 */ /* Error value, as set by journal_abort(). */ @@ -220,63 +215,63 @@ typedef struct journal_superblock_s /* 0x0024 */ /* Remaining fields are only valid in a version-2 superblock */ - __u32 s_feature_compat; /* compatible feature set */ - __u32 s_feature_incompat; /* incompatible feature set */ - __u32 s_feature_ro_compat; /* readonly-compatible feature set */ + __be32 s_feature_compat; /* compatible feature set */ + __be32 s_feature_incompat; /* incompatible feature set */ + __be32 s_feature_ro_compat; /* readonly-compatible feature set */ /* 0x0030 */ __u8 s_uuid[16]; /* 128-bit uuid for journal */ /* 0x0040 */ - __u32 s_nr_users; /* Nr of filesystems sharing log */ + __be32 s_nr_users; /* Nr of filesystems sharing log */ - __u32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ + __be32 s_dynsuper; /* Blocknr of dynamic superblock copy*/ /* 0x0048 */ - __u32 s_max_transaction; /* Limit of journal blocks per trans.*/ - __u32 s_max_trans_data; /* Limit of data blocks per trans. */ + __be32 s_max_transaction; /* Limit of journal blocks per trans.*/ + __be32 s_max_trans_data; /* Limit of data blocks per trans. */ /* 0x0050 */ __u8 s_checksum_type; /* checksum type */ __u8 s_padding2[3]; - __u32 s_padding[42]; - __u32 s_checksum; /* crc32c(superblock) */ + __be32 s_padding[42]; + __be32 s_checksum; /* crc32c(superblock) */ /* 0x0100 */ - __u8 s_users[JFS_USERS_SIZE]; /* ids of all fs'es sharing the log */ + __u8 s_users[JBD2_USERS_SIZE]; /* ids of all fs'es sharing the log */ /* 0x0400 */ } journal_superblock_t; -#define JFS_HAS_COMPAT_FEATURE(j,mask) \ +#define JBD2_HAS_COMPAT_FEATURE(j,mask) \ ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_compat & ext2fs_cpu_to_be32((mask)))) -#define JFS_HAS_RO_COMPAT_FEATURE(j,mask) \ +#define JBD2_HAS_RO_COMPAT_FEATURE(j,mask) \ ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_ro_compat & ext2fs_cpu_to_be32((mask)))) -#define JFS_HAS_INCOMPAT_FEATURE(j,mask) \ +#define JBD2_HAS_INCOMPAT_FEATURE(j,mask) \ ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_incompat & ext2fs_cpu_to_be32((mask)))) -#define JFS_FEATURE_COMPAT_CHECKSUM 0x00000001 +#define JBD2_FEATURE_COMPAT_CHECKSUM 0x00000001 -#define JFS_FEATURE_INCOMPAT_REVOKE 0x00000001 -#define JFS_FEATURE_INCOMPAT_64BIT 0x00000002 -#define JFS_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 -#define JFS_FEATURE_INCOMPAT_CSUM_V2 0x00000008 -#define JFS_FEATURE_INCOMPAT_CSUM_V3 0x00000010 +#define JBD2_FEATURE_INCOMPAT_REVOKE 0x00000001 +#define JBD2_FEATURE_INCOMPAT_64BIT 0x00000002 +#define JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT 0x00000004 +#define JBD2_FEATURE_INCOMPAT_CSUM_V2 0x00000008 +#define JBD2_FEATURE_INCOMPAT_CSUM_V3 0x00000010 /* Features known to this kernel version: */ -#define JFS_KNOWN_COMPAT_FEATURES 0 -#define JFS_KNOWN_ROCOMPAT_FEATURES 0 -#define JFS_KNOWN_INCOMPAT_FEATURES (JFS_FEATURE_INCOMPAT_REVOKE|\ - JFS_FEATURE_INCOMPAT_ASYNC_COMMIT|\ - JFS_FEATURE_INCOMPAT_64BIT|\ - JFS_FEATURE_INCOMPAT_CSUM_V2|\ - JFS_FEATURE_INCOMPAT_CSUM_V3) +#define JBD2_KNOWN_COMPAT_FEATURES 0 +#define JBD2_KNOWN_ROCOMPAT_FEATURES 0 +#define JBD2_KNOWN_INCOMPAT_FEATURES (JBD2_FEATURE_INCOMPAT_REVOKE|\ + JBD2_FEATURE_INCOMPAT_ASYNC_COMMIT| \ + JBD2_FEATURE_INCOMPAT_64BIT|\ + JBD2_FEATURE_INCOMPAT_CSUM_V2| \ + JBD2_FEATURE_INCOMPAT_CSUM_V3) #ifdef NO_INLINE_FUNCS extern size_t journal_tag_bytes(journal_t *journal); -extern int journal_has_csum_v2or3(journal_t *journal); +extern int jbd2_journal_has_csum_v2or3(journal_t *journal); extern int tid_gt(tid_t x, tid_t y) EXT2FS_ATTR((unused)); extern int tid_geq(tid_t x, tid_t y) EXT2FS_ATTR((unused)); #endif @@ -301,94 +296,94 @@ extern int tid_geq(tid_t x, tid_t y) EXT2FS_ATTR((unused)); #endif /* INCLUDE_INLINE_FUNCS */ /* journal feature predicate functions */ -#define JFS_FEATURE_COMPAT_FUNCS(name, flagname) \ -_INLINE_ int jfs_has_feature_##name(journal_t *j); \ -_INLINE_ int jfs_has_feature_##name(journal_t *j) \ +#define JBD2_FEATURE_COMPAT_FUNCS(name, flagname) \ +_INLINE_ int jbd2_has_feature_##name(journal_t *j); \ +_INLINE_ int jbd2_has_feature_##name(journal_t *j) \ { \ return ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_compat & \ - ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname)) != 0); \ + ext2fs_cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname)) != 0); \ } \ -_INLINE_ void jfs_set_feature_##name(journal_t *j); \ -_INLINE_ void jfs_set_feature_##name(journal_t *j) \ +_INLINE_ void jbd2_set_feature_##name(journal_t *j); \ +_INLINE_ void jbd2_set_feature_##name(journal_t *j) \ { \ (j)->j_superblock->s_feature_compat |= \ - ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname); \ + ext2fs_cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname); \ } \ -_INLINE_ void jfs_clear_feature_##name(journal_t *j); \ -_INLINE_ void jfs_clear_feature_##name(journal_t *j) \ +_INLINE_ void jbd2_clear_feature_##name(journal_t *j); \ +_INLINE_ void jbd2_clear_feature_##name(journal_t *j) \ { \ (j)->j_superblock->s_feature_compat &= \ - ~ext2fs_cpu_to_be32(JFS_FEATURE_COMPAT_##flagname); \ + ~ext2fs_cpu_to_be32(JBD2_FEATURE_COMPAT_##flagname); \ } -#define JFS_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ -_INLINE_ int jfs_has_feature_##name(journal_t *j); \ -_INLINE_ int jfs_has_feature_##name(journal_t *j) \ +#define JBD2_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ +_INLINE_ int jbd2_has_feature_##name(journal_t *j); \ +_INLINE_ int jbd2_has_feature_##name(journal_t *j) \ { \ return ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_ro_compat & \ - ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname)) != 0); \ + ext2fs_cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname)) != 0); \ } \ -_INLINE_ void jfs_set_feature_##name(journal_t *j); \ -_INLINE_ void jfs_set_feature_##name(journal_t *j) \ +_INLINE_ void jbd2_set_feature_##name(journal_t *j); \ +_INLINE_ void jbd2_set_feature_##name(journal_t *j) \ { \ (j)->j_superblock->s_feature_ro_compat |= \ - ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname); \ + ext2fs_cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname); \ } \ -_INLINE_ void jfs_clear_feature_##name(journal_t *j); \ -_INLINE_ void jfs_clear_feature_##name(journal_t *j) \ +_INLINE_ void jbd2_clear_feature_##name(journal_t *j); \ +_INLINE_ void jbd2_clear_feature_##name(journal_t *j) \ { \ (j)->j_superblock->s_feature_ro_compat &= \ - ~ext2fs_cpu_to_be32(JFS_FEATURE_RO_COMPAT_##flagname); \ + ~ext2fs_cpu_to_be32(JBD2_FEATURE_RO_COMPAT_##flagname); \ } -#define JFS_FEATURE_INCOMPAT_FUNCS(name, flagname) \ -_INLINE_ int jfs_has_feature_##name(journal_t *j); \ -_INLINE_ int jfs_has_feature_##name(journal_t *j) \ +#define JBD2_FEATURE_INCOMPAT_FUNCS(name, flagname) \ +_INLINE_ int jbd2_has_feature_##name(journal_t *j); \ +_INLINE_ int jbd2_has_feature_##name(journal_t *j) \ { \ return ((j)->j_format_version >= 2 && \ ((j)->j_superblock->s_feature_incompat & \ - ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname)) != 0); \ + ext2fs_cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname)) != 0); \ } \ -_INLINE_ void jfs_set_feature_##name(journal_t *j); \ -_INLINE_ void jfs_set_feature_##name(journal_t *j) \ +_INLINE_ void jbd2_set_feature_##name(journal_t *j); \ +_INLINE_ void jbd2_set_feature_##name(journal_t *j) \ { \ (j)->j_superblock->s_feature_incompat |= \ - ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname); \ + ext2fs_cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname); \ } \ -_INLINE_ void jfs_clear_feature_##name(journal_t *j); \ -_INLINE_ void jfs_clear_feature_##name(journal_t *j) \ +_INLINE_ void jbd2_clear_feature_##name(journal_t *j); \ +_INLINE_ void jbd2_clear_feature_##name(journal_t *j) \ { \ (j)->j_superblock->s_feature_incompat &= \ - ~ext2fs_cpu_to_be32(JFS_FEATURE_INCOMPAT_##flagname); \ + ~ext2fs_cpu_to_be32(JBD2_FEATURE_INCOMPAT_##flagname); \ } #else -#define JFS_FEATURE_COMPAT_FUNCS(name, flagname) \ -extern int jfs_has_feature_##name(journal_t *j); \ -extern void jfs_set_feature_##name(journal_t *j); \ -extern void jfs_clear_feature_##name(journal_t *j); +#define JBD2_FEATURE_COMPAT_FUNCS(name, flagname) \ +extern int jbd2_has_feature_##name(journal_t *j); \ +extern void jbd2_set_feature_##name(journal_t *j); \ +extern void jbd2_clear_feature_##name(journal_t *j); -#define JFS_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ -extern int jfs_has_feature_##name(journal_t *j); \ -extern void jfs_set_feature_##name(journal_t *j); \ -extern void jfs_clear_feature_##name(journal_t *j); +#define JBD2_FEATURE_RO_COMPAT_FUNCS(name, flagname) \ +extern int jbd2_has_feature_##name(journal_t *j); \ +extern void jbd2_set_feature_##name(journal_t *j); \ +extern void jbd2_clear_feature_##name(journal_t *j); -#define JFS_FEATURE_INCOMPAT_FUNCS(name, flagname) \ -extern int jfs_has_feature_##name(journal_t *j); \ -extern void jfs_set_feature_##name(journal_t *j); \ -extern void jfs_clear_feature_##name(journal_t *j); +#define JBD2_FEATURE_INCOMPAT_FUNCS(name, flagname) \ +extern int jbd2_has_feature_##name(journal_t *j); \ +extern void jbd2_set_feature_##name(journal_t *j); \ +extern void jbd2_clear_feature_##name(journal_t *j); #endif /* (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) */ -JFS_FEATURE_COMPAT_FUNCS(checksum, CHECKSUM) +JBD2_FEATURE_COMPAT_FUNCS(checksum, CHECKSUM) -JFS_FEATURE_INCOMPAT_FUNCS(revoke, REVOKE) -JFS_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT) -JFS_FEATURE_INCOMPAT_FUNCS(async_commit, ASYNC_COMMIT) -JFS_FEATURE_INCOMPAT_FUNCS(csum2, CSUM_V2) -JFS_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3) +JBD2_FEATURE_INCOMPAT_FUNCS(revoke, REVOKE) +JBD2_FEATURE_INCOMPAT_FUNCS(64bit, 64BIT) +JBD2_FEATURE_INCOMPAT_FUNCS(async_commit, ASYNC_COMMIT) +JBD2_FEATURE_INCOMPAT_FUNCS(csum2, CSUM_V2) +JBD2_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3) #if (defined(E2FSCK_INCLUDE_INLINE_FUNCS) || !defined(NO_INLINE_FUNCS)) /* @@ -398,23 +393,23 @@ _INLINE_ size_t journal_tag_bytes(journal_t *journal) { size_t sz; - if (jfs_has_feature_csum3(journal)) + if (jbd2_has_feature_csum3(journal)) return sizeof(journal_block_tag3_t); sz = sizeof(journal_block_tag_t); - if (jfs_has_feature_csum2(journal)) + if (jbd2_has_feature_csum2(journal)) sz += sizeof(__u16); - if (jfs_has_feature_64bit(journal)) + if (jbd2_has_feature_64bit(journal)) return sz; return sz - sizeof(__u32); } -_INLINE_ int journal_has_csum_v2or3(journal_t *journal) +_INLINE_ int jbd2_journal_has_csum_v2or3(journal_t *journal) { - if (jfs_has_feature_csum2(journal) || jfs_has_feature_csum3(journal)) + if (jbd2_has_feature_csum2(journal) || jbd2_has_feature_csum3(journal)) return 1; return 0; diff --git a/src/ext2fs/link.c b/src/ext2fs/link.c index 65dc8877..5b578c76 100644 --- a/src/ext2fs/link.c +++ b/src/ext2fs/link.c @@ -18,6 +18,155 @@ #include "ext2_fs.h" #include "ext2fs.h" +#include "ext2fsP.h" + +#define EXT2_DX_ROOT_OFF 24 + +struct dx_frame { + __u8 *buf; + blk64_t pblock; + struct ext2_dx_countlimit *head; + struct ext2_dx_entry *entries; + struct ext2_dx_entry *at; +}; + +struct dx_lookup_info { + const char *name; + int namelen; + int hash_alg; + __u32 hash; + int levels; + struct dx_frame frames[EXT4_HTREE_LEVEL]; +}; + +static errcode_t alloc_dx_frame(ext2_filsys fs, struct dx_frame *frame) +{ + return ext2fs_get_mem(fs->blocksize, &frame->buf); +} + +static void dx_release(struct dx_lookup_info *info) +{ +// struct ext2_dx_root_info *root; + int level; + + for (level = 0; level < info->levels; level++) { + if (info->frames[level].buf == NULL) + break; + ext2fs_free_mem(&(info->frames[level].buf)); + } + info->levels = 0; +} + +static void dx_search_entry(struct dx_frame *frame, int count, __u32 hash) +{ + struct ext2_dx_entry *p, *q, *m; + + p = frame->entries + 1; + q = frame->entries + count - 1; + while (p <= q) { + m = p + (q - p) / 2; + if (ext2fs_le32_to_cpu(m->hash) > hash) + q = m - 1; + else + p = m + 1; + } + frame->at = p - 1; +} + +static errcode_t load_logical_dir_block(ext2_filsys fs, ext2_ino_t dir, + struct ext2_inode *diri, blk64_t block, + blk64_t *pblk, void *buf) +{ + errcode_t errcode; + int ret_flags; + + errcode = ext2fs_bmap2(fs, dir, diri, NULL, 0, block, &ret_flags, + pblk); + if (errcode) + return errcode; + if (ret_flags & BMAP_RET_UNINIT) + return EXT2_ET_DIR_CORRUPTED; + return ext2fs_read_dir_block4(fs, *pblk, buf, 0, dir); +} + +static errcode_t dx_lookup(ext2_filsys fs, ext2_ino_t dir, + struct ext2_inode *diri, struct dx_lookup_info *info) +{ + struct ext2_dx_root_info *root; + errcode_t errcode; + int level = 0; + int count, limit; + int hash_alg; + int hash_flags = diri->i_flags & EXT4_CASEFOLD_FL; + __u32 minor_hash; + struct dx_frame *frame; + + errcode = alloc_dx_frame(fs, &(info->frames[0])); + if (errcode) + return errcode; + info->levels = 1; + + errcode = load_logical_dir_block(fs, dir, diri, 0, + &(info->frames[0].pblock), + info->frames[0].buf); + if (errcode) + goto out_err; + root = (struct ext2_dx_root_info*)(info->frames[0].buf + EXT2_DX_ROOT_OFF); + hash_alg = root->hash_version; + if (hash_alg != EXT2_HASH_TEA && hash_alg != EXT2_HASH_HALF_MD4 && + hash_alg != EXT2_HASH_LEGACY) { + errcode = EXT2_ET_DIRHASH_UNSUPP; + goto out_err; + } + if (hash_alg <= EXT2_HASH_TEA && + fs->super->s_flags & EXT2_FLAGS_UNSIGNED_HASH) + hash_alg += 3; + if (root->indirect_levels >= ext2_dir_htree_level(fs)) { + errcode = EXT2_ET_DIR_CORRUPTED; + goto out_err; + } + info->hash_alg = hash_alg; + + errcode = ext2fs_dirhash2(hash_alg, info->name, info->namelen, + fs->encoding, hash_flags, + fs->super->s_hash_seed, &info->hash, + &minor_hash); + if (errcode) + goto out_err; + + for (level = 0; level <= root->indirect_levels; level++) { + frame = &(info->frames[level]); + if (level > 0) { + errcode = alloc_dx_frame(fs, frame); + if (errcode) + goto out_err; + info->levels++; + + errcode = load_logical_dir_block(fs, dir, diri, + ext2fs_le32_to_cpu(info->frames[level-1].at->block) & 0x0fffffff, + &(frame->pblock), frame->buf); + if (errcode) + goto out_err; + } + errcode = ext2fs_get_dx_countlimit(fs, (struct ext2_dir_entry*)frame->buf, + &(frame->head), NULL); + if (errcode) + goto out_err; + count = ext2fs_le16_to_cpu(frame->head->count); + limit = ext2fs_le16_to_cpu(frame->head->limit); + frame->entries = (struct ext2_dx_entry *)(frame->head); + if (!count || count > limit) { + errcode = EXT2_ET_DIR_CORRUPTED; + goto out_err; + } + + dx_search_entry(frame, count, info->hash); + } + return 0; +out_err: + dx_release(info); + return errcode; +} struct link_struct { ext2_filsys fs; @@ -31,7 +180,9 @@ struct link_struct { struct ext2_super_block *sb; }; -static int link_proc(struct ext2_dir_entry *dirent, +static int link_proc(ext2_ino_t dir EXT2FS_ATTR((unused)), + int entru EXT2FS_ATTR((unused)), + struct ext2_dir_entry *dirent, int offset, int blocksize, char *buf, @@ -42,7 +193,6 @@ static int link_proc(struct ext2_dir_entry *dirent, unsigned int rec_len, min_rec_len, curr_rec_len; int ret = 0; int csum_size = 0; - struct ext2_dir_entry_tail *t; if (ls->done) return DIRENT_ABORT; @@ -70,40 +220,6 @@ static int link_proc(struct ext2_dir_entry *dirent, ret = DIRENT_CHANGED; } - /* - * Since ext2fs_link blows away htree data, we need to be - * careful -- if metadata_csum is enabled and we're passed in - * a dirent that contains htree data, we need to create the - * fake entry at the end of the block that hides the checksum. - */ - - /* De-convert a dx_node block */ - if (csum_size && - curr_rec_len == ls->fs->blocksize && - !dirent->inode) { - curr_rec_len -= csum_size; - ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); - if (ls->err) - return DIRENT_ABORT; - t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize); - ext2fs_initialize_dirent_tail(ls->fs, t); - ret = DIRENT_CHANGED; - } - - /* De-convert a dx_root block */ - if (csum_size && - curr_rec_len == ls->fs->blocksize - EXT2_DIR_REC_LEN(1) && - offset == EXT2_DIR_REC_LEN(1) && - dirent->name[0] == '.' && dirent->name[1] == '.') { - curr_rec_len -= csum_size; - ls->err = ext2fs_set_rec_len(ls->fs, curr_rec_len, dirent); - if (ls->err) - return DIRENT_ABORT; - t = EXT2_DIRENT_TAIL(buf, ls->fs->blocksize); - ext2fs_initialize_dirent_tail(ls->fs, t); - ret = DIRENT_CHANGED; - } - /* * If the directory entry is used, see if we can split the * directory entry to make room for the new name. If so, @@ -144,6 +260,343 @@ static int link_proc(struct ext2_dir_entry *dirent, return DIRENT_ABORT|DIRENT_CHANGED; } +static errcode_t add_dirent_to_buf(ext2_filsys fs, e2_blkcnt_t blockcnt, + char *buf, ext2_ino_t dir, + struct ext2_inode *diri, const char *name, + ext2_ino_t ino, int flags, blk64_t *pblkp) +{ + struct dir_context ctx; + struct link_struct ls; + errcode_t retval; + + retval = load_logical_dir_block(fs, dir, diri, blockcnt, pblkp, buf); + if (retval) + return retval; + ctx.errcode = 0; + ctx.func = link_proc; + ctx.dir = dir; + ctx.flags = DIRENT_FLAG_INCLUDE_EMPTY; + ctx.buf = buf; + ctx.priv_data = &ls; + + ls.fs = fs; + ls.name = name; + ls.namelen = strlen(name); + ls.inode = ino; + ls.flags = flags; + ls.done = 0; + ls.sb = fs->super; + ls.blocksize = fs->blocksize; + ls.err = 0; + + ext2fs_process_dir_block(fs, pblkp, blockcnt, 0, 0, &ctx); + if (ctx.errcode) + return ctx.errcode; + if (ls.err) + return ls.err; + if (!ls.done) + return EXT2_ET_DIR_NO_SPACE; + return 0; +} + +struct dx_hash_map { + __u32 hash; + int size; + int off; +}; + +static EXT2_QSORT_TYPE dx_hash_map_cmp(const void *ap, const void *bp) +{ + const struct dx_hash_map *a = ap, *b = bp; + + if (a->hash < b->hash) + return -1; + if (a->hash > b->hash) + return 1; + return 0; +} + +static errcode_t dx_move_dirents(ext2_filsys fs, struct dx_hash_map *map, + int count, __u8 *from, __u8 *to) +{ + struct ext2_dir_entry *de; + int i; + int rec_len = 0; + errcode_t retval; + int csum_size = 0; + __u8 *base = to; + + if (ext2fs_has_feature_metadata_csum(fs->super)) + csum_size = sizeof(struct ext2_dir_entry_tail); + + for (i = 0; i < count; i++) { + de = (struct ext2_dir_entry*)(from + map[i].off); + rec_len = EXT2_DIR_REC_LEN(ext2fs_dirent_name_len(de)); + memcpy(to, de, rec_len); + retval = ext2fs_set_rec_len(fs, rec_len, (struct ext2_dir_entry*)to); + if (retval) + return retval; + to += rec_len; + } + /* + * Update rec_len of the last dir entry to stretch to the end of block + */ + to -= rec_len; + rec_len = fs->blocksize - (to - base) - csum_size; + retval = ext2fs_set_rec_len(fs, rec_len, (struct ext2_dir_entry*)to); + if (retval) + return retval; + if (csum_size) + ext2fs_initialize_dirent_tail(fs, + EXT2_DIRENT_TAIL(base, fs->blocksize)); + return 0; +} + +static errcode_t dx_insert_entry(ext2_filsys fs, ext2_ino_t dir, + struct dx_lookup_info *info, int level, + __u32 hash, blk64_t lblk) +{ + int pcount; + struct ext2_dx_entry *top, *new; + + pcount = ext2fs_le16_to_cpu(info->frames[level].head->count); + top = info->frames[level].entries + pcount; + new = info->frames[level].at + 1; + memmove(new + 1, new, (char *)top - (char *)new); + new->hash = ext2fs_cpu_to_le32(hash); + new->block = ext2fs_cpu_to_le32(lblk); + info->frames[level].head->count = ext2fs_cpu_to_le16(pcount + 1); + return ext2fs_write_dir_block4(fs, info->frames[level].pblock, + info->frames[level].buf, 0, dir); +} + +static errcode_t dx_split_leaf(ext2_filsys fs, ext2_ino_t dir, + struct ext2_inode *diri, + struct dx_lookup_info *info, __u8 *buf, + blk64_t leaf_pblk, blk64_t new_lblk, + blk64_t new_pblk) +{ + int hash_flags = diri->i_flags & EXT4_CASEFOLD_FL; + struct ext2_dir_entry *de; + void *buf2; + errcode_t retval = 0; + int rec_len; + int offset, move_size; + int i, count = 0; + struct dx_hash_map *map; + int continued; + __u32 minor_hash; + + retval = ext2fs_get_mem(fs->blocksize, &buf2); + if (retval) + return retval; + retval = ext2fs_get_array(fs->blocksize / 12, + sizeof(struct dx_hash_map), &map); + if (retval) { + ext2fs_free_mem(&buf2); + return retval; + } + for (offset = 0; offset < fs->blocksize; offset += rec_len) { + de = (struct ext2_dir_entry*)(buf + offset); + retval = ext2fs_get_rec_len(fs, de, &rec_len); + if (retval) + goto out; + if (ext2fs_dirent_name_len(de) > 0 && de->inode) { + map[count].off = offset; + map[count].size = rec_len; + retval = ext2fs_dirhash2(info->hash_alg, de->name, + ext2fs_dirent_name_len(de), + fs->encoding, hash_flags, + fs->super->s_hash_seed, + &(map[count].hash), + &minor_hash); + if (retval) + goto out; + count++; + } + } + qsort(map, count, sizeof(struct dx_hash_map), dx_hash_map_cmp); + move_size = 0; + /* Find place to split block */ + for (i = count - 1; i >= 0; i--) { + if (move_size + map[i].size / 2 > fs->blocksize / 2) + break; + move_size += map[i].size; + } + /* Let i be the first entry to move */ + i++; + /* Move selected directory entries to new block */ + retval = dx_move_dirents(fs, map + i, count - i, buf, buf2); + if (retval) + goto out; + retval = ext2fs_write_dir_block4(fs, new_pblk, buf2, 0, dir); + if (retval) + goto out; + /* Repack remaining entries in the old block */ + retval = dx_move_dirents(fs, map, i, buf, buf2); + if (retval) + goto out; + retval = ext2fs_write_dir_block4(fs, leaf_pblk, buf2, 0, dir); + if (retval) + goto out; + /* Update parent node */ + continued = map[i].hash == map[i-1].hash; + retval = dx_insert_entry(fs, dir, info, info->levels - 1, + map[i].hash + continued, new_lblk); +out: + ext2fs_free_mem(&buf2); + ext2fs_free_mem(&map); + return retval; +} + +static errcode_t dx_grow_tree(ext2_filsys fs, ext2_ino_t dir, + struct ext2_inode *diri, + struct dx_lookup_info *info, __u8 *buf, + blk64_t leaf_pblk) +{ + int i; + errcode_t retval; + ext2_off64_t size = EXT2_I_SIZE(diri); + blk64_t lblk, pblk; + struct ext2_dir_entry *de; + struct ext2_dx_countlimit *head; + int csum_size = 0; + int count; + + if (ext2fs_has_feature_metadata_csum(fs->super)) + csum_size = sizeof(struct ext2_dx_tail); + + /* Find level which can accommodate new child */ + for (i = info->levels - 1; i >= 0; i--) + if (ext2fs_le16_to_cpu(info->frames[i].head->count) < + ext2fs_le16_to_cpu(info->frames[i].head->limit)) + break; + /* Need to grow tree depth? */ + if (i < 0 && info->levels >= ext2_dir_htree_level(fs)) + return EXT2_ET_DIR_NO_SPACE; + lblk = size / fs->blocksize; + size += fs->blocksize; + retval = ext2fs_inode_size_set(fs, diri, size); + if (retval) + return retval; + retval = ext2fs_fallocate(fs, + EXT2_FALLOCATE_FORCE_INIT | EXT2_FALLOCATE_ZERO_BLOCKS, + dir, diri, 0, lblk, 1); + if (retval) + return retval; + retval = ext2fs_write_inode(fs, dir, diri); + if (retval) + return retval; + retval = ext2fs_bmap2(fs, dir, diri, NULL, 0, lblk, NULL, &pblk); + if (retval) + return retval; + /* Only leaf addition needed? */ + if (i == info->levels - 1) + return dx_split_leaf(fs, dir, diri, info, buf, leaf_pblk, + lblk, pblk); + + de = (struct ext2_dir_entry*)buf; + de->inode = 0; + ext2fs_dirent_set_name_len(de, 0); + ext2fs_dirent_set_file_type(de, 0); + retval = ext2fs_set_rec_len(fs, fs->blocksize, de); + if (retval) + return retval; + head = (struct ext2_dx_countlimit*)(buf + 8); + count = ext2fs_le16_to_cpu(info->frames[i+1].head->count); + /* Growing tree depth? */ + if (i < 0) { + struct ext2_dx_root_info *root; + + memcpy(head, info->frames[0].entries, + count * sizeof(struct ext2_dx_entry)); + head->limit = ext2fs_cpu_to_le16( + (fs->blocksize - (8 + csum_size)) / + sizeof(struct ext2_dx_entry)); + /* head->count gets set by memcpy above to correct value */ + + /* Now update tree root */ + info->frames[0].head->count = ext2fs_cpu_to_le16(1); + info->frames[0].entries[0].block = ext2fs_cpu_to_le32(lblk); + root = (struct ext2_dx_root_info*)(info->frames[0].buf + EXT2_DX_ROOT_OFF); + root->indirect_levels++; + } else { + /* Splitting internal node in two */ + int count1 = count / 2; + int count2 = count - count1; + __u32 split_hash = ext2fs_le32_to_cpu(info->frames[i+1].entries[count1].hash); + + memcpy(head, info->frames[i+1].entries + count1, + count2 * sizeof(struct ext2_dx_entry)); + head->count = ext2fs_cpu_to_le16(count2); + head->limit = ext2fs_cpu_to_le16( + (fs->blocksize - (8ULL + csum_size)) / + sizeof(struct ext2_dx_entry)); + info->frames[i+1].head->count = ext2fs_cpu_to_le16(count1); + + /* Update parent node */ + retval = dx_insert_entry(fs, dir, info, i, split_hash, lblk); + if (retval) + return retval; + + } + /* Writeout split block / updated root */ + retval = ext2fs_write_dir_block4(fs, info->frames[i+1].pblock, + info->frames[i+1].buf, 0, dir); + if (retval) + return retval; + /* Writeout new tree block */ + retval = ext2fs_write_dir_block4(fs, pblk, buf, 0, dir); + if (retval) + return retval; + return 0; +} + +static errcode_t dx_link(ext2_filsys fs, ext2_ino_t dir, + struct ext2_inode *diri, const char *name, + ext2_ino_t ino, int flags) +{ + struct dx_lookup_info dx_info; + errcode_t retval; + void *blockbuf; + int restart = 0; + blk64_t leaf_pblk; + + retval = ext2fs_get_mem(fs->blocksize, &blockbuf); + if (retval) + return retval; + + dx_info.name = name; + dx_info.namelen = strlen(name); +again: + retval = dx_lookup(fs, dir, diri, &dx_info); + if (retval) + goto free_buf; + + retval = add_dirent_to_buf(fs, + ext2fs_le32_to_cpu(dx_info.frames[dx_info.levels-1].at->block) & 0x0fffffff, + blockbuf, dir, diri, name, ino, flags, &leaf_pblk); + /* + * Success or error other than ENOSPC...? We are done. We may need upto + * two tries to add entry. One to split htree node and another to add + * new leaf block. + */ + if (restart >= dx_info.levels || retval != EXT2_ET_DIR_NO_SPACE) + goto free_frames; + retval = dx_grow_tree(fs, dir, diri, &dx_info, blockbuf, leaf_pblk); + if (retval) + goto free_frames; + /* Restart everything now that the tree is larger */ + restart++; + dx_release(&dx_info); + goto again; +free_frames: + dx_release(&dx_info); +free_buf: + ext2fs_free_mem(&blockbuf); + return retval; +} + /* * Note: the low 3 bits of the flags field are used as the directory * entry filetype. @@ -163,6 +616,12 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, if (!(fs->flags & EXT2_FLAG_RW)) return EXT2_ET_RO_FILSYS; + if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0) + return retval; + + if (inode.i_flags & EXT2_INDEX_FL) + return dx_link(fs, dir, &inode, name, ino, flags); + ls.fs = fs; ls.name = name; ls.namelen = name ? strlen(name) : 0; @@ -173,8 +632,8 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, ls.blocksize = fs->blocksize; ls.err = 0; - retval = ext2fs_dir_iterate(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, - 0, link_proc, &ls); + retval = ext2fs_dir_iterate2(fs, dir, DIRENT_FLAG_INCLUDE_EMPTY, + NULL, link_proc, &ls); if (retval) return retval; if (ls.err) @@ -182,20 +641,5 @@ errcode_t ext2fs_link(ext2_filsys fs, ext2_ino_t dir, const char *name, if (!ls.done) return EXT2_ET_DIR_NO_SPACE; - - if ((retval = ext2fs_read_inode(fs, dir, &inode)) != 0) - return retval; - - /* - * If this function changes to preserve the htree, remove the - * two hunks in link_proc that shove checksum tails into the - * former dx_root/dx_node blocks. - */ - if (inode.i_flags & EXT2_INDEX_FL) { - inode.i_flags &= ~EXT2_INDEX_FL; - if ((retval = ext2fs_write_inode(fs, dir, &inode)) != 0) - return retval; - } - return 0; } diff --git a/src/ext2fs/mkdir.c b/src/ext2fs/mkdir.c index 2a63aad1..437c8ffc 100644 --- a/src/ext2fs/mkdir.c +++ b/src/ext2fs/mkdir.c @@ -43,6 +43,7 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, blk64_t blk; char *block = 0; int inline_data = 0; + int drop_refcount = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); @@ -143,6 +144,14 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, } } + /* + * Update accounting.... + */ + if (!inline_data) + ext2fs_block_alloc_stats2(fs, blk, +1); + ext2fs_inode_alloc_stats2(fs, ino, +1, 1); + drop_refcount = 1; + /* * Link the directory into the filesystem hierarchy */ @@ -174,17 +183,16 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, if (retval) goto cleanup; } - - /* - * Update accounting.... - */ - if (!inline_data) - ext2fs_block_alloc_stats2(fs, blk, +1); - ext2fs_inode_alloc_stats2(fs, ino, +1, 1); + drop_refcount = 0; cleanup: if (block) ext2fs_free_mem(&block); + if (drop_refcount) { + if (!inline_data) + ext2fs_block_alloc_stats2(fs, blk, -1); + ext2fs_inode_alloc_stats2(fs, ino, -1, 1); + } return retval; } diff --git a/src/ext2fs/mkjournal.c b/src/ext2fs/mkjournal.c index 4b83543f..768c6150 100644 --- a/src/ext2fs/mkjournal.c +++ b/src/ext2fs/mkjournal.c @@ -52,7 +52,7 @@ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, errcode_t retval; journal_superblock_t *jsb; - if (num_blocks < JFS_MIN_JOURNAL_BLOCKS) + if (num_blocks < JBD2_MIN_JOURNAL_BLOCKS) return EXT2_ET_JOURNAL_TOO_SMALL; if ((retval = ext2fs_get_mem(fs->blocksize, &jsb))) @@ -60,11 +60,11 @@ errcode_t ext2fs_create_journal_superblock(ext2_filsys fs, memset (jsb, 0, fs->blocksize); - jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); + jsb->s_header.h_magic = htonl(JBD2_MAGIC_NUMBER); if (flags & EXT2_MKJOURNAL_V1_SUPER) - jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V1); + jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V1); else - jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); + jsb->s_header.h_blocktype = htonl(JBD2_SUPERBLOCK_V2); jsb->s_blocksize = htonl(fs->blocksize); jsb->s_maxlen = htonl(num_blocks); jsb->s_nr_users = htonl(1); @@ -394,8 +394,8 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) return retval; jsb = (journal_superblock_t *) buf; - if ((jsb->s_header.h_magic != (unsigned) ntohl(JFS_MAGIC_NUMBER)) || - (jsb->s_header.h_blocktype != (unsigned) ntohl(JFS_SUPERBLOCK_V2))) + if ((jsb->s_header.h_magic != (unsigned) ntohl(JBD2_MAGIC_NUMBER)) || + (jsb->s_header.h_blocktype != (unsigned) ntohl(JBD2_SUPERBLOCK_V2))) return EXT2_ET_NO_JOURNAL_SB; if (ntohl(jsb->s_blocksize) != (unsigned long) fs->blocksize) @@ -403,7 +403,7 @@ errcode_t ext2fs_add_journal_device(ext2_filsys fs, ext2_filsys journal_dev) /* Check and see if this filesystem has already been added */ nr_users = ntohl(jsb->s_nr_users); - if (nr_users > JFS_USERS_MAX) + if (nr_users > JBD2_USERS_MAX) return EXT2_ET_CORRUPT_JOURNAL_SB; for (i=0; i < nr_users; i++) { if (memcmp(fs->super->s_uuid, @@ -575,7 +575,7 @@ main(int argc, char **argv) exit(1); } - retval = ext2fs_add_journal_inode(fs, JFS_MIN_JOURNAL_BLOCKS, 0); + retval = ext2fs_add_journal_inode(fs, JBD2_MIN_JOURNAL_BLOCKS, 0); if (retval) { com_err(argv[0], retval, "while adding journal to %s", device_name); diff --git a/src/ext2fs/mmp.c b/src/ext2fs/mmp.c index 7f87ab48..e9d0b951 100644 --- a/src/ext2fs/mmp.c +++ b/src/ext2fs/mmp.c @@ -59,8 +59,21 @@ errcode_t ext2fs_mmp_read(ext2_filsys fs, blk64_t mmp_blk, void *buf) * regardless of how the io_manager is doing reads, to avoid caching of * the MMP block by the io_manager or the VM. It needs to be fresh. */ if (fs->mmp_fd <= 0) { - fs->mmp_fd = open(fs->device_name, O_RDWR | O_DIRECT); + int flags = O_RDWR | O_DIRECT; + +retry: + fs->mmp_fd = open(fs->device_name, flags); if (fs->mmp_fd < 0) { + struct stat st; + + /* Avoid O_DIRECT for filesystem image files if open + * fails, since it breaks when running on tmpfs. */ + if (errno == EINVAL && (flags & O_DIRECT) && + stat(fs->device_name, &st) == 0 && + S_ISREG(st.st_mode)) { + flags &= ~O_DIRECT; + goto retry; + } retval = EXT2_ET_MMP_OPEN_DIRECT; goto out; } diff --git a/src/ext2fs/nt_io.c b/src/ext2fs/nt_io.c index 87dbb859..a4231bef 100644 --- a/src/ext2fs/nt_io.c +++ b/src/ext2fs/nt_io.c @@ -81,7 +81,7 @@ static errcode_t nt_write_blk(io_channel channel, unsigned long block, int count static errcode_t nt_write_blk64(io_channel channel, unsigned long long block, int count, const void* data); static errcode_t nt_flush(io_channel channel); -static struct struct_io_manager struct_nt_manager = { +struct struct_io_manager struct_nt_manager = { .magic = EXT2_ET_MAGIC_IO_MANAGER, .name = "NT I/O Manager", .open = nt_open, @@ -94,10 +94,7 @@ static struct struct_io_manager struct_nt_manager = { .flush = nt_flush }; -io_manager nt_io_manager(void) -{ - return &struct_nt_manager; -} +io_manager nt_io_manager = &struct_nt_manager; // Convert Win32 errors to unix errno typedef struct { @@ -530,7 +527,7 @@ static errcode_t nt_open(const char *name, int flags, io_channel *channel) // Initialize data io->magic = EXT2_ET_MAGIC_IO_CHANNEL; - io->manager = nt_io_manager(); + io->manager = nt_io_manager; strcpy(io->name, name); io->block_size = EXT2_MIN_BLOCK_SIZE; io->refcount = 1; diff --git a/src/ext2fs/openfs.c b/src/ext2fs/openfs.c index 009df244..cb7366df 100644 --- a/src/ext2fs/openfs.c +++ b/src/ext2fs/openfs.c @@ -29,7 +29,6 @@ #include "ext2_fs.h" - #include "ext2fs.h" #include "e2image.h" @@ -135,6 +134,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, int j; #endif char *time_env; + int csum_retries = 0; EXT2_CHECK_MAGIC(manager, EXT2_ET_MAGIC_IO_MANAGER); @@ -223,6 +223,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, if (retval) goto cleanup; } +retry: retval = io_channel_read_blk(fs->io, superblock, -SUPERBLOCK_SIZE, fs->super); if (retval) @@ -234,8 +235,11 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, retval = 0; if (!ext2fs_verify_csum_type(fs, fs->super)) retval = EXT2_ET_UNKNOWN_CSUM; - if (!ext2fs_superblock_csum_verify(fs, fs->super)) + if (!ext2fs_superblock_csum_verify(fs, fs->super)) { + if (csum_retries++ < 3) + goto retry; retval = EXT2_ET_SB_CSUM_INVALID; + } } #ifdef WORDS_BIGENDIAN @@ -395,6 +399,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, } fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count, EXT2_DESC_PER_BLOCK(fs->super)); + if (flags & EXT2_FLAG_SUPER_ONLY) + goto skip_read_bg; retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize, &fs->group_desc); if (retval) @@ -435,7 +441,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, gdp = (struct ext2_group_desc *) dest; for (j=0; j < groups_per_block*first_meta_bg; j++) { gdp = ext2fs_group_desc(fs, fs->group_desc, j); - ext2fs_swap_group_desc2(fs, gdp); + if (gdp) + ext2fs_swap_group_desc2(fs, gdp); } #endif dest += fs->blocksize*first_meta_bg; @@ -455,7 +462,8 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, for (j=0; j < groups_per_block; j++) { gdp = ext2fs_group_desc(fs, fs->group_desc, i * groups_per_block + j); - ext2fs_swap_group_desc2(fs, gdp); + if (gdp) + ext2fs_swap_group_desc2(fs, gdp); } #endif dest += fs->blocksize; @@ -481,7 +489,7 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, if (fs->flags & EXT2_FLAG_RW) ext2fs_mark_super_dirty(fs); } - +skip_read_bg: if (ext2fs_has_feature_mmp(fs->super) && !(flags & EXT2_FLAG_SKIP_MMP) && (flags & (EXT2_FLAG_RW | EXT2_FLAG_EXCLUSIVE))) { @@ -503,6 +511,9 @@ errcode_t ext2fs_open2(const char *name, const char *io_options, ext2fs_set_feature_shared_blocks(fs->super); } +// if (ext2fs_has_feature_casefold(fs->super)) +// fs->encoding = ext2fs_load_nls_table(fs->super->s_encoding); + fs->flags &= ~EXT2_FLAG_NOFREE_ON_ERROR; *ret_fs = fs; diff --git a/src/ext2fs/rw_bitmaps.c b/src/ext2fs/rw_bitmaps.c index 03cfb4e2..35c409bb 100644 --- a/src/ext2fs/rw_bitmaps.c +++ b/src/ext2fs/rw_bitmaps.c @@ -195,6 +195,16 @@ static errcode_t mark_uninit_bg_group_blocks(ext2_filsys fs) return 0; } +static int bitmap_tail_verify(unsigned char *bitmap, int first, int last) +{ + int i; + + for (i = first; i <= last; i++) + if (bitmap[i] != 0xff) + return 0; + return 1; +} + static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) { dgrp_t i; @@ -203,6 +213,7 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) errcode_t retval; int block_nbytes = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8; int inode_nbytes = EXT2_INODES_PER_GROUP(fs->super) / 8; + int tail_flags = 0; int csum_flag; unsigned int cnt; blk64_t blk; @@ -295,9 +306,10 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) for (i = 0; i < fs->group_desc_count; i++) { if (block_bitmap) { blk = ext2fs_block_bitmap_loc(fs, i); - if (csum_flag && - ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && - ext2fs_group_desc_csum_verify(fs, i)) + if ((csum_flag && + ext2fs_bg_flags_test(fs, i, EXT2_BG_BLOCK_UNINIT) && + ext2fs_group_desc_csum_verify(fs, i)) || + (blk >= ext2fs_blocks_count(fs->super))) blk = 0; if (blk) { retval = io_channel_read_blk64(fs->io, blk, @@ -315,6 +327,9 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) EXT2_ET_BLOCK_BITMAP_CSUM_INVALID; goto cleanup; } + if (!bitmap_tail_verify((unsigned char *) block_bitmap, + block_nbytes, fs->blocksize - 1)) + tail_flags |= EXT2_FLAG_BBITMAP_TAIL_PROBLEM; } else memset(block_bitmap, 0, block_nbytes); cnt = block_nbytes << 3; @@ -322,13 +337,14 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) blk_itr, cnt, block_bitmap); if (retval) goto cleanup; - blk_itr += (blk64_t)block_nbytes << 3; + blk_itr += block_nbytes << 3; } if (inode_bitmap) { blk = ext2fs_inode_bitmap_loc(fs, i); - if (csum_flag && - ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && - ext2fs_group_desc_csum_verify(fs, i)) + if ((csum_flag && + ext2fs_bg_flags_test(fs, i, EXT2_BG_INODE_UNINIT) && + ext2fs_group_desc_csum_verify(fs, i)) || + (blk >= ext2fs_blocks_count(fs->super))) blk = 0; if (blk) { retval = io_channel_read_blk64(fs->io, blk, @@ -347,6 +363,9 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) EXT2_ET_INODE_BITMAP_CSUM_INVALID; goto cleanup; } + if (!bitmap_tail_verify((unsigned char *) inode_bitmap, + inode_nbytes, fs->blocksize - 1)) + tail_flags |= EXT2_FLAG_IBITMAP_TAIL_PROBLEM; } else memset(inode_bitmap, 0, inode_nbytes); cnt = inode_nbytes << 3; @@ -366,19 +385,24 @@ static errcode_t read_bitmaps(ext2_filsys fs, int do_inode, int do_block) } success_cleanup: - if (inode_bitmap) + if (inode_bitmap) { ext2fs_free_mem(&inode_bitmap); - if (block_bitmap) + fs->flags &= ~EXT2_FLAG_IBITMAP_TAIL_PROBLEM; + } + if (block_bitmap) { ext2fs_free_mem(&block_bitmap); + fs->flags &= ~EXT2_FLAG_BBITMAP_TAIL_PROBLEM; + } + fs->flags |= tail_flags; return 0; cleanup: if (do_block) { - ext2fs_free_mem(&fs->block_map); + ext2fs_free_block_bitmap(fs->block_map); fs->block_map = 0; } if (do_inode) { - ext2fs_free_mem(&fs->inode_map); + ext2fs_free_inode_bitmap(fs->inode_map); fs->inode_map = 0; } if (inode_bitmap) diff --git a/src/ext2fs/symlink.c b/src/ext2fs/symlink.c index 7f78c5f7..a66fb7ec 100644 --- a/src/ext2fs/symlink.c +++ b/src/ext2fs/symlink.c @@ -54,6 +54,7 @@ errcode_t ext2fs_symlink(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t ino, int fastlink, inlinelink; unsigned int target_len; char *block_buf = 0; + int drop_refcount = 0; EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); @@ -162,6 +163,14 @@ need_block: goto cleanup; } + /* + * Update accounting.... + */ + if (!fastlink && !inlinelink) + ext2fs_block_alloc_stats2(fs, blk, +1); + ext2fs_inode_alloc_stats2(fs, ino, +1, 0); + drop_refcount = 1; + /* * Link the symlink into the filesystem hierarchy */ @@ -178,17 +187,16 @@ need_block: if (retval) goto cleanup; } - - /* - * Update accounting.... - */ - if (!fastlink && !inlinelink) - ext2fs_block_alloc_stats2(fs, blk, +1); - ext2fs_inode_alloc_stats2(fs, ino, +1, 0); + drop_refcount = 0; cleanup: if (block_buf) ext2fs_free_mem(&block_buf); + if (drop_refcount) { + if (!fastlink && !inlinelink) + ext2fs_block_alloc_stats2(fs, blk, -1); + ext2fs_inode_alloc_stats2(fs, ino, -1, 0); + } return retval; } diff --git a/src/format_ext.c b/src/format_ext.c index 5601ee7b..68d0bedf 100644 --- a/src/format_ext.c +++ b/src/format_ext.c @@ -39,7 +39,7 @@ #include "ext2fs/ext2fs.h" extern const char* FileSystemLabel[FS_MAX]; -extern io_manager nt_io_manager(void); +extern io_manager nt_io_manager; extern DWORD ext2_last_winerror(DWORD default_error); static float ext2_percent_start = 0.0f, ext2_percent_share = 0.5f; const float ext2_max_marker = 80.0f; @@ -172,6 +172,8 @@ const char* error_message(errcode_t error_code) case EXT2_ET_INODE_CORRUPTED: case EXT2_ET_EA_INODE_CORRUPTED: return "Inode is corrupted"; + case EXT2_ET_NO_GDESC: + return "Group descriptors not loaded"; default: if ((error_code > EXT2_ET_BASE) && error_code < (EXT2_ET_BASE + 1000)) { static_sprintf(error_string, "Unknown ext2fs error %ld (EXT2_ET_BASE + %ld)", error_code, error_code - EXT2_ET_BASE); @@ -202,7 +204,7 @@ const char* GetExtFsLabel(DWORD DriveIndex, uint64_t PartitionOffset) static char label[EXT2_LABEL_LEN + 1]; errcode_t r; ext2_filsys ext2fs = NULL; - io_manager manager = nt_io_manager(); + io_manager manager = nt_io_manager; char* volume_name = GetExtPartitionName(DriveIndex, PartitionOffset); if (volume_name == NULL) @@ -238,7 +240,7 @@ BOOL FormatExtFs(DWORD DriveIndex, uint64_t PartitionOffset, DWORD BlockSize, LP char* volume_name = NULL; int i, count; struct ext2_super_block features = { 0 }; - io_manager manager = nt_io_manager(); + io_manager manager = nt_io_manager; blk_t journal_size; blk64_t size = 0, cur; ext2_filsys ext2fs = NULL; diff --git a/src/rufus.rc b/src/rufus.rc index fed3433a..8aa67275 100644 --- a/src/rufus.rc +++ b/src/rufus.rc @@ -35,7 +35,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL IDD_DIALOG DIALOGEX 12, 12, 232, 326 STYLE DS_SETFONT | DS_MODALFRAME | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU EXSTYLE WS_EX_ACCEPTFILES -CAPTION "Rufus 3.14.1732" +CAPTION "Rufus 3.14.1733" FONT 9, "Segoe UI Symbol", 400, 0, 0x0 BEGIN LTEXT "Drive Properties",IDS_DRIVE_PROPERTIES_TXT,8,6,53,12,NOT WS_GROUP @@ -397,8 +397,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 3,14,1732,0 - PRODUCTVERSION 3,14,1732,0 + FILEVERSION 3,14,1733,0 + PRODUCTVERSION 3,14,1733,0 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -416,13 +416,13 @@ BEGIN VALUE "Comments", "https://rufus.ie" VALUE "CompanyName", "Akeo Consulting" VALUE "FileDescription", "Rufus" - VALUE "FileVersion", "3.14.1732" + VALUE "FileVersion", "3.14.1733" VALUE "InternalName", "Rufus" VALUE "LegalCopyright", "© 2011-2021 Pete Batard (GPL v3)" VALUE "LegalTrademarks", "https://www.gnu.org/licenses/gpl-3.0.html" VALUE "OriginalFilename", "rufus-3.14.exe" VALUE "ProductName", "Rufus" - VALUE "ProductVersion", "3.14.1732" + VALUE "ProductVersion", "3.14.1733" END END BLOCK "VarFileInfo"