mirror of
https://github.com/pbatard/rufus.git
synced 2024-08-14 23:57:05 +00:00
[ext2fs] update ext2fs to latest
* Also drop nt_io_manager() as a function call and just use a direct ref to the manager.
This commit is contained in:
parent
fce645543f
commit
3056d54cc1
31 changed files with 1365 additions and 369 deletions
|
@ -53,6 +53,7 @@
|
|||
<ClCompile Include="..\src\ext2fs\crc32c.c" />
|
||||
<ClCompile Include="..\src\ext2fs\csum.c" />
|
||||
<ClCompile Include="..\src\ext2fs\dirblock.c" />
|
||||
<ClCompile Include="..\src\ext2fs\dirhash.c" />
|
||||
<ClCompile Include="..\src\ext2fs\dir_iterate.c" />
|
||||
<ClCompile Include="..\src\ext2fs\extent.c" />
|
||||
<ClCompile Include="..\src\ext2fs\ext_attr.c" />
|
||||
|
|
|
@ -162,6 +162,9 @@
|
|||
<ClCompile Include="..\src\ext2fs\namei.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\src\ext2fs\dirhash.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\src\ext2fs\ext2_fs.h">
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
307
src/ext2fs/dirhash.c
Normal file
307
src/ext2fs/dirhash.c
Normal file
|
@ -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 <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#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 <jeremy@zip.com.au> 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);
|
||||
}
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,22 @@
|
|||
#include "hashmap.h"
|
||||
#include <string.h>
|
||||
|
||||
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;
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
10
src/rufus.rc
10
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"
|
||||
|
|
Loading…
Reference in a new issue