pmt: initial 2.9.1 update
This commit is contained in:
554
jni/e2fsprogs/lib/ext2fs/alloc.c
Executable file
554
jni/e2fsprogs/lib/ext2fs/alloc.c
Executable file
@@ -0,0 +1,554 @@
|
||||
/*
|
||||
* alloc.c --- allocate new inodes, blocks for ext2fs
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
|
||||
#else
|
||||
# define dbg_printf(f, a...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Clear the uninit block bitmap flag if necessary
|
||||
*/
|
||||
void ext2fs_clear_block_uninit(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
if (group >= fs->group_desc_count ||
|
||||
!ext2fs_has_group_desc_csum(fs) ||
|
||||
!(ext2fs_bg_flags_test(fs, group, EXT2_BG_BLOCK_UNINIT)))
|
||||
return;
|
||||
|
||||
/* uninit block bitmaps are now initialized in read_bitmaps() */
|
||||
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
ext2fs_mark_bb_dirty(fs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for uninit inode bitmaps and deal with them appropriately
|
||||
*/
|
||||
static void check_inode_uninit(ext2_filsys fs, ext2fs_inode_bitmap map,
|
||||
dgrp_t group)
|
||||
{
|
||||
ext2_ino_t i, ino;
|
||||
|
||||
if (group >= fs->group_desc_count ||
|
||||
!ext2fs_has_group_desc_csum(fs) ||
|
||||
!(ext2fs_bg_flags_test(fs, group, EXT2_BG_INODE_UNINIT)))
|
||||
return;
|
||||
|
||||
ino = (group * fs->super->s_inodes_per_group) + 1;
|
||||
for (i=0; i < fs->super->s_inodes_per_group; i++, ino++)
|
||||
ext2fs_fast_unmark_inode_bitmap2(map, ino);
|
||||
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
|
||||
/* Mimics what the kernel does */
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
ext2fs_mark_ib_dirty(fs);
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
}
|
||||
|
||||
/*
|
||||
* Right now, just search forward from the parent directory's block
|
||||
* group to find the next free inode.
|
||||
*
|
||||
* Should have a special policy for directories.
|
||||
*/
|
||||
errcode_t ext2fs_new_inode(ext2_filsys fs, ext2_ino_t dir,
|
||||
int mode EXT2FS_ATTR((unused)),
|
||||
ext2fs_inode_bitmap map, ext2_ino_t *ret)
|
||||
{
|
||||
ext2_ino_t start_inode = 0;
|
||||
ext2_ino_t i, ino_in_group, upto, first_zero;
|
||||
errcode_t retval;
|
||||
dgrp_t group;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (!map)
|
||||
map = fs->inode_map;
|
||||
if (!map)
|
||||
return EXT2_ET_NO_INODE_BITMAP;
|
||||
|
||||
if (dir > 0) {
|
||||
group = (dir - 1) / EXT2_INODES_PER_GROUP(fs->super);
|
||||
start_inode = (group * EXT2_INODES_PER_GROUP(fs->super)) + 1;
|
||||
}
|
||||
if (start_inode < EXT2_FIRST_INODE(fs->super))
|
||||
start_inode = EXT2_FIRST_INODE(fs->super);
|
||||
if (start_inode > fs->super->s_inodes_count)
|
||||
return EXT2_ET_INODE_ALLOC_FAIL;
|
||||
i = start_inode;
|
||||
do {
|
||||
ino_in_group = (i - 1) % EXT2_INODES_PER_GROUP(fs->super);
|
||||
group = (i - 1) / EXT2_INODES_PER_GROUP(fs->super);
|
||||
|
||||
check_inode_uninit(fs, map, group);
|
||||
upto = i + (EXT2_INODES_PER_GROUP(fs->super) - ino_in_group);
|
||||
if (i < start_inode && upto >= start_inode)
|
||||
upto = start_inode - 1;
|
||||
if (upto > fs->super->s_inodes_count)
|
||||
upto = fs->super->s_inodes_count;
|
||||
|
||||
retval = ext2fs_find_first_zero_inode_bitmap2(map, i, upto,
|
||||
&first_zero);
|
||||
if (retval == 0) {
|
||||
i = first_zero;
|
||||
break;
|
||||
}
|
||||
if (retval != ENOENT)
|
||||
return EXT2_ET_INODE_ALLOC_FAIL;
|
||||
i = upto + 1;
|
||||
if (i > fs->super->s_inodes_count)
|
||||
i = EXT2_FIRST_INODE(fs->super);
|
||||
} while (i != start_inode);
|
||||
|
||||
if (ext2fs_test_inode_bitmap2(map, i))
|
||||
return EXT2_ET_INODE_ALLOC_FAIL;
|
||||
*ret = i;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Stupid algorithm --- we now just search forward starting from the
|
||||
* goal. Should put in a smarter one someday....
|
||||
*/
|
||||
errcode_t ext2fs_new_block3(ext2_filsys fs, blk64_t goal,
|
||||
ext2fs_block_bitmap map, blk64_t *ret,
|
||||
struct blk_alloc_ctx *ctx)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t b = 0;
|
||||
errcode_t (*gab)(ext2_filsys fs, blk64_t goal, blk64_t *ret);
|
||||
errcode_t (*gab2)(ext2_filsys, blk64_t, blk64_t *,
|
||||
struct blk_alloc_ctx *);
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (!map) {
|
||||
/*
|
||||
* In case there are clients out there whose get_alloc_block
|
||||
* handlers call ext2fs_new_block2 with a NULL block map,
|
||||
* temporarily swap out the function pointer so that we don't
|
||||
* end up in an infinite loop.
|
||||
*/
|
||||
if (fs->get_alloc_block2) {
|
||||
gab2 = fs->get_alloc_block2;
|
||||
fs->get_alloc_block2 = NULL;
|
||||
retval = gab2(fs, goal, &b, ctx);
|
||||
fs->get_alloc_block2 = gab2;
|
||||
goto allocated;
|
||||
} else if (fs->get_alloc_block) {
|
||||
gab = fs->get_alloc_block;
|
||||
fs->get_alloc_block = NULL;
|
||||
retval = gab(fs, goal, &b);
|
||||
fs->get_alloc_block = gab;
|
||||
goto allocated;
|
||||
}
|
||||
}
|
||||
if (!map)
|
||||
map = fs->block_map;
|
||||
if (!map)
|
||||
return EXT2_ET_NO_BLOCK_BITMAP;
|
||||
if (!goal || (goal >= ext2fs_blocks_count(fs->super)))
|
||||
goal = fs->super->s_first_data_block;
|
||||
goal &= ~EXT2FS_CLUSTER_MASK(fs);
|
||||
|
||||
retval = ext2fs_find_first_zero_block_bitmap2(map,
|
||||
goal, ext2fs_blocks_count(fs->super) - 1, &b);
|
||||
if ((retval == ENOENT) && (goal != fs->super->s_first_data_block))
|
||||
retval = ext2fs_find_first_zero_block_bitmap2(map,
|
||||
fs->super->s_first_data_block, goal - 1, &b);
|
||||
allocated:
|
||||
if (retval == ENOENT)
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ext2fs_clear_block_uninit(fs, ext2fs_group_of_blk2(fs, b));
|
||||
*ret = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_new_block2(ext2_filsys fs, blk64_t goal,
|
||||
ext2fs_block_bitmap map, blk64_t *ret)
|
||||
{
|
||||
return ext2fs_new_block3(fs, goal, map, ret, NULL);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_new_block(ext2_filsys fs, blk_t goal,
|
||||
ext2fs_block_bitmap map, blk_t *ret)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t val;
|
||||
retval = ext2fs_new_block2(fs, goal, map, &val);
|
||||
if (!retval)
|
||||
*ret = (blk_t) val;
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function zeros out the allocated block, and updates all of the
|
||||
* appropriate filesystem records.
|
||||
*/
|
||||
errcode_t ext2fs_alloc_block3(ext2_filsys fs, blk64_t goal, char *block_buf,
|
||||
blk64_t *ret, struct blk_alloc_ctx *ctx)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t block;
|
||||
|
||||
if (fs->get_alloc_block2) {
|
||||
retval = (fs->get_alloc_block2)(fs, goal, &block, ctx);
|
||||
if (retval)
|
||||
goto fail;
|
||||
} else if (fs->get_alloc_block) {
|
||||
retval = (fs->get_alloc_block)(fs, goal, &block);
|
||||
if (retval)
|
||||
goto fail;
|
||||
} else {
|
||||
if (!fs->block_map) {
|
||||
retval = ext2fs_read_block_bitmap(fs);
|
||||
if (retval)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
retval = ext2fs_new_block3(fs, goal, 0, &block, ctx);
|
||||
if (retval)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (block_buf) {
|
||||
memset(block_buf, 0, fs->blocksize);
|
||||
retval = io_channel_write_blk64(fs->io, block, 1, block_buf);
|
||||
} else
|
||||
retval = ext2fs_zero_blocks2(fs, block, 1, NULL, NULL);
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
ext2fs_block_alloc_stats2(fs, block, +1);
|
||||
*ret = block;
|
||||
|
||||
fail:
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_alloc_block2(ext2_filsys fs, blk64_t goal,
|
||||
char *block_buf, blk64_t *ret)
|
||||
{
|
||||
return ext2fs_alloc_block3(fs, goal, block_buf, ret, NULL);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_alloc_block(ext2_filsys fs, blk_t goal,
|
||||
char *block_buf, blk_t *ret)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t ret64, goal64 = goal;
|
||||
retval = ext2fs_alloc_block3(fs, goal64, block_buf, &ret64, NULL);
|
||||
if (!retval)
|
||||
*ret = (blk_t)ret64;
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_free_blocks2(ext2_filsys fs, blk64_t start, blk64_t finish,
|
||||
int num, ext2fs_block_bitmap map, blk64_t *ret)
|
||||
{
|
||||
blk64_t b = start;
|
||||
int c_ratio;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (!map)
|
||||
map = fs->block_map;
|
||||
if (!map)
|
||||
return EXT2_ET_NO_BLOCK_BITMAP;
|
||||
if (!b)
|
||||
b = fs->super->s_first_data_block;
|
||||
if (!finish)
|
||||
finish = start;
|
||||
if (!num)
|
||||
num = 1;
|
||||
c_ratio = 1 << ext2fs_get_bitmap_granularity(map);
|
||||
b &= ~(c_ratio - 1);
|
||||
finish &= ~(c_ratio -1);
|
||||
do {
|
||||
if (b + num - 1 >= ext2fs_blocks_count(fs->super)) {
|
||||
if (finish > start)
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
b = fs->super->s_first_data_block;
|
||||
}
|
||||
if (ext2fs_fast_test_block_bitmap_range2(map, b, num)) {
|
||||
*ret = b;
|
||||
return 0;
|
||||
}
|
||||
b += c_ratio;
|
||||
} while (b != finish);
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish,
|
||||
int num, ext2fs_block_bitmap map, blk_t *ret)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t val;
|
||||
retval = ext2fs_get_free_blocks2(fs, start, finish, num, map, &val);
|
||||
if(!retval)
|
||||
*ret = (blk_t) val;
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ext2fs_set_alloc_block_callback(ext2_filsys fs,
|
||||
errcode_t (*func)(ext2_filsys fs,
|
||||
blk64_t goal,
|
||||
blk64_t *ret),
|
||||
errcode_t (**old)(ext2_filsys fs,
|
||||
blk64_t goal,
|
||||
blk64_t *ret))
|
||||
{
|
||||
if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
|
||||
return;
|
||||
|
||||
if (old)
|
||||
*old = fs->get_alloc_block;
|
||||
|
||||
fs->get_alloc_block = func;
|
||||
}
|
||||
|
||||
blk64_t ext2fs_find_inode_goal(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t lblk)
|
||||
{
|
||||
dgrp_t group;
|
||||
__u8 log_flex;
|
||||
struct ext2fs_extent extent;
|
||||
ext2_extent_handle_t handle = NULL;
|
||||
errcode_t err;
|
||||
|
||||
/* Make sure data stored in inode->i_block is neither fast symlink nor
|
||||
* inline data.
|
||||
*/
|
||||
if (inode == NULL || ext2fs_is_fast_symlink(inode) ||
|
||||
inode->i_flags & EXT4_INLINE_DATA_FL)
|
||||
goto no_blocks;
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL) {
|
||||
err = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (err)
|
||||
goto no_blocks;
|
||||
err = ext2fs_extent_goto2(handle, 0, lblk);
|
||||
if (err)
|
||||
goto no_blocks;
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
|
||||
if (err)
|
||||
goto no_blocks;
|
||||
ext2fs_extent_free(handle);
|
||||
return extent.e_pblk + (lblk - extent.e_lblk);
|
||||
}
|
||||
|
||||
/* block mapped file; see if block zero is mapped? */
|
||||
if (inode->i_block[0])
|
||||
return inode->i_block[0];
|
||||
|
||||
no_blocks:
|
||||
ext2fs_extent_free(handle);
|
||||
log_flex = fs->super->s_log_groups_per_flex;
|
||||
group = ext2fs_group_of_ino(fs, ino);
|
||||
if (log_flex)
|
||||
group = group & ~((1 << (log_flex)) - 1);
|
||||
return ext2fs_group_first_block2(fs, group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Starting at _goal_, scan around the filesystem to find a run of free blocks
|
||||
* that's at least _len_ blocks long. Possible flags:
|
||||
* - EXT2_NEWRANGE_EXACT_GOAL: The range of blocks must start at _goal_.
|
||||
* - EXT2_NEWRANGE_MIN_LENGTH: do not return a allocation shorter than _len_.
|
||||
* - EXT2_NEWRANGE_ZERO_BLOCKS: Zero blocks pblk to pblk+plen before returning.
|
||||
*
|
||||
* The starting block is returned in _pblk_ and the length is returned via
|
||||
* _plen_. The blocks are not marked in the bitmap; the caller must mark
|
||||
* however much of the returned run they actually use, hopefully via
|
||||
* ext2fs_block_alloc_stats_range().
|
||||
*
|
||||
* This function can return a range that is longer than what was requested.
|
||||
*/
|
||||
errcode_t ext2fs_new_range(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk64_t len, ext2fs_block_bitmap map, blk64_t *pblk,
|
||||
blk64_t *plen)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t start, end, b;
|
||||
int looped = 0;
|
||||
blk64_t max_blocks = ext2fs_blocks_count(fs->super);
|
||||
errcode_t (*nrf)(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk64_t len, blk64_t *pblk, blk64_t *plen);
|
||||
|
||||
dbg_printf("%s: flags=0x%x goal=%llu len=%llu\n", __func__, flags,
|
||||
goal, len);
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
if (len == 0 || (flags & ~EXT2_NEWRANGE_ALL_FLAGS))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (!map && fs->new_range) {
|
||||
/*
|
||||
* In case there are clients out there whose new_range
|
||||
* handlers call ext2fs_new_range with a NULL block map,
|
||||
* temporarily swap out the function pointer so that we don't
|
||||
* end up in an infinite loop.
|
||||
*/
|
||||
nrf = fs->new_range;
|
||||
fs->new_range = NULL;
|
||||
retval = nrf(fs, flags, goal, len, pblk, plen);
|
||||
fs->new_range = nrf;
|
||||
if (retval)
|
||||
return retval;
|
||||
start = *pblk;
|
||||
end = *pblk + *plen;
|
||||
goto allocated;
|
||||
}
|
||||
if (!map)
|
||||
map = fs->block_map;
|
||||
if (!map)
|
||||
return EXT2_ET_NO_BLOCK_BITMAP;
|
||||
if (!goal || goal >= ext2fs_blocks_count(fs->super))
|
||||
goal = fs->super->s_first_data_block;
|
||||
|
||||
start = goal;
|
||||
while (!looped || start <= goal) {
|
||||
retval = ext2fs_find_first_zero_block_bitmap2(map, start,
|
||||
max_blocks - 1,
|
||||
&start);
|
||||
if (retval == ENOENT) {
|
||||
/*
|
||||
* If there are no free blocks beyond the starting
|
||||
* point, try scanning the whole filesystem, unless the
|
||||
* user told us only to allocate from _goal_, or if
|
||||
* we're already scanning the whole filesystem.
|
||||
*/
|
||||
if (flags & EXT2_NEWRANGE_FIXED_GOAL ||
|
||||
start == fs->super->s_first_data_block)
|
||||
goto fail;
|
||||
start = fs->super->s_first_data_block;
|
||||
continue;
|
||||
} else if (retval)
|
||||
goto errout;
|
||||
|
||||
if (flags & EXT2_NEWRANGE_FIXED_GOAL && start != goal)
|
||||
goto fail;
|
||||
|
||||
b = min(start + len - 1, max_blocks - 1);
|
||||
retval = ext2fs_find_first_set_block_bitmap2(map, start, b,
|
||||
&end);
|
||||
if (retval == ENOENT)
|
||||
end = b + 1;
|
||||
else if (retval)
|
||||
goto errout;
|
||||
|
||||
if (!(flags & EXT2_NEWRANGE_MIN_LENGTH) ||
|
||||
(end - start) >= len) {
|
||||
/* Success! */
|
||||
*pblk = start;
|
||||
*plen = end - start;
|
||||
dbg_printf("%s: new_range goal=%llu--%llu "
|
||||
"blk=%llu--%llu %llu\n",
|
||||
__func__, goal, goal + len - 1,
|
||||
*pblk, *pblk + *plen - 1, *plen);
|
||||
allocated:
|
||||
for (b = start; b < end;
|
||||
b += fs->super->s_blocks_per_group)
|
||||
ext2fs_clear_block_uninit(fs,
|
||||
ext2fs_group_of_blk2(fs, b));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (flags & EXT2_NEWRANGE_FIXED_GOAL)
|
||||
goto fail;
|
||||
start = end;
|
||||
if (start >= max_blocks) {
|
||||
if (looped)
|
||||
goto fail;
|
||||
looped = 1;
|
||||
start = fs->super->s_first_data_block;
|
||||
}
|
||||
}
|
||||
|
||||
fail:
|
||||
retval = EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
errout:
|
||||
return retval;
|
||||
}
|
||||
|
||||
void ext2fs_set_new_range_callback(ext2_filsys fs,
|
||||
errcode_t (*func)(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk64_t len, blk64_t *pblk, blk64_t *plen),
|
||||
errcode_t (**old)(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk64_t len, blk64_t *pblk, blk64_t *plen))
|
||||
{
|
||||
if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
|
||||
return;
|
||||
|
||||
if (old)
|
||||
*old = fs->new_range;
|
||||
|
||||
fs->new_range = func;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_alloc_range(ext2_filsys fs, int flags, blk64_t goal,
|
||||
blk_t len, blk64_t *ret)
|
||||
{
|
||||
int newr_flags = EXT2_NEWRANGE_MIN_LENGTH;
|
||||
errcode_t retval;
|
||||
blk64_t plen;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
if (len == 0 || (flags & ~EXT2_ALLOCRANGE_ALL_FLAGS))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (flags & EXT2_ALLOCRANGE_FIXED_GOAL)
|
||||
newr_flags |= EXT2_NEWRANGE_FIXED_GOAL;
|
||||
|
||||
retval = ext2fs_new_range(fs, newr_flags, goal, len, NULL, ret, &plen);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (plen < len)
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
|
||||
if (flags & EXT2_ALLOCRANGE_ZERO_BLOCKS) {
|
||||
retval = ext2fs_zero_blocks2(fs, *ret, len, NULL, NULL);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
ext2fs_block_alloc_stats_range(fs, *ret, len, +1);
|
||||
return retval;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/alloc.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/alloc.o
Executable file
Binary file not shown.
81
jni/e2fsprogs/lib/ext2fs/alloc_sb.c
Executable file
81
jni/e2fsprogs/lib/ext2fs/alloc_sb.c
Executable file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
* alloc_sb.c --- Allocate the superblock and block group descriptors for a
|
||||
* newly initialized filesystem. Used by mke2fs when initializing a filesystem
|
||||
*
|
||||
* Copyright (C) 1994, 1995, 1996, 2003 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* This function reserves the superblock and block group descriptors
|
||||
* for a given block group. It currently returns the number of free
|
||||
* blocks assuming that inode table and allocation bitmaps will be in
|
||||
* the group. This is not necessarily the case when the flex_bg
|
||||
* feature is enabled, so callers should take care! It was only
|
||||
* really intended for use by mke2fs, and even there it's not that
|
||||
* useful. In the future, when we redo this function for 64-bit block
|
||||
* numbers, we should probably return the number of blocks used by the
|
||||
* super block and group descriptors instead.
|
||||
*
|
||||
* See also the comment for ext2fs_super_and_bgd_loc()
|
||||
*/
|
||||
int ext2fs_reserve_super_and_bgd(ext2_filsys fs,
|
||||
dgrp_t group,
|
||||
ext2fs_block_bitmap bmap)
|
||||
{
|
||||
blk64_t super_blk, old_desc_blk, new_desc_blk;
|
||||
blk_t used_blks;
|
||||
int old_desc_blocks, num_blocks;
|
||||
|
||||
ext2fs_super_and_bgd_loc2(fs, group, &super_blk,
|
||||
&old_desc_blk, &new_desc_blk, &used_blks);
|
||||
|
||||
if (ext2fs_has_feature_meta_bg(fs->super))
|
||||
old_desc_blocks = fs->super->s_first_meta_bg;
|
||||
else
|
||||
old_desc_blocks =
|
||||
fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
|
||||
|
||||
if (super_blk || (group == 0))
|
||||
ext2fs_mark_block_bitmap2(bmap, super_blk);
|
||||
if ((group == 0) && (fs->blocksize == 1024) &&
|
||||
EXT2FS_CLUSTER_RATIO(fs) > 1)
|
||||
ext2fs_mark_block_bitmap2(bmap, 0);
|
||||
|
||||
if (old_desc_blk) {
|
||||
num_blocks = old_desc_blocks;
|
||||
if (old_desc_blk + num_blocks >= ext2fs_blocks_count(fs->super))
|
||||
num_blocks = ext2fs_blocks_count(fs->super) -
|
||||
old_desc_blk;
|
||||
ext2fs_mark_block_bitmap_range2(bmap, old_desc_blk, num_blocks);
|
||||
}
|
||||
if (new_desc_blk)
|
||||
ext2fs_mark_block_bitmap2(bmap, new_desc_blk);
|
||||
|
||||
num_blocks = ext2fs_group_blocks_count(fs, group);
|
||||
num_blocks -= 2 + fs->inode_blocks_per_group + used_blks;
|
||||
|
||||
return num_blocks ;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/alloc_sb.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/alloc_sb.o
Executable file
Binary file not shown.
165
jni/e2fsprogs/lib/ext2fs/alloc_stats.c
Executable file
165
jni/e2fsprogs/lib/ext2fs/alloc_stats.c
Executable file
@@ -0,0 +1,165 @@
|
||||
/*
|
||||
* alloc_stats.c --- Update allocation statistics for ext2fs
|
||||
*
|
||||
* Copyright (C) 2001 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 "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
void ext2fs_inode_alloc_stats2(ext2_filsys fs, ext2_ino_t ino,
|
||||
int inuse, int isdir)
|
||||
{
|
||||
int group = ext2fs_group_of_ino(fs, ino);
|
||||
|
||||
if (ino > fs->super->s_inodes_count) {
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err("ext2fs_inode_alloc_stats2", 0,
|
||||
"Illegal inode number: %lu", (unsigned long) ino);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (inuse > 0)
|
||||
ext2fs_mark_inode_bitmap2(fs->inode_map, ino);
|
||||
else
|
||||
ext2fs_unmark_inode_bitmap2(fs->inode_map, ino);
|
||||
ext2fs_bg_free_inodes_count_set(fs, group, ext2fs_bg_free_inodes_count(fs, group) - inuse);
|
||||
if (isdir)
|
||||
ext2fs_bg_used_dirs_count_set(fs, group, ext2fs_bg_used_dirs_count(fs, group) + inuse);
|
||||
|
||||
/* We don't strictly need to be clearing the uninit flag if inuse < 0
|
||||
* (i.e. freeing inodes) but it also means something is bad. */
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_INODE_UNINIT);
|
||||
if (ext2fs_has_group_desc_csum(fs)) {
|
||||
ext2_ino_t first_unused_inode = fs->super->s_inodes_per_group -
|
||||
ext2fs_bg_itable_unused(fs, group) +
|
||||
group * fs->super->s_inodes_per_group + 1;
|
||||
|
||||
if (ino >= first_unused_inode)
|
||||
ext2fs_bg_itable_unused_set(fs, group, group * fs->super->s_inodes_per_group + fs->super->s_inodes_per_group - ino);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
}
|
||||
|
||||
fs->super->s_free_inodes_count -= inuse;
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
ext2fs_mark_ib_dirty(fs);
|
||||
}
|
||||
|
||||
void ext2fs_inode_alloc_stats(ext2_filsys fs, ext2_ino_t ino, int inuse)
|
||||
{
|
||||
ext2fs_inode_alloc_stats2(fs, ino, inuse, 0);
|
||||
}
|
||||
|
||||
void ext2fs_block_alloc_stats2(ext2_filsys fs, blk64_t blk, int inuse)
|
||||
{
|
||||
int group = ext2fs_group_of_blk2(fs, blk);
|
||||
|
||||
if (blk < fs->super->s_first_data_block ||
|
||||
blk >= ext2fs_blocks_count(fs->super)) {
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err("ext2fs_block_alloc_stats", 0,
|
||||
"Illegal block number: %lu", (unsigned long) blk);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
if (inuse > 0)
|
||||
ext2fs_mark_block_bitmap2(fs->block_map, blk);
|
||||
else
|
||||
ext2fs_unmark_block_bitmap2(fs->block_map, blk);
|
||||
ext2fs_bg_free_blocks_count_set(fs, group, ext2fs_bg_free_blocks_count(fs, group) - inuse);
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
|
||||
ext2fs_free_blocks_count_add(fs->super,
|
||||
-inuse * (blk64_t) EXT2FS_CLUSTER_RATIO(fs));
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
ext2fs_mark_bb_dirty(fs);
|
||||
if (fs->block_alloc_stats)
|
||||
(fs->block_alloc_stats)(fs, (blk64_t) blk, inuse);
|
||||
}
|
||||
|
||||
void ext2fs_block_alloc_stats(ext2_filsys fs, blk_t blk, int inuse)
|
||||
{
|
||||
ext2fs_block_alloc_stats2(fs, blk, inuse);
|
||||
}
|
||||
|
||||
void ext2fs_set_block_alloc_stats_callback(ext2_filsys fs,
|
||||
void (*func)(ext2_filsys fs,
|
||||
blk64_t blk,
|
||||
int inuse),
|
||||
void (**old)(ext2_filsys fs,
|
||||
blk64_t blk,
|
||||
int inuse))
|
||||
{
|
||||
if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
|
||||
return;
|
||||
if (old)
|
||||
*old = fs->block_alloc_stats;
|
||||
|
||||
fs->block_alloc_stats = func;
|
||||
}
|
||||
|
||||
void ext2fs_block_alloc_stats_range(ext2_filsys fs, blk64_t blk,
|
||||
blk_t num, int inuse)
|
||||
{
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (blk + num > ext2fs_blocks_count(fs->super)) {
|
||||
com_err("ext2fs_block_alloc_stats_range", 0,
|
||||
"Illegal block range: %llu (%u) ",
|
||||
(unsigned long long) blk, num);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (inuse == 0)
|
||||
return;
|
||||
if (inuse > 0) {
|
||||
ext2fs_mark_block_bitmap_range2(fs->block_map, blk, num);
|
||||
inuse = 1;
|
||||
} else {
|
||||
ext2fs_unmark_block_bitmap_range2(fs->block_map, blk, num);
|
||||
inuse = -1;
|
||||
}
|
||||
while (num) {
|
||||
int group = ext2fs_group_of_blk2(fs, blk);
|
||||
blk64_t last_blk = ext2fs_group_last_block2(fs, group);
|
||||
blk64_t n = num;
|
||||
|
||||
if (blk + num > last_blk)
|
||||
n = last_blk - blk + 1;
|
||||
|
||||
ext2fs_bg_free_blocks_count_set(fs, group,
|
||||
ext2fs_bg_free_blocks_count(fs, group) -
|
||||
inuse*n/EXT2FS_CLUSTER_RATIO(fs));
|
||||
ext2fs_bg_flags_clear(fs, group, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
ext2fs_free_blocks_count_add(fs->super, -inuse * (blk64_t) n);
|
||||
blk += n;
|
||||
num -= n;
|
||||
}
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
ext2fs_mark_bb_dirty(fs);
|
||||
if (fs->block_alloc_stats_range)
|
||||
(fs->block_alloc_stats_range)(fs, blk, num, inuse);
|
||||
}
|
||||
|
||||
void ext2fs_set_block_alloc_stats_range_callback(ext2_filsys fs,
|
||||
void (*func)(ext2_filsys fs, blk64_t blk,
|
||||
blk_t num, int inuse),
|
||||
void (**old)(ext2_filsys fs, blk64_t blk,
|
||||
blk_t num, int inuse))
|
||||
{
|
||||
if (!fs || fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS)
|
||||
return;
|
||||
if (old)
|
||||
*old = fs->block_alloc_stats_range;
|
||||
|
||||
fs->block_alloc_stats_range = func;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/alloc_stats.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/alloc_stats.o
Executable file
Binary file not shown.
278
jni/e2fsprogs/lib/ext2fs/alloc_tables.c
Executable file
278
jni/e2fsprogs/lib/ext2fs/alloc_tables.c
Executable file
@@ -0,0 +1,278 @@
|
||||
/*
|
||||
* alloc_tables.c --- Allocate tables for a newly initialized
|
||||
* filesystem. Used by mke2fs when initializing a filesystem
|
||||
*
|
||||
* Copyright (C) 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
/*
|
||||
* This routine searches for free blocks that can allocate a full
|
||||
* group of bitmaps or inode tables for a flexbg group. Returns the
|
||||
* block number with a correct offset were the bitmaps and inode
|
||||
* tables can be allocated continuously and in order.
|
||||
*/
|
||||
static blk64_t flexbg_offset(ext2_filsys fs, dgrp_t group, blk64_t start_blk,
|
||||
ext2fs_block_bitmap bmap, int rem_grp,
|
||||
int elem_size)
|
||||
{
|
||||
int flexbg, flexbg_size, size;
|
||||
blk64_t last_blk, first_free = 0;
|
||||
dgrp_t last_grp;
|
||||
|
||||
flexbg_size = 1U << fs->super->s_log_groups_per_flex;
|
||||
flexbg = group / flexbg_size;
|
||||
size = rem_grp * elem_size;
|
||||
|
||||
if (size > (int) (fs->super->s_blocks_per_group / 4))
|
||||
size = (int) fs->super->s_blocks_per_group / 4;
|
||||
|
||||
/*
|
||||
* Don't do a long search if the previous block search is still valid,
|
||||
* but skip minor obstructions such as group descriptor backups.
|
||||
*/
|
||||
if (start_blk && start_blk < ext2fs_blocks_count(fs->super) &&
|
||||
ext2fs_get_free_blocks2(fs, start_blk, start_blk + size, elem_size,
|
||||
bmap, &first_free) == 0)
|
||||
return first_free;
|
||||
|
||||
start_blk = ext2fs_group_first_block2(fs, flexbg_size * flexbg);
|
||||
last_grp = group | (flexbg_size - 1);
|
||||
if (last_grp > fs->group_desc_count-1)
|
||||
last_grp = fs->group_desc_count-1;
|
||||
last_blk = ext2fs_group_last_block2(fs, last_grp);
|
||||
|
||||
/* Find the first available block */
|
||||
if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, size,
|
||||
bmap, &first_free) == 0)
|
||||
return first_free;
|
||||
|
||||
if (ext2fs_get_free_blocks2(fs, start_blk, last_blk, elem_size,
|
||||
bmap, &first_free) == 0)
|
||||
return first_free;
|
||||
|
||||
if (ext2fs_get_free_blocks2(fs, 0, last_blk, elem_size, bmap,
|
||||
&first_free) == 0)
|
||||
return first_free;
|
||||
|
||||
return first_free;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group,
|
||||
ext2fs_block_bitmap bmap)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t group_blk, start_blk, last_blk, new_blk;
|
||||
dgrp_t last_grp = 0;
|
||||
int rem_grps = 0, flexbg_size = 0, table_offset = 0;
|
||||
|
||||
group_blk = ext2fs_group_first_block2(fs, group);
|
||||
last_blk = ext2fs_group_last_block2(fs, group);
|
||||
|
||||
if (!bmap)
|
||||
bmap = fs->block_map;
|
||||
|
||||
if (ext2fs_has_feature_flex_bg(fs->super) &&
|
||||
fs->super->s_log_groups_per_flex) {
|
||||
flexbg_size = 1U << fs->super->s_log_groups_per_flex;
|
||||
last_grp = group | (flexbg_size - 1);
|
||||
if (last_grp > fs->group_desc_count-1)
|
||||
last_grp = fs->group_desc_count-1;
|
||||
rem_grps = last_grp - group + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the block and inode bitmaps, if necessary
|
||||
*/
|
||||
if (fs->stride && !flexbg_size) {
|
||||
retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk,
|
||||
1, bmap, &start_blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
start_blk += fs->inode_blocks_per_group;
|
||||
start_blk += ((fs->stride * group) %
|
||||
(last_blk - start_blk + 1));
|
||||
if (start_blk >= last_blk)
|
||||
start_blk = group_blk;
|
||||
} else
|
||||
start_blk = group_blk;
|
||||
|
||||
if (flexbg_size) {
|
||||
blk64_t prev_block = 0;
|
||||
|
||||
table_offset = flexbg_size;
|
||||
if (group % flexbg_size)
|
||||
prev_block = ext2fs_block_bitmap_loc(fs, group - 1) + 1;
|
||||
else if (last_grp == fs->group_desc_count-1) {
|
||||
/*
|
||||
* If we are allocating for the last flex_bg
|
||||
* keep the metadata tables contiguous
|
||||
*/
|
||||
table_offset = last_grp & (flexbg_size - 1);
|
||||
if (table_offset == 0)
|
||||
table_offset = flexbg_size;
|
||||
else
|
||||
table_offset++;
|
||||
}
|
||||
/* FIXME: Take backup group descriptor blocks into account
|
||||
* if the flexbg allocations will grow to overlap them... */
|
||||
start_blk = flexbg_offset(fs, group, prev_block, bmap,
|
||||
rem_grps, 1);
|
||||
last_blk = ext2fs_group_last_block2(fs, last_grp);
|
||||
}
|
||||
|
||||
if (!ext2fs_block_bitmap_loc(fs, group)) {
|
||||
retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk,
|
||||
1, bmap, &new_blk);
|
||||
if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
|
||||
retval = ext2fs_get_free_blocks2(fs, group_blk,
|
||||
last_blk, 1, bmap, &new_blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
ext2fs_mark_block_bitmap2(bmap, new_blk);
|
||||
ext2fs_block_bitmap_loc_set(fs, group, new_blk);
|
||||
if (flexbg_size) {
|
||||
dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk);
|
||||
ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1);
|
||||
ext2fs_free_blocks_count_add(fs->super, -1);
|
||||
ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, gr);
|
||||
}
|
||||
}
|
||||
|
||||
if (flexbg_size) {
|
||||
blk64_t prev_block = 0;
|
||||
if (group % flexbg_size)
|
||||
prev_block = ext2fs_inode_bitmap_loc(fs, group - 1) + 1;
|
||||
else
|
||||
prev_block = ext2fs_block_bitmap_loc(fs, group) +
|
||||
table_offset;
|
||||
/* FIXME: Take backup group descriptor blocks into account
|
||||
* if the flexbg allocations will grow to overlap them... */
|
||||
start_blk = flexbg_offset(fs, group, prev_block, bmap,
|
||||
rem_grps, 1);
|
||||
last_blk = ext2fs_group_last_block2(fs, last_grp);
|
||||
}
|
||||
|
||||
if (!ext2fs_inode_bitmap_loc(fs, group)) {
|
||||
retval = ext2fs_get_free_blocks2(fs, start_blk, last_blk,
|
||||
1, bmap, &new_blk);
|
||||
if (retval == EXT2_ET_BLOCK_ALLOC_FAIL)
|
||||
retval = ext2fs_get_free_blocks2(fs, group_blk,
|
||||
last_blk, 1, bmap, &new_blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
ext2fs_mark_block_bitmap2(bmap, new_blk);
|
||||
ext2fs_inode_bitmap_loc_set(fs, group, new_blk);
|
||||
if (flexbg_size) {
|
||||
dgrp_t gr = ext2fs_group_of_blk2(fs, new_blk);
|
||||
ext2fs_bg_free_blocks_count_set(fs, gr, ext2fs_bg_free_blocks_count(fs, gr) - 1);
|
||||
ext2fs_free_blocks_count_add(fs->super, -1);
|
||||
ext2fs_bg_flags_clear(fs, gr, EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, gr);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate the inode table
|
||||
*/
|
||||
if (flexbg_size) {
|
||||
blk64_t prev_block = 0;
|
||||
|
||||
if (group % flexbg_size)
|
||||
prev_block = ext2fs_inode_table_loc(fs, group - 1) +
|
||||
fs->inode_blocks_per_group;
|
||||
else
|
||||
prev_block = ext2fs_inode_bitmap_loc(fs, group) +
|
||||
table_offset;
|
||||
|
||||
/* FIXME: Take backup group descriptor blocks into account
|
||||
* if the flexbg allocations will grow to overlap them... */
|
||||
group_blk = flexbg_offset(fs, group, prev_block, bmap,
|
||||
rem_grps, fs->inode_blocks_per_group);
|
||||
last_blk = ext2fs_group_last_block2(fs, last_grp);
|
||||
}
|
||||
|
||||
if (!ext2fs_inode_table_loc(fs, group)) {
|
||||
retval = ext2fs_get_free_blocks2(fs, group_blk, last_blk,
|
||||
fs->inode_blocks_per_group,
|
||||
bmap, &new_blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ext2fs_mark_block_bitmap_range2(bmap,
|
||||
new_blk, fs->inode_blocks_per_group);
|
||||
if (flexbg_size) {
|
||||
blk64_t num, blk;
|
||||
num = fs->inode_blocks_per_group;
|
||||
blk = new_blk;
|
||||
while (num) {
|
||||
int gr = ext2fs_group_of_blk2(fs, blk);
|
||||
last_blk = ext2fs_group_last_block2(fs, gr);
|
||||
blk64_t n = num;
|
||||
|
||||
if (blk + num > last_blk)
|
||||
n = last_blk - blk + 1;
|
||||
|
||||
ext2fs_bg_free_blocks_count_set(fs, gr,
|
||||
ext2fs_bg_free_blocks_count(fs, gr) -
|
||||
n/EXT2FS_CLUSTER_RATIO(fs));
|
||||
ext2fs_bg_flags_clear(fs, gr,
|
||||
EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_group_desc_csum_set(fs, gr);
|
||||
ext2fs_free_blocks_count_add(fs->super, -n);
|
||||
blk += n;
|
||||
num -= n;
|
||||
}
|
||||
}
|
||||
ext2fs_inode_table_loc_set(fs, group, new_blk);
|
||||
}
|
||||
ext2fs_group_desc_csum_set(fs, group);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_tables(ext2_filsys fs)
|
||||
{
|
||||
errcode_t retval;
|
||||
dgrp_t i;
|
||||
struct ext2fs_numeric_progress_struct progress;
|
||||
|
||||
if (fs->progress_ops && fs->progress_ops->init)
|
||||
(fs->progress_ops->init)(fs, &progress, NULL,
|
||||
fs->group_desc_count);
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
if (fs->progress_ops && fs->progress_ops->update)
|
||||
(fs->progress_ops->update)(fs, &progress, i);
|
||||
retval = ext2fs_allocate_group_table(fs, i, fs->block_map);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (fs->progress_ops && fs->progress_ops->close)
|
||||
(fs->progress_ops->close)(fs, &progress, NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/alloc_tables.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/alloc_tables.o
Executable file
Binary file not shown.
116
jni/e2fsprogs/lib/ext2fs/atexit.c
Executable file
116
jni/e2fsprogs/lib/ext2fs/atexit.c
Executable file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* atexit.c --- Clean things up when we exit normally.
|
||||
*
|
||||
* Copyright Oracle, 2014
|
||||
* Author Darrick J. Wong <darrick.wong@oracle.com>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct exit_data {
|
||||
ext2_exit_fn func;
|
||||
void *data;
|
||||
};
|
||||
|
||||
static struct exit_data *items;
|
||||
static size_t nr_items;
|
||||
|
||||
static void handle_exit(void)
|
||||
{
|
||||
struct exit_data *ed;
|
||||
|
||||
for (ed = items + nr_items - 1; ed >= items; ed--) {
|
||||
if (ed->func == NULL)
|
||||
continue;
|
||||
ed->func(ed->data);
|
||||
}
|
||||
|
||||
ext2fs_free_mem(&items);
|
||||
nr_items = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Schedule a function to be called at (normal) program termination.
|
||||
* If you want this to be called during a signal exit, you must capture
|
||||
* the signal and call exit() yourself!
|
||||
*/
|
||||
errcode_t ext2fs_add_exit_fn(ext2_exit_fn func, void *data)
|
||||
{
|
||||
struct exit_data *ed, *free_ed = NULL;
|
||||
size_t x;
|
||||
errcode_t ret;
|
||||
|
||||
if (func == NULL)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
for (x = 0, ed = items; x < nr_items; x++, ed++) {
|
||||
if (ed->func == func && ed->data == data)
|
||||
return EXT2_ET_FILE_EXISTS;
|
||||
if (ed->func == NULL)
|
||||
free_ed = ed;
|
||||
}
|
||||
|
||||
if (free_ed) {
|
||||
free_ed->func = func;
|
||||
free_ed->data = data;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (nr_items == 0) {
|
||||
ret = atexit(handle_exit);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = ext2fs_resize_mem(0, (nr_items + 1) * sizeof(struct exit_data),
|
||||
&items);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
items[nr_items].func = func;
|
||||
items[nr_items].data = data;
|
||||
nr_items++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Remove a function from the exit cleanup list. */
|
||||
errcode_t ext2fs_remove_exit_fn(ext2_exit_fn func, void *data)
|
||||
{
|
||||
struct exit_data *ed;
|
||||
size_t x;
|
||||
|
||||
if (func == NULL)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
for (x = 0, ed = items; x < nr_items; x++, ed++) {
|
||||
if (ed->func == NULL)
|
||||
return 0;
|
||||
if (ed->func == func && ed->data == data) {
|
||||
size_t sz = (nr_items - (x + 1)) *
|
||||
sizeof(struct exit_data);
|
||||
memmove(ed, ed + 1, sz);
|
||||
memset(items + nr_items - 1, 0,
|
||||
sizeof(struct exit_data));
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/atexit.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/atexit.o
Executable file
Binary file not shown.
328
jni/e2fsprogs/lib/ext2fs/badblocks.c
Executable file
328
jni/e2fsprogs/lib/ext2fs/badblocks.c
Executable file
@@ -0,0 +1,328 @@
|
||||
/*
|
||||
* badblocks.c --- routines to manipulate the bad block structure
|
||||
*
|
||||
* Copyright (C) 1994, 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
/*
|
||||
* Helper function for making a badblocks list
|
||||
*/
|
||||
static errcode_t make_u32_list(int size, int num, __u32 *list,
|
||||
ext2_u32_list *ret)
|
||||
{
|
||||
ext2_u32_list bb;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_list), &bb);
|
||||
if (retval)
|
||||
return retval;
|
||||
memset(bb, 0, sizeof(struct ext2_struct_u32_list));
|
||||
bb->magic = EXT2_ET_MAGIC_BADBLOCKS_LIST;
|
||||
bb->size = size ? size : 10;
|
||||
bb->num = num;
|
||||
retval = ext2fs_get_array(bb->size, sizeof(blk_t), &bb->list);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&bb);
|
||||
return retval;
|
||||
}
|
||||
if (list)
|
||||
memcpy(bb->list, list, bb->size * sizeof(blk_t));
|
||||
else
|
||||
memset(bb->list, 0, bb->size * sizeof(blk_t));
|
||||
*ret = bb;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This procedure creates an empty u32 list.
|
||||
*/
|
||||
errcode_t ext2fs_u32_list_create(ext2_u32_list *ret, int size)
|
||||
{
|
||||
return make_u32_list(size, 0, 0, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* This procedure creates an empty badblocks list.
|
||||
*/
|
||||
errcode_t ext2fs_badblocks_list_create(ext2_badblocks_list *ret, int size)
|
||||
{
|
||||
return make_u32_list(size, 0, 0, (ext2_badblocks_list *) ret);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This procedure copies a badblocks list
|
||||
*/
|
||||
errcode_t ext2fs_u32_copy(ext2_u32_list src, ext2_u32_list *dest)
|
||||
{
|
||||
errcode_t retval;
|
||||
|
||||
retval = make_u32_list(src->size, src->num, src->list, dest);
|
||||
if (retval)
|
||||
return retval;
|
||||
(*dest)->badblocks_flags = src->badblocks_flags;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_badblocks_copy(ext2_badblocks_list src,
|
||||
ext2_badblocks_list *dest)
|
||||
{
|
||||
return ext2fs_u32_copy((ext2_u32_list) src,
|
||||
(ext2_u32_list *) dest);
|
||||
}
|
||||
|
||||
/*
|
||||
* This procedure frees a badblocks list.
|
||||
*
|
||||
* (note: moved to closefs.c)
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* This procedure adds a block to a badblocks list.
|
||||
*/
|
||||
errcode_t ext2fs_u32_list_add(ext2_u32_list bb, __u32 blk)
|
||||
{
|
||||
errcode_t retval;
|
||||
int i, j;
|
||||
unsigned long old_size;
|
||||
|
||||
EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
|
||||
|
||||
if (bb->num >= bb->size) {
|
||||
old_size = bb->size * sizeof(__u32);
|
||||
bb->size += 100;
|
||||
retval = ext2fs_resize_mem(old_size, bb->size * sizeof(__u32),
|
||||
&bb->list);
|
||||
if (retval) {
|
||||
bb->size -= 100;
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Add special case code for appending to the end of the list
|
||||
*/
|
||||
i = bb->num-1;
|
||||
if ((bb->num != 0) && (bb->list[i] == blk))
|
||||
return 0;
|
||||
if ((bb->num == 0) || (bb->list[i] < blk)) {
|
||||
bb->list[bb->num++] = blk;
|
||||
return 0;
|
||||
}
|
||||
|
||||
j = bb->num;
|
||||
for (i=0; i < bb->num; i++) {
|
||||
if (bb->list[i] == blk)
|
||||
return 0;
|
||||
if (bb->list[i] > blk) {
|
||||
j = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (i=bb->num; i > j; i--)
|
||||
bb->list[i] = bb->list[i-1];
|
||||
bb->list[j] = blk;
|
||||
bb->num++;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_badblocks_list_add(ext2_badblocks_list bb, blk_t blk)
|
||||
{
|
||||
return ext2fs_u32_list_add((ext2_u32_list) bb, (__u32) blk);
|
||||
}
|
||||
|
||||
/*
|
||||
* This procedure finds a particular block is on a badblocks
|
||||
* list.
|
||||
*/
|
||||
int ext2fs_u32_list_find(ext2_u32_list bb, __u32 blk)
|
||||
{
|
||||
int low, high, mid;
|
||||
|
||||
if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
|
||||
return -1;
|
||||
|
||||
if (bb->num == 0)
|
||||
return -1;
|
||||
|
||||
low = 0;
|
||||
high = bb->num-1;
|
||||
if (blk == bb->list[low])
|
||||
return low;
|
||||
if (blk == bb->list[high])
|
||||
return high;
|
||||
|
||||
while (low < high) {
|
||||
mid = ((unsigned)low + (unsigned)high)/2;
|
||||
if (mid == low || mid == high)
|
||||
break;
|
||||
if (blk == bb->list[mid])
|
||||
return mid;
|
||||
if (blk < bb->list[mid])
|
||||
high = mid;
|
||||
else
|
||||
low = mid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This procedure tests to see if a particular block is on a badblocks
|
||||
* list.
|
||||
*/
|
||||
int ext2fs_u32_list_test(ext2_u32_list bb, __u32 blk)
|
||||
{
|
||||
if (ext2fs_u32_list_find(bb, blk) < 0)
|
||||
return 0;
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ext2fs_badblocks_list_test(ext2_badblocks_list bb, blk_t blk)
|
||||
{
|
||||
return ext2fs_u32_list_test((ext2_u32_list) bb, (__u32) blk);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove a block from the badblock list
|
||||
*/
|
||||
int ext2fs_u32_list_del(ext2_u32_list bb, __u32 blk)
|
||||
{
|
||||
int remloc, i;
|
||||
|
||||
if (bb->num == 0)
|
||||
return -1;
|
||||
|
||||
remloc = ext2fs_u32_list_find(bb, blk);
|
||||
if (remloc < 0)
|
||||
return -1;
|
||||
|
||||
for (i = remloc ; i < bb->num-1; i++)
|
||||
bb->list[i] = bb->list[i+1];
|
||||
bb->num--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ext2fs_badblocks_list_del(ext2_u32_list bb, __u32 blk)
|
||||
{
|
||||
ext2fs_u32_list_del(bb, blk);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_u32_list_iterate_begin(ext2_u32_list bb,
|
||||
ext2_u32_iterate *ret)
|
||||
{
|
||||
ext2_u32_iterate iter;
|
||||
errcode_t retval;
|
||||
|
||||
EXT2_CHECK_MAGIC(bb, EXT2_ET_MAGIC_BADBLOCKS_LIST);
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2_struct_u32_iterate), &iter);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
iter->magic = EXT2_ET_MAGIC_BADBLOCKS_ITERATE;
|
||||
iter->bb = bb;
|
||||
iter->ptr = 0;
|
||||
*ret = iter;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_badblocks_list_iterate_begin(ext2_badblocks_list bb,
|
||||
ext2_badblocks_iterate *ret)
|
||||
{
|
||||
return ext2fs_u32_list_iterate_begin((ext2_u32_list) bb,
|
||||
(ext2_u32_iterate *) ret);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_u32_list_iterate(ext2_u32_iterate iter, __u32 *blk)
|
||||
{
|
||||
ext2_u32_list bb;
|
||||
|
||||
if (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE)
|
||||
return 0;
|
||||
|
||||
bb = iter->bb;
|
||||
|
||||
if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
|
||||
return 0;
|
||||
|
||||
if (iter->ptr < bb->num) {
|
||||
*blk = bb->list[iter->ptr++];
|
||||
return 1;
|
||||
}
|
||||
*blk = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2fs_badblocks_list_iterate(ext2_badblocks_iterate iter, blk_t *blk)
|
||||
{
|
||||
return ext2fs_u32_list_iterate((ext2_u32_iterate) iter,
|
||||
(__u32 *) blk);
|
||||
}
|
||||
|
||||
|
||||
void ext2fs_u32_list_iterate_end(ext2_u32_iterate iter)
|
||||
{
|
||||
if (!iter || (iter->magic != EXT2_ET_MAGIC_BADBLOCKS_ITERATE))
|
||||
return;
|
||||
|
||||
iter->bb = 0;
|
||||
ext2fs_free_mem(&iter);
|
||||
}
|
||||
|
||||
void ext2fs_badblocks_list_iterate_end(ext2_badblocks_iterate iter)
|
||||
{
|
||||
ext2fs_u32_list_iterate_end((ext2_u32_iterate) iter);
|
||||
}
|
||||
|
||||
|
||||
int ext2fs_u32_list_equal(ext2_u32_list bb1, ext2_u32_list bb2)
|
||||
{
|
||||
EXT2_CHECK_MAGIC(bb1, EXT2_ET_MAGIC_BADBLOCKS_LIST);
|
||||
EXT2_CHECK_MAGIC(bb2, EXT2_ET_MAGIC_BADBLOCKS_LIST);
|
||||
|
||||
if (bb1->num != bb2->num)
|
||||
return 0;
|
||||
|
||||
if (memcmp(bb1->list, bb2->list, bb1->num * sizeof(blk_t)) != 0)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ext2fs_badblocks_equal(ext2_badblocks_list bb1, ext2_badblocks_list bb2)
|
||||
{
|
||||
return ext2fs_u32_list_equal((ext2_u32_list) bb1,
|
||||
(ext2_u32_list) bb2);
|
||||
}
|
||||
|
||||
int ext2fs_u32_list_count(ext2_u32_list bb)
|
||||
{
|
||||
return bb->num;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/badblocks.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/badblocks.o
Executable file
Binary file not shown.
64
jni/e2fsprogs/lib/ext2fs/bb_compat.c
Executable file
64
jni/e2fsprogs/lib/ext2fs/bb_compat.c
Executable file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* bb_compat.c --- compatibility badblocks routines
|
||||
*
|
||||
* Copyright (C) 1997 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
errcode_t badblocks_list_create(badblocks_list *ret, int size)
|
||||
{
|
||||
return ext2fs_badblocks_list_create(ret, size);
|
||||
}
|
||||
|
||||
void badblocks_list_free(badblocks_list bb)
|
||||
{
|
||||
ext2fs_badblocks_list_free(bb);
|
||||
}
|
||||
|
||||
errcode_t badblocks_list_add(badblocks_list bb, blk_t blk)
|
||||
{
|
||||
return ext2fs_badblocks_list_add(bb, blk);
|
||||
}
|
||||
|
||||
int badblocks_list_test(badblocks_list bb, blk_t blk)
|
||||
{
|
||||
return ext2fs_badblocks_list_test(bb, blk);
|
||||
}
|
||||
|
||||
errcode_t badblocks_list_iterate_begin(badblocks_list bb,
|
||||
badblocks_iterate *ret)
|
||||
{
|
||||
return ext2fs_badblocks_list_iterate_begin(bb, ret);
|
||||
}
|
||||
|
||||
int badblocks_list_iterate(badblocks_iterate iter, blk_t *blk)
|
||||
{
|
||||
return ext2fs_badblocks_list_iterate(iter, blk);
|
||||
}
|
||||
|
||||
void badblocks_list_iterate_end(badblocks_iterate iter)
|
||||
{
|
||||
ext2fs_badblocks_list_iterate_end(iter);
|
||||
}
|
||||
270
jni/e2fsprogs/lib/ext2fs/bb_inode.c
Executable file
270
jni/e2fsprogs/lib/ext2fs/bb_inode.c
Executable file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* bb_inode.c --- routines to update the bad block inode.
|
||||
*
|
||||
* WARNING: This routine modifies a lot of state in the filesystem; if
|
||||
* this routine returns an error, the bad block inode may be in an
|
||||
* inconsistent state.
|
||||
*
|
||||
* Copyright (C) 1994, 1995 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
struct set_badblock_record {
|
||||
ext2_badblocks_iterate bb_iter;
|
||||
int bad_block_count;
|
||||
blk_t *ind_blocks;
|
||||
int max_ind_blocks;
|
||||
int ind_blocks_size;
|
||||
int ind_blocks_ptr;
|
||||
char *block_buf;
|
||||
errcode_t err;
|
||||
};
|
||||
|
||||
static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk_t ref_block, int ref_offset,
|
||||
void *priv_data);
|
||||
static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk_t ref_block, int ref_offset,
|
||||
void *priv_data);
|
||||
|
||||
/*
|
||||
* Given a bad blocks bitmap, update the bad blocks inode to reflect
|
||||
* the map.
|
||||
*/
|
||||
errcode_t ext2fs_update_bb_inode(ext2_filsys fs, ext2_badblocks_list bb_list)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct set_badblock_record rec;
|
||||
struct ext2_inode inode;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (!fs->block_map)
|
||||
return EXT2_ET_NO_BLOCK_BITMAP;
|
||||
|
||||
memset(&rec, 0, sizeof(rec));
|
||||
rec.max_ind_blocks = 10;
|
||||
retval = ext2fs_get_array(rec.max_ind_blocks, sizeof(blk_t),
|
||||
&rec.ind_blocks);
|
||||
if (retval)
|
||||
return retval;
|
||||
memset(rec.ind_blocks, 0, rec.max_ind_blocks * sizeof(blk_t));
|
||||
retval = ext2fs_get_mem(fs->blocksize, &rec.block_buf);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
memset(rec.block_buf, 0, fs->blocksize);
|
||||
rec.err = 0;
|
||||
|
||||
/*
|
||||
* First clear the old bad blocks (while saving the indirect blocks)
|
||||
*/
|
||||
retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
|
||||
BLOCK_FLAG_DEPTH_TRAVERSE, 0,
|
||||
clear_bad_block_proc, &rec);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
if (rec.err) {
|
||||
retval = rec.err;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now set the bad blocks!
|
||||
*
|
||||
* First, mark the bad blocks as used. This prevents a bad
|
||||
* block from being used as an indirect block for the bad
|
||||
* block inode (!).
|
||||
*/
|
||||
if (bb_list) {
|
||||
retval = ext2fs_badblocks_list_iterate_begin(bb_list,
|
||||
&rec.bb_iter);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
retval = ext2fs_block_iterate2(fs, EXT2_BAD_INO,
|
||||
BLOCK_FLAG_APPEND, 0,
|
||||
set_bad_block_proc, &rec);
|
||||
ext2fs_badblocks_list_iterate_end(rec.bb_iter);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
if (rec.err) {
|
||||
retval = rec.err;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the bad block inode's mod time and block count
|
||||
* field.
|
||||
*/
|
||||
retval = ext2fs_read_inode(fs, EXT2_BAD_INO, &inode);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
inode.i_atime = inode.i_mtime = fs->now ? fs->now : time(0);
|
||||
if (!inode.i_ctime)
|
||||
inode.i_ctime = fs->now ? fs->now : time(0);
|
||||
ext2fs_iblk_set(fs, &inode, rec.bad_block_count);
|
||||
retval = ext2fs_inode_size_set(fs, &inode,
|
||||
rec.bad_block_count * fs->blocksize);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
retval = ext2fs_write_inode(fs, EXT2_BAD_INO, &inode);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
cleanup:
|
||||
ext2fs_free_mem(&rec.ind_blocks);
|
||||
ext2fs_free_mem(&rec.block_buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function for update_bb_inode()
|
||||
*
|
||||
* Clear the bad blocks in the bad block inode, while saving the
|
||||
* indirect blocks.
|
||||
*/
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
static int clear_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk_t ref_block EXT2FS_ATTR((unused)),
|
||||
int ref_offset EXT2FS_ATTR((unused)),
|
||||
void *priv_data)
|
||||
{
|
||||
struct set_badblock_record *rec = (struct set_badblock_record *)
|
||||
priv_data;
|
||||
errcode_t retval;
|
||||
unsigned long old_size;
|
||||
|
||||
if (!*block_nr)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* If the block number is outrageous, clear it and ignore it.
|
||||
*/
|
||||
if (*block_nr >= ext2fs_blocks_count(fs->super) ||
|
||||
*block_nr < fs->super->s_first_data_block) {
|
||||
*block_nr = 0;
|
||||
return BLOCK_CHANGED;
|
||||
}
|
||||
|
||||
if (blockcnt < 0) {
|
||||
if (rec->ind_blocks_size >= rec->max_ind_blocks) {
|
||||
old_size = rec->max_ind_blocks * sizeof(blk_t);
|
||||
rec->max_ind_blocks += 10;
|
||||
retval = ext2fs_resize_mem(old_size,
|
||||
rec->max_ind_blocks * sizeof(blk_t),
|
||||
&rec->ind_blocks);
|
||||
if (retval) {
|
||||
rec->max_ind_blocks -= 10;
|
||||
rec->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
}
|
||||
rec->ind_blocks[rec->ind_blocks_size++] = *block_nr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the block as unused, and update accounting information
|
||||
*/
|
||||
ext2fs_block_alloc_stats2(fs, *block_nr, -1);
|
||||
|
||||
*block_nr = 0;
|
||||
return BLOCK_CHANGED;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper function for update_bb_inode()
|
||||
*
|
||||
* Set the block list in the bad block inode, using the supplied bitmap.
|
||||
*/
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk_t ref_block EXT2FS_ATTR((unused)),
|
||||
int ref_offset EXT2FS_ATTR((unused)),
|
||||
void *priv_data)
|
||||
{
|
||||
struct set_badblock_record *rec = (struct set_badblock_record *)
|
||||
priv_data;
|
||||
errcode_t retval;
|
||||
blk_t blk;
|
||||
|
||||
if (blockcnt >= 0) {
|
||||
/*
|
||||
* Get the next bad block.
|
||||
*/
|
||||
if (!ext2fs_badblocks_list_iterate(rec->bb_iter, &blk))
|
||||
return BLOCK_ABORT;
|
||||
rec->bad_block_count++;
|
||||
} else {
|
||||
/*
|
||||
* An indirect block; fetch a block from the
|
||||
* previously used indirect block list. The block
|
||||
* most be not marked as used; if so, get another one.
|
||||
* If we run out of reserved indirect blocks, allocate
|
||||
* a new one.
|
||||
*/
|
||||
retry:
|
||||
if (rec->ind_blocks_ptr < rec->ind_blocks_size) {
|
||||
blk = rec->ind_blocks[rec->ind_blocks_ptr++];
|
||||
if (ext2fs_test_block_bitmap2(fs->block_map, blk))
|
||||
goto retry;
|
||||
} else {
|
||||
retval = ext2fs_new_block(fs, 0, 0, &blk);
|
||||
if (retval) {
|
||||
rec->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
}
|
||||
retval = io_channel_write_blk64(fs->io, blk, 1, rec->block_buf);
|
||||
if (retval) {
|
||||
rec->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update block counts
|
||||
*/
|
||||
ext2fs_block_alloc_stats2(fs, blk, +1);
|
||||
|
||||
*block_nr = blk;
|
||||
return BLOCK_CHANGED;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/bb_inode.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/bb_inode.o
Executable file
Binary file not shown.
320
jni/e2fsprogs/lib/ext2fs/bitmaps.c
Executable file
320
jni/e2fsprogs/lib/ext2fs/bitmaps.c
Executable file
@@ -0,0 +1,320 @@
|
||||
/*
|
||||
* bitmaps.c --- routines to read, write, and manipulate the inode and
|
||||
* block bitmaps.
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
#include "bmap64.h"
|
||||
|
||||
void ext2fs_free_inode_bitmap(ext2fs_inode_bitmap bitmap)
|
||||
{
|
||||
ext2fs_free_generic_bmap(bitmap);
|
||||
}
|
||||
|
||||
void ext2fs_free_block_bitmap(ext2fs_block_bitmap bitmap)
|
||||
{
|
||||
ext2fs_free_generic_bmap(bitmap);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_copy_bitmap(ext2fs_generic_bitmap src,
|
||||
ext2fs_generic_bitmap *dest)
|
||||
{
|
||||
return (ext2fs_copy_generic_bmap(src, dest));
|
||||
}
|
||||
void ext2fs_set_bitmap_padding(ext2fs_generic_bitmap map)
|
||||
{
|
||||
ext2fs_set_generic_bmap_padding(map);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_inode_bitmap(ext2_filsys fs,
|
||||
const char *descr,
|
||||
ext2fs_inode_bitmap *ret)
|
||||
{
|
||||
__u64 start, end, real_end;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (ext2fs_has_feature_journal_dev(fs->super))
|
||||
return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
|
||||
|
||||
fs->write_bitmaps = ext2fs_write_bitmaps;
|
||||
|
||||
start = 1;
|
||||
end = fs->super->s_inodes_count;
|
||||
real_end = (__u64)EXT2_INODES_PER_GROUP(fs->super) *
|
||||
fs->group_desc_count;
|
||||
|
||||
/* Are we permitted to use new-style bitmaps? */
|
||||
if (fs->flags & EXT2_FLAG_64BITS)
|
||||
return (ext2fs_alloc_generic_bmap(fs,
|
||||
EXT2_ET_MAGIC_INODE_BITMAP64,
|
||||
fs->default_bitmap_type,
|
||||
start, end, real_end, descr, ret));
|
||||
|
||||
/* Otherwise, check to see if the file system is small enough
|
||||
* to use old-style 32-bit bitmaps */
|
||||
if ((end > ~0U) || (real_end > ~0U))
|
||||
return EXT2_ET_CANT_USE_LEGACY_BITMAPS;
|
||||
|
||||
return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP, fs,
|
||||
start, end, real_end,
|
||||
descr, 0,
|
||||
(ext2fs_generic_bitmap *) ret));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_block_bitmap(ext2_filsys fs,
|
||||
const char *descr,
|
||||
ext2fs_block_bitmap *ret)
|
||||
{
|
||||
__u64 start, end, real_end;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (ext2fs_has_feature_journal_dev(fs->super))
|
||||
return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
|
||||
|
||||
fs->write_bitmaps = ext2fs_write_bitmaps;
|
||||
|
||||
start = EXT2FS_B2C(fs, fs->super->s_first_data_block);
|
||||
end = EXT2FS_B2C(fs, ext2fs_blocks_count(fs->super)-1);
|
||||
real_end = ((__u64) EXT2_CLUSTERS_PER_GROUP(fs->super)
|
||||
* (__u64) fs->group_desc_count)-1 + start;
|
||||
|
||||
if (fs->flags & EXT2_FLAG_64BITS)
|
||||
return (ext2fs_alloc_generic_bmap(fs,
|
||||
EXT2_ET_MAGIC_BLOCK_BITMAP64,
|
||||
fs->default_bitmap_type,
|
||||
start, end, real_end, descr, ret));
|
||||
|
||||
if ((end > ~0U) || (real_end > ~0U))
|
||||
return EXT2_ET_CANT_USE_LEGACY_BITMAPS;
|
||||
|
||||
return (ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP, fs,
|
||||
start, end, real_end,
|
||||
descr, 0,
|
||||
(ext2fs_generic_bitmap *) ret));
|
||||
}
|
||||
|
||||
/*
|
||||
* ext2fs_allocate_block_bitmap() really allocates a per-cluster
|
||||
* bitmap for backwards compatibility. This function allocates a
|
||||
* block bitmap which is truly per-block, even if clusters/bigalloc
|
||||
* are enabled. mke2fs and e2fsck need this for tracking the
|
||||
* allocation of the file system metadata blocks.
|
||||
*/
|
||||
errcode_t ext2fs_allocate_subcluster_bitmap(ext2_filsys fs,
|
||||
const char *descr,
|
||||
ext2fs_block_bitmap *ret)
|
||||
{
|
||||
__u64 start, end, real_end;
|
||||
ext2fs_generic_bitmap bmap;
|
||||
ext2fs_generic_bitmap_64 bmap64;
|
||||
errcode_t retval;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (ext2fs_has_feature_journal_dev(fs->super))
|
||||
return EXT2_ET_EXTERNAL_JOURNAL_NOSUPP;
|
||||
|
||||
fs->write_bitmaps = ext2fs_write_bitmaps;
|
||||
|
||||
if (!fs->cluster_ratio_bits)
|
||||
return ext2fs_allocate_block_bitmap(fs, descr, ret);
|
||||
|
||||
if ((fs->flags & EXT2_FLAG_64BITS) == 0)
|
||||
return EXT2_ET_CANT_USE_LEGACY_BITMAPS;
|
||||
|
||||
start = fs->super->s_first_data_block;
|
||||
end = ext2fs_blocks_count(fs->super)-1;
|
||||
real_end = ((__u64) EXT2_BLOCKS_PER_GROUP(fs->super)
|
||||
* (__u64) fs->group_desc_count)-1 + start;
|
||||
|
||||
retval = ext2fs_alloc_generic_bmap(fs, EXT2_ET_MAGIC_BLOCK_BITMAP64,
|
||||
fs->default_bitmap_type, start,
|
||||
end, real_end, descr, &bmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
bmap64 = (ext2fs_generic_bitmap_64) bmap;
|
||||
bmap64->cluster_bits = 0;
|
||||
*ret = bmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2fs_get_bitmap_granularity(ext2fs_block_bitmap bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return 0;
|
||||
|
||||
return bmap->cluster_bits;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_inode_bitmap_end(ext2fs_inode_bitmap bitmap,
|
||||
ext2_ino_t end, ext2_ino_t *oend)
|
||||
{
|
||||
__u64 tmp_oend;
|
||||
int retval;
|
||||
|
||||
retval = ext2fs_fudge_generic_bmap_end((ext2fs_generic_bitmap) bitmap,
|
||||
EXT2_ET_FUDGE_INODE_BITMAP_END,
|
||||
end, &tmp_oend);
|
||||
if (oend)
|
||||
*oend = tmp_oend;
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_block_bitmap_end(ext2fs_block_bitmap bitmap,
|
||||
blk_t end, blk_t *oend)
|
||||
{
|
||||
return (ext2fs_fudge_generic_bitmap_end(bitmap,
|
||||
EXT2_ET_MAGIC_BLOCK_BITMAP,
|
||||
EXT2_ET_FUDGE_BLOCK_BITMAP_END,
|
||||
end, oend));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_block_bitmap_end2(ext2fs_block_bitmap bitmap,
|
||||
blk64_t end, blk64_t *oend)
|
||||
{
|
||||
return (ext2fs_fudge_generic_bmap_end(bitmap,
|
||||
EXT2_ET_FUDGE_BLOCK_BITMAP_END,
|
||||
end, oend));
|
||||
}
|
||||
|
||||
void ext2fs_clear_inode_bitmap(ext2fs_inode_bitmap bitmap)
|
||||
{
|
||||
ext2fs_clear_generic_bmap(bitmap);
|
||||
}
|
||||
|
||||
void ext2fs_clear_block_bitmap(ext2fs_block_bitmap bitmap)
|
||||
{
|
||||
ext2fs_clear_generic_bmap(bitmap);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_inode_bitmap(__u32 new_end, __u32 new_real_end,
|
||||
ext2fs_inode_bitmap bmap)
|
||||
{
|
||||
return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_INODE_BITMAP,
|
||||
new_end, new_real_end, bmap));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_inode_bitmap2(__u64 new_end, __u64 new_real_end,
|
||||
ext2fs_inode_bitmap bmap)
|
||||
{
|
||||
return (ext2fs_resize_generic_bmap(bmap, new_end, new_real_end));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end,
|
||||
ext2fs_block_bitmap bmap)
|
||||
{
|
||||
return (ext2fs_resize_generic_bitmap(EXT2_ET_MAGIC_BLOCK_BITMAP,
|
||||
new_end, new_real_end, bmap));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_block_bitmap2(__u64 new_end, __u64 new_real_end,
|
||||
ext2fs_block_bitmap bmap)
|
||||
{
|
||||
return (ext2fs_resize_generic_bmap(bmap, new_end, new_real_end));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_compare_block_bitmap(ext2fs_block_bitmap bm1,
|
||||
ext2fs_block_bitmap bm2)
|
||||
{
|
||||
return (ext2fs_compare_generic_bmap(EXT2_ET_NEQ_BLOCK_BITMAP,
|
||||
bm1, bm2));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1,
|
||||
ext2fs_inode_bitmap bm2)
|
||||
{
|
||||
return (ext2fs_compare_generic_bmap(EXT2_ET_NEQ_INODE_BITMAP,
|
||||
bm1, bm2));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_inode_bitmap_range(ext2fs_inode_bitmap bmap,
|
||||
ext2_ino_t start, unsigned int num,
|
||||
void *in)
|
||||
{
|
||||
return (ext2fs_set_generic_bitmap_range(bmap,
|
||||
EXT2_ET_MAGIC_INODE_BITMAP,
|
||||
start, num, in));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_inode_bitmap_range2(ext2fs_inode_bitmap bmap,
|
||||
__u64 start, size_t num,
|
||||
void *in)
|
||||
{
|
||||
return (ext2fs_set_generic_bmap_range(bmap, start, num, in));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_inode_bitmap_range(ext2fs_inode_bitmap bmap,
|
||||
ext2_ino_t start, unsigned int num,
|
||||
void *out)
|
||||
{
|
||||
return (ext2fs_get_generic_bitmap_range(bmap,
|
||||
EXT2_ET_MAGIC_INODE_BITMAP,
|
||||
start, num, out));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_inode_bitmap_range2(ext2fs_inode_bitmap bmap,
|
||||
__u64 start, size_t num,
|
||||
void *out)
|
||||
{
|
||||
return (ext2fs_get_generic_bmap_range(bmap, start, num, out));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_block_bitmap_range(ext2fs_block_bitmap bmap,
|
||||
blk_t start, unsigned int num,
|
||||
void *in)
|
||||
{
|
||||
return (ext2fs_set_generic_bitmap_range(bmap,
|
||||
EXT2_ET_MAGIC_BLOCK_BITMAP,
|
||||
start, num, in));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_block_bitmap_range2(ext2fs_block_bitmap bmap,
|
||||
blk64_t start, size_t num,
|
||||
void *in)
|
||||
{
|
||||
return (ext2fs_set_generic_bmap_range(bmap, start, num, in));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_block_bitmap_range(ext2fs_block_bitmap bmap,
|
||||
blk_t start, unsigned int num,
|
||||
void *out)
|
||||
{
|
||||
return (ext2fs_get_generic_bitmap_range(bmap,
|
||||
EXT2_ET_MAGIC_BLOCK_BITMAP,
|
||||
start, num, out));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_block_bitmap_range2(ext2fs_block_bitmap bmap,
|
||||
blk64_t start, size_t num,
|
||||
void *out)
|
||||
{
|
||||
return (ext2fs_get_generic_bmap_range(bmap, start, num, out));
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/bitmaps.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/bitmaps.o
Executable file
Binary file not shown.
148
jni/e2fsprogs/lib/ext2fs/bitops.c
Executable file
148
jni/e2fsprogs/lib/ext2fs/bitops.c
Executable file
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* bitops.c --- Bitmap frobbing code. See bitops.h for the inlined
|
||||
* routines.
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996 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>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* C language bitmap functions written by Theodore Ts'o, 9/26/92.
|
||||
* Modified by Pete A. Zaitcev 7/14/95 to be portable to big endian
|
||||
* systems, as well as non-32 bit systems.
|
||||
*/
|
||||
|
||||
int ext2fs_set_bit(unsigned int nr,void * addr)
|
||||
{
|
||||
int mask, retval;
|
||||
unsigned char *ADDR = (unsigned char *) addr;
|
||||
|
||||
ADDR += nr >> 3;
|
||||
mask = 1 << (nr & 0x07);
|
||||
retval = mask & *ADDR;
|
||||
*ADDR |= mask;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ext2fs_clear_bit(unsigned int nr, void * addr)
|
||||
{
|
||||
int mask, retval;
|
||||
unsigned char *ADDR = (unsigned char *) addr;
|
||||
|
||||
ADDR += nr >> 3;
|
||||
mask = 1 << (nr & 0x07);
|
||||
retval = mask & *ADDR;
|
||||
*ADDR &= ~mask;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ext2fs_test_bit(unsigned int nr, const void * addr)
|
||||
{
|
||||
int mask;
|
||||
const unsigned char *ADDR = (const unsigned char *) addr;
|
||||
|
||||
ADDR += nr >> 3;
|
||||
mask = 1 << (nr & 0x07);
|
||||
return (mask & *ADDR);
|
||||
}
|
||||
|
||||
void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg,
|
||||
const char *description)
|
||||
{
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (description)
|
||||
com_err(0, errcode, "#%lu for %s", arg, description);
|
||||
else
|
||||
com_err(0, errcode, "#%lu", arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Bitmap functions that take a 64-bit offset */
|
||||
|
||||
int ext2fs_set_bit64(__u64 nr, void * addr)
|
||||
{
|
||||
int mask, retval;
|
||||
unsigned char *ADDR = (unsigned char *) addr;
|
||||
|
||||
ADDR += nr >> 3;
|
||||
mask = 1 << (nr & 0x07);
|
||||
retval = mask & *ADDR;
|
||||
*ADDR |= mask;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ext2fs_clear_bit64(__u64 nr, void * addr)
|
||||
{
|
||||
int mask, retval;
|
||||
unsigned char *ADDR = (unsigned char *) addr;
|
||||
|
||||
ADDR += nr >> 3;
|
||||
mask = 1 << (nr & 0x07);
|
||||
retval = mask & *ADDR;
|
||||
*ADDR &= ~mask;
|
||||
return retval;
|
||||
}
|
||||
|
||||
int ext2fs_test_bit64(__u64 nr, const void * addr)
|
||||
{
|
||||
int mask;
|
||||
const unsigned char *ADDR = (const unsigned char *) addr;
|
||||
|
||||
ADDR += nr >> 3;
|
||||
mask = 1 << (nr & 0x07);
|
||||
return (mask & *ADDR);
|
||||
}
|
||||
|
||||
static unsigned int popcount8(unsigned int w)
|
||||
{
|
||||
unsigned int res = w - ((w >> 1) & 0x55);
|
||||
res = (res & 0x33) + ((res >> 2) & 0x33);
|
||||
return (res + (res >> 4)) & 0x0F;
|
||||
}
|
||||
|
||||
static unsigned int popcount32(unsigned int w)
|
||||
{
|
||||
unsigned int res = w - ((w >> 1) & 0x55555555);
|
||||
res = (res & 0x33333333) + ((res >> 2) & 0x33333333);
|
||||
res = (res + (res >> 4)) & 0x0F0F0F0F;
|
||||
res = res + (res >> 8);
|
||||
return (res + (res >> 16)) & 0x000000FF;
|
||||
}
|
||||
|
||||
unsigned int ext2fs_bitcount(const void *addr, unsigned int nbytes)
|
||||
{
|
||||
const unsigned char *cp = addr;
|
||||
const __u32 *p;
|
||||
unsigned int res = 0;
|
||||
|
||||
while (((((uintptr_t) cp) & 3) != 0) && (nbytes > 0)) {
|
||||
res += popcount8(*cp++);
|
||||
nbytes--;
|
||||
}
|
||||
p = (const __u32 *) cp;
|
||||
|
||||
while (nbytes > 4) {
|
||||
res += popcount32(*p++);
|
||||
nbytes -= 4;
|
||||
}
|
||||
cp = (const unsigned char *) p;
|
||||
|
||||
while (nbytes > 0) {
|
||||
res += popcount8(*cp++);
|
||||
nbytes--;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/bitops.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/bitops.o
Executable file
Binary file not shown.
492
jni/e2fsprogs/lib/ext2fs/blkmap64_ba.c
Executable file
492
jni/e2fsprogs/lib/ext2fs/blkmap64_ba.c
Executable file
@@ -0,0 +1,492 @@
|
||||
/*
|
||||
* blkmap64_ba.c --- Simple bitarray implementation for bitmaps
|
||||
*
|
||||
* Copyright (C) 2008 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
#include "bmap64.h"
|
||||
|
||||
/*
|
||||
* Private data for bit array implementation of bitmap ops.
|
||||
* Currently, this is just a pointer to our big flat hunk of memory,
|
||||
* exactly equivalent to the old-skool char * bitmap member.
|
||||
*/
|
||||
|
||||
struct ext2fs_ba_private_struct {
|
||||
char *bitarray;
|
||||
};
|
||||
|
||||
typedef struct ext2fs_ba_private_struct *ext2fs_ba_private;
|
||||
|
||||
static errcode_t ba_alloc_private_data (ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
ext2fs_ba_private bp;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
|
||||
/*
|
||||
* Since we only have the one pointer, we could just shove our
|
||||
* private data in the void *private field itself, but then
|
||||
* we'd have to do a fair bit of rewriting if we ever added a
|
||||
* field. I'm agnostic.
|
||||
*/
|
||||
retval = ext2fs_get_mem(sizeof (ext2fs_ba_private), &bp);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
|
||||
|
||||
retval = ext2fs_get_mem(size, &bp->bitarray);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&bp);
|
||||
bp = 0;
|
||||
return retval;
|
||||
}
|
||||
bitmap->private = (void *) bp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t ba_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),
|
||||
ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
ext2fs_ba_private bp;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
|
||||
retval = ba_alloc_private_data (bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
bp = (ext2fs_ba_private) bitmap->private;
|
||||
size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
|
||||
memset(bp->bitarray, 0, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ba_free_bmap(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
|
||||
if (!bp)
|
||||
return;
|
||||
|
||||
if (bp->bitarray) {
|
||||
ext2fs_free_mem (&bp->bitarray);
|
||||
bp->bitarray = 0;
|
||||
}
|
||||
ext2fs_free_mem (&bp);
|
||||
bp = 0;
|
||||
}
|
||||
|
||||
static errcode_t ba_copy_bmap(ext2fs_generic_bitmap_64 src,
|
||||
ext2fs_generic_bitmap_64 dest)
|
||||
{
|
||||
ext2fs_ba_private src_bp = (ext2fs_ba_private) src->private;
|
||||
ext2fs_ba_private dest_bp;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
|
||||
retval = ba_alloc_private_data (dest);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
dest_bp = (ext2fs_ba_private) dest->private;
|
||||
|
||||
size = (size_t) (((src->real_end - src->start) / 8) + 1);
|
||||
memcpy (dest_bp->bitarray, src_bp->bitarray, size);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t ba_resize_bmap(ext2fs_generic_bitmap_64 bmap,
|
||||
__u64 new_end, __u64 new_real_end)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bmap->private;
|
||||
errcode_t retval;
|
||||
size_t size, new_size;
|
||||
__u64 bitno;
|
||||
|
||||
/*
|
||||
* If we're expanding the bitmap, make sure all of the new
|
||||
* parts of the bitmap are zero.
|
||||
*/
|
||||
if (new_end > bmap->end) {
|
||||
bitno = bmap->real_end;
|
||||
if (bitno > new_end)
|
||||
bitno = new_end;
|
||||
for (; bitno > bmap->end; bitno--)
|
||||
ext2fs_clear_bit64(bitno - bmap->start, bp->bitarray);
|
||||
}
|
||||
if (new_real_end == bmap->real_end) {
|
||||
bmap->end = new_end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = ((bmap->real_end - bmap->start) / 8) + 1;
|
||||
new_size = ((new_real_end - bmap->start) / 8) + 1;
|
||||
|
||||
if (size != new_size) {
|
||||
retval = ext2fs_resize_mem(size, new_size, &bp->bitarray);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (new_size > size)
|
||||
memset(bp->bitarray + size, 0, new_size - size);
|
||||
|
||||
bmap->end = new_end;
|
||||
bmap->real_end = new_real_end;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
static int ba_mark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
|
||||
return ext2fs_set_bit64(bitno - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static int ba_unmark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
|
||||
return ext2fs_clear_bit64(bitno - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static int ba_test_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
|
||||
return ext2fs_test_bit64(bitno - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static void ba_mark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
|
||||
unsigned int num)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
ext2fs_fast_set_bit64(bitno + i - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static void ba_unmark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
|
||||
unsigned int num)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
blk64_t bitno = (blk64_t) arg;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < num; i++)
|
||||
ext2fs_fast_clear_bit64(bitno + i - bitmap->start, bp->bitarray);
|
||||
}
|
||||
|
||||
static int ba_test_clear_bmap_extent(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, unsigned int len)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
__u64 start_byte, len_byte = len >> 3;
|
||||
unsigned int start_bit, len_bit = len % 8;
|
||||
unsigned int first_bit = 0;
|
||||
unsigned int last_bit = 0;
|
||||
int mark_count = 0;
|
||||
int mark_bit = 0;
|
||||
int i;
|
||||
const char *ADDR;
|
||||
|
||||
ADDR = bp->bitarray;
|
||||
start -= bitmap->start;
|
||||
start_byte = start >> 3;
|
||||
start_bit = start % 8;
|
||||
|
||||
if (start_bit != 0) {
|
||||
/*
|
||||
* The compared start block number or start inode number
|
||||
* is not the first bit in a byte.
|
||||
*/
|
||||
mark_count = 8 - start_bit;
|
||||
if (len < 8 - start_bit) {
|
||||
mark_count = (int)len;
|
||||
mark_bit = len + start_bit - 1;
|
||||
} else
|
||||
mark_bit = 7;
|
||||
|
||||
for (i = mark_count; i > 0; i--, mark_bit--)
|
||||
first_bit |= 1 << mark_bit;
|
||||
|
||||
/*
|
||||
* Compare blocks or inodes in the first byte.
|
||||
* If there is any marked bit, this function returns 0.
|
||||
*/
|
||||
if (first_bit & ADDR[start_byte])
|
||||
return 0;
|
||||
else if (len <= 8 - start_bit)
|
||||
return 1;
|
||||
|
||||
start_byte++;
|
||||
len_bit = (len - mark_count) % 8;
|
||||
len_byte = (len - mark_count) >> 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* The compared start block number or start inode number is
|
||||
* the first bit in a byte.
|
||||
*/
|
||||
if (len_bit != 0) {
|
||||
/*
|
||||
* The compared end block number or end inode number is
|
||||
* not the last bit in a byte.
|
||||
*/
|
||||
for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--)
|
||||
last_bit |= 1 << mark_bit;
|
||||
|
||||
/*
|
||||
* Compare blocks or inodes in the last byte.
|
||||
* If there is any marked bit, this function returns 0.
|
||||
*/
|
||||
if (last_bit & ADDR[start_byte + len_byte])
|
||||
return 0;
|
||||
else if (len_byte == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check whether all bytes are 0 */
|
||||
return ext2fs_mem_is_zero(ADDR + start_byte, len_byte);
|
||||
}
|
||||
|
||||
|
||||
static errcode_t ba_set_bmap_range(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, size_t num, void *in)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
|
||||
memcpy (bp->bitarray + (start >> 3), in, (num + 7) >> 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t ba_get_bmap_range(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, size_t num, void *out)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
|
||||
memcpy (out, bp->bitarray + (start >> 3), (num + 7) >> 3);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void ba_clear_bmap(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private) bitmap->private;
|
||||
|
||||
memset(bp->bitarray, 0,
|
||||
(size_t) (((bitmap->real_end - bitmap->start) / 8) + 1));
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
static void ba_print_stats(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
fprintf(stderr, "%16llu Bytes used by bitarray\n", (unsigned long long)
|
||||
((bitmap->real_end - bitmap->start) >> 3) + 1 +
|
||||
sizeof(struct ext2fs_ba_private_struct));
|
||||
}
|
||||
#else
|
||||
static void ba_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused)))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Find the first zero bit between start and end, inclusive. */
|
||||
static errcode_t ba_find_first_zero(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private;
|
||||
unsigned long bitpos = start - bitmap->start;
|
||||
unsigned long count = end - start + 1;
|
||||
int byte_found = 0; /* whether a != 0xff byte has been found */
|
||||
const unsigned char *pos;
|
||||
unsigned long max_loop_count, i;
|
||||
|
||||
/* scan bits until we hit a byte boundary */
|
||||
while ((bitpos & 0x7) != 0 && count > 0) {
|
||||
if (!ext2fs_test_bit64(bitpos, bp->bitarray)) {
|
||||
*out = bitpos + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
bitpos++;
|
||||
count--;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return ENOENT;
|
||||
|
||||
pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3);
|
||||
/* scan bytes until 8-byte (64-bit) aligned */
|
||||
while (count >= 8 && (((uintptr_t)pos) & 0x07)) {
|
||||
if (*pos != 0xff) {
|
||||
byte_found = 1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
count -= 8;
|
||||
bitpos += 8;
|
||||
}
|
||||
|
||||
if (!byte_found) {
|
||||
max_loop_count = count >> 6; /* 8-byte blocks */
|
||||
i = max_loop_count;
|
||||
while (i) {
|
||||
if (*((const __u64 *)pos) != ((__u64)-1))
|
||||
break;
|
||||
pos += 8;
|
||||
i--;
|
||||
}
|
||||
count -= 64 * (max_loop_count - i);
|
||||
bitpos += 64 * (max_loop_count - i);
|
||||
|
||||
max_loop_count = count >> 3;
|
||||
i = max_loop_count;
|
||||
while (i) {
|
||||
if (*pos != 0xff) {
|
||||
byte_found = 1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
i--;
|
||||
}
|
||||
count -= 8 * (max_loop_count - i);
|
||||
bitpos += 8 * (max_loop_count - i);
|
||||
}
|
||||
|
||||
/* Here either count < 8 or byte_found == 1. */
|
||||
while (count-- > 0) {
|
||||
if (!ext2fs_test_bit64(bitpos, bp->bitarray)) {
|
||||
*out = bitpos + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
bitpos++;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/* Find the first one bit between start and end, inclusive. */
|
||||
static errcode_t ba_find_first_set(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
ext2fs_ba_private bp = (ext2fs_ba_private)bitmap->private;
|
||||
unsigned long bitpos = start - bitmap->start;
|
||||
unsigned long count = end - start + 1;
|
||||
int byte_found = 0; /* whether a != 0xff byte has been found */
|
||||
const unsigned char *pos;
|
||||
unsigned long max_loop_count, i;
|
||||
|
||||
/* scan bits until we hit a byte boundary */
|
||||
while ((bitpos & 0x7) != 0 && count > 0) {
|
||||
if (ext2fs_test_bit64(bitpos, bp->bitarray)) {
|
||||
*out = bitpos + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
bitpos++;
|
||||
count--;
|
||||
}
|
||||
|
||||
if (!count)
|
||||
return ENOENT;
|
||||
|
||||
pos = ((unsigned char *)bp->bitarray) + (bitpos >> 3);
|
||||
/* scan bytes until 8-byte (64-bit) aligned */
|
||||
while (count >= 8 && (((uintptr_t)pos) & 0x07)) {
|
||||
if (*pos != 0) {
|
||||
byte_found = 1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
count -= 8;
|
||||
bitpos += 8;
|
||||
}
|
||||
|
||||
if (!byte_found) {
|
||||
max_loop_count = count >> 6; /* 8-byte blocks */
|
||||
i = max_loop_count;
|
||||
while (i) {
|
||||
if (*((const __u64 *)pos) != 0)
|
||||
break;
|
||||
pos += 8;
|
||||
i--;
|
||||
}
|
||||
count -= 64 * (max_loop_count - i);
|
||||
bitpos += 64 * (max_loop_count - i);
|
||||
|
||||
max_loop_count = count >> 3;
|
||||
i = max_loop_count;
|
||||
while (i) {
|
||||
if (*pos != 0) {
|
||||
byte_found = 1;
|
||||
break;
|
||||
}
|
||||
pos++;
|
||||
i--;
|
||||
}
|
||||
count -= 8 * (max_loop_count - i);
|
||||
bitpos += 8 * (max_loop_count - i);
|
||||
}
|
||||
|
||||
/* Here either count < 8 or byte_found == 1. */
|
||||
while (count-- > 0) {
|
||||
if (ext2fs_test_bit64(bitpos, bp->bitarray)) {
|
||||
*out = bitpos + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
bitpos++;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
struct ext2_bitmap_ops ext2fs_blkmap64_bitarray = {
|
||||
.type = EXT2FS_BMAP64_BITARRAY,
|
||||
.new_bmap = ba_new_bmap,
|
||||
.free_bmap = ba_free_bmap,
|
||||
.copy_bmap = ba_copy_bmap,
|
||||
.resize_bmap = ba_resize_bmap,
|
||||
.mark_bmap = ba_mark_bmap,
|
||||
.unmark_bmap = ba_unmark_bmap,
|
||||
.test_bmap = ba_test_bmap,
|
||||
.test_clear_bmap_extent = ba_test_clear_bmap_extent,
|
||||
.mark_bmap_extent = ba_mark_bmap_extent,
|
||||
.unmark_bmap_extent = ba_unmark_bmap_extent,
|
||||
.set_bmap_range = ba_set_bmap_range,
|
||||
.get_bmap_range = ba_get_bmap_range,
|
||||
.clear_bmap = ba_clear_bmap,
|
||||
.print_stats = ba_print_stats,
|
||||
.find_first_zero = ba_find_first_zero,
|
||||
.find_first_set = ba_find_first_set
|
||||
};
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/blkmap64_ba.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/blkmap64_ba.o
Executable file
Binary file not shown.
998
jni/e2fsprogs/lib/ext2fs/blkmap64_rb.c
Executable file
998
jni/e2fsprogs/lib/ext2fs/blkmap64_rb.c
Executable file
@@ -0,0 +1,998 @@
|
||||
/*
|
||||
* blkmap64_rb.c --- Simple rb-tree implementation for bitmaps
|
||||
*
|
||||
* (C)2010 Red Hat, Inc., Lukas Czerner <lczerner@redhat.com>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_LINUX_TYPES_H
|
||||
#include <linux/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
#include "bmap64.h"
|
||||
#include "rbtree.h"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
struct bmap_rb_extent {
|
||||
struct rb_node node;
|
||||
__u64 start;
|
||||
__u64 count;
|
||||
};
|
||||
|
||||
struct ext2fs_rb_private {
|
||||
struct rb_root root;
|
||||
struct bmap_rb_extent *wcursor;
|
||||
struct bmap_rb_extent *rcursor;
|
||||
struct bmap_rb_extent *rcursor_next;
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
__u64 mark_hit;
|
||||
__u64 test_hit;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline static struct bmap_rb_extent *node_to_extent(struct rb_node *node)
|
||||
{
|
||||
/*
|
||||
* This depends on the fact the struct rb_node is at the
|
||||
* beginning of the bmap_rb_extent structure. We use this
|
||||
* instead of the ext2fs_rb_entry macro because it causes gcc
|
||||
* -Wall to generate a huge amount of noise.
|
||||
*/
|
||||
return (struct bmap_rb_extent *) node;
|
||||
}
|
||||
|
||||
static int rb_insert_extent(__u64 start, __u64 count,
|
||||
struct ext2fs_rb_private *);
|
||||
static void rb_get_new_extent(struct bmap_rb_extent **, __u64, __u64);
|
||||
|
||||
/* #define DEBUG_RB */
|
||||
|
||||
#ifdef DEBUG_RB
|
||||
static void print_tree(struct rb_root *root)
|
||||
{
|
||||
struct rb_node *node = NULL;
|
||||
struct bmap_rb_extent *ext;
|
||||
|
||||
fprintf(stderr, "\t\t\t=================================\n");
|
||||
node = ext2fs_rb_first(root);
|
||||
for (node = ext2fs_rb_first(root); node != NULL;
|
||||
node = ext2fs_rb_next(node)) {
|
||||
ext = node_to_extent(node);
|
||||
fprintf(stderr, "\t\t\t--> (%llu -> %llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count);
|
||||
}
|
||||
fprintf(stderr, "\t\t\t=================================\n");
|
||||
}
|
||||
|
||||
static void check_tree(struct rb_root *root, const char *msg)
|
||||
{
|
||||
struct rb_node *node;
|
||||
struct bmap_rb_extent *ext, *old = NULL;
|
||||
|
||||
for (node = ext2fs_rb_first(root); node;
|
||||
node = ext2fs_rb_next(node)) {
|
||||
ext = node_to_extent(node);
|
||||
if (ext->count == 0) {
|
||||
fprintf(stderr, "Tree Error: count is zero\n");
|
||||
fprintf(stderr, "extent: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count,
|
||||
(unsigned long long) ext->count);
|
||||
goto err_out;
|
||||
}
|
||||
if (ext->start + ext->count < ext->start) {
|
||||
fprintf(stderr,
|
||||
"Tree Error: start or count is crazy\n");
|
||||
fprintf(stderr, "extent: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count,
|
||||
(unsigned long long) ext->count);
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
if (old) {
|
||||
if (old->start > ext->start) {
|
||||
fprintf(stderr, "Tree Error: start is crazy\n");
|
||||
fprintf(stderr, "extent: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) old->start,
|
||||
(unsigned long long) old->start + old->count,
|
||||
(unsigned long long) old->count);
|
||||
fprintf(stderr,
|
||||
"extent next: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count,
|
||||
(unsigned long long) ext->count);
|
||||
goto err_out;
|
||||
}
|
||||
if ((old->start + old->count) >= ext->start) {
|
||||
fprintf(stderr,
|
||||
"Tree Error: extent is crazy\n");
|
||||
fprintf(stderr, "extent: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) old->start,
|
||||
(unsigned long long) old->start + old->count,
|
||||
(unsigned long long) old->count);
|
||||
fprintf(stderr,
|
||||
"extent next: %llu -> %llu (%llu)\n",
|
||||
(unsigned long long) ext->start,
|
||||
(unsigned long long) ext->start + ext->count,
|
||||
(unsigned long long) ext->count);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
old = ext;
|
||||
}
|
||||
return;
|
||||
|
||||
err_out:
|
||||
fprintf(stderr, "%s\n", msg);
|
||||
print_tree(root);
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
#define check_tree(root, msg) do {} while (0)
|
||||
#define print_tree(root) do {} while (0)
|
||||
#endif
|
||||
|
||||
static void rb_get_new_extent(struct bmap_rb_extent **ext, __u64 start,
|
||||
__u64 count)
|
||||
{
|
||||
struct bmap_rb_extent *new_ext;
|
||||
int retval;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent),
|
||||
&new_ext);
|
||||
if (retval)
|
||||
abort();
|
||||
|
||||
new_ext->start = start;
|
||||
new_ext->count = count;
|
||||
*ext = new_ext;
|
||||
}
|
||||
|
||||
inline
|
||||
static void rb_free_extent(struct ext2fs_rb_private *bp,
|
||||
struct bmap_rb_extent *ext)
|
||||
{
|
||||
if (bp->wcursor == ext)
|
||||
bp->wcursor = NULL;
|
||||
if (bp->rcursor == ext)
|
||||
bp->rcursor = NULL;
|
||||
if (bp->rcursor_next == ext)
|
||||
bp->rcursor_next = NULL;
|
||||
ext2fs_free_mem(&ext);
|
||||
}
|
||||
|
||||
static errcode_t rb_alloc_private_data (ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof (struct ext2fs_rb_private), &bp);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
bp->root = RB_ROOT;
|
||||
bp->rcursor = NULL;
|
||||
bp->rcursor_next = NULL;
|
||||
bp->wcursor = NULL;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
bp->test_hit = 0;
|
||||
bp->mark_hit = 0;
|
||||
#endif
|
||||
|
||||
bitmap->private = (void *) bp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t rb_new_bmap(ext2_filsys fs EXT2FS_ATTR((unused)),
|
||||
ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
errcode_t retval;
|
||||
|
||||
retval = rb_alloc_private_data (bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rb_free_tree(struct rb_root *root)
|
||||
{
|
||||
struct bmap_rb_extent *ext;
|
||||
struct rb_node *node, *next;
|
||||
|
||||
for (node = ext2fs_rb_first(root); node; node = next) {
|
||||
next = ext2fs_rb_next(node);
|
||||
ext = node_to_extent(node);
|
||||
ext2fs_rb_erase(node, root);
|
||||
ext2fs_free_mem(&ext);
|
||||
}
|
||||
}
|
||||
|
||||
static void rb_free_bmap(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
|
||||
rb_free_tree(&bp->root);
|
||||
ext2fs_free_mem(&bp);
|
||||
bp = 0;
|
||||
}
|
||||
|
||||
static errcode_t rb_copy_bmap(ext2fs_generic_bitmap_64 src,
|
||||
ext2fs_generic_bitmap_64 dest)
|
||||
{
|
||||
struct ext2fs_rb_private *src_bp, *dest_bp;
|
||||
struct bmap_rb_extent *src_ext, *dest_ext;
|
||||
struct rb_node *dest_node, *src_node, *dest_last, **n;
|
||||
errcode_t retval = 0;
|
||||
|
||||
retval = rb_alloc_private_data (dest);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
src_bp = (struct ext2fs_rb_private *) src->private;
|
||||
dest_bp = (struct ext2fs_rb_private *) dest->private;
|
||||
src_bp->rcursor = NULL;
|
||||
dest_bp->rcursor = NULL;
|
||||
|
||||
src_node = ext2fs_rb_first(&src_bp->root);
|
||||
while (src_node) {
|
||||
src_ext = node_to_extent(src_node);
|
||||
retval = ext2fs_get_mem(sizeof (struct bmap_rb_extent),
|
||||
&dest_ext);
|
||||
if (retval)
|
||||
break;
|
||||
|
||||
memcpy(dest_ext, src_ext, sizeof(struct bmap_rb_extent));
|
||||
|
||||
dest_node = &dest_ext->node;
|
||||
n = &dest_bp->root.rb_node;
|
||||
|
||||
dest_last = NULL;
|
||||
if (*n) {
|
||||
dest_last = ext2fs_rb_last(&dest_bp->root);
|
||||
n = &(dest_last)->rb_right;
|
||||
}
|
||||
|
||||
ext2fs_rb_link_node(dest_node, dest_last, n);
|
||||
ext2fs_rb_insert_color(dest_node, &dest_bp->root);
|
||||
|
||||
src_node = ext2fs_rb_next(src_node);
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void rb_truncate(__u64 new_max, struct rb_root *root)
|
||||
{
|
||||
struct bmap_rb_extent *ext;
|
||||
struct rb_node *node;
|
||||
|
||||
node = ext2fs_rb_last(root);
|
||||
while (node) {
|
||||
ext = node_to_extent(node);
|
||||
|
||||
if ((ext->start + ext->count - 1) <= new_max)
|
||||
break;
|
||||
else if (ext->start > new_max) {
|
||||
ext2fs_rb_erase(node, root);
|
||||
ext2fs_free_mem(&ext);
|
||||
node = ext2fs_rb_last(root);
|
||||
continue;
|
||||
} else
|
||||
ext->count = new_max - ext->start + 1;
|
||||
}
|
||||
}
|
||||
|
||||
static errcode_t rb_resize_bmap(ext2fs_generic_bitmap_64 bmap,
|
||||
__u64 new_end, __u64 new_real_end)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bmap->private;
|
||||
bp->rcursor = NULL;
|
||||
bp->wcursor = NULL;
|
||||
|
||||
rb_truncate(((new_end < bmap->end) ? new_end : bmap->end) - bmap->start,
|
||||
&bp->root);
|
||||
|
||||
bmap->end = new_end;
|
||||
bmap->real_end = new_real_end;
|
||||
|
||||
if (bmap->end < bmap->real_end)
|
||||
rb_insert_extent(bmap->end + 1 - bmap->start,
|
||||
bmap->real_end - bmap->end, bp);
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
inline static int
|
||||
rb_test_bit(struct ext2fs_rb_private *bp, __u64 bit)
|
||||
{
|
||||
struct bmap_rb_extent *rcursor, *next_ext = NULL;
|
||||
struct rb_node *parent = NULL, *next;
|
||||
struct rb_node **n = &bp->root.rb_node;
|
||||
struct bmap_rb_extent *ext;
|
||||
|
||||
rcursor = bp->rcursor;
|
||||
if (!rcursor)
|
||||
goto search_tree;
|
||||
|
||||
if (bit >= rcursor->start && bit < rcursor->start + rcursor->count) {
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
bp->test_hit++;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
next_ext = bp->rcursor_next;
|
||||
if (!next_ext) {
|
||||
next = ext2fs_rb_next(&rcursor->node);
|
||||
if (next)
|
||||
next_ext = node_to_extent(next);
|
||||
bp->rcursor_next = next_ext;
|
||||
}
|
||||
if (next_ext) {
|
||||
if ((bit >= rcursor->start + rcursor->count) &&
|
||||
(bit < next_ext->start)) {
|
||||
#ifdef BMAP_STATS_OPS
|
||||
bp->test_hit++;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
bp->rcursor = NULL;
|
||||
bp->rcursor_next = NULL;
|
||||
|
||||
rcursor = bp->wcursor;
|
||||
if (!rcursor)
|
||||
goto search_tree;
|
||||
|
||||
if (bit >= rcursor->start && bit < rcursor->start + rcursor->count)
|
||||
return 1;
|
||||
|
||||
search_tree:
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (bit < ext->start)
|
||||
n = &(*n)->rb_left;
|
||||
else if (bit >= (ext->start + ext->count))
|
||||
n = &(*n)->rb_right;
|
||||
else {
|
||||
bp->rcursor = ext;
|
||||
bp->rcursor_next = NULL;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rb_insert_extent(__u64 start, __u64 count,
|
||||
struct ext2fs_rb_private *bp)
|
||||
{
|
||||
struct rb_root *root = &bp->root;
|
||||
struct rb_node *parent = NULL, **n = &root->rb_node;
|
||||
struct rb_node *new_node, *node, *next;
|
||||
struct bmap_rb_extent *new_ext;
|
||||
struct bmap_rb_extent *ext;
|
||||
int retval = 0;
|
||||
|
||||
if (count == 0)
|
||||
return 0;
|
||||
|
||||
bp->rcursor_next = NULL;
|
||||
ext = bp->wcursor;
|
||||
if (ext) {
|
||||
if (start >= ext->start &&
|
||||
start <= (ext->start + ext->count)) {
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
bp->mark_hit++;
|
||||
#endif
|
||||
goto got_extent;
|
||||
}
|
||||
}
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start > (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else {
|
||||
got_extent:
|
||||
if ((start + count) <= (ext->start + ext->count))
|
||||
return 1;
|
||||
|
||||
if ((ext->start + ext->count) == start)
|
||||
retval = 0;
|
||||
else
|
||||
retval = 1;
|
||||
|
||||
count += (start - ext->start);
|
||||
start = ext->start;
|
||||
new_ext = ext;
|
||||
new_node = &ext->node;
|
||||
|
||||
goto skip_insert;
|
||||
}
|
||||
}
|
||||
|
||||
rb_get_new_extent(&new_ext, start, count);
|
||||
|
||||
new_node = &new_ext->node;
|
||||
ext2fs_rb_link_node(new_node, parent, n);
|
||||
ext2fs_rb_insert_color(new_node, root);
|
||||
bp->wcursor = new_ext;
|
||||
|
||||
node = ext2fs_rb_prev(new_node);
|
||||
if (node) {
|
||||
ext = node_to_extent(node);
|
||||
if ((ext->start + ext->count) == start) {
|
||||
start = ext->start;
|
||||
count += ext->count;
|
||||
ext2fs_rb_erase(node, root);
|
||||
rb_free_extent(bp, ext);
|
||||
}
|
||||
}
|
||||
|
||||
skip_insert:
|
||||
/* See if we can merge extent to the right */
|
||||
for (node = ext2fs_rb_next(new_node); node != NULL; node = next) {
|
||||
next = ext2fs_rb_next(node);
|
||||
ext = node_to_extent(node);
|
||||
|
||||
if ((ext->start + ext->count) <= start)
|
||||
continue;
|
||||
|
||||
/* No more merging */
|
||||
if ((start + count) < ext->start)
|
||||
break;
|
||||
|
||||
/* ext is embedded in new_ext interval */
|
||||
if ((start + count) >= (ext->start + ext->count)) {
|
||||
ext2fs_rb_erase(node, root);
|
||||
rb_free_extent(bp, ext);
|
||||
continue;
|
||||
} else {
|
||||
/* merge ext with new_ext */
|
||||
count += ((ext->start + ext->count) -
|
||||
(start + count));
|
||||
ext2fs_rb_erase(node, root);
|
||||
rb_free_extent(bp, ext);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
new_ext->start = start;
|
||||
new_ext->count = count;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rb_remove_extent(__u64 start, __u64 count,
|
||||
struct ext2fs_rb_private *bp)
|
||||
{
|
||||
struct rb_root *root = &bp->root;
|
||||
struct rb_node *parent = NULL, **n = &root->rb_node;
|
||||
struct rb_node *node;
|
||||
struct bmap_rb_extent *ext;
|
||||
__u64 new_start, new_count;
|
||||
int retval = 0;
|
||||
|
||||
if (ext2fs_rb_empty_root(root))
|
||||
return 0;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
continue;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((start > ext->start) &&
|
||||
(start + count) < (ext->start + ext->count)) {
|
||||
/* We have to split extent into two */
|
||||
new_start = start + count;
|
||||
new_count = (ext->start + ext->count) - new_start;
|
||||
|
||||
ext->count = start - ext->start;
|
||||
|
||||
rb_insert_extent(new_start, new_count, bp);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ((start + count) >= (ext->start + ext->count)) {
|
||||
ext->count = start - ext->start;
|
||||
retval = 1;
|
||||
}
|
||||
|
||||
if (0 == ext->count) {
|
||||
parent = ext2fs_rb_next(&ext->node);
|
||||
ext2fs_rb_erase(&ext->node, root);
|
||||
rb_free_extent(bp, ext);
|
||||
break;
|
||||
}
|
||||
|
||||
if (start == ext->start) {
|
||||
ext->start += count;
|
||||
ext->count -= count;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* See if we should delete or truncate extent on the right */
|
||||
for (; parent != NULL; parent = node) {
|
||||
node = ext2fs_rb_next(parent);
|
||||
ext = node_to_extent(parent);
|
||||
if ((ext->start + ext->count) <= start)
|
||||
continue;
|
||||
|
||||
/* No more extents to be removed/truncated */
|
||||
if ((start + count) < ext->start)
|
||||
break;
|
||||
|
||||
/* The entire extent is within the region to be removed */
|
||||
if ((start + count) >= (ext->start + ext->count)) {
|
||||
ext2fs_rb_erase(parent, root);
|
||||
rb_free_extent(bp, ext);
|
||||
retval = 1;
|
||||
continue;
|
||||
} else {
|
||||
/* modify the last extent in region to be removed */
|
||||
ext->count -= ((start + count) - ext->start);
|
||||
ext->start = start + count;
|
||||
retval = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rb_mark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
int retval;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
retval = rb_insert_extent(arg, 1, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static int rb_unmark_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
int retval;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
retval = rb_remove_extent(arg, 1, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
inline
|
||||
static int rb_test_bmap(ext2fs_generic_bitmap_64 bitmap, __u64 arg)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
return rb_test_bit(bp, arg);
|
||||
}
|
||||
|
||||
static void rb_mark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
|
||||
unsigned int num)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
rb_insert_extent(arg, num, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
}
|
||||
|
||||
static void rb_unmark_bmap_extent(ext2fs_generic_bitmap_64 bitmap, __u64 arg,
|
||||
unsigned int num)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
arg -= bitmap->start;
|
||||
|
||||
rb_remove_extent(arg, num, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
}
|
||||
|
||||
static int rb_test_clear_bmap_extent(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, unsigned int len)
|
||||
{
|
||||
struct rb_node *parent = NULL, **n;
|
||||
struct rb_node *node, *next;
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct bmap_rb_extent *ext;
|
||||
int retval = 1;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
n = &bp->root.rb_node;
|
||||
start -= bitmap->start;
|
||||
|
||||
if (len == 0 || ext2fs_rb_empty_root(&bp->root))
|
||||
return 1;
|
||||
|
||||
/*
|
||||
* If we find nothing, we should examine whole extent, but
|
||||
* when we find match, the extent is not clean, thus be return
|
||||
* false.
|
||||
*/
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else {
|
||||
/*
|
||||
* We found extent int the tree -> extent is not
|
||||
* clean
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
node = parent;
|
||||
while (node) {
|
||||
next = ext2fs_rb_next(node);
|
||||
ext = node_to_extent(node);
|
||||
node = next;
|
||||
|
||||
if ((ext->start + ext->count) <= start)
|
||||
continue;
|
||||
|
||||
/* No more merging */
|
||||
if ((start + len) <= ext->start)
|
||||
break;
|
||||
|
||||
retval = 0;
|
||||
break;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t rb_set_bmap_range(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, size_t num, void *in)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
unsigned char *cp = in;
|
||||
size_t i;
|
||||
int first_set = -1;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
|
||||
for (i = 0; i < num; i++) {
|
||||
if ((i & 7) == 0) {
|
||||
unsigned char c = cp[i/8];
|
||||
if (c == 0xFF) {
|
||||
if (first_set == -1)
|
||||
first_set = i;
|
||||
i += 7;
|
||||
continue;
|
||||
}
|
||||
if ((c == 0x00) && (first_set == -1)) {
|
||||
i += 7;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (ext2fs_test_bit(i, in)) {
|
||||
if (first_set == -1)
|
||||
first_set = i;
|
||||
continue;
|
||||
}
|
||||
if (first_set == -1)
|
||||
continue;
|
||||
|
||||
rb_insert_extent(start + first_set - bitmap->start,
|
||||
i - first_set, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
first_set = -1;
|
||||
}
|
||||
if (first_set != -1) {
|
||||
rb_insert_extent(start + first_set - bitmap->start,
|
||||
num - first_set, bp);
|
||||
check_tree(&bp->root, __func__);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t rb_get_bmap_range(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, size_t num, void *out)
|
||||
{
|
||||
|
||||
struct rb_node *parent = NULL, *next, **n;
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct bmap_rb_extent *ext;
|
||||
__u64 count, pos;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
n = &bp->root.rb_node;
|
||||
start -= bitmap->start;
|
||||
|
||||
if (ext2fs_rb_empty_root(&bp->root))
|
||||
return 0;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else
|
||||
break;
|
||||
}
|
||||
|
||||
memset(out, 0, (num + 7) >> 3);
|
||||
|
||||
for (; parent != NULL; parent = next) {
|
||||
next = ext2fs_rb_next(parent);
|
||||
ext = node_to_extent(parent);
|
||||
|
||||
pos = ext->start;
|
||||
count = ext->count;
|
||||
if (pos >= start + num)
|
||||
break;
|
||||
if (pos < start) {
|
||||
if (pos + count < start)
|
||||
continue;
|
||||
count -= start - pos;
|
||||
pos = start;
|
||||
}
|
||||
if (pos + count > start + num)
|
||||
count = start + num - pos;
|
||||
|
||||
while (count > 0) {
|
||||
if ((count >= 8) &&
|
||||
((pos - start) % 8) == 0) {
|
||||
int nbytes = count >> 3;
|
||||
int offset = (pos - start) >> 3;
|
||||
|
||||
memset(((char *) out) + offset, 0xFF, nbytes);
|
||||
pos += nbytes << 3;
|
||||
count -= nbytes << 3;
|
||||
continue;
|
||||
}
|
||||
ext2fs_fast_set_bit64((pos - start), out);
|
||||
pos++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rb_clear_bmap(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
|
||||
rb_free_tree(&bp->root);
|
||||
bp->rcursor = NULL;
|
||||
bp->rcursor_next = NULL;
|
||||
bp->wcursor = NULL;
|
||||
check_tree(&bp->root, __func__);
|
||||
}
|
||||
|
||||
static errcode_t rb_find_first_zero(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
struct rb_node *parent = NULL, **n;
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct bmap_rb_extent *ext;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
n = &bp->root.rb_node;
|
||||
start -= bitmap->start;
|
||||
end -= bitmap->start;
|
||||
|
||||
if (start > end)
|
||||
return EINVAL;
|
||||
|
||||
if (ext2fs_rb_empty_root(&bp->root))
|
||||
return ENOENT;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else if (ext->start + ext->count <= end) {
|
||||
*out = ext->start + ext->count + bitmap->start;
|
||||
return 0;
|
||||
} else
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
*out = start + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t rb_find_first_set(ext2fs_generic_bitmap_64 bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
struct rb_node *parent = NULL, **n;
|
||||
struct rb_node *node;
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct bmap_rb_extent *ext;
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
n = &bp->root.rb_node;
|
||||
start -= bitmap->start;
|
||||
end -= bitmap->start;
|
||||
|
||||
if (start > end)
|
||||
return EINVAL;
|
||||
|
||||
if (ext2fs_rb_empty_root(&bp->root))
|
||||
return ENOENT;
|
||||
|
||||
while (*n) {
|
||||
parent = *n;
|
||||
ext = node_to_extent(parent);
|
||||
if (start < ext->start) {
|
||||
n = &(*n)->rb_left;
|
||||
} else if (start >= (ext->start + ext->count)) {
|
||||
n = &(*n)->rb_right;
|
||||
} else {
|
||||
/* The start bit is set */
|
||||
*out = start + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
node = parent;
|
||||
ext = node_to_extent(node);
|
||||
if (ext->start < start) {
|
||||
node = ext2fs_rb_next(node);
|
||||
if (node == NULL)
|
||||
return ENOENT;
|
||||
ext = node_to_extent(node);
|
||||
}
|
||||
if (ext->start <= end) {
|
||||
*out = ext->start + bitmap->start;
|
||||
return 0;
|
||||
}
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2fs_rb_private *bp;
|
||||
struct rb_node *node = NULL;
|
||||
struct bmap_rb_extent *ext;
|
||||
__u64 count = 0;
|
||||
__u64 max_size = 0;
|
||||
__u64 min_size = ULONG_MAX;
|
||||
__u64 size = 0, avg_size = 0;
|
||||
double eff;
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
__u64 mark_all, test_all;
|
||||
double m_hit = 0.0, t_hit = 0.0;
|
||||
#endif
|
||||
|
||||
bp = (struct ext2fs_rb_private *) bitmap->private;
|
||||
|
||||
for (node = ext2fs_rb_first(&bp->root); node != NULL;
|
||||
node = ext2fs_rb_next(node)) {
|
||||
ext = node_to_extent(node);
|
||||
count++;
|
||||
if (ext->count > max_size)
|
||||
max_size = ext->count;
|
||||
if (ext->count < min_size)
|
||||
min_size = ext->count;
|
||||
size += ext->count;
|
||||
}
|
||||
|
||||
if (count)
|
||||
avg_size = size / count;
|
||||
if (min_size == ULONG_MAX)
|
||||
min_size = 0;
|
||||
eff = (double)((count * sizeof(struct bmap_rb_extent)) << 3) /
|
||||
(bitmap->real_end - bitmap->start);
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
mark_all = bitmap->stats.mark_count + bitmap->stats.mark_ext_count;
|
||||
test_all = bitmap->stats.test_count + bitmap->stats.test_ext_count;
|
||||
if (mark_all)
|
||||
m_hit = ((double)bp->mark_hit / mark_all) * 100;
|
||||
if (test_all)
|
||||
t_hit = ((double)bp->test_hit / test_all) * 100;
|
||||
|
||||
fprintf(stderr, "%16llu cache hits on test (%.2f%%)\n"
|
||||
"%16llu cache hits on mark (%.2f%%)\n",
|
||||
bp->test_hit, t_hit, bp->mark_hit, m_hit);
|
||||
#endif
|
||||
fprintf(stderr, "%16llu extents (%llu bytes)\n",
|
||||
(unsigned long long) count, (unsigned long long)
|
||||
((count * sizeof(struct bmap_rb_extent)) +
|
||||
sizeof(struct ext2fs_rb_private)));
|
||||
fprintf(stderr, "%16llu bits minimum size\n",
|
||||
(unsigned long long) min_size);
|
||||
fprintf(stderr, "%16llu bits maximum size\n"
|
||||
"%16llu bits average size\n",
|
||||
(unsigned long long) max_size, (unsigned long long) avg_size);
|
||||
fprintf(stderr, "%16llu bits set in bitmap (out of %llu)\n",
|
||||
(unsigned long long) size,
|
||||
(unsigned long long) bitmap->real_end - bitmap->start);
|
||||
fprintf(stderr,
|
||||
"%16.4lf memory / bitmap bit memory ratio (bitarray = 1)\n",
|
||||
eff);
|
||||
}
|
||||
#else
|
||||
static void rb_print_stats(ext2fs_generic_bitmap_64 bitmap EXT2FS_ATTR((unused)))
|
||||
{
|
||||
}
|
||||
#endif
|
||||
|
||||
struct ext2_bitmap_ops ext2fs_blkmap64_rbtree = {
|
||||
.type = EXT2FS_BMAP64_RBTREE,
|
||||
.new_bmap = rb_new_bmap,
|
||||
.free_bmap = rb_free_bmap,
|
||||
.copy_bmap = rb_copy_bmap,
|
||||
.resize_bmap = rb_resize_bmap,
|
||||
.mark_bmap = rb_mark_bmap,
|
||||
.unmark_bmap = rb_unmark_bmap,
|
||||
.test_bmap = rb_test_bmap,
|
||||
.test_clear_bmap_extent = rb_test_clear_bmap_extent,
|
||||
.mark_bmap_extent = rb_mark_bmap_extent,
|
||||
.unmark_bmap_extent = rb_unmark_bmap_extent,
|
||||
.set_bmap_range = rb_set_bmap_range,
|
||||
.get_bmap_range = rb_get_bmap_range,
|
||||
.clear_bmap = rb_clear_bmap,
|
||||
.print_stats = rb_print_stats,
|
||||
.find_first_zero = rb_find_first_zero,
|
||||
.find_first_set = rb_find_first_set,
|
||||
};
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/blkmap64_rb.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/blkmap64_rb.o
Executable file
Binary file not shown.
606
jni/e2fsprogs/lib/ext2fs/blknum.c
Executable file
606
jni/e2fsprogs/lib/ext2fs/blknum.c
Executable file
@@ -0,0 +1,606 @@
|
||||
/*
|
||||
* blknum.c --- Functions to handle blk64_t and high/low 64-bit block
|
||||
* number.
|
||||
*
|
||||
* Copyright IBM Corporation, 2007
|
||||
* Author Jose R. Santos <jrs@us.ibm.com>
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* Return the group # of a block
|
||||
*/
|
||||
dgrp_t ext2fs_group_of_blk2(ext2_filsys fs, blk64_t blk)
|
||||
{
|
||||
return (blk - fs->super->s_first_data_block) /
|
||||
fs->super->s_blocks_per_group;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the first block (inclusive) in a group
|
||||
*/
|
||||
blk64_t ext2fs_group_first_block2(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
return fs->super->s_first_data_block +
|
||||
EXT2_GROUPS_TO_BLOCKS(fs->super, group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the last block (inclusive) in a group
|
||||
*/
|
||||
blk64_t ext2fs_group_last_block2(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
return (group == fs->group_desc_count - 1 ?
|
||||
ext2fs_blocks_count(fs->super) - 1 :
|
||||
ext2fs_group_first_block2(fs, group) +
|
||||
(fs->super->s_blocks_per_group - 1));
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the number of blocks in a group
|
||||
*/
|
||||
int ext2fs_group_blocks_count(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
int num_blocks;
|
||||
|
||||
if (group == fs->group_desc_count - 1) {
|
||||
num_blocks = (ext2fs_blocks_count(fs->super) -
|
||||
fs->super->s_first_data_block) %
|
||||
fs->super->s_blocks_per_group;
|
||||
if (!num_blocks)
|
||||
num_blocks = fs->super->s_blocks_per_group;
|
||||
} else
|
||||
num_blocks = fs->super->s_blocks_per_group;
|
||||
|
||||
return num_blocks;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode data block count
|
||||
*/
|
||||
blk64_t ext2fs_inode_data_blocks2(ext2_filsys fs,
|
||||
struct ext2_inode *inode)
|
||||
{
|
||||
return (inode->i_blocks |
|
||||
(ext2fs_has_feature_huge_file(fs->super) ?
|
||||
(__u64) inode->osd2.linux2.l_i_blocks_hi << 32 : 0)) -
|
||||
(inode->i_file_acl ? EXT2_CLUSTER_SIZE(fs->super) >> 9 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode i_blocks count
|
||||
*/
|
||||
blk64_t ext2fs_inode_i_blocks(ext2_filsys fs,
|
||||
struct ext2_inode *inode)
|
||||
{
|
||||
return (inode->i_blocks |
|
||||
(ext2fs_has_feature_huge_file(fs->super) ?
|
||||
(__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
|
||||
*/
|
||||
blk64_t ext2fs_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_blocks_count_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the fs block count
|
||||
*/
|
||||
void ext2fs_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
super->s_blocks_count = blk;
|
||||
if (ext2fs_has_feature_64bit(super))
|
||||
super->s_blocks_count_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to the current fs block count
|
||||
*/
|
||||
void ext2fs_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
blk64_t tmp;
|
||||
tmp = ext2fs_blocks_count(super) + blk;
|
||||
ext2fs_blocks_count_set(super, tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the fs reserved block count
|
||||
*/
|
||||
blk64_t ext2fs_r_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_r_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_r_blocks_count_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the fs reserved block count
|
||||
*/
|
||||
void ext2fs_r_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
super->s_r_blocks_count = blk;
|
||||
if (ext2fs_has_feature_64bit(super))
|
||||
super->s_r_blocks_count_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to the current reserved fs block count
|
||||
*/
|
||||
void ext2fs_r_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
blk64_t tmp;
|
||||
tmp = ext2fs_r_blocks_count(super) + blk;
|
||||
ext2fs_r_blocks_count_set(super, tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the fs free block count
|
||||
*/
|
||||
blk64_t ext2fs_free_blocks_count(struct ext2_super_block *super)
|
||||
{
|
||||
return super->s_free_blocks_count |
|
||||
(ext2fs_has_feature_64bit(super) ?
|
||||
(__u64) super->s_free_blocks_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the fs free block count
|
||||
*/
|
||||
void ext2fs_free_blocks_count_set(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
super->s_free_blocks_count = blk;
|
||||
if (ext2fs_has_feature_64bit(super))
|
||||
super->s_free_blocks_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add to the current free fs block count
|
||||
*/
|
||||
void ext2fs_free_blocks_count_add(struct ext2_super_block *super, blk64_t blk)
|
||||
{
|
||||
blk64_t tmp;
|
||||
tmp = ext2fs_free_blocks_count(super) + blk;
|
||||
ext2fs_free_blocks_count_set(super, tmp);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get a pointer to a block group descriptor. We need the explicit
|
||||
* pointer to the group desc for code that swaps block group
|
||||
* descriptors before writing them out, as it wants to make a copy and
|
||||
* do the swap there.
|
||||
*/
|
||||
struct ext2_group_desc *ext2fs_group_desc(ext2_filsys fs,
|
||||
struct opaque_ext2_group_desc *gdp,
|
||||
dgrp_t group)
|
||||
{
|
||||
struct ext2_group_desc *ret_gdp;
|
||||
errcode_t retval;
|
||||
static char *buf = 0;
|
||||
static unsigned bufsize = 0;
|
||||
blk64_t blk;
|
||||
int desc_size = EXT2_DESC_SIZE(fs->super) & ~7;
|
||||
int desc_per_blk = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
|
||||
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 */
|
||||
static struct ext4_group_desc *ext4fs_group_desc(ext2_filsys fs,
|
||||
struct opaque_ext2_group_desc *gdp,
|
||||
dgrp_t group)
|
||||
{
|
||||
return (struct ext4_group_desc *)ext2fs_group_desc(fs, gdp, group);
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the block bitmap checksum of a group
|
||||
*/
|
||||
__u32 ext2fs_block_bitmap_checksum(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
__u32 csum;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
csum = gdp->bg_block_bitmap_csum_lo;
|
||||
if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_BLOCK_BITMAP_CSUM_HI_LOCATION)
|
||||
csum |= ((__u32)gdp->bg_block_bitmap_csum_hi << 16);
|
||||
return csum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the block bitmap block of a group
|
||||
*/
|
||||
blk64_t ext2fs_block_bitmap_loc(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_block_bitmap |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u64)gdp->bg_block_bitmap_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the block bitmap block of a group
|
||||
*/
|
||||
void ext2fs_block_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_block_bitmap = blk;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_block_bitmap_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode bitmap checksum of a group
|
||||
*/
|
||||
__u32 ext2fs_inode_bitmap_checksum(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
__u32 csum;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
csum = gdp->bg_inode_bitmap_csum_lo;
|
||||
if (EXT2_DESC_SIZE(fs->super) >= EXT4_BG_INODE_BITMAP_CSUM_HI_END)
|
||||
csum |= ((__u32)gdp->bg_inode_bitmap_csum_hi << 16);
|
||||
return csum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode bitmap block of a group
|
||||
*/
|
||||
blk64_t ext2fs_inode_bitmap_loc(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_inode_bitmap |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u64) gdp->bg_inode_bitmap_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the inode bitmap block of a group
|
||||
*/
|
||||
void ext2fs_inode_bitmap_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_inode_bitmap = blk;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_inode_bitmap_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the inode table block of a group
|
||||
*/
|
||||
blk64_t ext2fs_inode_table_loc(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_inode_table |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u64) gdp->bg_inode_table_hi << 32 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the inode table block of a group
|
||||
*/
|
||||
void ext2fs_inode_table_loc_set(ext2_filsys fs, dgrp_t group, blk64_t blk)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_inode_table = blk;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_inode_table_hi = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the free blocks count of a group
|
||||
*/
|
||||
__u32 ext2fs_bg_free_blocks_count(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_free_blocks_count |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u32) gdp->bg_free_blocks_count_hi << 16 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the free blocks count of a group
|
||||
*/
|
||||
void ext2fs_bg_free_blocks_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_free_blocks_count = n;
|
||||
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_free_blocks_count_hi = (__u32) n >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the free inodes count of a group
|
||||
*/
|
||||
__u32 ext2fs_bg_free_inodes_count(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_free_inodes_count |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u32) gdp->bg_free_inodes_count_hi << 16 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the free inodes count of a group
|
||||
*/
|
||||
void ext2fs_bg_free_inodes_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_free_inodes_count = n;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_free_inodes_count_hi = (__u32) n >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the used dirs count of a group
|
||||
*/
|
||||
__u32 ext2fs_bg_used_dirs_count(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_used_dirs_count |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u32) gdp->bg_used_dirs_count_hi << 16 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the used dirs count of a group
|
||||
*/
|
||||
void ext2fs_bg_used_dirs_count_set(ext2_filsys fs, dgrp_t group, __u32 n)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_used_dirs_count = n;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_used_dirs_count_hi = (__u32) n >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the unused inodes count of a group
|
||||
*/
|
||||
__u32 ext2fs_bg_itable_unused(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_itable_unused |
|
||||
(ext2fs_has_feature_64bit(fs->super) ?
|
||||
(__u32) gdp->bg_itable_unused_hi << 16 : 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the unused inodes count of a group
|
||||
*/
|
||||
void ext2fs_bg_itable_unused_set(ext2_filsys fs, dgrp_t group, __u32 n)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_itable_unused = n;
|
||||
if (ext2fs_has_feature_64bit(fs->super))
|
||||
gdp->bg_itable_unused_hi = (__u32) n >> 16;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the flags for this block group
|
||||
*/
|
||||
__u16 ext2fs_bg_flags(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_flags;
|
||||
}
|
||||
|
||||
/*
|
||||
* Zero out the flags for this block group
|
||||
*/
|
||||
void ext2fs_bg_flags_zap(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_flags = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the value of a particular flag for this block group
|
||||
*/
|
||||
int ext2fs_bg_flags_test(ext2_filsys fs, dgrp_t group, __u16 bg_flag)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_flags & bg_flag;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set a flag or set of flags for this block group
|
||||
*/
|
||||
void ext2fs_bg_flags_set(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_flags |= bg_flags;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Clear a flag or set of flags for this block group
|
||||
*/
|
||||
void ext2fs_bg_flags_clear(ext2_filsys fs, dgrp_t group, __u16 bg_flags)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_flags &= ~bg_flags;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the checksum for this block group
|
||||
*/
|
||||
__u16 ext2fs_bg_checksum(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
return gdp->bg_checksum;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the checksum for this block group to a previously calculated value
|
||||
*/
|
||||
void ext2fs_bg_checksum_set(ext2_filsys fs, dgrp_t group, __u16 checksum)
|
||||
{
|
||||
struct ext4_group_desc *gdp;
|
||||
|
||||
gdp = ext4fs_group_desc(fs, fs->group_desc, group);
|
||||
gdp->bg_checksum = checksum;
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the acl block of a file
|
||||
*/
|
||||
blk64_t ext2fs_file_acl_block(ext2_filsys fs, const struct ext2_inode *inode)
|
||||
{
|
||||
blk64_t blk = inode->i_file_acl;
|
||||
|
||||
if (fs && ext2fs_has_feature_64bit(fs->super))
|
||||
blk |= ((__u64) inode->osd2.linux2.l_i_file_acl_high) << 32;
|
||||
return blk;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the acl block of a file
|
||||
*/
|
||||
void ext2fs_file_acl_block_set(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t blk)
|
||||
{
|
||||
inode->i_file_acl = blk;
|
||||
if (fs && ext2fs_has_feature_64bit(fs->super))
|
||||
inode->osd2.linux2.l_i_file_acl_high = (__u64) blk >> 32;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the size of the inode
|
||||
*/
|
||||
errcode_t ext2fs_inode_size_set(ext2_filsys fs, struct ext2_inode *inode,
|
||||
ext2_off64_t size)
|
||||
{
|
||||
if (size < 0)
|
||||
return EINVAL;
|
||||
|
||||
/* If writing a large inode, set the large_file or large_dir flag */
|
||||
if (ext2fs_needs_large_file_feature(size)) {
|
||||
int dirty_sb = 0;
|
||||
|
||||
if (LINUX_S_ISREG(inode->i_mode)) {
|
||||
if (!ext2fs_has_feature_large_file(fs->super)) {
|
||||
ext2fs_set_feature_large_file(fs->super);
|
||||
dirty_sb = 1;
|
||||
}
|
||||
} else if (LINUX_S_ISDIR(inode->i_mode)) {
|
||||
if (!ext2fs_has_feature_largedir(fs->super)) {
|
||||
ext2fs_set_feature_largedir(fs->super);
|
||||
dirty_sb = 1;
|
||||
}
|
||||
} else {
|
||||
/* Only regular files get to be larger than 4GB */
|
||||
return EXT2_ET_FILE_TOO_BIG;
|
||||
}
|
||||
if (dirty_sb) {
|
||||
if (fs->super->s_rev_level == EXT2_GOOD_OLD_REV)
|
||||
ext2fs_update_dynamic_rev(fs);
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
}
|
||||
}
|
||||
|
||||
inode->i_size = size & 0xffffffff;
|
||||
inode->i_size_high = (size >> 32);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/blknum.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/blknum.o
Executable file
Binary file not shown.
659
jni/e2fsprogs/lib/ext2fs/block.c
Executable file
659
jni/e2fsprogs/lib/ext2fs/block.c
Executable file
@@ -0,0 +1,659 @@
|
||||
/*
|
||||
* block.c --- iterate over all blocks in an inode
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
struct block_context {
|
||||
ext2_filsys fs;
|
||||
int (*func)(ext2_filsys fs,
|
||||
blk64_t *blocknr,
|
||||
e2_blkcnt_t bcount,
|
||||
blk64_t ref_blk,
|
||||
int ref_offset,
|
||||
void *priv_data);
|
||||
e2_blkcnt_t bcount;
|
||||
int bsize;
|
||||
int flags;
|
||||
errcode_t errcode;
|
||||
char *ind_buf;
|
||||
char *dind_buf;
|
||||
char *tind_buf;
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
#define check_for_ro_violation_return(ctx, ret) \
|
||||
do { \
|
||||
if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
|
||||
((ret) & BLOCK_CHANGED)) { \
|
||||
(ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
|
||||
ret |= BLOCK_ABORT | BLOCK_ERROR; \
|
||||
return ret; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define check_for_ro_violation_goto(ctx, ret, label) \
|
||||
do { \
|
||||
if (((ctx)->flags & BLOCK_FLAG_READ_ONLY) && \
|
||||
((ret) & BLOCK_CHANGED)) { \
|
||||
(ctx)->errcode = EXT2_ET_RO_BLOCK_ITERATE; \
|
||||
ret |= BLOCK_ABORT | BLOCK_ERROR; \
|
||||
goto label; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int block_iterate_ind(blk_t *ind_block, blk_t ref_block,
|
||||
int ref_offset, struct block_context *ctx)
|
||||
{
|
||||
int ret = 0, changed = 0;
|
||||
int i, flags, limit, offset;
|
||||
blk_t *block_nr;
|
||||
blk64_t blk64;
|
||||
|
||||
limit = ctx->fs->blocksize >> 2;
|
||||
if (!(ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
|
||||
!(ctx->flags & BLOCK_FLAG_DATA_ONLY)) {
|
||||
blk64 = *ind_block;
|
||||
ret = (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_IND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*ind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
if (!*ind_block || (ret & BLOCK_ABORT)) {
|
||||
ctx->bcount += limit;
|
||||
return ret;
|
||||
}
|
||||
if (*ind_block >= ext2fs_blocks_count(ctx->fs->super) ||
|
||||
*ind_block < ctx->fs->super->s_first_data_block) {
|
||||
ctx->errcode = EXT2_ET_BAD_IND_BLOCK;
|
||||
ret |= BLOCK_ERROR;
|
||||
return ret;
|
||||
}
|
||||
ctx->errcode = ext2fs_read_ind_block(ctx->fs, *ind_block,
|
||||
ctx->ind_buf);
|
||||
if (ctx->errcode) {
|
||||
ret |= BLOCK_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
block_nr = (blk_t *) ctx->ind_buf;
|
||||
offset = 0;
|
||||
if (ctx->flags & BLOCK_FLAG_APPEND) {
|
||||
for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
|
||||
blk64 = *block_nr;
|
||||
flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
|
||||
*ind_block, offset,
|
||||
ctx->priv_data);
|
||||
*block_nr = blk64;
|
||||
changed |= flags;
|
||||
if (flags & BLOCK_ABORT) {
|
||||
ret |= BLOCK_ABORT;
|
||||
break;
|
||||
}
|
||||
offset += sizeof(blk_t);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < limit; i++, ctx->bcount++, block_nr++) {
|
||||
if (*block_nr == 0)
|
||||
goto skip_sparse;
|
||||
blk64 = *block_nr;
|
||||
flags = (*ctx->func)(ctx->fs, &blk64, ctx->bcount,
|
||||
*ind_block, offset,
|
||||
ctx->priv_data);
|
||||
*block_nr = blk64;
|
||||
changed |= flags;
|
||||
if (flags & BLOCK_ABORT) {
|
||||
ret |= BLOCK_ABORT;
|
||||
break;
|
||||
}
|
||||
skip_sparse:
|
||||
offset += sizeof(blk_t);
|
||||
}
|
||||
}
|
||||
check_for_ro_violation_return(ctx, changed);
|
||||
if (changed & BLOCK_CHANGED) {
|
||||
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *ind_block,
|
||||
ctx->ind_buf);
|
||||
if (ctx->errcode)
|
||||
ret |= BLOCK_ERROR | BLOCK_ABORT;
|
||||
}
|
||||
if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
|
||||
!(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
|
||||
!(ret & BLOCK_ABORT)) {
|
||||
blk64 = *ind_block;
|
||||
ret |= (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_IND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*ind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int block_iterate_dind(blk_t *dind_block, blk_t ref_block,
|
||||
int ref_offset, struct block_context *ctx)
|
||||
{
|
||||
int ret = 0, changed = 0;
|
||||
int i, flags, limit, offset;
|
||||
blk_t *block_nr;
|
||||
blk64_t blk64;
|
||||
|
||||
limit = ctx->fs->blocksize >> 2;
|
||||
if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
|
||||
BLOCK_FLAG_DATA_ONLY))) {
|
||||
blk64 = *dind_block;
|
||||
ret = (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_DIND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*dind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
if (!*dind_block || (ret & BLOCK_ABORT)) {
|
||||
ctx->bcount += limit*limit;
|
||||
return ret;
|
||||
}
|
||||
if (*dind_block >= ext2fs_blocks_count(ctx->fs->super) ||
|
||||
*dind_block < ctx->fs->super->s_first_data_block) {
|
||||
ctx->errcode = EXT2_ET_BAD_DIND_BLOCK;
|
||||
ret |= BLOCK_ERROR;
|
||||
return ret;
|
||||
}
|
||||
ctx->errcode = ext2fs_read_ind_block(ctx->fs, *dind_block,
|
||||
ctx->dind_buf);
|
||||
if (ctx->errcode) {
|
||||
ret |= BLOCK_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
block_nr = (blk_t *) ctx->dind_buf;
|
||||
offset = 0;
|
||||
if (ctx->flags & BLOCK_FLAG_APPEND) {
|
||||
for (i = 0; i < limit; i++, block_nr++) {
|
||||
flags = block_iterate_ind(block_nr,
|
||||
*dind_block, offset,
|
||||
ctx);
|
||||
changed |= flags;
|
||||
if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
|
||||
ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
|
||||
break;
|
||||
}
|
||||
offset += sizeof(blk_t);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < limit; i++, block_nr++) {
|
||||
if (*block_nr == 0) {
|
||||
ctx->bcount += limit;
|
||||
continue;
|
||||
}
|
||||
flags = block_iterate_ind(block_nr,
|
||||
*dind_block, offset,
|
||||
ctx);
|
||||
changed |= flags;
|
||||
if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
|
||||
ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
|
||||
break;
|
||||
}
|
||||
offset += sizeof(blk_t);
|
||||
}
|
||||
}
|
||||
check_for_ro_violation_return(ctx, changed);
|
||||
if (changed & BLOCK_CHANGED) {
|
||||
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *dind_block,
|
||||
ctx->dind_buf);
|
||||
if (ctx->errcode)
|
||||
ret |= BLOCK_ERROR | BLOCK_ABORT;
|
||||
}
|
||||
if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
|
||||
!(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
|
||||
!(ret & BLOCK_ABORT)) {
|
||||
blk64 = *dind_block;
|
||||
ret |= (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_DIND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*dind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int block_iterate_tind(blk_t *tind_block, blk_t ref_block,
|
||||
int ref_offset, struct block_context *ctx)
|
||||
{
|
||||
int ret = 0, changed = 0;
|
||||
int i, flags, limit, offset;
|
||||
blk_t *block_nr;
|
||||
blk64_t blk64;
|
||||
|
||||
limit = ctx->fs->blocksize >> 2;
|
||||
if (!(ctx->flags & (BLOCK_FLAG_DEPTH_TRAVERSE |
|
||||
BLOCK_FLAG_DATA_ONLY))) {
|
||||
blk64 = *tind_block;
|
||||
ret = (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_TIND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*tind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
if (!*tind_block || (ret & BLOCK_ABORT)) {
|
||||
ctx->bcount += ((unsigned long long) limit)*limit*limit;
|
||||
return ret;
|
||||
}
|
||||
if (*tind_block >= ext2fs_blocks_count(ctx->fs->super) ||
|
||||
*tind_block < ctx->fs->super->s_first_data_block) {
|
||||
ctx->errcode = EXT2_ET_BAD_TIND_BLOCK;
|
||||
ret |= BLOCK_ERROR;
|
||||
return ret;
|
||||
}
|
||||
ctx->errcode = ext2fs_read_ind_block(ctx->fs, *tind_block,
|
||||
ctx->tind_buf);
|
||||
if (ctx->errcode) {
|
||||
ret |= BLOCK_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
block_nr = (blk_t *) ctx->tind_buf;
|
||||
offset = 0;
|
||||
if (ctx->flags & BLOCK_FLAG_APPEND) {
|
||||
for (i = 0; i < limit; i++, block_nr++) {
|
||||
flags = block_iterate_dind(block_nr,
|
||||
*tind_block,
|
||||
offset, ctx);
|
||||
changed |= flags;
|
||||
if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
|
||||
ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
|
||||
break;
|
||||
}
|
||||
offset += sizeof(blk_t);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < limit; i++, block_nr++) {
|
||||
if (*block_nr == 0) {
|
||||
ctx->bcount += limit*limit;
|
||||
continue;
|
||||
}
|
||||
flags = block_iterate_dind(block_nr,
|
||||
*tind_block,
|
||||
offset, ctx);
|
||||
changed |= flags;
|
||||
if (flags & (BLOCK_ABORT | BLOCK_ERROR)) {
|
||||
ret |= flags & (BLOCK_ABORT | BLOCK_ERROR);
|
||||
break;
|
||||
}
|
||||
offset += sizeof(blk_t);
|
||||
}
|
||||
}
|
||||
check_for_ro_violation_return(ctx, changed);
|
||||
if (changed & BLOCK_CHANGED) {
|
||||
ctx->errcode = ext2fs_write_ind_block(ctx->fs, *tind_block,
|
||||
ctx->tind_buf);
|
||||
if (ctx->errcode)
|
||||
ret |= BLOCK_ERROR | BLOCK_ABORT;
|
||||
}
|
||||
if ((ctx->flags & BLOCK_FLAG_DEPTH_TRAVERSE) &&
|
||||
!(ctx->flags & BLOCK_FLAG_DATA_ONLY) &&
|
||||
!(ret & BLOCK_ABORT)) {
|
||||
blk64 = *tind_block;
|
||||
ret |= (*ctx->func)(ctx->fs, &blk64,
|
||||
BLOCK_COUNT_TIND, ref_block,
|
||||
ref_offset, ctx->priv_data);
|
||||
*tind_block = blk64;
|
||||
}
|
||||
check_for_ro_violation_return(ctx, ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_block_iterate3(ext2_filsys fs,
|
||||
ext2_ino_t ino,
|
||||
int flags,
|
||||
char *block_buf,
|
||||
int (*func)(ext2_filsys fs,
|
||||
blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk64_t ref_blk,
|
||||
int ref_offset,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
int i;
|
||||
int r, ret = 0;
|
||||
struct ext2_inode inode;
|
||||
errcode_t retval;
|
||||
struct block_context ctx;
|
||||
int limit;
|
||||
blk64_t blk64;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
ctx.errcode = ext2fs_read_inode(fs, ino, &inode);
|
||||
if (ctx.errcode)
|
||||
return ctx.errcode;
|
||||
|
||||
/*
|
||||
* An inode with inline data has no blocks over which to
|
||||
* iterate, so return an error code indicating this fact.
|
||||
*/
|
||||
if (inode.i_flags & EXT4_INLINE_DATA_FL)
|
||||
return EXT2_ET_INLINE_DATA_CANT_ITERATE;
|
||||
|
||||
/*
|
||||
* Check to see if we need to limit large files
|
||||
*/
|
||||
if (flags & BLOCK_FLAG_NO_LARGE) {
|
||||
if (!LINUX_S_ISDIR(inode.i_mode) &&
|
||||
(inode.i_size_high != 0))
|
||||
return EXT2_ET_FILE_TOO_BIG;
|
||||
}
|
||||
|
||||
limit = fs->blocksize >> 2;
|
||||
|
||||
ctx.fs = fs;
|
||||
ctx.func = func;
|
||||
ctx.priv_data = priv_data;
|
||||
ctx.flags = flags;
|
||||
ctx.bcount = 0;
|
||||
if (block_buf) {
|
||||
ctx.ind_buf = block_buf;
|
||||
} else {
|
||||
retval = ext2fs_get_array(3, fs->blocksize, &ctx.ind_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
ctx.dind_buf = ctx.ind_buf + fs->blocksize;
|
||||
ctx.tind_buf = ctx.dind_buf + fs->blocksize;
|
||||
|
||||
/*
|
||||
* Iterate over the HURD translator block (if present)
|
||||
*/
|
||||
if ((fs->super->s_creator_os == EXT2_OS_HURD) &&
|
||||
!(flags & BLOCK_FLAG_DATA_ONLY)) {
|
||||
if (inode.osd1.hurd1.h_i_translator) {
|
||||
blk64 = inode.osd1.hurd1.h_i_translator;
|
||||
ret |= (*ctx.func)(fs, &blk64,
|
||||
BLOCK_COUNT_TRANSLATOR,
|
||||
0, 0, priv_data);
|
||||
inode.osd1.hurd1.h_i_translator = (blk_t) blk64;
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
check_for_ro_violation_goto(&ctx, ret, abort_exit);
|
||||
}
|
||||
}
|
||||
|
||||
if (inode.i_flags & EXT4_EXTENTS_FL) {
|
||||
ext2_extent_handle_t handle;
|
||||
struct ext2fs_extent extent, next;
|
||||
e2_blkcnt_t blockcnt = 0;
|
||||
blk64_t blk, new_blk;
|
||||
int op = EXT2_EXTENT_ROOT;
|
||||
int uninit;
|
||||
unsigned int j;
|
||||
|
||||
ctx.errcode = ext2fs_extent_open2(fs, ino, &inode, &handle);
|
||||
if (ctx.errcode)
|
||||
goto abort_exit;
|
||||
|
||||
while (1) {
|
||||
if (op == EXT2_EXTENT_CURRENT)
|
||||
ctx.errcode = 0;
|
||||
else
|
||||
ctx.errcode = ext2fs_extent_get(handle, op,
|
||||
&extent);
|
||||
if (ctx.errcode) {
|
||||
if (ctx.errcode != EXT2_ET_EXTENT_NO_NEXT)
|
||||
break;
|
||||
ctx.errcode = 0;
|
||||
if (!(flags & BLOCK_FLAG_APPEND))
|
||||
break;
|
||||
next_block_set:
|
||||
blk = 0;
|
||||
r = (*ctx.func)(fs, &blk, blockcnt,
|
||||
0, 0, priv_data);
|
||||
ret |= r;
|
||||
check_for_ro_violation_goto(&ctx, ret,
|
||||
extent_done);
|
||||
if (r & BLOCK_CHANGED) {
|
||||
ctx.errcode =
|
||||
ext2fs_extent_set_bmap(handle,
|
||||
(blk64_t) blockcnt++,
|
||||
(blk64_t) blk, 0);
|
||||
if (ctx.errcode || (ret & BLOCK_ABORT))
|
||||
break;
|
||||
if (blk)
|
||||
goto next_block_set;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
op = EXT2_EXTENT_NEXT;
|
||||
blk = extent.e_pblk;
|
||||
if (!(extent.e_flags & EXT2_EXTENT_FLAGS_LEAF)) {
|
||||
if (ctx.flags & BLOCK_FLAG_DATA_ONLY)
|
||||
continue;
|
||||
if ((!(extent.e_flags &
|
||||
EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
|
||||
!(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE)) ||
|
||||
((extent.e_flags &
|
||||
EXT2_EXTENT_FLAGS_SECOND_VISIT) &&
|
||||
(ctx.flags & BLOCK_FLAG_DEPTH_TRAVERSE))) {
|
||||
ret |= (*ctx.func)(fs, &blk,
|
||||
-1, 0, 0, priv_data);
|
||||
if (ret & BLOCK_CHANGED) {
|
||||
extent.e_pblk = blk;
|
||||
ctx.errcode =
|
||||
ext2fs_extent_replace(handle, 0, &extent);
|
||||
if (ctx.errcode)
|
||||
break;
|
||||
}
|
||||
if (ret & BLOCK_ABORT)
|
||||
break;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
uninit = 0;
|
||||
if (extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
uninit = EXT2_EXTENT_SET_BMAP_UNINIT;
|
||||
|
||||
/*
|
||||
* Get the next extent before we start messing
|
||||
* with the current extent
|
||||
*/
|
||||
retval = ext2fs_extent_get(handle, op, &next);
|
||||
|
||||
#if 0
|
||||
printf("lblk %llu pblk %llu len %d blockcnt %llu\n",
|
||||
extent.e_lblk, extent.e_pblk,
|
||||
extent.e_len, blockcnt);
|
||||
#endif
|
||||
if (extent.e_lblk + extent.e_len <= (blk64_t) blockcnt)
|
||||
continue;
|
||||
if (extent.e_lblk > (blk64_t) blockcnt)
|
||||
blockcnt = extent.e_lblk;
|
||||
j = blockcnt - extent.e_lblk;
|
||||
blk += j;
|
||||
for (blockcnt = extent.e_lblk, j = 0;
|
||||
j < extent.e_len;
|
||||
blk++, blockcnt++, j++) {
|
||||
new_blk = blk;
|
||||
r = (*ctx.func)(fs, &new_blk, blockcnt,
|
||||
0, 0, priv_data);
|
||||
ret |= r;
|
||||
check_for_ro_violation_goto(&ctx, ret,
|
||||
extent_done);
|
||||
if (r & BLOCK_CHANGED) {
|
||||
ctx.errcode =
|
||||
ext2fs_extent_set_bmap(handle,
|
||||
(blk64_t) blockcnt,
|
||||
new_blk, uninit);
|
||||
if (ctx.errcode)
|
||||
goto extent_done;
|
||||
}
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto extent_done;
|
||||
}
|
||||
if (retval == 0) {
|
||||
extent = next;
|
||||
op = EXT2_EXTENT_CURRENT;
|
||||
}
|
||||
}
|
||||
|
||||
extent_done:
|
||||
ext2fs_extent_free(handle);
|
||||
ret |= BLOCK_ERROR; /* ctx.errcode is always valid here */
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Iterate over normal data blocks
|
||||
*/
|
||||
for (i = 0; i < EXT2_NDIR_BLOCKS ; i++, ctx.bcount++) {
|
||||
if (inode.i_block[i] || (flags & BLOCK_FLAG_APPEND)) {
|
||||
blk64 = inode.i_block[i];
|
||||
ret |= (*ctx.func)(fs, &blk64, ctx.bcount, 0, i,
|
||||
priv_data);
|
||||
inode.i_block[i] = (blk_t) blk64;
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
}
|
||||
}
|
||||
check_for_ro_violation_goto(&ctx, ret, abort_exit);
|
||||
if (inode.i_block[EXT2_IND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
|
||||
ret |= block_iterate_ind(&inode.i_block[EXT2_IND_BLOCK],
|
||||
0, EXT2_IND_BLOCK, &ctx);
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
} else
|
||||
ctx.bcount += limit;
|
||||
if (inode.i_block[EXT2_DIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
|
||||
ret |= block_iterate_dind(&inode.i_block[EXT2_DIND_BLOCK],
|
||||
0, EXT2_DIND_BLOCK, &ctx);
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
} else
|
||||
ctx.bcount += limit * limit;
|
||||
if (inode.i_block[EXT2_TIND_BLOCK] || (flags & BLOCK_FLAG_APPEND)) {
|
||||
ret |= block_iterate_tind(&inode.i_block[EXT2_TIND_BLOCK],
|
||||
0, EXT2_TIND_BLOCK, &ctx);
|
||||
if (ret & BLOCK_ABORT)
|
||||
goto abort_exit;
|
||||
}
|
||||
|
||||
abort_exit:
|
||||
if (ret & BLOCK_CHANGED) {
|
||||
retval = ext2fs_write_inode(fs, ino, &inode);
|
||||
if (retval) {
|
||||
ret |= BLOCK_ERROR;
|
||||
ctx.errcode = retval;
|
||||
}
|
||||
}
|
||||
errout:
|
||||
if (!block_buf)
|
||||
ext2fs_free_mem(&ctx.ind_buf);
|
||||
|
||||
return (ret & BLOCK_ERROR) ? ctx.errcode : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Emulate the old ext2fs_block_iterate function!
|
||||
*/
|
||||
|
||||
struct xlate64 {
|
||||
int (*func)(ext2_filsys fs,
|
||||
blk_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk_t ref_blk,
|
||||
int ref_offset,
|
||||
void *priv_data);
|
||||
void *real_private;
|
||||
};
|
||||
|
||||
static int xlate64_func(ext2_filsys fs, blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt, blk64_t ref_blk,
|
||||
int ref_offset, void *priv_data)
|
||||
{
|
||||
struct xlate64 *xl = (struct xlate64 *) priv_data;
|
||||
int ret;
|
||||
blk_t block32 = *blocknr;
|
||||
|
||||
ret = (*xl->func)(fs, &block32, blockcnt, (blk_t) ref_blk, ref_offset,
|
||||
xl->real_private);
|
||||
*blocknr = block32;
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_block_iterate2(ext2_filsys fs,
|
||||
ext2_ino_t ino,
|
||||
int flags,
|
||||
char *block_buf,
|
||||
int (*func)(ext2_filsys fs,
|
||||
blk_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk_t ref_blk,
|
||||
int ref_offset,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
struct xlate64 xl;
|
||||
|
||||
xl.real_private = priv_data;
|
||||
xl.func = func;
|
||||
|
||||
return ext2fs_block_iterate3(fs, ino, flags, block_buf,
|
||||
xlate64_func, &xl);
|
||||
}
|
||||
|
||||
|
||||
struct xlate {
|
||||
int (*func)(ext2_filsys fs,
|
||||
blk_t *blocknr,
|
||||
int bcount,
|
||||
void *priv_data);
|
||||
void *real_private;
|
||||
};
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
static int xlate_func(ext2_filsys fs, blk_t *blocknr, e2_blkcnt_t blockcnt,
|
||||
blk_t ref_block EXT2FS_ATTR((unused)),
|
||||
int ref_offset EXT2FS_ATTR((unused)),
|
||||
void *priv_data)
|
||||
{
|
||||
struct xlate *xl = (struct xlate *) priv_data;
|
||||
|
||||
return (*xl->func)(fs, blocknr, (int) blockcnt, xl->real_private);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_block_iterate(ext2_filsys fs,
|
||||
ext2_ino_t ino,
|
||||
int flags,
|
||||
char *block_buf,
|
||||
int (*func)(ext2_filsys fs,
|
||||
blk_t *blocknr,
|
||||
int blockcnt,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
struct xlate xl;
|
||||
|
||||
xl.real_private = priv_data;
|
||||
xl.func = func;
|
||||
|
||||
return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags,
|
||||
block_buf, xlate_func, &xl);
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/block.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/block.o
Executable file
Binary file not shown.
499
jni/e2fsprogs/lib/ext2fs/bmap.c
Executable file
499
jni/e2fsprogs/lib/ext2fs/bmap.c
Executable file
@@ -0,0 +1,499 @@
|
||||
/*
|
||||
* bmap.c --- logical to physical block mapping
|
||||
*
|
||||
* Copyright (C) 1997 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
#if defined(__GNUC__) && !defined(NO_INLINE_FUNCS)
|
||||
#define _BMAP_INLINE_ __inline__
|
||||
#else
|
||||
#define _BMAP_INLINE_
|
||||
#endif
|
||||
|
||||
extern errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
char *block_buf, int bmap_flags,
|
||||
blk_t block, blk_t *phys_blk);
|
||||
|
||||
#define inode_bmap(inode, nr) ((inode)->i_block[(nr)])
|
||||
|
||||
static _BMAP_INLINE_ errcode_t block_ind_bmap(ext2_filsys fs, int flags,
|
||||
blk_t ind, char *block_buf,
|
||||
int *blocks_alloc,
|
||||
blk_t nr, blk_t *ret_blk)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk_t b;
|
||||
|
||||
if (!ind) {
|
||||
if (flags & BMAP_SET)
|
||||
return EXT2_ET_SET_BMAP_NO_IND;
|
||||
*ret_blk = 0;
|
||||
return 0;
|
||||
}
|
||||
retval = io_channel_read_blk(fs->io, ind, 1, block_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (flags & BMAP_SET) {
|
||||
b = *ret_blk;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
b = ext2fs_swab32(b);
|
||||
#endif
|
||||
((blk_t *) block_buf)[nr] = b;
|
||||
return io_channel_write_blk(fs->io, ind, 1, block_buf);
|
||||
}
|
||||
|
||||
b = ((blk_t *) block_buf)[nr];
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
b = ext2fs_swab32(b);
|
||||
#endif
|
||||
|
||||
if (!b && (flags & BMAP_ALLOC)) {
|
||||
b = nr ? ext2fs_le32_to_cpu(((blk_t *)block_buf)[nr - 1]) : ind;
|
||||
retval = ext2fs_alloc_block(fs, b,
|
||||
block_buf + fs->blocksize, &b);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
((blk_t *) block_buf)[nr] = ext2fs_swab32(b);
|
||||
#else
|
||||
((blk_t *) block_buf)[nr] = b;
|
||||
#endif
|
||||
|
||||
retval = io_channel_write_blk(fs->io, ind, 1, block_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
(*blocks_alloc)++;
|
||||
}
|
||||
|
||||
*ret_blk = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static _BMAP_INLINE_ errcode_t block_dind_bmap(ext2_filsys fs, int flags,
|
||||
blk_t dind, char *block_buf,
|
||||
int *blocks_alloc,
|
||||
blk_t nr, blk_t *ret_blk)
|
||||
{
|
||||
blk_t b = 0;
|
||||
errcode_t retval;
|
||||
blk_t addr_per_block;
|
||||
|
||||
addr_per_block = (blk_t) fs->blocksize >> 2;
|
||||
|
||||
retval = block_ind_bmap(fs, flags & ~BMAP_SET, dind, block_buf,
|
||||
blocks_alloc, nr / addr_per_block, &b);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
|
||||
nr % addr_per_block, ret_blk);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static _BMAP_INLINE_ errcode_t block_tind_bmap(ext2_filsys fs, int flags,
|
||||
blk_t tind, char *block_buf,
|
||||
int *blocks_alloc,
|
||||
blk_t nr, blk_t *ret_blk)
|
||||
{
|
||||
blk_t b = 0;
|
||||
errcode_t retval;
|
||||
blk_t addr_per_block;
|
||||
|
||||
addr_per_block = (blk_t) fs->blocksize >> 2;
|
||||
|
||||
retval = block_dind_bmap(fs, flags & ~BMAP_SET, tind, block_buf,
|
||||
blocks_alloc, nr / addr_per_block, &b);
|
||||
if (retval)
|
||||
return retval;
|
||||
retval = block_ind_bmap(fs, flags, b, block_buf, blocks_alloc,
|
||||
nr % addr_per_block, ret_blk);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
char *block_buf, int bmap_flags, blk64_t block,
|
||||
int *ret_flags, int *blocks_alloc,
|
||||
blk64_t *phys_blk);
|
||||
|
||||
static errcode_t implied_cluster_alloc(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
blk64_t lblk, blk64_t *phys_blk)
|
||||
{
|
||||
blk64_t base_block, pblock = 0;
|
||||
int i;
|
||||
|
||||
if (!ext2fs_has_feature_bigalloc(fs->super))
|
||||
return 0;
|
||||
|
||||
base_block = lblk & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
/*
|
||||
* Except for the logical block (lblk) that was passed in, search all
|
||||
* blocks in this logical cluster for a mapping to a physical cluster.
|
||||
* If any such map exists, calculate the physical block that maps to
|
||||
* the logical block and return that.
|
||||
*
|
||||
* The old code wouldn't even look if (block % cluster_ratio) == 0;
|
||||
* this is incorrect if we're allocating blocks in reverse order.
|
||||
*/
|
||||
for (i = 0; i < EXT2FS_CLUSTER_RATIO(fs); i++) {
|
||||
if (base_block + i == lblk)
|
||||
continue;
|
||||
extent_bmap(fs, ino, inode, handle, 0, 0,
|
||||
base_block + i, 0, 0, &pblock);
|
||||
if (pblock)
|
||||
break;
|
||||
}
|
||||
if (pblock == 0)
|
||||
return 0;
|
||||
*phys_blk = pblock - i + (lblk - base_block);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Try to map a logical block to an already-allocated physical cluster. */
|
||||
errcode_t ext2fs_map_cluster_block(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t lblk,
|
||||
blk64_t *pblk)
|
||||
{
|
||||
ext2_extent_handle_t handle;
|
||||
errcode_t retval;
|
||||
|
||||
/* Need bigalloc and extents to be enabled */
|
||||
*pblk = 0;
|
||||
if (!ext2fs_has_feature_bigalloc(fs->super) ||
|
||||
!(inode->i_flags & EXT4_EXTENTS_FL))
|
||||
return 0;
|
||||
|
||||
retval = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = implied_cluster_alloc(fs, ino, inode, handle, lblk, pblk);
|
||||
if (retval)
|
||||
goto out2;
|
||||
|
||||
out2:
|
||||
ext2fs_extent_free(handle);
|
||||
out:
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t extent_bmap(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
char *block_buf, int bmap_flags, blk64_t block,
|
||||
int *ret_flags, int *blocks_alloc,
|
||||
blk64_t *phys_blk)
|
||||
{
|
||||
struct blk_alloc_ctx alloc_ctx;
|
||||
struct ext2fs_extent extent;
|
||||
unsigned int offset;
|
||||
errcode_t retval = 0;
|
||||
blk64_t blk64 = 0;
|
||||
int alloc = 0;
|
||||
int set_flags;
|
||||
|
||||
set_flags = bmap_flags & BMAP_UNINIT ? EXT2_EXTENT_SET_BMAP_UNINIT : 0;
|
||||
|
||||
if (bmap_flags & BMAP_SET) {
|
||||
retval = ext2fs_extent_set_bmap(handle, block,
|
||||
*phys_blk, set_flags);
|
||||
return retval;
|
||||
}
|
||||
retval = ext2fs_extent_goto(handle, block);
|
||||
if (retval) {
|
||||
/* If the extent is not found, return phys_blk = 0 */
|
||||
if (retval == EXT2_ET_EXTENT_NOT_FOUND) {
|
||||
extent.e_lblk = block;
|
||||
goto got_block;
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
retval = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &extent);
|
||||
if (retval)
|
||||
return retval;
|
||||
offset = block - extent.e_lblk;
|
||||
if (block >= extent.e_lblk && (offset <= extent.e_len)) {
|
||||
*phys_blk = extent.e_pblk + offset;
|
||||
if (ret_flags && extent.e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
*ret_flags |= BMAP_RET_UNINIT;
|
||||
}
|
||||
got_block:
|
||||
if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
|
||||
implied_cluster_alloc(fs, ino, inode, handle, block, &blk64);
|
||||
if (blk64)
|
||||
goto set_extent;
|
||||
retval = extent_bmap(fs, ino, inode, handle, block_buf,
|
||||
0, block-1, 0, blocks_alloc, &blk64);
|
||||
if (retval)
|
||||
blk64 = ext2fs_find_inode_goal(fs, ino, inode, block);
|
||||
alloc_ctx.ino = ino;
|
||||
alloc_ctx.inode = inode;
|
||||
alloc_ctx.lblk = extent.e_lblk;
|
||||
alloc_ctx.flags = BLOCK_ALLOC_DATA;
|
||||
retval = ext2fs_alloc_block3(fs, blk64, block_buf, &blk64,
|
||||
&alloc_ctx);
|
||||
if (retval)
|
||||
return retval;
|
||||
blk64 &= ~EXT2FS_CLUSTER_MASK(fs);
|
||||
blk64 += EXT2FS_CLUSTER_MASK(fs) & block;
|
||||
alloc++;
|
||||
set_extent:
|
||||
retval = ext2fs_extent_set_bmap(handle, block,
|
||||
blk64, set_flags);
|
||||
if (retval) {
|
||||
ext2fs_block_alloc_stats2(fs, blk64, -1);
|
||||
return retval;
|
||||
}
|
||||
/* Update inode after setting extent */
|
||||
retval = ext2fs_read_inode(fs, ino, inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
*blocks_alloc += alloc;
|
||||
*phys_blk = blk64;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ext2fs_file_block_offset_too_big(ext2_filsys fs,
|
||||
struct ext2_inode *inode,
|
||||
blk64_t offset)
|
||||
{
|
||||
blk64_t addr_per_block, max_map_block;
|
||||
|
||||
/* Kernel seems to cut us off at 4294967294 blocks */
|
||||
if (offset >= (1ULL << 32) - 1)
|
||||
return 1;
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL)
|
||||
return 0;
|
||||
|
||||
addr_per_block = fs->blocksize >> 2;
|
||||
max_map_block = addr_per_block;
|
||||
max_map_block += addr_per_block * addr_per_block;
|
||||
max_map_block += addr_per_block * addr_per_block * addr_per_block;
|
||||
max_map_block += 12;
|
||||
|
||||
return offset >= max_map_block;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_bmap2(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
|
||||
char *block_buf, int bmap_flags, blk64_t block,
|
||||
int *ret_flags, blk64_t *phys_blk)
|
||||
{
|
||||
struct ext2_inode inode_buf;
|
||||
ext2_extent_handle_t handle = 0;
|
||||
blk_t addr_per_block;
|
||||
blk_t b, blk32;
|
||||
blk64_t b64;
|
||||
char *buf = 0;
|
||||
errcode_t retval = 0;
|
||||
int blocks_alloc = 0, inode_dirty = 0;
|
||||
struct blk_alloc_ctx alloc_ctx = {
|
||||
.ino = ino,
|
||||
.inode = inode,
|
||||
.lblk = 0,
|
||||
.flags = BLOCK_ALLOC_DATA,
|
||||
};
|
||||
|
||||
if (!(bmap_flags & BMAP_SET))
|
||||
*phys_blk = 0;
|
||||
|
||||
if (ret_flags)
|
||||
*ret_flags = 0;
|
||||
|
||||
/* Read inode structure if necessary */
|
||||
if (!inode) {
|
||||
retval = ext2fs_read_inode(fs, ino, &inode_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
inode = &inode_buf;
|
||||
}
|
||||
addr_per_block = (blk_t) fs->blocksize >> 2;
|
||||
|
||||
if (ext2fs_file_block_offset_too_big(fs, inode, block))
|
||||
return EXT2_ET_FILE_TOO_BIG;
|
||||
|
||||
/*
|
||||
* If an inode has inline data, that means that it doesn't have
|
||||
* any blocks and we shouldn't map any blocks for it.
|
||||
*/
|
||||
if (inode->i_flags & EXT4_INLINE_DATA_FL)
|
||||
return EXT2_ET_INLINE_DATA_NO_BLOCK;
|
||||
|
||||
if (!block_buf) {
|
||||
retval = ext2fs_get_array(2, fs->blocksize, &buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
block_buf = buf;
|
||||
}
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL) {
|
||||
retval = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (retval)
|
||||
goto done;
|
||||
retval = extent_bmap(fs, ino, inode, handle, block_buf,
|
||||
bmap_flags, block, ret_flags,
|
||||
&blocks_alloc, phys_blk);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (block < EXT2_NDIR_BLOCKS) {
|
||||
if (bmap_flags & BMAP_SET) {
|
||||
b = *phys_blk;
|
||||
inode_bmap(inode, block) = b;
|
||||
inode_dirty++;
|
||||
goto done;
|
||||
}
|
||||
|
||||
*phys_blk = inode_bmap(inode, block);
|
||||
b = block ? inode_bmap(inode, block - 1) :
|
||||
ext2fs_find_inode_goal(fs, ino, inode, block);
|
||||
|
||||
if ((*phys_blk == 0) && (bmap_flags & BMAP_ALLOC)) {
|
||||
b64 = b;
|
||||
retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
|
||||
&alloc_ctx);
|
||||
b = b64;
|
||||
if (retval)
|
||||
goto done;
|
||||
inode_bmap(inode, block) = b;
|
||||
blocks_alloc++;
|
||||
*phys_blk = b;
|
||||
}
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Indirect block */
|
||||
block -= EXT2_NDIR_BLOCKS;
|
||||
blk32 = *phys_blk;
|
||||
if (block < addr_per_block) {
|
||||
b = inode_bmap(inode, EXT2_IND_BLOCK);
|
||||
if (!b) {
|
||||
if (!(bmap_flags & BMAP_ALLOC)) {
|
||||
if (bmap_flags & BMAP_SET)
|
||||
retval = EXT2_ET_SET_BMAP_NO_IND;
|
||||
goto done;
|
||||
}
|
||||
|
||||
b = inode_bmap(inode, EXT2_IND_BLOCK-1);
|
||||
b64 = b;
|
||||
retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
|
||||
&alloc_ctx);
|
||||
b = b64;
|
||||
if (retval)
|
||||
goto done;
|
||||
inode_bmap(inode, EXT2_IND_BLOCK) = b;
|
||||
blocks_alloc++;
|
||||
}
|
||||
retval = block_ind_bmap(fs, bmap_flags, b, block_buf,
|
||||
&blocks_alloc, block, &blk32);
|
||||
if (retval == 0)
|
||||
*phys_blk = blk32;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Doubly indirect block */
|
||||
block -= addr_per_block;
|
||||
if (block < addr_per_block * addr_per_block) {
|
||||
b = inode_bmap(inode, EXT2_DIND_BLOCK);
|
||||
if (!b) {
|
||||
if (!(bmap_flags & BMAP_ALLOC)) {
|
||||
if (bmap_flags & BMAP_SET)
|
||||
retval = EXT2_ET_SET_BMAP_NO_IND;
|
||||
goto done;
|
||||
}
|
||||
|
||||
b = inode_bmap(inode, EXT2_IND_BLOCK);
|
||||
b64 = b;
|
||||
retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
|
||||
&alloc_ctx);
|
||||
b = b64;
|
||||
if (retval)
|
||||
goto done;
|
||||
inode_bmap(inode, EXT2_DIND_BLOCK) = b;
|
||||
blocks_alloc++;
|
||||
}
|
||||
retval = block_dind_bmap(fs, bmap_flags, b, block_buf,
|
||||
&blocks_alloc, block, &blk32);
|
||||
if (retval == 0)
|
||||
*phys_blk = blk32;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Triply indirect block */
|
||||
block -= addr_per_block * addr_per_block;
|
||||
b = inode_bmap(inode, EXT2_TIND_BLOCK);
|
||||
if (!b) {
|
||||
if (!(bmap_flags & BMAP_ALLOC)) {
|
||||
if (bmap_flags & BMAP_SET)
|
||||
retval = EXT2_ET_SET_BMAP_NO_IND;
|
||||
goto done;
|
||||
}
|
||||
|
||||
b = inode_bmap(inode, EXT2_DIND_BLOCK);
|
||||
b64 = b;
|
||||
retval = ext2fs_alloc_block3(fs, b64, block_buf, &b64,
|
||||
&alloc_ctx);
|
||||
b = b64;
|
||||
if (retval)
|
||||
goto done;
|
||||
inode_bmap(inode, EXT2_TIND_BLOCK) = b;
|
||||
blocks_alloc++;
|
||||
}
|
||||
retval = block_tind_bmap(fs, bmap_flags, b, block_buf,
|
||||
&blocks_alloc, block, &blk32);
|
||||
if (retval == 0)
|
||||
*phys_blk = blk32;
|
||||
done:
|
||||
if (*phys_blk && retval == 0 && (bmap_flags & BMAP_ZERO))
|
||||
retval = ext2fs_zero_blocks2(fs, *phys_blk, 1, NULL, NULL);
|
||||
if (buf)
|
||||
ext2fs_free_mem(&buf);
|
||||
if (handle)
|
||||
ext2fs_extent_free(handle);
|
||||
if ((retval == 0) && (blocks_alloc || inode_dirty)) {
|
||||
ext2fs_iblk_add_blocks(fs, inode, blocks_alloc);
|
||||
retval = ext2fs_write_inode(fs, ino, inode);
|
||||
}
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_bmap(ext2_filsys fs, ext2_ino_t ino, struct ext2_inode *inode,
|
||||
char *block_buf, int bmap_flags, blk_t block,
|
||||
blk_t *phys_blk)
|
||||
{
|
||||
errcode_t ret;
|
||||
blk64_t ret_blk = *phys_blk;
|
||||
|
||||
ret = ext2fs_bmap2(fs, ino, inode, block_buf, bmap_flags, block,
|
||||
0, &ret_blk);
|
||||
if (ret)
|
||||
return ret;
|
||||
if (ret_blk >= ((long long) 1 << 32))
|
||||
return EOVERFLOW;
|
||||
*phys_blk = ret_blk;
|
||||
return 0;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/bmap.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/bmap.o
Executable file
Binary file not shown.
167
jni/e2fsprogs/lib/ext2fs/bmove.c
Executable file
167
jni/e2fsprogs/lib/ext2fs/bmove.c
Executable file
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* bmove.c --- Move blocks around to make way for a particular
|
||||
* filesystem structure.
|
||||
*
|
||||
* Copyright (C) 1997 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct process_block_struct {
|
||||
ext2_ino_t ino;
|
||||
struct ext2_inode * inode;
|
||||
ext2fs_block_bitmap reserve;
|
||||
ext2fs_block_bitmap alloc_map;
|
||||
errcode_t error;
|
||||
char *buf;
|
||||
int add_dir;
|
||||
int flags;
|
||||
};
|
||||
|
||||
static int process_block(ext2_filsys fs, blk64_t *block_nr,
|
||||
e2_blkcnt_t blockcnt, blk64_t ref_block,
|
||||
int ref_offset, void *priv_data)
|
||||
{
|
||||
struct process_block_struct *pb;
|
||||
errcode_t retval;
|
||||
int ret;
|
||||
blk64_t block, orig;
|
||||
|
||||
pb = (struct process_block_struct *) priv_data;
|
||||
block = orig = *block_nr;
|
||||
ret = 0;
|
||||
|
||||
/*
|
||||
* Let's see if this is one which we need to relocate
|
||||
*/
|
||||
if (ext2fs_test_block_bitmap2(pb->reserve, block)) {
|
||||
do {
|
||||
if (++block >= ext2fs_blocks_count(fs->super))
|
||||
block = fs->super->s_first_data_block;
|
||||
if (block == orig) {
|
||||
pb->error = EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
} while (ext2fs_test_block_bitmap2(pb->reserve, block) ||
|
||||
ext2fs_test_block_bitmap2(pb->alloc_map, block));
|
||||
|
||||
retval = io_channel_read_blk64(fs->io, orig, 1, pb->buf);
|
||||
if (retval) {
|
||||
pb->error = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
retval = io_channel_write_blk64(fs->io, block, 1, pb->buf);
|
||||
if (retval) {
|
||||
pb->error = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
*block_nr = block;
|
||||
ext2fs_mark_block_bitmap2(pb->alloc_map, block);
|
||||
ret = BLOCK_CHANGED;
|
||||
if (pb->flags & EXT2_BMOVE_DEBUG)
|
||||
printf("ino=%u, blockcnt=%lld, %llu->%llu\n",
|
||||
(unsigned) pb->ino, blockcnt,
|
||||
(unsigned long long) orig,
|
||||
(unsigned long long) block);
|
||||
}
|
||||
if (pb->add_dir) {
|
||||
retval = ext2fs_add_dir_block2(fs->dblist, pb->ino,
|
||||
block, blockcnt);
|
||||
if (retval) {
|
||||
pb->error = retval;
|
||||
ret |= BLOCK_ABORT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_move_blocks(ext2_filsys fs,
|
||||
ext2fs_block_bitmap reserve,
|
||||
ext2fs_block_bitmap alloc_map,
|
||||
int flags)
|
||||
{
|
||||
ext2_ino_t ino;
|
||||
struct ext2_inode inode;
|
||||
errcode_t retval;
|
||||
struct process_block_struct pb;
|
||||
ext2_inode_scan scan;
|
||||
char *block_buf;
|
||||
|
||||
retval = ext2fs_open_inode_scan(fs, 0, &scan);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
pb.reserve = reserve;
|
||||
pb.error = 0;
|
||||
pb.alloc_map = alloc_map ? alloc_map : fs->block_map;
|
||||
pb.flags = flags;
|
||||
|
||||
retval = ext2fs_get_array(4, fs->blocksize, &block_buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
pb.buf = block_buf + fs->blocksize * 3;
|
||||
|
||||
/*
|
||||
* If GET_DBLIST is set in the flags field, then we should
|
||||
* gather directory block information while we're doing the
|
||||
* block move.
|
||||
*/
|
||||
if (flags & EXT2_BMOVE_GET_DBLIST) {
|
||||
if (fs->dblist) {
|
||||
ext2fs_free_dblist(fs->dblist);
|
||||
fs->dblist = NULL;
|
||||
}
|
||||
retval = ext2fs_init_dblist(fs, 0);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_get_next_inode(scan, &ino, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
while (ino) {
|
||||
if ((inode.i_links_count == 0) ||
|
||||
!ext2fs_inode_has_valid_blocks2(fs, &inode))
|
||||
goto next;
|
||||
|
||||
pb.ino = ino;
|
||||
pb.inode = &inode;
|
||||
|
||||
pb.add_dir = (LINUX_S_ISDIR(inode.i_mode) &&
|
||||
flags & EXT2_BMOVE_GET_DBLIST);
|
||||
|
||||
retval = ext2fs_block_iterate3(fs, ino, 0, block_buf,
|
||||
process_block, &pb);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (pb.error)
|
||||
return pb.error;
|
||||
|
||||
next:
|
||||
retval = ext2fs_get_next_inode(scan, &ino, &inode);
|
||||
if (retval == EXT2_ET_BAD_BLOCK_IN_INODE_TABLE)
|
||||
goto next;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
199
jni/e2fsprogs/lib/ext2fs/brel_ma.c
Executable file
199
jni/e2fsprogs/lib/ext2fs/brel_ma.c
Executable file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
* brel_ma.c
|
||||
*
|
||||
* Copyright (C) 1996, 1997 Theodore Ts'o.
|
||||
*
|
||||
* TODO: rewrite to not use a direct array!!! (Fortunately this
|
||||
* module isn't really used yet.)
|
||||
*
|
||||
* %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 <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "brel.h"
|
||||
|
||||
static errcode_t bma_put(ext2_brel brel, blk64_t old,
|
||||
struct ext2_block_relocate_entry *ent);
|
||||
static errcode_t bma_get(ext2_brel brel, blk64_t old,
|
||||
struct ext2_block_relocate_entry *ent);
|
||||
static errcode_t bma_start_iter(ext2_brel brel);
|
||||
static errcode_t bma_next(ext2_brel brel, blk64_t *old,
|
||||
struct ext2_block_relocate_entry *ent);
|
||||
static errcode_t bma_move(ext2_brel brel, blk64_t old, blk64_t new);
|
||||
static errcode_t bma_delete(ext2_brel brel, blk64_t old);
|
||||
static errcode_t bma_free(ext2_brel brel);
|
||||
|
||||
struct brel_ma {
|
||||
__u32 magic;
|
||||
blk64_t max_block;
|
||||
struct ext2_block_relocate_entry *entries;
|
||||
};
|
||||
|
||||
errcode_t ext2fs_brel_memarray_create(char *name, blk64_t max_block,
|
||||
ext2_brel *new_brel)
|
||||
{
|
||||
ext2_brel brel = 0;
|
||||
errcode_t retval;
|
||||
struct brel_ma *ma = 0;
|
||||
size_t size;
|
||||
|
||||
*new_brel = 0;
|
||||
|
||||
/*
|
||||
* Allocate memory structures
|
||||
*/
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2_block_relocation_table),
|
||||
&brel);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memset(brel, 0, sizeof(struct ext2_block_relocation_table));
|
||||
|
||||
retval = ext2fs_get_mem(strlen(name)+1, &brel->name);
|
||||
if (retval)
|
||||
goto errout;
|
||||
strcpy(brel->name, name);
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct brel_ma), &ma);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memset(ma, 0, sizeof(struct brel_ma));
|
||||
brel->priv_data = ma;
|
||||
|
||||
size = (size_t) (sizeof(struct ext2_block_relocate_entry) *
|
||||
(max_block+1));
|
||||
retval = ext2fs_get_array(max_block+1,
|
||||
sizeof(struct ext2_block_relocate_entry), &ma->entries);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memset(ma->entries, 0, size);
|
||||
ma->max_block = max_block;
|
||||
|
||||
/*
|
||||
* Fill in the brel data structure
|
||||
*/
|
||||
brel->put = bma_put;
|
||||
brel->get = bma_get;
|
||||
brel->start_iter = bma_start_iter;
|
||||
brel->next = bma_next;
|
||||
brel->move = bma_move;
|
||||
brel->delete = bma_delete;
|
||||
brel->free = bma_free;
|
||||
|
||||
*new_brel = brel;
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
bma_free(brel);
|
||||
return retval;
|
||||
}
|
||||
|
||||
static errcode_t bma_put(ext2_brel brel, blk64_t old,
|
||||
struct ext2_block_relocate_entry *ent)
|
||||
{
|
||||
struct brel_ma *ma;
|
||||
|
||||
ma = brel->priv_data;
|
||||
if (old > ma->max_block)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
ma->entries[(unsigned)old] = *ent;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t bma_get(ext2_brel brel, blk64_t old,
|
||||
struct ext2_block_relocate_entry *ent)
|
||||
{
|
||||
struct brel_ma *ma;
|
||||
|
||||
ma = brel->priv_data;
|
||||
if (old > ma->max_block)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
if (ma->entries[(unsigned)old].new == 0)
|
||||
return ENOENT;
|
||||
*ent = ma->entries[old];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t bma_start_iter(ext2_brel brel)
|
||||
{
|
||||
brel->current = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t bma_next(ext2_brel brel, blk64_t *old,
|
||||
struct ext2_block_relocate_entry *ent)
|
||||
{
|
||||
struct brel_ma *ma;
|
||||
|
||||
ma = brel->priv_data;
|
||||
while (++brel->current < ma->max_block) {
|
||||
if (ma->entries[(unsigned)brel->current].new == 0)
|
||||
continue;
|
||||
*old = brel->current;
|
||||
*ent = ma->entries[(unsigned)brel->current];
|
||||
return 0;
|
||||
}
|
||||
*old = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t bma_move(ext2_brel brel, blk64_t old, blk64_t new)
|
||||
{
|
||||
struct brel_ma *ma;
|
||||
|
||||
ma = brel->priv_data;
|
||||
if ((old > ma->max_block) || (new > ma->max_block))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
if (ma->entries[(unsigned)old].new == 0)
|
||||
return ENOENT;
|
||||
ma->entries[(unsigned)new] = ma->entries[old];
|
||||
ma->entries[(unsigned)old].new = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t bma_delete(ext2_brel brel, blk64_t old)
|
||||
{
|
||||
struct brel_ma *ma;
|
||||
|
||||
ma = brel->priv_data;
|
||||
if (old > ma->max_block)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
if (ma->entries[(unsigned)old].new == 0)
|
||||
return ENOENT;
|
||||
ma->entries[(unsigned)old].new = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t bma_free(ext2_brel brel)
|
||||
{
|
||||
struct brel_ma *ma;
|
||||
|
||||
if (!brel)
|
||||
return 0;
|
||||
|
||||
ma = brel->priv_data;
|
||||
|
||||
if (ma) {
|
||||
if (ma->entries)
|
||||
ext2fs_free_mem(&ma->entries);
|
||||
ext2fs_free_mem(&ma);
|
||||
}
|
||||
if (brel->name)
|
||||
ext2fs_free_mem(&brel->name);
|
||||
ext2fs_free_mem(&brel);
|
||||
return 0;
|
||||
}
|
||||
104
jni/e2fsprogs/lib/ext2fs/check_desc.c
Executable file
104
jni/e2fsprogs/lib/ext2fs/check_desc.c
Executable file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* check_desc.c --- Check the group descriptors of an ext2 filesystem
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* This routine sanity checks the group descriptors
|
||||
*/
|
||||
errcode_t ext2fs_check_desc(ext2_filsys fs)
|
||||
{
|
||||
ext2fs_block_bitmap bmap;
|
||||
errcode_t retval;
|
||||
dgrp_t i;
|
||||
blk64_t first_block = fs->super->s_first_data_block;
|
||||
blk64_t last_block = ext2fs_blocks_count(fs->super)-1;
|
||||
blk64_t blk, b;
|
||||
unsigned int j;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (EXT2_DESC_SIZE(fs->super) & (EXT2_DESC_SIZE(fs->super) - 1))
|
||||
return EXT2_ET_BAD_DESC_SIZE;
|
||||
|
||||
retval = ext2fs_allocate_subcluster_bitmap(fs, "check_desc map", &bmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++)
|
||||
ext2fs_reserve_super_and_bgd(fs, i, bmap);
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
if (!ext2fs_has_feature_flex_bg(fs->super)) {
|
||||
first_block = ext2fs_group_first_block2(fs, i);
|
||||
last_block = ext2fs_group_last_block2(fs, i);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check to make sure the block bitmap for group is sane
|
||||
*/
|
||||
blk = ext2fs_block_bitmap_loc(fs, i);
|
||||
if (blk < first_block || blk > last_block ||
|
||||
ext2fs_test_block_bitmap2(bmap, blk)) {
|
||||
retval = EXT2_ET_GDESC_BAD_BLOCK_MAP;
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_mark_block_bitmap2(bmap, blk);
|
||||
|
||||
/*
|
||||
* Check to make sure the inode bitmap for group is sane
|
||||
*/
|
||||
blk = ext2fs_inode_bitmap_loc(fs, i);
|
||||
if (blk < first_block || blk > last_block ||
|
||||
ext2fs_test_block_bitmap2(bmap, blk)) {
|
||||
retval = EXT2_ET_GDESC_BAD_INODE_MAP;
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_mark_block_bitmap2(bmap, blk);
|
||||
|
||||
/*
|
||||
* Check to make sure the inode table for group is sane
|
||||
*/
|
||||
blk = ext2fs_inode_table_loc(fs, i);
|
||||
if (blk < first_block ||
|
||||
((blk + fs->inode_blocks_per_group - 1) > last_block)) {
|
||||
retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
for (j = 0, b = blk; j < fs->inode_blocks_per_group;
|
||||
j++, b++) {
|
||||
if (ext2fs_test_block_bitmap2(bmap, b)) {
|
||||
retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
ext2fs_mark_block_bitmap2(bmap, b);
|
||||
}
|
||||
}
|
||||
errout:
|
||||
ext2fs_free_block_bitmap(bmap);
|
||||
return retval;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/check_desc.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/check_desc.o
Executable file
Binary file not shown.
521
jni/e2fsprogs/lib/ext2fs/closefs.c
Executable file
521
jni/e2fsprogs/lib/ext2fs/closefs.c
Executable file
@@ -0,0 +1,521 @@
|
||||
/*
|
||||
* closefs.c --- close an ext2 filesystem
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
static int test_root(unsigned int a, unsigned int b)
|
||||
{
|
||||
while (1) {
|
||||
if (a < b)
|
||||
return 0;
|
||||
if (a == b)
|
||||
return 1;
|
||||
if (a % b)
|
||||
return 0;
|
||||
a = a / b;
|
||||
}
|
||||
}
|
||||
|
||||
int ext2fs_bg_has_super(ext2_filsys fs, dgrp_t group)
|
||||
{
|
||||
if (group == 0)
|
||||
return 1;
|
||||
if (ext2fs_has_feature_sparse_super2(fs->super)) {
|
||||
if (group == fs->super->s_backup_bgs[0] ||
|
||||
group == fs->super->s_backup_bgs[1])
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
if ((group <= 1) || !ext2fs_has_feature_sparse_super(fs->super))
|
||||
return 1;
|
||||
if (!(group & 1))
|
||||
return 0;
|
||||
if (test_root(group, 3) || (test_root(group, 5)) ||
|
||||
test_root(group, 7))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* ext2fs_super_and_bgd_loc2()
|
||||
* @fs: ext2 fs pointer
|
||||
* @group given block group
|
||||
* @ret_super_blk: if !NULL, returns super block location
|
||||
* @ret_old_desc_blk: if !NULL, returns location of the old block
|
||||
* group descriptor
|
||||
* @ret_new_desc_blk: if !NULL, returns location of meta_bg block
|
||||
* group descriptor
|
||||
* @ret_used_blks: if !NULL, returns number of blocks used by
|
||||
* super block and group_descriptors.
|
||||
*
|
||||
* Returns errcode_t of 0
|
||||
*/
|
||||
errcode_t ext2fs_super_and_bgd_loc2(ext2_filsys fs,
|
||||
dgrp_t group,
|
||||
blk64_t *ret_super_blk,
|
||||
blk64_t *ret_old_desc_blk,
|
||||
blk64_t *ret_new_desc_blk,
|
||||
blk_t *ret_used_blks)
|
||||
{
|
||||
blk64_t group_block, super_blk = 0, old_desc_blk = 0, new_desc_blk = 0;
|
||||
unsigned int meta_bg, meta_bg_size;
|
||||
blk_t numblocks = 0;
|
||||
blk64_t old_desc_blocks;
|
||||
int has_super;
|
||||
|
||||
group_block = ext2fs_group_first_block2(fs, group);
|
||||
if (group_block == 0 && fs->blocksize == 1024)
|
||||
group_block = 1; /* Deal with 1024 blocksize && bigalloc */
|
||||
|
||||
if (ext2fs_has_feature_meta_bg(fs->super))
|
||||
old_desc_blocks = fs->super->s_first_meta_bg;
|
||||
else
|
||||
old_desc_blocks =
|
||||
fs->desc_blocks + fs->super->s_reserved_gdt_blocks;
|
||||
|
||||
has_super = ext2fs_bg_has_super(fs, group);
|
||||
|
||||
if (has_super) {
|
||||
super_blk = group_block;
|
||||
numblocks++;
|
||||
}
|
||||
meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
meta_bg = group / meta_bg_size;
|
||||
|
||||
if (!ext2fs_has_feature_meta_bg(fs->super) ||
|
||||
(meta_bg < fs->super->s_first_meta_bg)) {
|
||||
if (has_super) {
|
||||
old_desc_blk = group_block + 1;
|
||||
numblocks += old_desc_blocks;
|
||||
}
|
||||
} else {
|
||||
if (((group % meta_bg_size) == 0) ||
|
||||
((group % meta_bg_size) == 1) ||
|
||||
((group % meta_bg_size) == (meta_bg_size-1))) {
|
||||
if (has_super)
|
||||
has_super = 1;
|
||||
new_desc_blk = group_block + has_super;
|
||||
numblocks++;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret_super_blk)
|
||||
*ret_super_blk = super_blk;
|
||||
if (ret_old_desc_blk)
|
||||
*ret_old_desc_blk = old_desc_blk;
|
||||
if (ret_new_desc_blk)
|
||||
*ret_new_desc_blk = new_desc_blk;
|
||||
if (ret_used_blks)
|
||||
*ret_used_blks = numblocks;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the location of the superblock, block group
|
||||
* descriptors for a given block group. It currently returns the
|
||||
* number of free blocks assuming that inode table and allocation
|
||||
* bitmaps will be in the group. This is not necessarily the case
|
||||
* when the flex_bg feature is enabled, so callers should take care!
|
||||
* It was only really intended for use by mke2fs, and even there it's
|
||||
* not that useful.
|
||||
*
|
||||
* The ext2fs_super_and_bgd_loc2() function is 64-bit block number
|
||||
* capable and returns the number of blocks used by super block and
|
||||
* group descriptors.
|
||||
*/
|
||||
int ext2fs_super_and_bgd_loc(ext2_filsys fs,
|
||||
dgrp_t group,
|
||||
blk_t *ret_super_blk,
|
||||
blk_t *ret_old_desc_blk,
|
||||
blk_t *ret_new_desc_blk,
|
||||
int *ret_meta_bg)
|
||||
{
|
||||
blk64_t ret_super_blk2;
|
||||
blk64_t ret_old_desc_blk2;
|
||||
blk64_t ret_new_desc_blk2;
|
||||
blk_t ret_used_blks;
|
||||
blk_t numblocks;
|
||||
unsigned int meta_bg_size;
|
||||
|
||||
ext2fs_super_and_bgd_loc2(fs, group, &ret_super_blk2,
|
||||
&ret_old_desc_blk2,
|
||||
&ret_new_desc_blk2,
|
||||
&ret_used_blks);
|
||||
|
||||
numblocks = ext2fs_group_blocks_count(fs, group);
|
||||
|
||||
if (ret_super_blk)
|
||||
*ret_super_blk = (blk_t)ret_super_blk2;
|
||||
if (ret_old_desc_blk)
|
||||
*ret_old_desc_blk = (blk_t)ret_old_desc_blk2;
|
||||
if (ret_new_desc_blk)
|
||||
*ret_new_desc_blk = (blk_t)ret_new_desc_blk2;
|
||||
if (ret_meta_bg) {
|
||||
meta_bg_size = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
*ret_meta_bg = group / meta_bg_size;
|
||||
}
|
||||
|
||||
numblocks -= 2 + fs->inode_blocks_per_group + ret_used_blks;
|
||||
|
||||
return numblocks;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function forces out the primary superblock. We need to only
|
||||
* write out those fields which we have changed, since if the
|
||||
* filesystem is mounted, it may have changed some of the other
|
||||
* fields.
|
||||
*
|
||||
* It takes as input a superblock which has already been byte swapped
|
||||
* (if necessary).
|
||||
*
|
||||
*/
|
||||
static errcode_t write_primary_superblock(ext2_filsys fs,
|
||||
struct ext2_super_block *super)
|
||||
{
|
||||
__u16 *old_super, *new_super;
|
||||
int check_idx, write_idx, size;
|
||||
errcode_t retval;
|
||||
|
||||
if (!fs->io->manager->write_byte || !fs->orig_super) {
|
||||
fallback:
|
||||
io_channel_set_blksize(fs->io, SUPERBLOCK_OFFSET);
|
||||
retval = io_channel_write_blk64(fs->io, 1, -SUPERBLOCK_SIZE,
|
||||
super);
|
||||
io_channel_set_blksize(fs->io, fs->blocksize);
|
||||
return retval;
|
||||
}
|
||||
|
||||
old_super = (__u16 *) fs->orig_super;
|
||||
new_super = (__u16 *) super;
|
||||
|
||||
for (check_idx = 0; check_idx < SUPERBLOCK_SIZE/2; check_idx++) {
|
||||
if (old_super[check_idx] == new_super[check_idx])
|
||||
continue;
|
||||
write_idx = check_idx;
|
||||
for (check_idx++; check_idx < SUPERBLOCK_SIZE/2; check_idx++)
|
||||
if (old_super[check_idx] == new_super[check_idx])
|
||||
break;
|
||||
size = 2 * (check_idx - write_idx);
|
||||
#if 0
|
||||
printf("Writing %d bytes starting at %d\n",
|
||||
size, write_idx*2);
|
||||
#endif
|
||||
retval = io_channel_write_byte(fs->io,
|
||||
SUPERBLOCK_OFFSET + (2 * write_idx), size,
|
||||
new_super + write_idx);
|
||||
if (retval == EXT2_ET_UNIMPLEMENTED)
|
||||
goto fallback;
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
memcpy(fs->orig_super, super, SUPERBLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Updates the revision to EXT2_DYNAMIC_REV
|
||||
*/
|
||||
void ext2fs_update_dynamic_rev(ext2_filsys fs)
|
||||
{
|
||||
struct ext2_super_block *sb = fs->super;
|
||||
|
||||
if (sb->s_rev_level > EXT2_GOOD_OLD_REV)
|
||||
return;
|
||||
|
||||
sb->s_rev_level = EXT2_DYNAMIC_REV;
|
||||
sb->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
|
||||
sb->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
|
||||
/* s_uuid is handled by e2fsck already */
|
||||
/* other fields should be left alone */
|
||||
}
|
||||
|
||||
static errcode_t write_backup_super(ext2_filsys fs, dgrp_t group,
|
||||
blk64_t group_block,
|
||||
struct ext2_super_block *super_shadow)
|
||||
{
|
||||
errcode_t retval;
|
||||
dgrp_t sgrp = group;
|
||||
|
||||
if (sgrp > ((1 << 16) - 1))
|
||||
sgrp = (1 << 16) - 1;
|
||||
|
||||
super_shadow->s_block_group_nr = ext2fs_cpu_to_le16(sgrp);
|
||||
|
||||
retval = ext2fs_superblock_csum_set(fs, super_shadow);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return io_channel_write_blk64(fs->io, group_block, -SUPERBLOCK_SIZE,
|
||||
super_shadow);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_flush(ext2_filsys fs)
|
||||
{
|
||||
return ext2fs_flush2(fs, 0);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_flush2(ext2_filsys fs, int flags)
|
||||
{
|
||||
dgrp_t i;
|
||||
errcode_t retval;
|
||||
unsigned long fs_state;
|
||||
__u32 feature_incompat;
|
||||
struct ext2_super_block *super_shadow = 0;
|
||||
struct opaque_ext2_group_desc *group_shadow = 0;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
struct ext2_group_desc *gdp;
|
||||
dgrp_t j;
|
||||
#endif
|
||||
char *group_ptr;
|
||||
blk64_t old_desc_blocks;
|
||||
struct ext2fs_numeric_progress_struct progress;
|
||||
|
||||
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;
|
||||
|
||||
fs->super->s_wtime = fs->now ? fs->now : time(NULL);
|
||||
fs->super->s_block_group_nr = 0;
|
||||
|
||||
/*
|
||||
* If the write_bitmaps() function is present, call it to
|
||||
* flush the bitmaps. This is done this way so that a simple
|
||||
* program that doesn't mess with the bitmaps doesn't need to
|
||||
* drag in the bitmaps.c code.
|
||||
*
|
||||
* Bitmap checksums live in the group descriptor, so the
|
||||
* bitmaps need to be written before the descriptors.
|
||||
*/
|
||||
if (fs->write_bitmaps) {
|
||||
retval = fs->write_bitmaps(fs);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Set the state of the FS to be non-valid. (The state has
|
||||
* already been backed up earlier, and will be restored after
|
||||
* we write out the backup superblocks.)
|
||||
*/
|
||||
fs->super->s_state &= ~EXT2_VALID_FS;
|
||||
ext2fs_clear_feature_journal_needs_recovery(fs->super);
|
||||
|
||||
/* Byte swap the superblock and the group descriptors if necessary */
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
retval = EXT2_ET_NO_MEMORY;
|
||||
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super_shadow);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(super_shadow, fs->super, sizeof(struct ext2_super_block));
|
||||
ext2fs_swap_super(super_shadow);
|
||||
|
||||
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;
|
||||
group_shadow = fs->group_desc;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* If this is an external journal device, don't write out the
|
||||
* block group descriptors or any of the backup superblocks
|
||||
*/
|
||||
if (ext2fs_has_feature_journal_dev(fs->super))
|
||||
goto write_primary_superblock_only;
|
||||
|
||||
/*
|
||||
* Write out the master group descriptors, and the backup
|
||||
* superblocks and group descriptors.
|
||||
*/
|
||||
group_ptr = (char *) group_shadow;
|
||||
if (ext2fs_has_feature_meta_bg(fs->super)) {
|
||||
old_desc_blocks = fs->super->s_first_meta_bg;
|
||||
if (old_desc_blocks > fs->desc_blocks)
|
||||
old_desc_blocks = fs->desc_blocks;
|
||||
} else
|
||||
old_desc_blocks = fs->desc_blocks;
|
||||
|
||||
if (fs->progress_ops && fs->progress_ops->init)
|
||||
(fs->progress_ops->init)(fs, &progress, NULL,
|
||||
fs->group_desc_count);
|
||||
|
||||
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
blk64_t super_blk, old_desc_blk, new_desc_blk;
|
||||
|
||||
if (fs->progress_ops && fs->progress_ops->update)
|
||||
(fs->progress_ops->update)(fs, &progress, i);
|
||||
ext2fs_super_and_bgd_loc2(fs, i, &super_blk, &old_desc_blk,
|
||||
&new_desc_blk, 0);
|
||||
|
||||
if (!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) &&i && super_blk) {
|
||||
retval = write_backup_super(fs, i, super_blk,
|
||||
super_shadow);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
if (fs->flags & EXT2_FLAG_SUPER_ONLY)
|
||||
continue;
|
||||
if ((old_desc_blk) &&
|
||||
(!(fs->flags & EXT2_FLAG_MASTER_SB_ONLY) || (i == 0))) {
|
||||
retval = io_channel_write_blk64(fs->io,
|
||||
old_desc_blk, old_desc_blocks, group_ptr);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
if (new_desc_blk) {
|
||||
int meta_bg = i / EXT2_DESC_PER_BLOCK(fs->super);
|
||||
|
||||
retval = io_channel_write_blk64(fs->io, new_desc_blk,
|
||||
1, group_ptr + (meta_bg*fs->blocksize));
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
|
||||
if (fs->progress_ops && fs->progress_ops->close)
|
||||
(fs->progress_ops->close)(fs, &progress, NULL);
|
||||
|
||||
write_primary_superblock_only:
|
||||
/*
|
||||
* Write out master superblock. This has to be done
|
||||
* separately, since it is located at a fixed location
|
||||
* (SUPERBLOCK_OFFSET). We flush all other pending changes
|
||||
* out to disk first, just to avoid a race condition with an
|
||||
* insy-tinsy window....
|
||||
*/
|
||||
|
||||
fs->super->s_block_group_nr = 0;
|
||||
fs->super->s_state = fs_state;
|
||||
fs->super->s_feature_incompat = feature_incompat;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
*super_shadow = *fs->super;
|
||||
ext2fs_swap_super(super_shadow);
|
||||
#endif
|
||||
|
||||
retval = ext2fs_superblock_csum_set(fs, super_shadow);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) {
|
||||
retval = io_channel_flush(fs->io);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
retval = write_primary_superblock(fs, super_shadow);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
fs->flags &= ~EXT2_FLAG_DIRTY;
|
||||
|
||||
if (!(flags & EXT2_FLAG_FLUSH_NO_SYNC)) {
|
||||
retval = io_channel_flush(fs->io);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
errout:
|
||||
fs->super->s_state = fs_state;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
if (super_shadow)
|
||||
ext2fs_free_mem(&super_shadow);
|
||||
if (group_shadow)
|
||||
ext2fs_free_mem(&group_shadow);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_close_free(ext2_filsys *fs_ptr)
|
||||
{
|
||||
errcode_t ret;
|
||||
ext2_filsys fs = *fs_ptr;
|
||||
|
||||
ret = ext2fs_close2(fs, 0);
|
||||
if (ret)
|
||||
ext2fs_free(fs);
|
||||
*fs_ptr = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_close(ext2_filsys fs)
|
||||
{
|
||||
return ext2fs_close2(fs, 0);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_close2(ext2_filsys fs, int flags)
|
||||
{
|
||||
errcode_t retval;
|
||||
int meta_blks;
|
||||
io_stats stats = 0;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (fs->write_bitmaps) {
|
||||
retval = fs->write_bitmaps(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (fs->super->s_kbytes_written &&
|
||||
fs->io->manager->get_stats)
|
||||
fs->io->manager->get_stats(fs->io, &stats);
|
||||
if (stats && stats->bytes_written && (fs->flags & EXT2_FLAG_RW)) {
|
||||
fs->super->s_kbytes_written += stats->bytes_written >> 10;
|
||||
meta_blks = fs->desc_blocks + 1;
|
||||
if (!(fs->flags & EXT2_FLAG_SUPER_ONLY))
|
||||
fs->super->s_kbytes_written += meta_blks /
|
||||
(fs->blocksize / 1024);
|
||||
if ((fs->flags & EXT2_FLAG_DIRTY) == 0)
|
||||
fs->flags |= EXT2_FLAG_SUPER_ONLY | EXT2_FLAG_DIRTY;
|
||||
}
|
||||
if (fs->flags & EXT2_FLAG_DIRTY) {
|
||||
retval = ext2fs_flush2(fs, flags);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_mmp_stop(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ext2fs_free(fs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/closefs.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/closefs.o
Executable file
Binary file not shown.
74
jni/e2fsprogs/lib/ext2fs/crc16.c
Executable file
74
jni/e2fsprogs/lib/ext2fs/crc16.c
Executable file
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* crc16.c
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2. See the file COPYING for more details.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <ext2fs/ext2_types.h>
|
||||
|
||||
#include "crc16.h"
|
||||
|
||||
/** CRC table for the CRC-16. The poly is 0x8005 (x16 + x15 + x2 + 1) */
|
||||
static __u16 const crc16_table[256] = {
|
||||
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
|
||||
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
|
||||
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
|
||||
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
|
||||
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
|
||||
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
|
||||
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
|
||||
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
|
||||
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
|
||||
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
|
||||
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
|
||||
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
|
||||
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
|
||||
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
|
||||
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
|
||||
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
|
||||
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
|
||||
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
|
||||
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
|
||||
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
|
||||
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
|
||||
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
|
||||
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
|
||||
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
|
||||
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
|
||||
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
|
||||
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
|
||||
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
|
||||
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
|
||||
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
|
||||
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
|
||||
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
|
||||
};
|
||||
|
||||
/**
|
||||
* Compute the CRC-16 for the data buffer
|
||||
*
|
||||
* @param crc previous CRC value
|
||||
* @param buffer data pointer
|
||||
* @param len number of bytes in the buffer
|
||||
* @return the updated CRC value
|
||||
*/
|
||||
crc16_t ext2fs_crc16(crc16_t crc, const void *buffer, unsigned int len)
|
||||
{
|
||||
const unsigned char *cp = buffer;
|
||||
|
||||
while (len--)
|
||||
/*
|
||||
* for an unknown reason, PPC treats __u16 as signed
|
||||
* and keeps doing sign extension on the value.
|
||||
* Instead, use only the low 16 bits of an unsigned
|
||||
* int for holding the CRC value to avoid this.
|
||||
*/
|
||||
crc = (((crc >> 8) & 0xffU) ^
|
||||
crc16_table[(crc ^ *cp++) & 0xffU]) & 0x0000ffffU;
|
||||
return crc;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/crc16.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/crc16.o
Executable file
Binary file not shown.
938
jni/e2fsprogs/lib/ext2fs/crc32c.c
Executable file
938
jni/e2fsprogs/lib/ext2fs/crc32c.c
Executable file
@@ -0,0 +1,938 @@
|
||||
/*
|
||||
* crc32c.c
|
||||
*
|
||||
* August 26, 2011 Darrick J. Wong <djwong at us.ibm.com>
|
||||
* Reuse Bob Pearson's slice-by-8 implementation for e2fsprogs.
|
||||
*
|
||||
* July 20, 2011 Bob Pearson <rpearson at systemfabricworks.com>
|
||||
* added slice by 8 algorithm to the existing conventional and
|
||||
* slice by 4 algorithms.
|
||||
*
|
||||
* Oct 15, 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* Nicer crc32 functions/docs submitted by linux@horizon.com. Thanks!
|
||||
* Code was from the public domain, copyright abandoned. Code was
|
||||
* subsequently included in the kernel, thus was re-licensed under the
|
||||
* GNU GPL v2.
|
||||
*
|
||||
* Oct 12, 2000 Matt Domsch <Matt_Domsch@dell.com>
|
||||
* Same crc32 function was used in 5 other places in the kernel.
|
||||
* I made one version, and deleted the others.
|
||||
* There are various incantations of crc32(). Some use a seed of 0 or ~0.
|
||||
* Some xor at the end with ~0. The generic crc32() function takes
|
||||
* seed as an argument, and doesn't xor at the end. Then individual
|
||||
* users can do whatever they need.
|
||||
* drivers/net/smc9194.c uses seed ~0, doesn't xor with ~0.
|
||||
* fs/jffs2 uses seed 0, doesn't xor with ~0.
|
||||
* fs/partitions/efi.c uses seed ~0, xor's with ~0.
|
||||
*
|
||||
* This source code is licensed under the GNU General Public License,
|
||||
* Version 2. See the file COPYING for more details.
|
||||
*/
|
||||
#include "config.h"
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#define min(x, y) ((x) > (y) ? (y) : (x))
|
||||
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask))
|
||||
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (__typeof__(x))(a) - 1)
|
||||
#define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
|
||||
#define PTR_ALIGN(p, a) ((__typeof__(p))ALIGN((unsigned long)(p), (a)))
|
||||
#include "crc32c_defs.h"
|
||||
|
||||
#include "ext2fs.h"
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define __constant_cpu_to_le32(x) ___constant_swab32((x))
|
||||
#define __constant_cpu_to_be32(x) (x)
|
||||
#define __be32_to_cpu(x) (x)
|
||||
#define __cpu_to_be32(x) (x)
|
||||
#define __cpu_to_le32(x) (ext2fs_cpu_to_le32((x)))
|
||||
#define __le32_to_cpu(x) (ext2fs_le32_to_cpu((x)))
|
||||
#else
|
||||
#define __constant_cpu_to_le32(x) (x)
|
||||
#define __constant_cpu_to_be32(x) ___constant_swab32((x))
|
||||
#define __be32_to_cpu(x) (ext2fs_be32_to_cpu((x)))
|
||||
#define __cpu_to_be32(x) (ext2fs_cpu_to_be32((x)))
|
||||
#define __cpu_to_le32(x) (x)
|
||||
#define __le32_to_cpu(x) (x)
|
||||
#endif
|
||||
|
||||
#if CRC_LE_BITS > 8
|
||||
# define tole(x) __constant_cpu_to_le32(x)
|
||||
#else
|
||||
# define tole(x) (x)
|
||||
#endif
|
||||
|
||||
#if CRC_BE_BITS > 8
|
||||
# define tobe(x) __constant_cpu_to_be32(x)
|
||||
#else
|
||||
# define tobe(x) (x)
|
||||
#endif
|
||||
|
||||
#include "crc32c_table.h"
|
||||
|
||||
#if CRC_LE_BITS > 8 || CRC_BE_BITS > 8
|
||||
|
||||
#if CRC_LE_BITS < 64 && CRC_BE_BITS < 64
|
||||
#define CRC_INLINE inline
|
||||
#else
|
||||
#define CRC_INLINE
|
||||
#endif
|
||||
|
||||
/* implements slicing-by-4 or slicing-by-8 algorithm */
|
||||
static CRC_INLINE uint32_t
|
||||
crc32_body(uint32_t crc, unsigned char const *buf, size_t len,
|
||||
const uint32_t (*tab)[256])
|
||||
{
|
||||
# ifndef WORDS_BIGENDIAN
|
||||
# define DO_CRC(x) (crc = t0[(crc ^ (x)) & 255] ^ (crc >> 8))
|
||||
# define DO_CRC4 (t3[(q) & 255] ^ t2[(q >> 8) & 255] ^ \
|
||||
t1[(q >> 16) & 255] ^ t0[(q >> 24) & 255])
|
||||
# define DO_CRC8 (t7[(q) & 255] ^ t6[(q >> 8) & 255] ^ \
|
||||
t5[(q >> 16) & 255] ^ t4[(q >> 24) & 255])
|
||||
# else
|
||||
# define DO_CRC(x) (crc = t0[((crc >> 24) ^ (x)) & 255] ^ (crc << 8))
|
||||
# define DO_CRC4 (t0[(q) & 255] ^ t1[(q >> 8) & 255] ^ \
|
||||
t2[(q >> 16) & 255] ^ t3[(q >> 24) & 255])
|
||||
# define DO_CRC8 (t4[(q) & 255] ^ t5[(q >> 8) & 255] ^ \
|
||||
t6[(q >> 16) & 255] ^ t7[(q >> 24) & 255])
|
||||
# endif
|
||||
const uint32_t *b;
|
||||
size_t rem_len;
|
||||
const uint32_t *t0 = tab[0], *t1 = tab[1], *t2 = tab[2], *t3 = tab[3];
|
||||
const uint32_t *t4 = tab[4], *t5 = tab[5], *t6 = tab[6], *t7 = tab[7];
|
||||
uint32_t q;
|
||||
|
||||
/* Align it */
|
||||
if (unlikely((uintptr_t)buf & 3 && len)) {
|
||||
do {
|
||||
DO_CRC(*buf++);
|
||||
} while ((--len) && ((uintptr_t)buf)&3);
|
||||
}
|
||||
|
||||
# if CRC_LE_BITS == 32
|
||||
rem_len = len & 3;
|
||||
len = len >> 2;
|
||||
# else
|
||||
rem_len = len & 7;
|
||||
len = len >> 3;
|
||||
# endif
|
||||
|
||||
b = (const uint32_t *)buf;
|
||||
for (--b; len; --len) {
|
||||
q = crc ^ *++b; /* use pre increment for speed */
|
||||
# if CRC_LE_BITS == 32
|
||||
crc = DO_CRC4;
|
||||
# else
|
||||
crc = DO_CRC8;
|
||||
q = *++b;
|
||||
crc ^= DO_CRC4;
|
||||
# endif
|
||||
}
|
||||
len = rem_len;
|
||||
/* And the last few bytes */
|
||||
if (len) {
|
||||
const uint8_t *p = (const uint8_t *)(b + 1) - 1;
|
||||
do {
|
||||
DO_CRC(*++p); /* use pre increment for speed */
|
||||
} while (--len);
|
||||
}
|
||||
return crc;
|
||||
#undef DO_CRC
|
||||
#undef DO_CRC4
|
||||
#undef DO_CRC8
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* crc32_le() - Calculate bitwise little-endian Ethernet AUTODIN II CRC32
|
||||
* @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
|
||||
* other uses, or the previous crc32 value if computing incrementally.
|
||||
* @p: pointer to buffer over which CRC is run
|
||||
* @len: length of buffer @p
|
||||
*/
|
||||
static inline uint32_t crc32_le_generic(uint32_t crc, unsigned char const *p,
|
||||
size_t len, const uint32_t (*tab)[256],
|
||||
uint32_t polynomial EXT2FS_ATTR((unused)))
|
||||
{
|
||||
#if CRC_LE_BITS == 1
|
||||
int i;
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? polynomial : 0);
|
||||
}
|
||||
# elif CRC_LE_BITS == 2
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
crc = (crc >> 2) ^ tab[0][crc & 3];
|
||||
crc = (crc >> 2) ^ tab[0][crc & 3];
|
||||
crc = (crc >> 2) ^ tab[0][crc & 3];
|
||||
crc = (crc >> 2) ^ tab[0][crc & 3];
|
||||
}
|
||||
# elif CRC_LE_BITS == 4
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
crc = (crc >> 4) ^ tab[0][crc & 15];
|
||||
crc = (crc >> 4) ^ tab[0][crc & 15];
|
||||
}
|
||||
# elif CRC_LE_BITS == 8
|
||||
/* aka Sarwate algorithm */
|
||||
while (len--) {
|
||||
crc ^= *p++;
|
||||
crc = (crc >> 8) ^ tab[0][crc & 255];
|
||||
}
|
||||
# else
|
||||
crc = __cpu_to_le32(crc);
|
||||
crc = crc32_body(crc, p, len, tab);
|
||||
crc = __le32_to_cpu(crc);
|
||||
#endif
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t ext2fs_crc32c_le(uint32_t crc, unsigned char const *p, size_t len)
|
||||
{
|
||||
return crc32_le_generic(crc, p, len, crc32ctable_le, CRC32C_POLY_LE);
|
||||
}
|
||||
|
||||
/**
|
||||
* crc32_be() - Calculate bitwise big-endian Ethernet AUTODIN II CRC32
|
||||
* @crc: seed value for computation. ~0 for Ethernet, sometimes 0 for
|
||||
* other uses, or the previous crc32 value if computing incrementally.
|
||||
* @p: pointer to buffer over which CRC is run
|
||||
* @len: length of buffer @p
|
||||
*/
|
||||
static inline uint32_t crc32_be_generic(uint32_t crc, unsigned char const *p,
|
||||
size_t len, const uint32_t (*tab)[256],
|
||||
uint32_t polynomial EXT2FS_ATTR((unused)))
|
||||
{
|
||||
#if CRC_BE_BITS == 1
|
||||
int i;
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
for (i = 0; i < 8; i++)
|
||||
crc =
|
||||
(crc << 1) ^ ((crc & 0x80000000) ? polynomial :
|
||||
0);
|
||||
}
|
||||
# elif CRC_BE_BITS == 2
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
crc = (crc << 2) ^ tab[0][crc >> 30];
|
||||
crc = (crc << 2) ^ tab[0][crc >> 30];
|
||||
crc = (crc << 2) ^ tab[0][crc >> 30];
|
||||
crc = (crc << 2) ^ tab[0][crc >> 30];
|
||||
}
|
||||
# elif CRC_BE_BITS == 4
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
crc = (crc << 4) ^ tab[0][crc >> 28];
|
||||
crc = (crc << 4) ^ tab[0][crc >> 28];
|
||||
}
|
||||
# elif CRC_BE_BITS == 8
|
||||
while (len--) {
|
||||
crc ^= *p++ << 24;
|
||||
crc = (crc << 8) ^ tab[0][crc >> 24];
|
||||
}
|
||||
# else
|
||||
crc = __cpu_to_be32(crc);
|
||||
crc = crc32_body(crc, p, len, tab);
|
||||
crc = __be32_to_cpu(crc);
|
||||
# endif
|
||||
return crc;
|
||||
}
|
||||
|
||||
uint32_t ext2fs_crc32_be(uint32_t crc, unsigned char const *p, size_t len)
|
||||
{
|
||||
return crc32_be_generic(crc, p, len, crc32table_be, CRCPOLY_BE);
|
||||
}
|
||||
|
||||
#ifdef UNITTEST
|
||||
static uint8_t test_buf[] = {
|
||||
0xd9, 0xd7, 0x6a, 0x13, 0x3a, 0xb1, 0x05, 0x48,
|
||||
0xda, 0xad, 0x14, 0xbd, 0x03, 0x3a, 0x58, 0x5e,
|
||||
0x6e, 0xd1, 0x56, 0xc9, 0x2e, 0xc4, 0xcb, 0x6b,
|
||||
0xe8, 0x77, 0x52, 0x37, 0x4e, 0x0f, 0x55, 0xd2,
|
||||
0x12, 0x65, 0x90, 0xc2, 0x41, 0x49, 0x81, 0x01,
|
||||
0xf5, 0x01, 0xeb, 0x2d, 0x78, 0x74, 0x23, 0x5d,
|
||||
0x84, 0x5c, 0x81, 0x92, 0x21, 0xe9, 0x8d, 0x1d,
|
||||
0x89, 0xf2, 0x4a, 0xac, 0xdd, 0xf9, 0xaf, 0xee,
|
||||
0x44, 0xe7, 0x6e, 0xed, 0xfb, 0xd8, 0x89, 0x0e,
|
||||
0x96, 0x62, 0xcd, 0xa4, 0x4b, 0xa9, 0xe5, 0x45,
|
||||
0xb1, 0x29, 0x9b, 0x0f, 0xfc, 0xbd, 0x83, 0xab,
|
||||
0xa8, 0x54, 0x96, 0x44, 0x2c, 0x7f, 0xbb, 0xe7,
|
||||
0x52, 0x29, 0x08, 0xee, 0x14, 0xc5, 0xc2, 0xec,
|
||||
0x5a, 0xeb, 0x40, 0x40, 0xea, 0xd1, 0x3d, 0x15,
|
||||
0x73, 0xaa, 0x8c, 0x73, 0xfc, 0xf2, 0x2b, 0x49,
|
||||
0x0b, 0x13, 0x96, 0xd9, 0x8e, 0x4b, 0xbc, 0xe0,
|
||||
0xf4, 0xd2, 0xe0, 0x2e, 0x7a, 0xf0, 0x5d, 0x1f,
|
||||
0xd2, 0x92, 0x97, 0xe0, 0xaa, 0x59, 0xab, 0xc9,
|
||||
0x5c, 0xa6, 0x51, 0x1a, 0xe3, 0xd6, 0x06, 0xb9,
|
||||
0xae, 0xb8, 0x76, 0x36, 0x79, 0x37, 0x52, 0xf6,
|
||||
0x34, 0xaf, 0x27, 0x19, 0xe1, 0xc0, 0x2b, 0xdd,
|
||||
0x01, 0x15, 0xcd, 0xce, 0x44, 0xf6, 0x4c, 0x18,
|
||||
0x92, 0x69, 0xbe, 0x8a, 0x76, 0x23, 0x52, 0x13,
|
||||
0x3f, 0xf9, 0xe0, 0xf5, 0x06, 0x28, 0x7c, 0xc7,
|
||||
0xf3, 0x42, 0x0f, 0xdd, 0x40, 0x33, 0xf7, 0x99,
|
||||
0xe2, 0xad, 0x26, 0xd9, 0x53, 0x10, 0x72, 0x0c,
|
||||
0x4e, 0x43, 0x4c, 0x61, 0xfe, 0xd9, 0xc1, 0x16,
|
||||
0xa1, 0x93, 0xca, 0x3c, 0x75, 0x7f, 0x07, 0x7a,
|
||||
0x65, 0xb3, 0x53, 0x2a, 0x52, 0x00, 0xa0, 0x62,
|
||||
0xe0, 0xa3, 0x1f, 0xad, 0xd7, 0xbb, 0xc0, 0x83,
|
||||
0x5d, 0x54, 0x87, 0x5f, 0xc8, 0x2f, 0xc8, 0xbf,
|
||||
0x69, 0x04, 0x91, 0xc8, 0xa6, 0x1d, 0x4d, 0x46,
|
||||
0x91, 0xfc, 0x26, 0xf4, 0x16, 0xd1, 0xa4, 0xbf,
|
||||
0x5c, 0xa2, 0x6c, 0xdd, 0xb4, 0x40, 0xf2, 0x2e,
|
||||
0xa2, 0xad, 0xf7, 0xf4, 0xa5, 0x8a, 0x3e, 0x23,
|
||||
0x64, 0x08, 0xc8, 0xa1, 0xa0, 0xf0, 0x5d, 0x70,
|
||||
0xd2, 0x77, 0xfd, 0xc8, 0x50, 0x83, 0x0f, 0xd6,
|
||||
0x2b, 0xe4, 0x1f, 0x52, 0x34, 0x33, 0x68, 0xfd,
|
||||
0x92, 0xbe, 0x9f, 0x97, 0x6b, 0x8d, 0x81, 0x91,
|
||||
0x0f, 0xef, 0x65, 0xc8, 0x0d, 0x15, 0x01, 0x77,
|
||||
0x58, 0xb2, 0xf4, 0x1b, 0x06, 0x7e, 0xf5, 0xca,
|
||||
0x15, 0x2e, 0x38, 0xd8, 0x81, 0x1c, 0x1c, 0xa0,
|
||||
0xb6, 0x13, 0x6a, 0x2b, 0x71, 0x34, 0x52, 0xd7,
|
||||
0x1d, 0xbd, 0x37, 0x59, 0xbc, 0x86, 0x25, 0x2b,
|
||||
0xa8, 0x93, 0xce, 0x1a, 0x03, 0x16, 0xfe, 0x01,
|
||||
0x57, 0x99, 0x24, 0x25, 0x2c, 0xb3, 0xab, 0x1e,
|
||||
0x2d, 0x65, 0x20, 0x89, 0x17, 0x02, 0x0e, 0x0a,
|
||||
0xf5, 0x1e, 0xc7, 0xff, 0x1f, 0x61, 0xa9, 0x54,
|
||||
0x18, 0xd4, 0xba, 0x50, 0x57, 0x02, 0xa1, 0xab,
|
||||
0x22, 0x2e, 0x07, 0xea, 0xa9, 0xa3, 0x83, 0x4f,
|
||||
0x27, 0xf5, 0xc5, 0xee, 0x3c, 0x3b, 0x10, 0xad,
|
||||
0x32, 0x2b, 0x1c, 0x03, 0xcb, 0xaf, 0x98, 0x83,
|
||||
0x54, 0xc3, 0x68, 0x63, 0xd4, 0xe0, 0x0e, 0x3c,
|
||||
0x1a, 0x4e, 0xc0, 0x81, 0xd0, 0xe8, 0x6a, 0x62,
|
||||
0x6b, 0x3e, 0x6f, 0xc4, 0xc6, 0x33, 0x4e, 0x26,
|
||||
0x21, 0xf5, 0x04, 0xdf, 0xfa, 0xce, 0x45, 0xaf,
|
||||
0xdc, 0x5e, 0x1b, 0xad, 0x93, 0xca, 0xf5, 0xcf,
|
||||
0xd7, 0xee, 0x0c, 0x5c, 0x5e, 0xb4, 0xf0, 0x92,
|
||||
0xd2, 0xf2, 0xf0, 0xa9, 0x1e, 0xab, 0x80, 0x68,
|
||||
0x46, 0xef, 0xcc, 0x26, 0x0c, 0x5c, 0xdd, 0x4e,
|
||||
0x83, 0xb8, 0xb9, 0x53, 0x6e, 0xf8, 0x93, 0x38,
|
||||
0x67, 0xa4, 0x41, 0x87, 0x72, 0xe7, 0x7e, 0x86,
|
||||
0xc9, 0x49, 0x00, 0x33, 0xb1, 0x38, 0x6c, 0x71,
|
||||
0xd7, 0x1d, 0x8e, 0x61, 0x01, 0xb6, 0x57, 0xa9,
|
||||
0xf1, 0xac, 0x15, 0xc2, 0x83, 0x77, 0xca, 0x64,
|
||||
0xca, 0x7b, 0x6c, 0xa1, 0x10, 0x1b, 0x13, 0xd0,
|
||||
0xd3, 0x9e, 0x9e, 0x10, 0x70, 0xc8, 0x1a, 0xbb,
|
||||
0x3f, 0x19, 0x86, 0xab, 0x01, 0x0e, 0xea, 0x34,
|
||||
0x22, 0xea, 0xe2, 0x15, 0xb7, 0xed, 0x21, 0x21,
|
||||
0x75, 0xa5, 0xe7, 0x08, 0xa1, 0x38, 0xe0, 0x91,
|
||||
0x05, 0x60, 0xea, 0xa7, 0x50, 0x27, 0x18, 0x07,
|
||||
0x9d, 0xe0, 0x18, 0x2b, 0xd4, 0x07, 0x59, 0x00,
|
||||
0xe6, 0x45, 0x18, 0x2a, 0x30, 0x6e, 0xf3, 0xb4,
|
||||
0xd0, 0xef, 0xa6, 0x5b, 0x71, 0xa2, 0x5a, 0x3b,
|
||||
0x89, 0x4c, 0xaf, 0x3f, 0xcb, 0x9f, 0x03, 0xfb,
|
||||
0x43, 0x7c, 0x6b, 0xd3, 0x6a, 0xea, 0xce, 0x4a,
|
||||
0x5f, 0x64, 0xb5, 0x62, 0xda, 0x5d, 0x27, 0xb7,
|
||||
0xb8, 0x11, 0xca, 0x33, 0x30, 0xec, 0x70, 0xf0,
|
||||
0x1b, 0x03, 0x50, 0xff, 0x5e, 0xa6, 0x08, 0xde,
|
||||
0x37, 0x70, 0xc0, 0x81, 0x55, 0x60, 0x17, 0xa1,
|
||||
0x85, 0xae, 0x26, 0x44, 0xe4, 0x67, 0x3c, 0x91,
|
||||
0xfd, 0xc4, 0x3d, 0x97, 0x72, 0x23, 0xf3, 0x3c,
|
||||
0x8f, 0xe0, 0xe2, 0xf2, 0x09, 0x96, 0x10, 0x67,
|
||||
0xb5, 0xfe, 0xff, 0x3d, 0x4a, 0xc8, 0x62, 0x11,
|
||||
0xa5, 0x98, 0xc1, 0x2d, 0x40, 0x82, 0x88, 0x8b,
|
||||
0xe5, 0xb0, 0x75, 0xbf, 0x2f, 0xa8, 0x6a, 0x55,
|
||||
0x49, 0x2e, 0x9c, 0x29, 0xd2, 0x7c, 0xbf, 0xf3,
|
||||
0xaa, 0x3a, 0x16, 0x4a, 0xa4, 0x15, 0xf3, 0x48,
|
||||
0xde, 0x38, 0x13, 0x44, 0x26, 0x02, 0xe6, 0xe9,
|
||||
0xa8, 0x24, 0x89, 0xb5, 0x43, 0x95, 0xe4, 0x4c,
|
||||
0xc3, 0xa0, 0xdf, 0xcc, 0x42, 0xf8, 0x8d, 0xb0,
|
||||
0x3b, 0xea, 0x10, 0xb7, 0xe1, 0x40, 0x54, 0xb9,
|
||||
0xa3, 0x2d, 0xfb, 0xb4, 0x91, 0xc0, 0x3e, 0x94,
|
||||
0xf1, 0xa1, 0x3c, 0xbe, 0xef, 0xb8, 0x70, 0x55,
|
||||
0x0a, 0x26, 0x93, 0xbf, 0xe6, 0x21, 0x92, 0x32,
|
||||
0x3c, 0x39, 0x27, 0x6a, 0x23, 0x48, 0x02, 0x35,
|
||||
0x3c, 0xd4, 0xcc, 0x04, 0xc0, 0x4e, 0xa7, 0x02,
|
||||
0x63, 0x37, 0xc2, 0xb8, 0x56, 0x1d, 0x57, 0x57,
|
||||
0x42, 0x04, 0x8d, 0xee, 0xcf, 0x8b, 0xc9, 0xc3,
|
||||
0xba, 0x3b, 0x15, 0xd7, 0xaf, 0xbf, 0x9e, 0xcd,
|
||||
0x44, 0xcf, 0xf0, 0x00, 0xb7, 0x3a, 0xfc, 0xa8,
|
||||
0x12, 0xab, 0x3a, 0x62, 0x01, 0x21, 0x46, 0xe9,
|
||||
0x1e, 0x48, 0x37, 0xfc, 0x13, 0x4d, 0xf6, 0x2a,
|
||||
0x72, 0x40, 0x75, 0x38, 0x71, 0xf2, 0x17, 0x20,
|
||||
0x2c, 0xdd, 0xc0, 0x49, 0xbc, 0x63, 0x33, 0xea,
|
||||
0x06, 0x75, 0x41, 0xe7, 0x5c, 0x1f, 0xfb, 0xf9,
|
||||
0x68, 0x83, 0xc2, 0x5a, 0x4a, 0x1e, 0x61, 0x08,
|
||||
0x57, 0xf3, 0x00, 0xba, 0x77, 0x92, 0x63, 0xa5,
|
||||
0xb7, 0xfe, 0x97, 0x22, 0xda, 0x5e, 0xd3, 0xaf,
|
||||
0xbc, 0x89, 0x0d, 0x4c, 0x37, 0xa9, 0x27, 0x4a,
|
||||
0x7f, 0xdb, 0x81, 0x39, 0x11, 0x86, 0x12, 0xf9,
|
||||
0x10, 0x50, 0xe4, 0xdb, 0x72, 0xf9, 0xae, 0x10,
|
||||
0x7c, 0xed, 0x50, 0x5c, 0x61, 0xeb, 0x42, 0x1e,
|
||||
0xa4, 0xf4, 0xf0, 0xfa, 0x45, 0x4d, 0x95, 0x2b,
|
||||
0xd4, 0x67, 0x4a, 0xe3, 0x8a, 0x15, 0x55, 0x92,
|
||||
0x77, 0x64, 0x8c, 0x51, 0x38, 0xf9, 0x26, 0x3e,
|
||||
0x68, 0xe2, 0xac, 0xbb, 0x64, 0x77, 0xe2, 0x82,
|
||||
0xa4, 0x42, 0x41, 0x38, 0xa0, 0xf0, 0xc9, 0xd8,
|
||||
0x6c, 0xe0, 0xef, 0x4c, 0xda, 0xb4, 0x92, 0xef,
|
||||
0x1b, 0xe3, 0x9b, 0xc1, 0x44, 0x3c, 0xb9, 0xb7,
|
||||
0x39, 0xac, 0x5c, 0x32, 0x39, 0xb4, 0x21, 0x85,
|
||||
0x93, 0xbc, 0xf2, 0x51, 0x43, 0xb7, 0xae, 0x1e,
|
||||
0x61, 0x9c, 0x38, 0x9c, 0xaa, 0xff, 0xde, 0xfc,
|
||||
0xbf, 0x85, 0xef, 0x17, 0x34, 0x36, 0x71, 0x5f,
|
||||
0x04, 0x16, 0xa6, 0x9e, 0xfd, 0x3a, 0x03, 0xd8,
|
||||
0xbf, 0x71, 0x70, 0x20, 0x8f, 0x7c, 0xfb, 0xff,
|
||||
0x61, 0xe0, 0xe2, 0x60, 0xa7, 0xb1, 0xc0, 0xe0,
|
||||
0xd9, 0x3f, 0xdc, 0x8d, 0x4a, 0xa4, 0x52, 0x61,
|
||||
0xaf, 0x9d, 0xdf, 0x8a, 0x0d, 0x41, 0xc0, 0x25,
|
||||
0x68, 0x12, 0x7b, 0xd5, 0xc7, 0xdb, 0x68, 0x70,
|
||||
0x2d, 0x7d, 0x95, 0x12, 0x03, 0x23, 0x0c, 0xe8,
|
||||
0x14, 0x41, 0x11, 0x28, 0xec, 0x9d, 0xd3, 0x28,
|
||||
0x77, 0x7a, 0x3c, 0x93, 0x8e, 0x5c, 0x7e, 0xb3,
|
||||
0x42, 0x9a, 0x18, 0x25, 0x93, 0xc8, 0xea, 0x43,
|
||||
0x1b, 0xbe, 0xd5, 0x27, 0xf1, 0xd4, 0xe0, 0x1e,
|
||||
0xce, 0xc7, 0xc7, 0x2c, 0x25, 0x35, 0x58, 0xb8,
|
||||
0x6c, 0xf3, 0xa2, 0xad, 0xe7, 0x58, 0x49, 0x47,
|
||||
0xf7, 0xca, 0xde, 0x8b, 0x81, 0xb7, 0x75, 0xf4,
|
||||
0x95, 0xa7, 0x5c, 0xc3, 0x2c, 0x0e, 0x1c, 0x52,
|
||||
0x9a, 0xc3, 0x2a, 0x00, 0x21, 0xa7, 0x51, 0x6b,
|
||||
0xf0, 0x05, 0x87, 0x8c, 0x42, 0x1b, 0xc3, 0x2e,
|
||||
0xa3, 0x76, 0x22, 0xd5, 0x7f, 0x56, 0x10, 0xef,
|
||||
0x98, 0x85, 0x65, 0x86, 0x71, 0x87, 0xd2, 0x8c,
|
||||
0xc0, 0x47, 0x20, 0xe8, 0xb5, 0x1c, 0xe3, 0xdd,
|
||||
0x3c, 0x5c, 0x03, 0xbb, 0x0e, 0x97, 0x3b, 0xe1,
|
||||
0x56, 0x9a, 0xd5, 0x0a, 0x63, 0xd5, 0x33, 0xaf,
|
||||
0x36, 0xca, 0xcf, 0x8f, 0x00, 0x28, 0xa3, 0x45,
|
||||
0xb8, 0xcd, 0xde, 0x73, 0xd4, 0xfa, 0x2d, 0x6f,
|
||||
0xdb, 0x93, 0xaa, 0xdd, 0x7f, 0xd2, 0x22, 0x9c,
|
||||
0x96, 0x48, 0x1e, 0xa8, 0x63, 0xbe, 0xbc, 0x0d,
|
||||
0x14, 0x3c, 0x2e, 0x11, 0x1f, 0xd2, 0xf4, 0x57,
|
||||
0xb3, 0x47, 0xf8, 0xa6, 0x1b, 0xc3, 0xa7, 0x95,
|
||||
0x2d, 0xd4, 0xca, 0xb8, 0x0d, 0xfb, 0x06, 0x85,
|
||||
0xda, 0x63, 0xf0, 0x3e, 0x9d, 0x5e, 0xee, 0xce,
|
||||
0xed, 0x74, 0x1d, 0x2c, 0x97, 0x3f, 0x71, 0x95,
|
||||
0x12, 0x03, 0xc5, 0x92, 0x46, 0x84, 0x1b, 0x07,
|
||||
0xe6, 0xb4, 0x1d, 0x3a, 0xf1, 0x89, 0x90, 0x50,
|
||||
0x10, 0x29, 0x34, 0xc0, 0x90, 0xbe, 0x4a, 0xa9,
|
||||
0x0d, 0xb0, 0x7b, 0xfb, 0x35, 0xee, 0x4e, 0x34,
|
||||
0xec, 0x5a, 0x58, 0xbc, 0xb8, 0xda, 0x38, 0x88,
|
||||
0x8c, 0x74, 0x1e, 0xc9, 0xab, 0x78, 0x2e, 0x2a,
|
||||
0x17, 0x8a, 0x43, 0x3d, 0xa1, 0x2a, 0x41, 0xb5,
|
||||
0xd6, 0xe8, 0x5b, 0xc5, 0x4a, 0x1c, 0x3c, 0x9f,
|
||||
0x8d, 0x3a, 0x69, 0x88, 0xf8, 0x80, 0xd2, 0x11,
|
||||
0xfc, 0x7e, 0x80, 0x8e, 0x7f, 0x85, 0x64, 0x9c,
|
||||
0x46, 0x58, 0xc8, 0x48, 0x98, 0x4b, 0xf5, 0x73,
|
||||
0x3f, 0x49, 0xce, 0x53, 0x2c, 0xd5, 0xfc, 0x33,
|
||||
0xf1, 0x6f, 0xd8, 0xe9, 0x2e, 0x70, 0x2e, 0xdc,
|
||||
0xe5, 0x43, 0x80, 0x38, 0xf2, 0x87, 0xed, 0x85,
|
||||
0xe4, 0x3e, 0x45, 0x14, 0x20, 0xcf, 0xa0, 0x61,
|
||||
0x4f, 0xe8, 0xd7, 0x5b, 0xb3, 0x0d, 0x0e, 0x4e,
|
||||
0x4d, 0xce, 0xbe, 0xba, 0xaa, 0x90, 0x09, 0xcb,
|
||||
0x4b, 0x5d, 0x08, 0xff, 0x52, 0xd5, 0x23, 0xbc,
|
||||
0xad, 0x8d, 0xd3, 0x06, 0x4a, 0xa0, 0x51, 0x56,
|
||||
0xa7, 0xd8, 0x33, 0xab, 0xbc, 0xd0, 0xdf, 0x92,
|
||||
0x87, 0x20, 0x2d, 0x7b, 0x5e, 0xfa, 0x30, 0xa7,
|
||||
0x06, 0x06, 0xe5, 0x4f, 0x2c, 0xb5, 0x61, 0xd7,
|
||||
0x54, 0xd3, 0xdf, 0xd0, 0x0a, 0xb0, 0x06, 0xce,
|
||||
0xf6, 0x86, 0xb7, 0x8e, 0xaa, 0x7b, 0x78, 0xd5,
|
||||
0xb9, 0xeb, 0x07, 0xac, 0x5f, 0xc5, 0xd2, 0x8c,
|
||||
0x40, 0xe0, 0x7f, 0x98, 0xd4, 0xe5, 0x4b, 0xca,
|
||||
0xfb, 0x47, 0xef, 0xef, 0xb9, 0x4d, 0x6d, 0x8f,
|
||||
0x82, 0x68, 0x74, 0x84, 0xe0, 0x0a, 0x93, 0x0f,
|
||||
0xb2, 0x01, 0xa9, 0x9f, 0x68, 0x6a, 0xe8, 0xf7,
|
||||
0xfb, 0x0b, 0xde, 0x17, 0xe0, 0x30, 0x38, 0x51,
|
||||
0xbc, 0x07, 0xb8, 0x2c, 0x91, 0x0f, 0xc1, 0x0e,
|
||||
0xa6, 0xf9, 0xf0, 0xd5, 0x48, 0x76, 0x8a, 0xde,
|
||||
0x74, 0xe3, 0x30, 0x65, 0x56, 0xb3, 0x5c, 0xe2,
|
||||
0x89, 0x8d, 0xda, 0x80, 0xad, 0x0f, 0x22, 0xfb,
|
||||
0x24, 0x1d, 0x16, 0xdd, 0x34, 0x4b, 0x90, 0x58,
|
||||
0x4e, 0x0c, 0x13, 0x28, 0xcf, 0x1d, 0xa4, 0xaa,
|
||||
0xb7, 0xf3, 0xb1, 0x66, 0xad, 0x3b, 0xcf, 0x79,
|
||||
0x12, 0x04, 0xd7, 0x79, 0xd9, 0x5f, 0xdf, 0x89,
|
||||
0xb2, 0x5b, 0xa7, 0x9a, 0x26, 0x1e, 0x67, 0x46,
|
||||
0x7c, 0x66, 0x95, 0x67, 0xe6, 0x45, 0x8b, 0x1f,
|
||||
0x65, 0x79, 0x9f, 0x6d, 0x11, 0x81, 0x17, 0x0d,
|
||||
0x11, 0xb0, 0x5c, 0xb4, 0xc7, 0x27, 0x87, 0xab,
|
||||
0x5d, 0x0a, 0x18, 0xae, 0x4e, 0x06, 0xa3, 0x3d,
|
||||
0xc7, 0xb0, 0x22, 0xba, 0x03, 0xa4, 0x0f, 0xe5,
|
||||
0x1c, 0x72, 0x2a, 0x04, 0xce, 0x83, 0xe9, 0xf3,
|
||||
0xd7, 0xc9, 0x67, 0x6c, 0x1e, 0x6b, 0x3c, 0x9b,
|
||||
0x0b, 0x5e, 0x6a, 0xa6, 0x79, 0x0a, 0xf1, 0xbe,
|
||||
0xd7, 0xb4, 0x6f, 0x45, 0x1e, 0xfb, 0x78, 0x97,
|
||||
0xaf, 0x34, 0x76, 0x95, 0x52, 0xf7, 0x3d, 0x5d,
|
||||
0x07, 0x28, 0x57, 0x9c, 0x4a, 0x0f, 0xcf, 0x0b,
|
||||
0x1b, 0xc4, 0xc2, 0x72, 0xd7, 0x72, 0x38, 0x9b,
|
||||
0xea, 0xeb, 0xee, 0xae, 0x34, 0xc8, 0x01, 0xd7,
|
||||
0xa5, 0xe3, 0xce, 0x41, 0xad, 0x02, 0x60, 0x23,
|
||||
0x18, 0x36, 0xba, 0x17, 0xfa, 0xcf, 0xe4, 0xda,
|
||||
0xdc, 0xfc, 0x82, 0xdc, 0x7c, 0x11, 0xf4, 0xb8,
|
||||
0x52, 0x5d, 0xf7, 0x2f, 0xc8, 0xfe, 0x4a, 0xe6,
|
||||
0xb9, 0xaf, 0x4b, 0x17, 0x18, 0x91, 0xc2, 0xfe,
|
||||
0xd7, 0x3a, 0x77, 0x0c, 0xa0, 0x43, 0x9c, 0x6f,
|
||||
0x13, 0x06, 0xbe, 0x6e, 0xe0, 0x1a, 0x3c, 0xf3,
|
||||
0xf5, 0xcc, 0x78, 0xfb, 0x5d, 0xd5, 0xda, 0xb7,
|
||||
0x58, 0xea, 0x86, 0x42, 0x6b, 0x32, 0xff, 0xb2,
|
||||
0xe2, 0xee, 0x03, 0x1f, 0xf4, 0xef, 0xdb, 0x53,
|
||||
0x79, 0xd5, 0x4e, 0xaf, 0x60, 0x8e, 0x02, 0xc2,
|
||||
0xcc, 0x39, 0x97, 0x7b, 0xfd, 0xa1, 0xf8, 0x7a,
|
||||
0x26, 0xe8, 0x55, 0xd6, 0xa4, 0x8b, 0xa0, 0x1b,
|
||||
0x2d, 0x63, 0xaa, 0x73, 0x71, 0x6e, 0xbf, 0x8b,
|
||||
0x3b, 0xe3, 0x1b, 0x0d, 0xbb, 0x2e, 0x44, 0x09,
|
||||
0x64, 0xac, 0xc7, 0x9e, 0xb5, 0xc6, 0x77, 0xb0,
|
||||
0x79, 0xb3, 0xaa, 0xfc, 0x67, 0x57, 0x9a, 0x50,
|
||||
0x81, 0x37, 0x14, 0x7c, 0xd7, 0xa0, 0xd4, 0x6a,
|
||||
0x79, 0x84, 0x51, 0x0e, 0x95, 0x0a, 0x30, 0xa3,
|
||||
0x60, 0x55, 0x48, 0x05, 0x16, 0xae, 0x43, 0x90,
|
||||
0xdc, 0x8e, 0x09, 0xbe, 0x79, 0xf6, 0x90, 0x74,
|
||||
0xf8, 0x20, 0x96, 0x4d, 0xa7, 0xf5, 0x1a, 0x2b,
|
||||
0xc7, 0x15, 0x9d, 0x18, 0xf7, 0x94, 0x87, 0xf7,
|
||||
0xf4, 0xfb, 0x0d, 0x61, 0xb6, 0xd7, 0xbe, 0x10,
|
||||
0x8e, 0x47, 0x3c, 0x10, 0x44, 0x90, 0x52, 0x21,
|
||||
0x83, 0xc0, 0xf5, 0x99, 0xaa, 0xbc, 0xf6, 0x55,
|
||||
0xae, 0xf5, 0xb2, 0xa4, 0xcd, 0x4d, 0xb9, 0x38,
|
||||
0x6c, 0xbc, 0x80, 0xc3, 0xad, 0xf4, 0x46, 0x31,
|
||||
0x01, 0x58, 0x2d, 0x88, 0x57, 0xc3, 0x23, 0xd1,
|
||||
0x64, 0xc9, 0xa3, 0x21, 0x6b, 0x8b, 0x8a, 0x23,
|
||||
0x2c, 0x4f, 0xa9, 0xcd, 0x67, 0xfa, 0x77, 0xad,
|
||||
0xa3, 0x16, 0xa2, 0xe5, 0x19, 0x14, 0x70, 0x41,
|
||||
0x5b, 0xda, 0x14, 0xde, 0xe3, 0xe5, 0xc1, 0x15,
|
||||
0xb4, 0x77, 0xa4, 0x9b, 0xb8, 0xb1, 0x28, 0x51,
|
||||
0x30, 0xb4, 0xf1, 0xf3, 0xf8, 0x6d, 0xd0, 0xc3,
|
||||
0x8c, 0x4c, 0x76, 0xb0, 0x9a, 0xdf, 0xc8, 0xbe,
|
||||
0xf8, 0x4a, 0x61, 0x6e, 0x3e, 0xd6, 0x3c, 0xe8,
|
||||
0xde, 0x56, 0xa0, 0x9c, 0x25, 0xbe, 0xce, 0x93,
|
||||
0x1f, 0x88, 0xfb, 0x9a, 0x1a, 0xe2, 0xff, 0x88,
|
||||
0xad, 0x10, 0xcb, 0x6c, 0xd6, 0xe7, 0x39, 0x0b,
|
||||
0xe5, 0x1a, 0x06, 0x05, 0x64, 0x5b, 0x0a, 0xdf,
|
||||
0x22, 0x58, 0xd7, 0xfb, 0x88, 0x12, 0xdd, 0xb7,
|
||||
0x52, 0x3a, 0xc9, 0xbf, 0x49, 0xdf, 0x8c, 0x87,
|
||||
0x9f, 0x84, 0xb5, 0x0a, 0xf6, 0x00, 0x52, 0xae,
|
||||
0x67, 0x12, 0x1a, 0x8c, 0x71, 0x15, 0xf5, 0xa1,
|
||||
0x13, 0x39, 0xf0, 0x91, 0x7e, 0x88, 0x7c, 0xb3,
|
||||
0x95, 0x50, 0x02, 0xa6, 0x63, 0xb5, 0x64, 0xfb,
|
||||
0x90, 0x87, 0x61, 0xe2, 0x27, 0xaf, 0x11, 0x0c,
|
||||
0x73, 0x83, 0xef, 0xa9, 0x28, 0xfe, 0xc8, 0x85,
|
||||
0x1a, 0x3a, 0xde, 0xf2, 0xe5, 0x25, 0x64, 0x6d,
|
||||
0xaa, 0x41, 0x4c, 0x80, 0x2e, 0x84, 0xff, 0xc1,
|
||||
0xc0, 0x54, 0x0c, 0x29, 0x1b, 0xa3, 0x07, 0x7c,
|
||||
0x33, 0x4c, 0x10, 0xf6, 0x6f, 0x79, 0xdf, 0xd3,
|
||||
0xf0, 0x24, 0x57, 0xf1, 0x60, 0xe1, 0xf0, 0xbd,
|
||||
0xc4, 0x1f, 0xf4, 0x67, 0xd2, 0xd3, 0xcc, 0x6a,
|
||||
0x07, 0x72, 0x44, 0x16, 0x85, 0x46, 0xd0, 0x73,
|
||||
0x87, 0xa9, 0xc7, 0x2f, 0xd1, 0xf5, 0xec, 0xe3,
|
||||
0x28, 0xa3, 0x93, 0x4f, 0xd7, 0x76, 0xc1, 0x3c,
|
||||
0x0d, 0x13, 0x33, 0xcf, 0x5b, 0xbd, 0x6a, 0x52,
|
||||
0x4e, 0xee, 0xc8, 0x5e, 0xa1, 0x58, 0x4a, 0x08,
|
||||
0x81, 0xd9, 0x23, 0xcc, 0xfb, 0x1c, 0xb2, 0xd8,
|
||||
0xa3, 0xe4, 0x53, 0xfe, 0xf4, 0x4b, 0x48, 0xc1,
|
||||
0x20, 0xa4, 0x97, 0xf8, 0x38, 0xa3, 0x69, 0xc1,
|
||||
0x11, 0xf0, 0xa1, 0x3b, 0xa9, 0x9a, 0x12, 0x61,
|
||||
0xe8, 0x8d, 0x99, 0x44, 0x3f, 0x94, 0x72, 0x82,
|
||||
0x19, 0x96, 0x62, 0xb0, 0xa6, 0x64, 0x05, 0x19,
|
||||
0x8f, 0xd6, 0x5d, 0x05, 0xbf, 0x79, 0x9e, 0x9d,
|
||||
0xe4, 0x93, 0x4c, 0xad, 0x61, 0x8c, 0x18, 0xda,
|
||||
0xb6, 0x2e, 0xb3, 0xca, 0x14, 0x4d, 0x53, 0xa4,
|
||||
0x97, 0x27, 0x10, 0x56, 0xa2, 0x67, 0x5a, 0x5a,
|
||||
0x5e, 0x13, 0xc0, 0xdb, 0xa7, 0x9f, 0x45, 0x5b,
|
||||
0xeb, 0x1a, 0x14, 0x0c, 0x8c, 0x38, 0x5e, 0x77,
|
||||
0x9a, 0xec, 0x75, 0x68, 0x93, 0x65, 0x02, 0x9c,
|
||||
0xfb, 0x62, 0x60, 0x49, 0xdd, 0xb2, 0x2a, 0x67,
|
||||
0x86, 0xe3, 0x8a, 0x7d, 0x8c, 0x46, 0x78, 0x81,
|
||||
0x60, 0x69, 0xf2, 0x3f, 0x74, 0x11, 0x35, 0xff,
|
||||
0x77, 0xa3, 0x66, 0x20, 0xfc, 0x98, 0x4a, 0x35,
|
||||
0x7a, 0x52, 0xe4, 0x90, 0x13, 0x80, 0xb9, 0xa6,
|
||||
0x73, 0x7a, 0x7d, 0x66, 0x6e, 0x6b, 0xb6, 0x43,
|
||||
0x10, 0xd5, 0x91, 0x2b, 0x66, 0xdd, 0x89, 0x87,
|
||||
0xe3, 0x8c, 0x58, 0x53, 0x2f, 0x40, 0x74, 0x45,
|
||||
0x1b, 0x77, 0x7a, 0xa4, 0x44, 0x19, 0x78, 0xba,
|
||||
0x87, 0x10, 0x41, 0x31, 0x32, 0x5f, 0x87, 0x68,
|
||||
0xde, 0x43, 0x4a, 0xef, 0x33, 0xb3, 0x11, 0x83,
|
||||
0xa9, 0xc2, 0x6f, 0x8d, 0x34, 0xe2, 0x95, 0x84,
|
||||
0x3a, 0x4f, 0x6f, 0x8c, 0x31, 0x1d, 0xb6, 0xf5,
|
||||
0x95, 0x0d, 0x01, 0x11, 0x20, 0xdf, 0x72, 0xf3,
|
||||
0x3f, 0x9a, 0x33, 0xaa, 0xb1, 0x06, 0x6a, 0x63,
|
||||
0x47, 0x91, 0x01, 0xdf, 0xb3, 0x54, 0x36, 0xfd,
|
||||
0x06, 0x2d, 0xb8, 0x08, 0xe3, 0xd3, 0x65, 0xac,
|
||||
0x66, 0x03, 0xee, 0xa4, 0x63, 0xbd, 0xd4, 0xce,
|
||||
0xbd, 0x79, 0xa7, 0x48, 0x38, 0xc5, 0x7d, 0xb5,
|
||||
0x71, 0x9a, 0x3c, 0x11, 0x7c, 0x6c, 0xe2, 0x54,
|
||||
0x02, 0x5d, 0x42, 0xab, 0x25, 0x93, 0x66, 0x01,
|
||||
0x37, 0x78, 0x35, 0x4a, 0x8c, 0x19, 0x4d, 0x00,
|
||||
0x75, 0x4f, 0xcc, 0xc0, 0x26, 0x82, 0xc1, 0x35,
|
||||
0x8c, 0xc7, 0xc2, 0x59, 0x01, 0x3e, 0x98, 0x22,
|
||||
0x88, 0x9c, 0x90, 0x75, 0x05, 0x33, 0x07, 0xb9,
|
||||
0x39, 0x81, 0x38, 0x58, 0x10, 0x29, 0xcf, 0xc8,
|
||||
0x98, 0xb2, 0x03, 0xd7, 0x5b, 0xb3, 0x18, 0xba,
|
||||
0x34, 0x0c, 0x9f, 0xab, 0xd7, 0xed, 0x29, 0x82,
|
||||
0x41, 0xe0, 0x20, 0x97, 0x57, 0x92, 0xb2, 0xb8,
|
||||
0x10, 0x2d, 0x0b, 0xa2, 0xc5, 0x8f, 0x90, 0x6f,
|
||||
0xed, 0x12, 0x56, 0x25, 0xbe, 0xfd, 0x75, 0xf7,
|
||||
0xb6, 0xf8, 0x40, 0x67, 0x39, 0x11, 0xfa, 0x15,
|
||||
0xae, 0x6a, 0x54, 0x5f, 0x32, 0x2b, 0xf8, 0x48,
|
||||
0x55, 0xbe, 0x86, 0x2f, 0x69, 0x48, 0x5b, 0x5d,
|
||||
0x4d, 0xb7, 0x35, 0xaa, 0xb6, 0x91, 0x88, 0x19,
|
||||
0x96, 0x1c, 0x68, 0xf6, 0x85, 0x9e, 0xb3, 0xb2,
|
||||
0xa3, 0x32, 0xd4, 0x52, 0x70, 0xb7, 0x62, 0xe3,
|
||||
0x14, 0xb6, 0x78, 0x5f, 0x1b, 0x1d, 0x04, 0x9c,
|
||||
0x26, 0x0c, 0x33, 0x94, 0xb1, 0x97, 0x08, 0xdb,
|
||||
0x0b, 0x39, 0x29, 0xd4, 0xbc, 0x6d, 0xdf, 0x02,
|
||||
0xc6, 0x99, 0xab, 0x99, 0x32, 0xe5, 0xce, 0x51,
|
||||
0x4f, 0xae, 0xb8, 0x8b, 0xe0, 0xaf, 0x07, 0xc4,
|
||||
0xf9, 0x41, 0x7c, 0x59, 0xa0, 0xac, 0x74, 0x4d,
|
||||
0x7e, 0x43, 0x77, 0x9c, 0x06, 0x49, 0x79, 0x8a,
|
||||
0x14, 0x73, 0x93, 0xa8, 0x5b, 0x1b, 0x34, 0x29,
|
||||
0x78, 0x04, 0x2f, 0xd7, 0x1f, 0x13, 0x90, 0xe0,
|
||||
0xdd, 0x3b, 0x42, 0x6b, 0x79, 0x6e, 0x52, 0xc7,
|
||||
0x0f, 0x38, 0xda, 0x01, 0x2c, 0x8d, 0xe6, 0x94,
|
||||
0x5d, 0x59, 0x27, 0x1d, 0x10, 0x4e, 0x11, 0x36,
|
||||
0xfb, 0x53, 0x16, 0x05, 0x25, 0xf2, 0x64, 0xd8,
|
||||
0xf9, 0xcd, 0x5c, 0xfe, 0xb4, 0x18, 0x44, 0x80,
|
||||
0x10, 0xbc, 0x3d, 0xf3, 0x1d, 0x5a, 0xf0, 0xc1,
|
||||
0xc3, 0x55, 0xff, 0x41, 0x3e, 0xe3, 0xef, 0x44,
|
||||
0xb2, 0xc0, 0x01, 0x18, 0xa2, 0x49, 0x88, 0x78,
|
||||
0x0d, 0x4c, 0xc8, 0x73, 0xcf, 0x30, 0x85, 0x3a,
|
||||
0x88, 0x90, 0x01, 0xcf, 0x69, 0x53, 0xa3, 0x18,
|
||||
0x3f, 0xd6, 0xe7, 0x94, 0x14, 0xa7, 0xae, 0xcd,
|
||||
0x6f, 0x11, 0x72, 0xfe, 0x2b, 0xb0, 0x81, 0x53,
|
||||
0xea, 0x67, 0xd6, 0xe4, 0xca, 0x42, 0xa0, 0xf9,
|
||||
0xb1, 0xd4, 0xb5, 0x3b, 0xc9, 0xf0, 0x36, 0xc1,
|
||||
0x1c, 0xf4, 0xb1, 0xf6, 0x84, 0xd0, 0x86, 0x6c,
|
||||
0x76, 0x9a, 0x03, 0xc2, 0xb6, 0x2e, 0x9a, 0x46,
|
||||
0xf5, 0x5f, 0x2c, 0x38, 0xac, 0xad, 0x6f, 0x2e,
|
||||
0x7a, 0x18, 0x2d, 0x22, 0x95, 0x5e, 0x5e, 0xc9,
|
||||
0x7a, 0x0a, 0x56, 0xe1, 0xc7, 0x15, 0xfd, 0xbf,
|
||||
0xff, 0xf7, 0x7e, 0x85, 0x20, 0xa9, 0x8a, 0x9c,
|
||||
0xa9, 0x7d, 0xe8, 0xed, 0xfc, 0x7f, 0xbb, 0xf0,
|
||||
0x05, 0x3f, 0xce, 0x4f, 0x4c, 0xee, 0xa4, 0xa0,
|
||||
0xcc, 0x9c, 0x62, 0x1e, 0xd6, 0xd0, 0x30, 0x37,
|
||||
0xb8, 0x98, 0x56, 0x1d, 0xaa, 0xd6, 0x5e, 0x73,
|
||||
0x12, 0xe4, 0x88, 0x82, 0x48, 0x64, 0x06, 0xd7,
|
||||
0x2a, 0x31, 0x50, 0x7b, 0x10, 0x17, 0xb8, 0x4c,
|
||||
0x5a, 0x8d, 0xf1, 0xfc, 0xf1, 0x33, 0x3b, 0x98,
|
||||
0x42, 0x18, 0x5b, 0x35, 0x78, 0xca, 0x8e, 0x41,
|
||||
0x52, 0xae, 0x6d, 0xe1, 0xa2, 0x9d, 0x5b, 0xbd,
|
||||
0xf3, 0x5f, 0x49, 0xc1, 0x27, 0x06, 0xc1, 0xaf,
|
||||
0xc0, 0xa3, 0x9d, 0xf3, 0x1c, 0x8e, 0x90, 0x8a,
|
||||
0xb0, 0x69, 0xb0, 0xc5, 0x11, 0x0c, 0x91, 0x14,
|
||||
0x1f, 0x5e, 0x10, 0xe1, 0x1d, 0x14, 0x30, 0x54,
|
||||
0x1e, 0x17, 0x3d, 0x31, 0x7b, 0xbf, 0x2f, 0x9d,
|
||||
0x6d, 0x63, 0x32, 0xf0, 0x9d, 0x9f, 0x95, 0x3d,
|
||||
0x0b, 0xd2, 0x4d, 0x10, 0xe2, 0x3f, 0x67, 0x69,
|
||||
0x43, 0x9a, 0x4a, 0x2c, 0x54, 0x71, 0xa8, 0xa0,
|
||||
0x9e, 0x9f, 0x10, 0xaf, 0x1b, 0xce, 0x99, 0xe3,
|
||||
0x25, 0x32, 0x10, 0x54, 0x80, 0xfe, 0xda, 0x57,
|
||||
0xd0, 0xb2, 0x92, 0x7f, 0xbb, 0x5f, 0xe7, 0x4d,
|
||||
0x1b, 0x3d, 0x46, 0x4d, 0xe4, 0x4c, 0xd6, 0xaf,
|
||||
0x1a, 0x32, 0x12, 0x40, 0xb8, 0x84, 0x8e, 0xe4,
|
||||
0x80, 0xce, 0x7e, 0xc1, 0x13, 0x8b, 0xb0, 0xb7,
|
||||
0x6f, 0x24, 0xba, 0x85, 0x50, 0x83, 0xc3, 0xcf,
|
||||
0x19, 0xb3, 0xf0, 0xc7, 0xee, 0x68, 0xbe, 0x9e,
|
||||
0x6d, 0xb9, 0xfb, 0xd5, 0x29, 0xce, 0x82, 0xcd,
|
||||
0x69, 0x16, 0x68, 0x6b, 0x6a, 0xf4, 0x02, 0x32,
|
||||
0xce, 0x60, 0x37, 0x0c, 0xb9, 0x38, 0x92, 0x9c,
|
||||
0x42, 0xa9, 0x0b, 0x53, 0x96, 0xfe, 0x39, 0xc1,
|
||||
0x24, 0x65, 0x9b, 0xcd, 0xe7, 0x8d, 0x36, 0x07,
|
||||
0x9f, 0x1d, 0x35, 0x8e, 0xdc, 0x4c, 0xb5, 0x68,
|
||||
0xc5, 0xfd, 0x44, 0x19, 0xf2, 0x6c, 0x59, 0x1c,
|
||||
0xb1, 0x0b, 0x35, 0x48, 0x86, 0x1a, 0x05, 0x22,
|
||||
0x03, 0x0c, 0x0c, 0xa2, 0x92, 0x90, 0x35, 0xfb,
|
||||
0x37, 0x94, 0xc7, 0x15, 0x84, 0xae, 0xe8, 0x05,
|
||||
0xa0, 0xf7, 0x30, 0x11, 0x5c, 0xe4, 0x5d, 0x3e,
|
||||
0x12, 0x54, 0x80, 0x54, 0x6b, 0x09, 0x8c, 0xce,
|
||||
0x80, 0x5e, 0xa7, 0xc8, 0x6a, 0x0c, 0x56, 0xe1,
|
||||
0x18, 0x7d, 0xc9, 0x39, 0xc1, 0xef, 0xe3, 0x25,
|
||||
0xa0, 0x8b, 0x2f, 0x60, 0x3a, 0x43, 0x39, 0xa6,
|
||||
0x28, 0x28, 0x7b, 0x4c, 0x77, 0xd4, 0x49, 0x61,
|
||||
0x46, 0xe9, 0x1b, 0x45, 0xd6, 0xb1, 0x56, 0xe1,
|
||||
0x7d, 0x34, 0xcd, 0x06, 0xb6, 0x67, 0x8d, 0x7d,
|
||||
0x7a, 0xe2, 0xbe, 0x68, 0x35, 0xa6, 0x78, 0xe5,
|
||||
0x47, 0x48, 0xb7, 0xc7, 0xde, 0xcd, 0xc9, 0x05,
|
||||
0xb4, 0xe7, 0x50, 0x48, 0xe1, 0x4b, 0xfe, 0x76,
|
||||
0x77, 0xc6, 0xf7, 0x5f, 0xcb, 0xc2, 0xa8, 0xd7,
|
||||
0xd6, 0x8a, 0xe5, 0x49, 0xd9, 0xca, 0x45, 0xf4,
|
||||
0xda, 0xcd, 0x33, 0xd1, 0x59, 0x2d, 0x9e, 0xc1,
|
||||
0x5c, 0xe6, 0x01, 0x18, 0xb8, 0xf0, 0x5e, 0xb1,
|
||||
0x69, 0x95, 0x2f, 0x02, 0x2a, 0xe7, 0x4a, 0xd7,
|
||||
0xd1, 0xc3, 0xd5, 0x6f, 0x15, 0xc8, 0xdc, 0x29,
|
||||
0xde, 0xb9, 0x3f, 0x8b, 0xa6, 0xbc, 0xdd, 0x25,
|
||||
0x84, 0x35, 0x3c, 0x90, 0x2d, 0xc2, 0x1e, 0x98,
|
||||
0x8a, 0x50, 0x09, 0x77, 0x42, 0xe9, 0x35, 0x8a,
|
||||
0x7c, 0x97, 0xbf, 0xe8, 0xbf, 0x56, 0xd0, 0x8b,
|
||||
0x65, 0xd3, 0xaf, 0x1e, 0x05, 0x94, 0xfa, 0xac,
|
||||
0xa8, 0x2b, 0x28, 0xcb, 0x37, 0x3e, 0xe8, 0xbb,
|
||||
0x66, 0x3a, 0xed, 0xb2, 0x48, 0x10, 0x0f, 0x3a,
|
||||
0x5a, 0xc5, 0xdb, 0x26, 0x0e, 0xaa, 0x5e, 0x69,
|
||||
0x15, 0xd6, 0x81, 0xae, 0xbd, 0xe6, 0x03, 0xf1,
|
||||
0xf6, 0x37, 0xc8, 0xde, 0x70, 0x1f, 0x64, 0xb9,
|
||||
0x5e, 0xbf, 0x2e, 0x4f, 0xb1, 0xea, 0xa0, 0x17,
|
||||
0xe6, 0x7c, 0xf9, 0x2f, 0x1e, 0xd8, 0x58, 0xde,
|
||||
0xa7, 0xf0, 0x46, 0x52, 0x95, 0xdf, 0xa4, 0x96,
|
||||
0xd0, 0xc4, 0x97, 0x2b, 0x95, 0xcd, 0x5e, 0x40,
|
||||
0x23, 0x5c, 0x10, 0xee, 0xba, 0x72, 0x9b, 0xcf,
|
||||
0x0b, 0xe8, 0x18, 0x3a, 0x70, 0xd2, 0x5e, 0x07,
|
||||
0x68, 0x93, 0xef, 0x4a, 0x5b, 0x8d, 0x72, 0x41,
|
||||
0x4e, 0xea, 0x33, 0x6a, 0x0a, 0x5e, 0xfb, 0x02,
|
||||
0x3f, 0xd4, 0xed, 0x5b, 0xe0, 0x42, 0x84, 0xd4,
|
||||
0xaa, 0x85, 0xdc, 0x5b, 0x67, 0xee, 0x71, 0x67,
|
||||
0xba, 0x8e, 0xd2, 0xbe, 0x61, 0xdf, 0x5a, 0x26,
|
||||
0xb9, 0xf0, 0x77, 0x81, 0x53, 0x24, 0x16, 0xcb,
|
||||
0x8c, 0xb8, 0x06, 0x6e, 0x68, 0xda, 0xc8, 0x2d,
|
||||
0x17, 0x54, 0xdb, 0x46, 0xcb, 0xfd, 0x1f, 0x3d,
|
||||
0x94, 0x81, 0x09, 0x4b, 0xfa, 0xb1, 0x46, 0xd9,
|
||||
0x11, 0xa3, 0xb7, 0x31, 0x9c, 0xd2, 0x38, 0xd6,
|
||||
0xba, 0x3d, 0xa3, 0x74, 0xd8, 0xf1, 0x24, 0xe8,
|
||||
0x9c, 0xcb, 0x1d, 0xf9, 0x4a, 0xf7, 0xc8, 0x4b,
|
||||
0xfe, 0x97, 0x7c, 0xa1, 0x02, 0xeb, 0x40, 0xc3,
|
||||
0x89, 0x71, 0x01, 0xcd, 0x33, 0x2a, 0xc2, 0x82,
|
||||
0xce, 0x62, 0x8d, 0x53, 0x7c, 0xdf, 0xce, 0xd7,
|
||||
0xf5, 0xa8, 0x4f, 0xf2, 0xf2, 0x2e, 0xc1, 0xeb,
|
||||
0x97, 0x99, 0x37, 0x3c, 0x53, 0xa6, 0xb4, 0x46,
|
||||
0x05, 0x64, 0x92, 0x87, 0x08, 0x3c, 0x23, 0x4b,
|
||||
0x9d, 0x67, 0x18, 0xf9, 0xe2, 0x0b, 0x1c, 0x39,
|
||||
0xd3, 0x87, 0x70, 0xc0, 0xb9, 0x1e, 0x52, 0x0a,
|
||||
0x0f, 0x48, 0xe2, 0xe7, 0x51, 0x72, 0x94, 0xf7,
|
||||
0xa3, 0xdc, 0xe5, 0x66, 0x33, 0x39, 0x54, 0x06,
|
||||
0x55, 0x93, 0x30, 0xf9, 0x5e, 0x76, 0x8f, 0xe0,
|
||||
0x59, 0x4d, 0x0d, 0xa7, 0xf5, 0xbe, 0xdb, 0x20,
|
||||
0xad, 0x0d, 0x76, 0x88, 0x5f, 0x9c, 0x7c, 0x75,
|
||||
0x2f, 0x2a, 0x0b, 0x79, 0x6e, 0xd3, 0xe2, 0x66,
|
||||
0xf5, 0x4a, 0x2d, 0x87, 0x87, 0x49, 0x84, 0x17,
|
||||
0xa2, 0x62, 0x4c, 0xbb, 0xe4, 0x6e, 0x98, 0x10,
|
||||
0xc9, 0xfb, 0x8a, 0x04, 0x68, 0x8d, 0x22, 0x66,
|
||||
0xad, 0xea, 0x2a, 0xc9, 0x97, 0x2d, 0x3c, 0xbc,
|
||||
0xd0, 0x77, 0x5f, 0xe6, 0xb8, 0x7f, 0xe6, 0xf6,
|
||||
0x39, 0xbf, 0x56, 0x0e, 0x26, 0x6d, 0xc5, 0x3e,
|
||||
0x53, 0x19, 0xd6, 0xb4, 0x57, 0x36, 0xa3, 0xc6,
|
||||
0xd3, 0x3d, 0x66, 0x79, 0x30, 0x5c, 0x14, 0x0c,
|
||||
0x0f, 0x3e, 0x96, 0xae, 0x90, 0x97, 0xab, 0x0d,
|
||||
0x9f, 0xc3, 0xe7, 0x66, 0x3e, 0xe0, 0x31, 0x43,
|
||||
0x4b, 0x01, 0xb3, 0x0e, 0x9e, 0x8c, 0x82, 0x4a,
|
||||
0x8c, 0xc7, 0x79, 0x85, 0xdf, 0x75, 0x0d, 0xb4,
|
||||
0x2b, 0x03, 0x14, 0xef, 0x72, 0x58, 0xfd, 0x64,
|
||||
0xc8, 0xe3, 0x0d, 0x9a, 0x14, 0x6f, 0x76, 0xf9,
|
||||
0x46, 0xd1, 0xd2, 0x81, 0xb3, 0x16, 0x6e, 0xc7,
|
||||
0x76, 0x82, 0xce, 0xf4, 0xee, 0x33, 0x00, 0xe6,
|
||||
0x77, 0xc4, 0xad, 0x4f, 0x06, 0xa7, 0x48, 0x80,
|
||||
0x9e, 0x21, 0x66, 0xca, 0x75, 0x69, 0x57, 0xcb,
|
||||
0xf0, 0x67, 0x6a, 0xaa, 0x8f, 0x88, 0x14, 0xbd,
|
||||
0x65, 0x62, 0xe2, 0xad, 0xcc, 0x22, 0x88, 0x7b,
|
||||
0x94, 0xbd, 0x0e, 0xcd, 0xb6, 0x69, 0xa2, 0xcb,
|
||||
0x7d, 0x57, 0x5c, 0xb4, 0x92, 0x80, 0x13, 0x99,
|
||||
0x84, 0xf3, 0x79, 0x0a, 0x2d, 0x70, 0xa4, 0xe0,
|
||||
0xde, 0xc6, 0x32, 0xb0, 0x8a, 0x62, 0xb5, 0xcf,
|
||||
0xfa, 0x5e, 0x5a, 0x92, 0x32, 0x7d, 0x34, 0x07,
|
||||
0xb5, 0x52, 0x3a, 0xb5, 0x7d, 0x0f, 0xa1, 0xba,
|
||||
0x56, 0xd0, 0x07, 0x76, 0x11, 0xf2, 0xc3, 0x33,
|
||||
0x9d, 0xbd, 0x12, 0x35, 0x5e, 0xf7, 0x05, 0x88,
|
||||
0x76, 0x94, 0xa6, 0xbf, 0xed, 0xb8, 0xa4, 0xa2,
|
||||
0x0c, 0xbe, 0x0f, 0x6a, 0xaf, 0xf3, 0x1b, 0x33,
|
||||
0x4a, 0xb7, 0x68, 0x3f, 0xbe, 0x95, 0x13, 0x97,
|
||||
0x0f, 0x15, 0x17, 0x1b, 0x23, 0xaa, 0x08, 0x78,
|
||||
0xa6, 0x5b, 0x08, 0xa2, 0x9d, 0x03, 0xa8, 0xa7,
|
||||
0x39, 0xdc, 0xbc, 0x9a, 0x85, 0xf5, 0xe5, 0x55,
|
||||
0x59, 0x3c, 0xef, 0xf9, 0x3f, 0x22, 0x8e, 0xf8,
|
||||
0xd8, 0x3e, 0x02, 0x0b, 0xd8, 0x78, 0x4b, 0x15,
|
||||
0x7f, 0xaa, 0x2c, 0xff, 0xbe, 0x77, 0x33, 0xc7,
|
||||
0x6a, 0x12, 0xaa, 0xa4, 0xbe, 0xc0, 0x3b, 0xcb,
|
||||
0x13, 0x9d, 0x9c, 0x5a, 0x9f, 0x8a, 0x57, 0x36,
|
||||
0x4f, 0x02, 0x5a, 0xf8, 0x1d, 0x97, 0x77, 0x43,
|
||||
0xc8, 0xa5, 0xb7, 0x9b, 0x10, 0x98, 0xfd, 0x58,
|
||||
0xbf, 0x42, 0xf6, 0xbf, 0xff, 0x6c, 0x40, 0x18,
|
||||
0x18, 0xdf, 0xac, 0x57, 0x71, 0xea, 0xcc, 0x8e,
|
||||
0xfd, 0xfe, 0x10, 0xfb, 0xb9, 0xfe, 0xbc, 0x9a,
|
||||
0x9c, 0x27, 0xe4, 0x10, 0x15, 0x94, 0x41, 0xa1,
|
||||
0xcc, 0xf6, 0x25, 0x49, 0x4f, 0x96, 0xc1, 0x8c,
|
||||
0x9e, 0x3e, 0x18, 0x29, 0x49, 0x92, 0xe7, 0xfe,
|
||||
0x22, 0xff, 0xed, 0x02, 0x16, 0x90, 0xef, 0xac,
|
||||
0xec, 0x95, 0x1d, 0x5b, 0x94, 0x9c, 0xf6, 0x7c,
|
||||
0x1b, 0x5a, 0x9d, 0xb0, 0x9b, 0x05, 0x36, 0xbf,
|
||||
0xef, 0xec, 0x63, 0x35, 0x40, 0x24, 0x45, 0x40,
|
||||
0x30, 0x1a, 0x9b, 0x90, 0xc3, 0xc2, 0xf7, 0x37,
|
||||
0xfb, 0x08, 0x8e, 0x48, 0x19, 0x48, 0xed, 0xa8,
|
||||
0xa8, 0x04, 0x6f, 0xd0, 0x33, 0xe9, 0xb8, 0x8d,
|
||||
0xe7, 0x1e, 0x5c, 0x47, 0x74, 0xc0, 0x66, 0x30,
|
||||
0x4e, 0xa7, 0x86, 0x73, 0xf1, 0xe5, 0x78, 0xa6,
|
||||
0xe0, 0xc1, 0xda, 0x13, 0x72, 0x07, 0x85, 0x34,
|
||||
0x63, 0x95, 0x49, 0x30, 0x4b, 0x9d, 0x03, 0xf1,
|
||||
0x7a, 0x6b, 0x91, 0xa2, 0x85, 0x41, 0xf9, 0x4a,
|
||||
0xd6, 0xff, 0xff, 0x86, 0xf7, 0xf0, 0xce, 0xb9,
|
||||
0x07, 0xf1, 0x88, 0x04, 0x33, 0xaa, 0xeb, 0x54,
|
||||
0xb2, 0x1c, 0x8e, 0x2e, 0x7b, 0x04, 0xa8, 0xcc,
|
||||
0x2c, 0x7a, 0xb3, 0xad, 0x1a, 0x89, 0x38, 0x89,
|
||||
0xd7, 0x11, 0x3a, 0x8c, 0xcf, 0xe3, 0xc5, 0xba,
|
||||
0xb0, 0xcc, 0xc4, 0xe3, 0x33, 0xf3, 0x18, 0xba,
|
||||
0xec, 0x56, 0xd9, 0x1c, 0x40, 0x70, 0x0d, 0x4e,
|
||||
0x97, 0x01, 0x23, 0xf3, 0x5a, 0xdc, 0xbf, 0x68,
|
||||
0x93, 0xc2, 0x1d, 0x8a, 0x96, 0xb7, 0xac, 0x18,
|
||||
0x6f, 0xf7, 0x84, 0x71, 0x0d, 0x3d, 0xf8, 0xba,
|
||||
0xdf, 0xb6, 0x89, 0x1d, 0x78, 0x19, 0xf2, 0x59,
|
||||
0xe9, 0x15, 0x55, 0x29, 0x73, 0x50, 0x59, 0x14,
|
||||
0x02, 0x21, 0x16, 0x8f, 0x0f, 0xdf, 0xa5, 0xf0,
|
||||
};
|
||||
|
||||
static struct crc_test {
|
||||
uint32_t crc; /* random starting crc */
|
||||
uint32_t start; /* random offset in buf */
|
||||
uint32_t length; /* random length of test */
|
||||
uint32_t crc32c_le; /* expected crc32c_le result */
|
||||
uint32_t crc32_be; /* expected crc32_be result */
|
||||
} test[] = {
|
||||
{0xffffffff, 0x00000000, 0x00001000, 0x13934bef, 0xd8ddcdc3},
|
||||
{0xfe7328ea, 0x00000763, 0x00000717, 0xed2c0d70, 0xc863aef8},
|
||||
{0x4c40684e, 0x00000721, 0x0000011e, 0xd7f46ccc, 0x173a11c4},
|
||||
{0x6b487f90, 0x00000264, 0x000007bc, 0x759e9939, 0xd6307c56},
|
||||
{0x9f5810db, 0x00000afa, 0x00000255, 0x2685197f, 0x2e5c9201},
|
||||
{0xb15c4755, 0x00000d5b, 0x000002a4, 0xd8fadcb5, 0xf682c4be},
|
||||
{0x06518253, 0x00000ffb, 0x00000004, 0xabee2433, 0x3d8abdf9},
|
||||
{0xd9e71c55, 0x00000a2a, 0x00000259, 0x96682af2, 0x47b4d26c},
|
||||
{0x0c1ae843, 0x00000ce4, 0x0000031b, 0x7b637c43, 0x62b47e8b},
|
||||
{0xec3cd517, 0x000002ff, 0x00000566, 0x5d719a77, 0xff5bc5b7},
|
||||
{0x77828e95, 0x0000067f, 0x0000038f, 0x43ee5b6c, 0x1a0cfacd},
|
||||
{0xec87b4e3, 0x00000d1c, 0x000002e3, 0x2ddd2eee, 0x275118a7},
|
||||
{0x412158bb, 0x00000eee, 0x00000111, 0x67b38ba2, 0xa74ecff5},
|
||||
{0x2e52de3e, 0x00000c4a, 0x000003b5, 0xbcc5d61d, 0xbd800707},
|
||||
{0x6ddaae8b, 0x00000d99, 0x00000266, 0x8b535544, 0xecbde1a1},
|
||||
{0x049b6cb1, 0x000009c5, 0x000000b0, 0xfc22cabc, 0xfb78eb9f},
|
||||
{0x77d4b954, 0x0000028a, 0x000007fa, 0x71d00923, 0x8c116f85},
|
||||
{0x5e192355, 0x00000ac1, 0x000001fa, 0xb966b81a, 0x5aa17bbe},
|
||||
{0x7d80b71d, 0x00000213, 0x000001e0, 0x2bba371a, 0xb5906aa6},
|
||||
{0x01f6f1e4, 0x000001d6, 0x00000395, 0xb7e8a647, 0x3ad112b1},
|
||||
{0x1dfabb13, 0x00000e14, 0x000001eb, 0x53917fba, 0xbaee0339},
|
||||
{0xb00a4449, 0x00000bf6, 0x00000409, 0xedecb577, 0x6f3a3979},
|
||||
{0x7ecd3981, 0x0000083f, 0x0000016b, 0xefef62b9, 0xe3e52eed},
|
||||
{0xf8f330d2, 0x000004be, 0x00000757, 0x9357c9f3, 0x0835bc1b},
|
||||
{0x03c38af2, 0x00000d23, 0x000002dc, 0x360fa8c0, 0x2ca885e6},
|
||||
{0x687bb79b, 0x00000f3d, 0x000000c2, 0x448d3be2, 0x79be2f78},
|
||||
{0x6710f550, 0x000009e9, 0x00000603, 0xdbfd1998, 0x1d25f627},
|
||||
{0x873171d1, 0x00000787, 0x000004d5, 0xab7f1b62, 0xa76a5656},
|
||||
{0x373b1314, 0x00000f0f, 0x000000f0, 0x184098ab, 0xba273974},
|
||||
{0x90fad9cd, 0x00000ead, 0x00000152, 0x23ce52ff, 0xb7bc958c},
|
||||
{0x19676fe7, 0x0000007d, 0x0000070d, 0xf8a76f1e, 0xf882b644},
|
||||
{0x89facd45, 0x000005f3, 0x00000473, 0x4331a006, 0xe9dc1396},
|
||||
{0x6f173747, 0x00000fc3, 0x0000003c, 0xb012f08e, 0xc6b888ee},
|
||||
{0x4b44a106, 0x0000075a, 0x0000008b, 0xf6f7ac38, 0x60cd2b74},
|
||||
{0xb620ad06, 0x00000774, 0x0000017e, 0xd34558e6, 0x3a0a615b},
|
||||
{0x976f21e9, 0x000008d7, 0x0000034a, 0xe533aa3a, 0xa99e60be},
|
||||
{0x687628c0, 0x000006c5, 0x0000061b, 0x3a840b15, 0x9bfcaef2},
|
||||
{0xe24ac108, 0x00000cd0, 0x0000032f, 0x51010ae8, 0x20958672},
|
||||
{0x361c44a3, 0x00000304, 0x00000719, 0xfd7bd481, 0xd70ff2b2},
|
||||
{0xd93ff95e, 0x00000db7, 0x0000008e, 0xcfbbc304, 0xad716acd},
|
||||
{0xed752d12, 0x00000883, 0x00000091, 0x65a6c868, 0x95c71c7b},
|
||||
{0xb4ff4b54, 0x000003d3, 0x000001c1, 0xf82597e7, 0x44b7f99b},
|
||||
{0x111b520f, 0x00000708, 0x000000eb, 0xc3e109f3, 0x71bc01ee},
|
||||
{0x62c806f2, 0x00000ba3, 0x0000045c, 0x874d3a72, 0xc539b753},
|
||||
{0x40d97470, 0x000005e1, 0x0000058d, 0x87a9684f, 0xea6073a5},
|
||||
{0x4312179c, 0x00000056, 0x0000070e, 0x809a00f5, 0x209aea3b},
|
||||
{0x13d5f84c, 0x00000a2d, 0x00000104, 0xf3d27578, 0xe087a8b6},
|
||||
{0x1f302cb2, 0x00000151, 0x00000014, 0x1e162693, 0x95e4b90e},
|
||||
{0xe491db24, 0x00000600, 0x000006f6, 0x7ff09615, 0x77611523},
|
||||
{0xf9a98069, 0x000002ba, 0x000002ad, 0x01af7387, 0xea925faa},
|
||||
{0xe9c477ad, 0x0000015f, 0x00000778, 0x6facf9a0, 0x1130f736},
|
||||
{0x353f32b2, 0x0000087c, 0x00000783, 0x6cc964ea, 0x32459994},
|
||||
{0x78e1b24f, 0x00000650, 0x000006a8, 0xb3bb7c27, 0x5a632f78},
|
||||
{0x61aa400e, 0x00000049, 0x00000254, 0xb8cd1681, 0xdf2652d5},
|
||||
{0xb84b10b0, 0x00000f73, 0x0000008c, 0x406a6450, 0x3619d31b},
|
||||
{0x9fa99c9c, 0x00000a7c, 0x000004d7, 0xfb3d21b4, 0xea31c743},
|
||||
{0x3fc9ebe3, 0x00000cd9, 0x000000d6, 0x43803f9c, 0x1f76a809},
|
||||
{0x529879cd, 0x000002f2, 0x00000595, 0x78b4c6a6, 0x63b9b93f},
|
||||
{0x3a933019, 0x00000516, 0x00000266, 0xdcb45436, 0x8f99c98c},
|
||||
{0x887b4977, 0x00000227, 0x0000038d, 0xc5f7c3d9, 0xaf5e3091},
|
||||
{0x770745de, 0x000008c6, 0x00000739, 0xf69145e8, 0x53d0dce1},
|
||||
{0x28be3b47, 0x00000c46, 0x0000032b, 0x764c028f, 0x106d0905},
|
||||
{0x5013a050, 0x00000cf6, 0x00000309, 0xea8fe164, 0x62180b57},
|
||||
{0x2ec4c9ba, 0x000006e8, 0x0000078d, 0xa35557a9, 0xf44430a4},
|
||||
{0xa9f950c9, 0x00000d33, 0x000002cc, 0x41ea8618, 0x587b4eb3},
|
||||
{0x5b520229, 0x000007b2, 0x00000484, 0x44569f1f, 0x92406c32},
|
||||
{0xd8dcbbfc, 0x0000002f, 0x0000048c, 0xdb88ab8b, 0x13bfe70e},
|
||||
{0x25529792, 0x00000d1d, 0x000002e2, 0x20cda404, 0x19d3b4e4},
|
||||
{0x9f3f6d71, 0x00000238, 0x0000079a, 0x0720443e, 0x3c107021},
|
||||
{0x64121215, 0x000007ff, 0x0000038f, 0x6aacff2c, 0xb82fdc3e},
|
||||
{0xfb6cdde0, 0x00000ef8, 0x00000107, 0xbd43a0f1, 0xab0d3c1d},
|
||||
{0x221c9d6f, 0x000007b6, 0x0000014f, 0xb67f834b, 0x1371ad05},
|
||||
{0x030e1de4, 0x00000836, 0x000004b4, 0x0d67d26a, 0xe2e72df1},
|
||||
{0xb56fa6cf, 0x00000c07, 0x000003f8, 0x60601ac1, 0x039de73e},
|
||||
{0xb55c89f5, 0x0000098e, 0x000001d4, 0x2400efbe, 0xfe39a2bb},
|
||||
{0x5e90b6d5, 0x0000070b, 0x000003ea, 0x3bb5d6ea, 0xf0f794a0},
|
||||
{0x2a7045ae, 0x00000961, 0x00000633, 0xfca89e4b, 0xe66ce41c},
|
||||
{0x8b374ea9, 0x000006ba, 0x00000780, 0xbce036ed, 0x4cb28ef7},
|
||||
{0x8bd90bc9, 0x00000562, 0x00000369, 0xcb26a24b, 0x40236d1d},
|
||||
{0x5b1b1762, 0x000000fd, 0x0000051a, 0x33cdda07, 0xc32e420a},
|
||||
{0xa4153555, 0x0000058f, 0x000005c7, 0xbe50eeca, 0x83a67f35},
|
||||
{0x0be1f931, 0x00000651, 0x00000672, 0x95a25753, 0x88f1aac1},
|
||||
{0xb7e78618, 0x00000a7f, 0x000002bb, 0xe06bcc1c, 0x74274f66},
|
||||
{0x4a9bc41b, 0x00000e51, 0x000001ae, 0x709e8d2c, 0x54eff534},
|
||||
{0xfc359d13, 0x00000440, 0x000002f8, 0x0a58451f, 0x55e9363f},
|
||||
{0x5aa48619, 0x000006d1, 0x00000284, 0x928ead83, 0x31041c06},
|
||||
{0xa609afa8, 0x0000053e, 0x00000272, 0xb048c141, 0x4704efba},
|
||||
{0x3f108afb, 0x00000949, 0x00000150, 0x9a6bb5bc, 0x4e4430c8},
|
||||
{0x79bec2d3, 0x000008ed, 0x00000712, 0x32692d57, 0x11d52a7b},
|
||||
{0x9429e067, 0x00000bc3, 0x0000043c, 0x5295ceff, 0x04640f4d},
|
||||
{0xae58b96a, 0x0000082d, 0x000007d2, 0xc2a681ba, 0xf7ca4a2c},
|
||||
{0x95df24be, 0x00000985, 0x000004c1, 0x3a287765, 0x2c4af003},
|
||||
{0x5e94976f, 0x00000596, 0x000004ed, 0xff00c489, 0x5ae11687},
|
||||
{0xf5e5f1de, 0x00000d31, 0x000002ce, 0x35f28e91, 0x30d47957},
|
||||
{0xa2c219cf, 0x00000a3c, 0x00000374, 0x707d21eb, 0x2a14a255},
|
||||
{0xf21b6ceb, 0x00000919, 0x00000135, 0x0847fb8b, 0xcb8d3b93},
|
||||
{0xaa988728, 0x00000787, 0x00000771, 0x885aeaa4, 0x6531b509},
|
||||
{0xaa5dfaac, 0x000003e5, 0x0000051b, 0x52c48ab7, 0xe43cc5e9},
|
||||
{0x0a053968, 0x00000d2a, 0x000002d5, 0x7a90256d, 0x8004765c},
|
||||
{0x1421dc20, 0x00000eef, 0x00000110, 0x97d6da24, 0x1378f6ff},
|
||||
{0xb47c2166, 0x00000a6a, 0x00000209, 0xcfd6cc52, 0x676e14a5},
|
||||
{0x77dd1955, 0x000000de, 0x00000266, 0xba74bcaa, 0xc71b429c},
|
||||
{0x68a03cc2, 0x0000082f, 0x000007b0, 0x752bd5d8, 0x19ed14aa},
|
||||
{0x0226b0a3, 0x00000a5f, 0x000005a0, 0x82de4970, 0xf654d3ed},
|
||||
{0x637bf3b1, 0x00000d93, 0x0000026c, 0x5c7115cb, 0x3cccb57e},
|
||||
{0x3b120edf, 0x00000c13, 0x000003ec, 0x80d7d20f, 0x92132798},
|
||||
{0xe2456780, 0x000002eb, 0x00000641, 0xc0a5d289, 0x6160c87a},
|
||||
{0x9b2e7125, 0x00000c0c, 0x000003f3, 0xcc15f57e, 0x6f00f637},
|
||||
{0x153033ef, 0x00000787, 0x000006b6, 0x3cde443b, 0xb46caa6e},
|
||||
{0x18458b3f, 0x0000066c, 0x00000561, 0x9a2bd8c6, 0xb6c29121},
|
||||
{0x4ff9d4b9, 0x00000c8f, 0x0000033a, 0xd0ee6d6d, 0xc81cf380},
|
||||
{0xdf84b5d9, 0x00000802, 0x0000029a, 0xdab0d74a, 0xb2464559},
|
||||
{0x81ee15df, 0x000003ce, 0x00000725, 0x9942e2de, 0x4ccf571b},
|
||||
{0x5c768e04, 0x00000afd, 0x00000160, 0x36110831, 0xae0b305a},
|
||||
{0xe5e18094, 0x00000b4b, 0x000000a0, 0xffa3e4a7, 0x6c8a4f09},
|
||||
{0xed7263b6, 0x00000d0d, 0x000002f2, 0xb0006a35, 0x7e04af8c},
|
||||
{0x5bfde7d7, 0x000006fb, 0x00000554, 0xa4193b76, 0xb3a91d12},
|
||||
{0x67f4a743, 0x00000b85, 0x0000047a, 0xf05c8d8f, 0xfb472fdf},
|
||||
{0xf13bdf22, 0x00000ff7, 0x00000008, 0x816351eb, 0xf347f235},
|
||||
{0x08ecc608, 0x00000d5d, 0x00000098, 0x90492772, 0x0b7f1521},
|
||||
{0x296f52ba, 0x000004f9, 0x00000788, 0x5e5a4896, 0x1cc67088},
|
||||
{0xbe4624c2, 0x00000427, 0x000004ef, 0xcd267b94, 0x550caefd},
|
||||
{0x906f7c7c, 0x00000a05, 0x0000003f, 0x03fcfc33, 0x9ed82a02},
|
||||
{0x8f7b323e, 0x00000458, 0x000004c7, 0xcd4969c8, 0x633c38a8},
|
||||
{0x88d6593d, 0x00000597, 0x000005b5, 0xf199cd3b, 0x0491452f},
|
||||
{0x978a7768, 0x00000268, 0x000001d3, 0xb28c95bd, 0x1a42fe61},
|
||||
{0x857a621e, 0x000007a7, 0x000003a8, 0xf4bf84ab, 0xcd0694c6},
|
||||
{0xb0e121ef, 0x000005be, 0x00000644, 0x28747c14, 0xf0510c72},
|
||||
{0, 0, 0, 0, 0},
|
||||
};
|
||||
|
||||
static int test_crc32c(void)
|
||||
{
|
||||
struct crc_test *t = test;
|
||||
int failures = 0;
|
||||
|
||||
while (t->length) {
|
||||
uint32_t be, le;
|
||||
le = ext2fs_crc32c_le(t->crc, test_buf + t->start, t->length);
|
||||
be = ext2fs_crc32_be(t->crc, test_buf + t->start, t->length);
|
||||
if (le != t->crc32c_le) {
|
||||
printf("Test %d LE fails, %x != %x\n",
|
||||
(int) (t - test), le, t->crc32c_le);
|
||||
failures++;
|
||||
}
|
||||
if (be != t->crc32_be) {
|
||||
printf("Test %d BE fails, %x != %x\n",
|
||||
(int) (t - test), be, t->crc32_be);
|
||||
failures++;
|
||||
}
|
||||
t++;
|
||||
}
|
||||
|
||||
return failures;
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = test_crc32c();
|
||||
if (!ret)
|
||||
printf("No failures.\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* UNITTEST */
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/crc32c.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/crc32c.o
Executable file
Binary file not shown.
1011
jni/e2fsprogs/lib/ext2fs/csum.c
Executable file
1011
jni/e2fsprogs/lib/ext2fs/csum.c
Executable file
File diff suppressed because it is too large
Load Diff
BIN
jni/e2fsprogs/lib/ext2fs/csum.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/csum.o
Executable file
Binary file not shown.
403
jni/e2fsprogs/lib/ext2fs/dblist.c
Executable file
403
jni/e2fsprogs/lib/ext2fs/dblist.c
Executable file
@@ -0,0 +1,403 @@
|
||||
/*
|
||||
* dblist.c -- directory block list functions
|
||||
*
|
||||
* Copyright 1997 by 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b);
|
||||
static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b);
|
||||
static EXT2_QSORT_TYPE (*sortfunc32)(const void *a, const void *b);
|
||||
|
||||
/*
|
||||
* helper function for making a new directory block list (for
|
||||
* initialize and copy).
|
||||
*/
|
||||
static errcode_t make_dblist(ext2_filsys fs, ext2_ino_t size,
|
||||
ext2_ino_t count,
|
||||
struct ext2_db_entry2 *list,
|
||||
ext2_dblist *ret_dblist)
|
||||
{
|
||||
ext2_dblist dblist = NULL;
|
||||
errcode_t retval;
|
||||
ext2_ino_t num_dirs;
|
||||
size_t len;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if ((ret_dblist == 0) && fs->dblist &&
|
||||
(fs->dblist->magic == EXT2_ET_MAGIC_DBLIST))
|
||||
return 0;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2_struct_dblist), &dblist);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
memset(dblist, 0, sizeof(struct ext2_struct_dblist));
|
||||
|
||||
dblist->magic = EXT2_ET_MAGIC_DBLIST;
|
||||
dblist->fs = fs;
|
||||
if (size)
|
||||
dblist->size = size;
|
||||
else {
|
||||
retval = ext2fs_get_num_dirs(fs, &num_dirs);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
dblist->size = (num_dirs * 2) + 12;
|
||||
}
|
||||
len = (size_t) sizeof(struct ext2_db_entry2) * dblist->size;
|
||||
dblist->count = count;
|
||||
retval = ext2fs_get_array(dblist->size, sizeof(struct ext2_db_entry2),
|
||||
&dblist->list);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
if (list)
|
||||
memcpy(dblist->list, list, len);
|
||||
else
|
||||
memset(dblist->list, 0, len);
|
||||
if (ret_dblist)
|
||||
*ret_dblist = dblist;
|
||||
else
|
||||
fs->dblist = dblist;
|
||||
return 0;
|
||||
cleanup:
|
||||
if (dblist)
|
||||
ext2fs_free_mem(&dblist);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize a directory block list
|
||||
*/
|
||||
errcode_t ext2fs_init_dblist(ext2_filsys fs, ext2_dblist *ret_dblist)
|
||||
{
|
||||
ext2_dblist dblist;
|
||||
errcode_t retval;
|
||||
|
||||
retval = make_dblist(fs, 0, 0, 0, &dblist);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
dblist->sorted = 1;
|
||||
if (ret_dblist)
|
||||
*ret_dblist = dblist;
|
||||
else
|
||||
fs->dblist = dblist;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a directory block list
|
||||
*/
|
||||
errcode_t ext2fs_copy_dblist(ext2_dblist src, ext2_dblist *dest)
|
||||
{
|
||||
ext2_dblist dblist;
|
||||
errcode_t retval;
|
||||
|
||||
retval = make_dblist(src->fs, src->size, src->count, src->list,
|
||||
&dblist);
|
||||
if (retval)
|
||||
return retval;
|
||||
dblist->sorted = src->sorted;
|
||||
*dest = dblist;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Close a directory block list
|
||||
*
|
||||
* (moved to closefs.c)
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Add a directory block to the directory block list
|
||||
*/
|
||||
errcode_t ext2fs_add_dir_block2(ext2_dblist dblist, ext2_ino_t ino,
|
||||
blk64_t blk, e2_blkcnt_t blockcnt)
|
||||
{
|
||||
struct ext2_db_entry2 *new_entry;
|
||||
errcode_t retval;
|
||||
unsigned long old_size;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
if (dblist->count >= dblist->size) {
|
||||
old_size = dblist->size * sizeof(struct ext2_db_entry2);
|
||||
dblist->size += dblist->size > 200 ? dblist->size / 2 : 100;
|
||||
retval = ext2fs_resize_mem(old_size, (size_t) dblist->size *
|
||||
sizeof(struct ext2_db_entry2),
|
||||
&dblist->list);
|
||||
if (retval) {
|
||||
dblist->size = old_size / sizeof(struct ext2_db_entry2);
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
new_entry = dblist->list + ( dblist->count++);
|
||||
new_entry->blk = blk;
|
||||
new_entry->ino = ino;
|
||||
new_entry->blockcnt = blockcnt;
|
||||
|
||||
dblist->sorted = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the directory block to the directory block list
|
||||
*/
|
||||
errcode_t ext2fs_set_dir_block2(ext2_dblist dblist, ext2_ino_t ino,
|
||||
blk64_t blk, e2_blkcnt_t blockcnt)
|
||||
{
|
||||
dgrp_t i;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
for (i=0; i < dblist->count; i++) {
|
||||
if ((dblist->list[i].ino != ino) ||
|
||||
(dblist->list[i].blockcnt != blockcnt))
|
||||
continue;
|
||||
dblist->list[i].blk = blk;
|
||||
dblist->sorted = 0;
|
||||
return 0;
|
||||
}
|
||||
return EXT2_ET_DB_NOT_FOUND;
|
||||
}
|
||||
|
||||
void ext2fs_dblist_sort2(ext2_dblist dblist,
|
||||
EXT2_QSORT_TYPE (*sortfunc)(const void *,
|
||||
const void *))
|
||||
{
|
||||
if (!sortfunc)
|
||||
sortfunc = dir_block_cmp2;
|
||||
qsort(dblist->list, (size_t) dblist->count,
|
||||
sizeof(struct ext2_db_entry2), sortfunc);
|
||||
dblist->sorted = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function iterates over the directory block list
|
||||
*/
|
||||
errcode_t ext2fs_dblist_iterate3(ext2_dblist dblist,
|
||||
int (*func)(ext2_filsys fs,
|
||||
struct ext2_db_entry2 *db_info,
|
||||
void *priv_data),
|
||||
unsigned long long start,
|
||||
unsigned long long count,
|
||||
void *priv_data)
|
||||
{
|
||||
unsigned long long i, end;
|
||||
int ret;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
end = start + count;
|
||||
if (!dblist->sorted)
|
||||
ext2fs_dblist_sort2(dblist, 0);
|
||||
if (end > dblist->count)
|
||||
end = dblist->count;
|
||||
for (i = start; i < end; i++) {
|
||||
ret = (*func)(dblist->fs, &dblist->list[i], priv_data);
|
||||
if (ret & DBLIST_ABORT)
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_iterate2(ext2_dblist dblist,
|
||||
int (*func)(ext2_filsys fs,
|
||||
struct ext2_db_entry2 *db_info,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
return ext2fs_dblist_iterate3(dblist, func, 0, dblist->count,
|
||||
priv_data);
|
||||
}
|
||||
|
||||
static EXT2_QSORT_TYPE dir_block_cmp2(const void *a, const void *b)
|
||||
{
|
||||
const struct ext2_db_entry2 *db_a =
|
||||
(const struct ext2_db_entry2 *) a;
|
||||
const struct ext2_db_entry2 *db_b =
|
||||
(const struct ext2_db_entry2 *) b;
|
||||
|
||||
if (db_a->blk != db_b->blk)
|
||||
return (int) (db_a->blk - db_b->blk);
|
||||
|
||||
if (db_a->ino != db_b->ino)
|
||||
return (int) (db_a->ino - db_b->ino);
|
||||
|
||||
return (db_a->blockcnt - db_b->blockcnt);
|
||||
}
|
||||
|
||||
blk64_t ext2fs_dblist_count2(ext2_dblist dblist)
|
||||
{
|
||||
return dblist->count;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_get_last2(ext2_dblist dblist,
|
||||
struct ext2_db_entry2 **entry)
|
||||
{
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
if (dblist->count == 0)
|
||||
return EXT2_ET_DBLIST_EMPTY;
|
||||
|
||||
if (entry)
|
||||
*entry = dblist->list + ( dblist->count-1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_drop_last(ext2_dblist dblist)
|
||||
{
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
if (dblist->count == 0)
|
||||
return EXT2_ET_DBLIST_EMPTY;
|
||||
|
||||
dblist->count--;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Legacy 32-bit versions
|
||||
*/
|
||||
|
||||
/*
|
||||
* Add a directory block to the directory block list
|
||||
*/
|
||||
errcode_t ext2fs_add_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
|
||||
int blockcnt)
|
||||
{
|
||||
return ext2fs_add_dir_block2(dblist, ino, blk, blockcnt);
|
||||
}
|
||||
|
||||
/*
|
||||
* Change the directory block to the directory block list
|
||||
*/
|
||||
errcode_t ext2fs_set_dir_block(ext2_dblist dblist, ext2_ino_t ino, blk_t blk,
|
||||
int blockcnt)
|
||||
{
|
||||
return ext2fs_set_dir_block2(dblist, ino, blk, blockcnt);
|
||||
}
|
||||
|
||||
void ext2fs_dblist_sort(ext2_dblist dblist,
|
||||
EXT2_QSORT_TYPE (*sortfunc)(const void *,
|
||||
const void *))
|
||||
{
|
||||
if (sortfunc) {
|
||||
sortfunc32 = sortfunc;
|
||||
sortfunc = dir_block_cmp;
|
||||
} else
|
||||
sortfunc = dir_block_cmp2;
|
||||
qsort(dblist->list, (size_t) dblist->count,
|
||||
sizeof(struct ext2_db_entry2), sortfunc);
|
||||
dblist->sorted = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function iterates over the directory block list
|
||||
*/
|
||||
struct iterate_passthrough {
|
||||
int (*func)(ext2_filsys fs,
|
||||
struct ext2_db_entry *db_info,
|
||||
void *priv_data);
|
||||
void *priv_data;
|
||||
};
|
||||
|
||||
static int passthrough_func(ext2_filsys fs,
|
||||
struct ext2_db_entry2 *db_info,
|
||||
void *priv_data)
|
||||
{
|
||||
struct iterate_passthrough *p = priv_data;
|
||||
struct ext2_db_entry db;
|
||||
int ret;
|
||||
|
||||
db.ino = db_info->ino;
|
||||
db.blk = (blk_t) db_info->blk;
|
||||
db.blockcnt = (int) db_info->blockcnt;
|
||||
ret = (p->func)(fs, &db, p->priv_data);
|
||||
db_info->ino = db.ino;
|
||||
db_info->blk = db.blk;
|
||||
db_info->blockcnt = db.blockcnt;
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_iterate(ext2_dblist dblist,
|
||||
int (*func)(ext2_filsys fs,
|
||||
struct ext2_db_entry *db_info,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
struct iterate_passthrough pass;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
pass.func = func;
|
||||
pass.priv_data = priv_data;
|
||||
|
||||
return ext2fs_dblist_iterate2(dblist, passthrough_func, &pass);
|
||||
}
|
||||
|
||||
static EXT2_QSORT_TYPE dir_block_cmp(const void *a, const void *b)
|
||||
{
|
||||
const struct ext2_db_entry2 *db_a =
|
||||
(const struct ext2_db_entry2 *) a;
|
||||
const struct ext2_db_entry2 *db_b =
|
||||
(const struct ext2_db_entry2 *) b;
|
||||
|
||||
struct ext2_db_entry a32, b32;
|
||||
|
||||
a32.ino = db_a->ino; a32.blk = db_a->blk;
|
||||
a32.blockcnt = db_a->blockcnt;
|
||||
|
||||
b32.ino = db_b->ino; b32.blk = db_b->blk;
|
||||
b32.blockcnt = db_b->blockcnt;
|
||||
|
||||
return sortfunc32(&a32, &b32);
|
||||
}
|
||||
|
||||
int ext2fs_dblist_count(ext2_dblist dblist)
|
||||
{
|
||||
return dblist->count;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dblist_get_last(ext2_dblist dblist,
|
||||
struct ext2_db_entry **entry)
|
||||
{
|
||||
static struct ext2_db_entry ret_entry;
|
||||
struct ext2_db_entry2 *last;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
if (dblist->count == 0)
|
||||
return EXT2_ET_DBLIST_EMPTY;
|
||||
|
||||
if (!entry)
|
||||
return 0;
|
||||
|
||||
last = dblist->list + dblist->count -1;
|
||||
|
||||
ret_entry.ino = last->ino;
|
||||
ret_entry.blk = last->blk;
|
||||
ret_entry.blockcnt = last->blockcnt;
|
||||
*entry = &ret_entry;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/dblist.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/dblist.o
Executable file
Binary file not shown.
88
jni/e2fsprogs/lib/ext2fs/dblist_dir.c
Executable file
88
jni/e2fsprogs/lib/ext2fs/dblist_dir.c
Executable file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* dblist_dir.c --- iterate by directory entry
|
||||
*
|
||||
* Copyright 1997 by 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry2 *db_info,
|
||||
void *priv_data);
|
||||
|
||||
errcode_t ext2fs_dblist_dir_iterate(ext2_dblist dblist,
|
||||
int flags,
|
||||
char *block_buf,
|
||||
int (*func)(ext2_ino_t dir,
|
||||
int entry,
|
||||
struct ext2_dir_entry *dirent,
|
||||
int offset,
|
||||
int blocksize,
|
||||
char *buf,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct dir_context ctx;
|
||||
|
||||
EXT2_CHECK_MAGIC(dblist, EXT2_ET_MAGIC_DBLIST);
|
||||
|
||||
ctx.dir = 0;
|
||||
ctx.flags = flags;
|
||||
if (block_buf)
|
||||
ctx.buf = block_buf;
|
||||
else {
|
||||
retval = ext2fs_get_mem(dblist->fs->blocksize, &ctx.buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
ctx.func = func;
|
||||
ctx.priv_data = priv_data;
|
||||
ctx.errcode = 0;
|
||||
|
||||
retval = ext2fs_dblist_iterate2(dblist, db_dir_proc, &ctx);
|
||||
|
||||
if (!block_buf)
|
||||
ext2fs_free_mem(&ctx.buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
return ctx.errcode;
|
||||
}
|
||||
|
||||
static int db_dir_proc(ext2_filsys fs, struct ext2_db_entry2 *db_info,
|
||||
void *priv_data)
|
||||
{
|
||||
struct ext2_inode inode;
|
||||
struct dir_context *ctx;
|
||||
int ret;
|
||||
|
||||
ctx = (struct dir_context *) priv_data;
|
||||
ctx->dir = db_info->ino;
|
||||
ctx->errcode = 0;
|
||||
|
||||
ctx->errcode = ext2fs_read_inode(fs, ctx->dir, &inode);
|
||||
if (ctx->errcode)
|
||||
return DBLIST_ABORT;
|
||||
if (inode.i_flags & EXT4_INLINE_DATA_FL)
|
||||
ret = ext2fs_inline_data_dir_iterate(fs, ctx->dir, ctx);
|
||||
else
|
||||
ret = ext2fs_process_dir_block(fs, &db_info->blk,
|
||||
db_info->blockcnt, 0, 0,
|
||||
priv_data);
|
||||
if ((ret & BLOCK_ABORT) && !ctx->errcode)
|
||||
return DBLIST_ABORT;
|
||||
return 0;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/dblist_dir.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/dblist_dir.o
Executable file
Binary file not shown.
187
jni/e2fsprogs/lib/ext2fs/digest_encode.c
Executable file
187
jni/e2fsprogs/lib/ext2fs/digest_encode.c
Executable file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* lib/ext2fs/digest_encode.c
|
||||
*
|
||||
* A function to encode a digest using 64 characters that are valid in a
|
||||
* filename per ext2fs rules.
|
||||
*
|
||||
* Written by Uday Savagaonkar, 2014.
|
||||
*
|
||||
* Copyright 2014 Google Inc. All Rights Reserved.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include "ext2fs.h"
|
||||
|
||||
static const char *lookup_table =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,";
|
||||
|
||||
/**
|
||||
* ext2fs_digest_encode() -
|
||||
*
|
||||
* Encodes the input digest using characters from the set [a-zA-Z0-9_+].
|
||||
* The encoded string is roughly 4/3 times the size of the input string.
|
||||
*/
|
||||
int ext2fs_digest_encode(const char *src, int len, char *dst)
|
||||
{
|
||||
int i = 0, bits = 0, ac = 0;
|
||||
char *cp = dst;
|
||||
|
||||
while (i < len) {
|
||||
ac += (((unsigned char) src[i]) << bits);
|
||||
bits += 8;
|
||||
do {
|
||||
*cp++ = lookup_table[ac & 0x3f];
|
||||
ac >>= 6;
|
||||
bits -= 6;
|
||||
} while (bits >= 6);
|
||||
i++;
|
||||
}
|
||||
if (bits)
|
||||
*cp++ = lookup_table[ac & 0x3f];
|
||||
return cp - dst;
|
||||
}
|
||||
|
||||
int ext2fs_digest_decode(const char *src, int len, char *dst)
|
||||
{
|
||||
int i = 0, bits = 0, ac = 0;
|
||||
const char *p;
|
||||
char *cp = dst;
|
||||
|
||||
while (i < len) {
|
||||
p = strchr(lookup_table, src[i]);
|
||||
if (p == NULL || src[i] == 0)
|
||||
return -1;
|
||||
ac += (p - lookup_table) << bits;
|
||||
bits += 6;
|
||||
if (bits >= 8) {
|
||||
*cp++ = ac & 0xff;
|
||||
ac >>= 8;
|
||||
bits -= 8;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (ac)
|
||||
return -1;
|
||||
return cp - dst;
|
||||
}
|
||||
|
||||
|
||||
#ifdef UNITTEST
|
||||
static const struct {
|
||||
unsigned char d[32];
|
||||
unsigned int len;
|
||||
const char *ed;
|
||||
} tests[] = {
|
||||
{ { 0xe3, 0xb0, 0xc4, 0x42, 0x98, 0xfc, 0x1c, 0x14,
|
||||
0x9a, 0xfb, 0xf4, 0xc8, 0x99, 0x6f, 0xb9, 0x24,
|
||||
0x27, 0xae, 0x41, 0xe4, 0x64, 0x9b, 0x93, 0x4c,
|
||||
0xa4, 0x95, 0x99, 0x1b, 0x78, 0x52, 0xb8, 0x55 }, 32,
|
||||
"jDLxChJ,cQhm7TPyZ+WukcirBROZbOJTkWZmbgnU4WF"
|
||||
},
|
||||
{ { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
|
||||
0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
|
||||
0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
|
||||
0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad }, 32,
|
||||
"6inF,+YAPreQBBk3d5qIjA7AhNqlXoHn0Cx,hJPAV0K"
|
||||
},
|
||||
{ { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
|
||||
0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
|
||||
0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
|
||||
0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 }, 32,
|
||||
"k0oahJtB4gb5AbykM4DY5MKPknFZ,HyZ2ze7Unx2GEM"
|
||||
},
|
||||
{ { 0x00, }, 1,
|
||||
"AA"
|
||||
},
|
||||
{ { 0x01, }, 1,
|
||||
"BA"
|
||||
},
|
||||
{ { 0x01, 0x02 }, 2,
|
||||
"BIA"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03 }, 3,
|
||||
"BIwA"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03, 0x04 }, 4,
|
||||
"BIwAEA"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03, 0x04, 0xff }, 5,
|
||||
"BIwAE8P"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe }, 6,
|
||||
"BIwAE8v,"
|
||||
},
|
||||
{ { 0x01, 0x02, 0x03, 0x04, 0xff, 0xfe, 0xfd }, 7,
|
||||
"BIwAE8v,9D"
|
||||
},
|
||||
};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int i, ret, len;
|
||||
int errors = 0;
|
||||
char tmp[1024], tmp2[1024];
|
||||
|
||||
if (argc == 3 && !strcmp(argv[1], "encode")) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
ext2fs_digest_encode(argv[2], strlen(argv[2]), tmp);
|
||||
puts(tmp);
|
||||
exit(0);
|
||||
}
|
||||
if (argc == 3 && !strcmp(argv[1], "decode")) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
ret = ext2fs_digest_decode(argv[2], strlen(argv[2]), tmp);
|
||||
puts(tmp);
|
||||
fprintf(stderr, "returned %d\n", ret);
|
||||
exit(0);
|
||||
}
|
||||
for (i = 0; i < (int)(sizeof(tests) / sizeof(tests[0])); i++) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
ret = ext2fs_digest_encode((const char *) tests[i].d,
|
||||
tests[i].len, tmp);
|
||||
len = strlen(tmp);
|
||||
printf("Test Digest %d (returned %d): ", i, ret);
|
||||
if (ret != len) {
|
||||
printf("FAILED returned %d, string length was %d\n",
|
||||
ret, len);
|
||||
errors++;
|
||||
continue;
|
||||
} else if (strcmp(tmp, tests[i].ed) != 0) {
|
||||
printf("FAILED: got %s, expected %s\n", tmp,
|
||||
tests[i].ed);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
ret = ext2fs_digest_decode(tmp, len, tmp2);
|
||||
if (ret != tests[i].len) {
|
||||
printf("FAILED decode returned %d, expected %d\n",
|
||||
ret, tests[i].len);
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
if (memcmp(tmp2, tests[i].d, ret) != 0) {
|
||||
puts("FAILED: decode mismatched");
|
||||
errors++;
|
||||
continue;
|
||||
}
|
||||
printf("OK\n");
|
||||
}
|
||||
for (i = 1; i < argc; i++) {
|
||||
memset(tmp, 0, sizeof(tmp));
|
||||
ret = ext2fs_digest_encode(argv[i], strlen(argv[i]), tmp);
|
||||
len = strlen(tmp);
|
||||
printf("Digest of '%s' is '%s' (returned %d, length %d)\n",
|
||||
argv[i], tmp, ret, len);
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
#endif /* UNITTEST */
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/digest_encode.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/digest_encode.o
Executable file
Binary file not shown.
315
jni/e2fsprogs/lib/ext2fs/dir_iterate.c
Executable file
315
jni/e2fsprogs/lib/ext2fs/dir_iterate.c
Executable file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* dir_iterate.c --- ext2fs directory iteration operations
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1994, 1995, 1996, 1997 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
#define EXT4_MAX_REC_LEN ((1<<16)-1)
|
||||
|
||||
errcode_t ext2fs_get_rec_len(ext2_filsys fs,
|
||||
struct ext2_dir_entry *dirent,
|
||||
unsigned int *rec_len)
|
||||
{
|
||||
unsigned int len = dirent->rec_len;
|
||||
|
||||
if (fs->blocksize < 65536)
|
||||
*rec_len = len;
|
||||
else if (len == EXT4_MAX_REC_LEN || len == 0)
|
||||
*rec_len = fs->blocksize;
|
||||
else
|
||||
*rec_len = (len & 65532) | ((len & 3) << 16);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_rec_len(ext2_filsys fs,
|
||||
unsigned int len,
|
||||
struct ext2_dir_entry *dirent)
|
||||
{
|
||||
if ((len > fs->blocksize) || (fs->blocksize > (1 << 18)) || (len & 3))
|
||||
return EINVAL;
|
||||
if (len < 65536) {
|
||||
dirent->rec_len = len;
|
||||
return 0;
|
||||
}
|
||||
if (len == fs->blocksize) {
|
||||
if (fs->blocksize == 65536)
|
||||
dirent->rec_len = EXT4_MAX_REC_LEN;
|
||||
else
|
||||
dirent->rec_len = 0;
|
||||
} else
|
||||
dirent->rec_len = (len & 65532) | ((len >> 16) & 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function checks to see whether or not a potential deleted
|
||||
* directory entry looks valid. What we do is check the deleted entry
|
||||
* and each successive entry to make sure that they all look valid and
|
||||
* that the last deleted entry ends at the beginning of the next
|
||||
* undeleted entry. Returns 1 if the deleted entry looks valid, zero
|
||||
* if not valid.
|
||||
*/
|
||||
static int ext2fs_validate_entry(ext2_filsys fs, char *buf,
|
||||
unsigned int offset,
|
||||
unsigned int final_offset)
|
||||
{
|
||||
struct ext2_dir_entry *dirent;
|
||||
unsigned int rec_len;
|
||||
#define DIRENT_MIN_LENGTH 12
|
||||
|
||||
while ((offset < final_offset) &&
|
||||
(offset <= fs->blocksize - DIRENT_MIN_LENGTH)) {
|
||||
dirent = (struct ext2_dir_entry *)(buf + offset);
|
||||
if (ext2fs_get_rec_len(fs, dirent, &rec_len))
|
||||
return 0;
|
||||
offset += rec_len;
|
||||
if ((rec_len < 8) ||
|
||||
((rec_len % 4) != 0) ||
|
||||
((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len))
|
||||
return 0;
|
||||
}
|
||||
return (offset == final_offset);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dir_iterate2(ext2_filsys fs,
|
||||
ext2_ino_t dir,
|
||||
int flags,
|
||||
char *block_buf,
|
||||
int (*func)(ext2_ino_t dir,
|
||||
int entry,
|
||||
struct ext2_dir_entry *dirent,
|
||||
int offset,
|
||||
int blocksize,
|
||||
char *buf,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
struct dir_context ctx;
|
||||
errcode_t retval;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
retval = ext2fs_check_directory(fs, dir);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
ctx.dir = dir;
|
||||
ctx.flags = flags;
|
||||
if (block_buf)
|
||||
ctx.buf = block_buf;
|
||||
else {
|
||||
retval = ext2fs_get_mem(fs->blocksize, &ctx.buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
ctx.func = func;
|
||||
ctx.priv_data = priv_data;
|
||||
ctx.errcode = 0;
|
||||
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_READ_ONLY, 0,
|
||||
ext2fs_process_dir_block, &ctx);
|
||||
if (!block_buf)
|
||||
ext2fs_free_mem(&ctx.buf);
|
||||
if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE) {
|
||||
(void) ext2fs_inline_data_dir_iterate(fs, dir, &ctx);
|
||||
retval = 0;
|
||||
}
|
||||
if (retval)
|
||||
return retval;
|
||||
return ctx.errcode;
|
||||
}
|
||||
|
||||
struct xlate {
|
||||
int (*func)(struct ext2_dir_entry *dirent,
|
||||
int offset,
|
||||
int blocksize,
|
||||
char *buf,
|
||||
void *priv_data);
|
||||
void *real_private;
|
||||
};
|
||||
|
||||
static int xlate_func(ext2_ino_t dir EXT2FS_ATTR((unused)),
|
||||
int entry EXT2FS_ATTR((unused)),
|
||||
struct ext2_dir_entry *dirent, int offset,
|
||||
int blocksize, char *buf, void *priv_data)
|
||||
{
|
||||
struct xlate *xl = (struct xlate *) priv_data;
|
||||
|
||||
return (*xl->func)(dirent, offset, blocksize, buf, xl->real_private);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_dir_iterate(ext2_filsys fs,
|
||||
ext2_ino_t dir,
|
||||
int flags,
|
||||
char *block_buf,
|
||||
int (*func)(struct ext2_dir_entry *dirent,
|
||||
int offset,
|
||||
int blocksize,
|
||||
char *buf,
|
||||
void *priv_data),
|
||||
void *priv_data)
|
||||
{
|
||||
struct xlate xl;
|
||||
|
||||
xl.real_private = priv_data;
|
||||
xl.func = func;
|
||||
|
||||
return ext2fs_dir_iterate2(fs, dir, flags, block_buf,
|
||||
xlate_func, &xl);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Helper function which is private to this module. Used by
|
||||
* ext2fs_dir_iterate() and ext2fs_dblist_dir_iterate()
|
||||
*/
|
||||
int ext2fs_process_dir_block(ext2_filsys fs,
|
||||
blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk64_t ref_block EXT2FS_ATTR((unused)),
|
||||
int ref_offset EXT2FS_ATTR((unused)),
|
||||
void *priv_data)
|
||||
{
|
||||
struct dir_context *ctx = (struct dir_context *) priv_data;
|
||||
unsigned int offset = 0;
|
||||
unsigned int next_real_entry = 0;
|
||||
int ret = 0;
|
||||
int changed = 0;
|
||||
int do_abort = 0;
|
||||
unsigned int rec_len, size, buflen;
|
||||
int entry;
|
||||
struct ext2_dir_entry *dirent;
|
||||
int csum_size = 0;
|
||||
int inline_data;
|
||||
errcode_t retval = 0;
|
||||
|
||||
if (blockcnt < 0)
|
||||
return 0;
|
||||
|
||||
entry = blockcnt ? DIRENT_OTHER_FILE : DIRENT_DOT_FILE;
|
||||
|
||||
/* If a dir has inline data, we don't need to read block */
|
||||
inline_data = !!(ctx->flags & DIRENT_FLAG_INCLUDE_INLINE_DATA);
|
||||
if (!inline_data) {
|
||||
ctx->errcode = ext2fs_read_dir_block4(fs, *blocknr, ctx->buf, 0,
|
||||
ctx->dir);
|
||||
if (ctx->errcode)
|
||||
return BLOCK_ABORT;
|
||||
/* If we handle a normal dir, we traverse the entire block */
|
||||
buflen = fs->blocksize;
|
||||
} else {
|
||||
buflen = ctx->buflen;
|
||||
}
|
||||
|
||||
if (ext2fs_has_feature_metadata_csum(fs->super))
|
||||
csum_size = sizeof(struct ext2_dir_entry_tail);
|
||||
|
||||
if (buflen < 8) {
|
||||
ctx->errcode = EXT2_ET_DIR_CORRUPTED;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
while (offset < buflen - 8) {
|
||||
dirent = (struct ext2_dir_entry *) (ctx->buf + offset);
|
||||
if (ext2fs_get_rec_len(fs, dirent, &rec_len))
|
||||
return BLOCK_ABORT;
|
||||
if (((offset + rec_len) > buflen) ||
|
||||
(rec_len < 8) ||
|
||||
((rec_len % 4) != 0) ||
|
||||
((ext2fs_dirent_name_len(dirent)+8) > (int) rec_len)) {
|
||||
ctx->errcode = EXT2_ET_DIR_CORRUPTED;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
if (!dirent->inode) {
|
||||
/*
|
||||
* We just need to check metadata_csum when this
|
||||
* dir hasn't inline data. That means that 'buflen'
|
||||
* should be blocksize.
|
||||
*/
|
||||
if (!inline_data &&
|
||||
(offset == buflen - csum_size) &&
|
||||
(dirent->rec_len == csum_size) &&
|
||||
(dirent->name_len == EXT2_DIR_NAME_LEN_CSUM)) {
|
||||
if (!(ctx->flags & DIRENT_FLAG_INCLUDE_CSUM))
|
||||
goto next;
|
||||
entry = DIRENT_CHECKSUM;
|
||||
} else if (!(ctx->flags & DIRENT_FLAG_INCLUDE_EMPTY))
|
||||
goto next;
|
||||
}
|
||||
|
||||
ret = (ctx->func)(ctx->dir,
|
||||
(next_real_entry > offset) ?
|
||||
DIRENT_DELETED_FILE : entry,
|
||||
dirent, offset,
|
||||
buflen, ctx->buf,
|
||||
ctx->priv_data);
|
||||
if (entry < DIRENT_OTHER_FILE)
|
||||
entry++;
|
||||
|
||||
if (ret & DIRENT_CHANGED) {
|
||||
if (ext2fs_get_rec_len(fs, dirent, &rec_len))
|
||||
return BLOCK_ABORT;
|
||||
changed++;
|
||||
}
|
||||
if (ret & DIRENT_ABORT) {
|
||||
do_abort++;
|
||||
break;
|
||||
}
|
||||
next:
|
||||
if (next_real_entry == offset)
|
||||
next_real_entry += rec_len;
|
||||
|
||||
if (ctx->flags & DIRENT_FLAG_INCLUDE_REMOVED) {
|
||||
size = (ext2fs_dirent_name_len(dirent) + 11) & ~3;
|
||||
|
||||
if (rec_len != size) {
|
||||
unsigned int final_offset;
|
||||
|
||||
final_offset = offset + rec_len;
|
||||
offset += size;
|
||||
while (offset < final_offset &&
|
||||
!ext2fs_validate_entry(fs, ctx->buf,
|
||||
offset,
|
||||
final_offset))
|
||||
offset += 4;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
offset += rec_len;
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
if (!inline_data) {
|
||||
ctx->errcode = ext2fs_write_dir_block4(fs, *blocknr,
|
||||
ctx->buf,
|
||||
0, ctx->dir);
|
||||
if (ctx->errcode)
|
||||
return BLOCK_ABORT;
|
||||
} else {
|
||||
/*
|
||||
* return BLOCK_INLINE_DATA_CHANGED to notify caller
|
||||
* that inline data has been changed.
|
||||
*/
|
||||
retval = BLOCK_INLINE_DATA_CHANGED;
|
||||
}
|
||||
}
|
||||
if (do_abort)
|
||||
return retval | BLOCK_ABORT;
|
||||
return retval;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/dir_iterate.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/dir_iterate.o
Executable file
Binary file not shown.
113
jni/e2fsprogs/lib/ext2fs/dirblock.c
Executable file
113
jni/e2fsprogs/lib/ext2fs/dirblock.c
Executable file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* dirblock.c --- directory block routines.
|
||||
*
|
||||
* Copyright (C) 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
errcode_t ext2fs_read_dir_block4(ext2_filsys fs, blk64_t block,
|
||||
void *buf, int flags EXT2FS_ATTR((unused)),
|
||||
ext2_ino_t ino)
|
||||
{
|
||||
errcode_t retval;
|
||||
int corrupt = 0;
|
||||
|
||||
retval = io_channel_read_blk64(fs->io, block, 1, buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (!(fs->flags & EXT2_FLAG_IGNORE_CSUM_ERRORS) &&
|
||||
!ext2fs_dir_block_csum_verify(fs, ino,
|
||||
(struct ext2_dir_entry *)buf))
|
||||
corrupt = 1;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
retval = ext2fs_dirent_swab_in(fs, buf, flags);
|
||||
#endif
|
||||
if (!retval && corrupt)
|
||||
retval = EXT2_ET_DIR_CSUM_INVALID;
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_read_dir_block3(ext2_filsys fs, blk64_t block,
|
||||
void *buf, int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return ext2fs_read_dir_block4(fs, block, buf, flags, 0);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_read_dir_block2(ext2_filsys fs, blk_t block,
|
||||
void *buf, int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return ext2fs_read_dir_block3(fs, block, buf, flags);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_read_dir_block(ext2_filsys fs, blk_t block,
|
||||
void *buf)
|
||||
{
|
||||
return ext2fs_read_dir_block3(fs, block, buf, 0);
|
||||
}
|
||||
|
||||
|
||||
errcode_t ext2fs_write_dir_block4(ext2_filsys fs, blk64_t block,
|
||||
void *inbuf, int flags EXT2FS_ATTR((unused)),
|
||||
ext2_ino_t ino)
|
||||
{
|
||||
errcode_t retval;
|
||||
char *buf = inbuf;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
retval = ext2fs_get_mem(fs->blocksize, &buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
memcpy(buf, inbuf, fs->blocksize);
|
||||
retval = ext2fs_dirent_swab_out(fs, buf, flags);
|
||||
if (retval)
|
||||
return retval;
|
||||
#endif
|
||||
retval = ext2fs_dir_block_csum_set(fs, ino,
|
||||
(struct ext2_dir_entry *)buf);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
retval = io_channel_write_blk64(fs->io, block, 1, buf);
|
||||
|
||||
out:
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
ext2fs_free_mem(&buf);
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_write_dir_block3(ext2_filsys fs, blk64_t block,
|
||||
void *inbuf, int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return ext2fs_write_dir_block4(fs, block, inbuf, flags, 0);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_write_dir_block2(ext2_filsys fs, blk_t block,
|
||||
void *inbuf, int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
return ext2fs_write_dir_block3(fs, block, inbuf, flags);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block,
|
||||
void *inbuf)
|
||||
{
|
||||
return ext2fs_write_dir_block3(fs, block, inbuf, 0);
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/dirblock.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/dirblock.o
Executable file
Binary file not shown.
307
jni/e2fsprogs/lib/ext2fs/dirhash.c
Executable file
307
jni/e2fsprogs/lib/ext2fs/dirhash.c
Executable 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);
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/dirhash.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/dirhash.o
Executable file
Binary file not shown.
459
jni/e2fsprogs/lib/ext2fs/dosio.c
Executable file
459
jni/e2fsprogs/lib/ext2fs/dosio.c
Executable file
@@ -0,0 +1,459 @@
|
||||
/*
|
||||
* dosio.c -- Disk I/O module for the ext2fs/DOS library.
|
||||
*
|
||||
* Copyright (c) 1997 by Theodore Ts'o.
|
||||
*
|
||||
* Copyright (c) 1997 Mark Habersack
|
||||
*
|
||||
* %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 <bios.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <io.h>
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <ext2fs/ext2_types.h>
|
||||
#include "utils.h"
|
||||
#include "dosio.h"
|
||||
#include "et/com_err.h"
|
||||
#include "ext2_err.h"
|
||||
#include "ext2fs/io.h"
|
||||
|
||||
/*
|
||||
* Some helper macros
|
||||
*/
|
||||
#define LINUX_EXT2FS 0x83
|
||||
#define LINUX_SWAP 0x82
|
||||
#define WRITE_ERR(_msg_) write(2, _msg_, strlen(_msg_))
|
||||
#define WRITE_ERR_S(_msg_) write(2, _msg_, sizeof(_msg_))
|
||||
|
||||
/*
|
||||
* Exported variables
|
||||
*/
|
||||
unsigned long _dio_error;
|
||||
unsigned long _dio_hw_error;
|
||||
|
||||
/*
|
||||
* Array of all opened partitions
|
||||
*/
|
||||
static PARTITION **partitions = NULL;
|
||||
static unsigned short npart = 0; /* Number of mapped partitions */
|
||||
static PARTITION *active = NULL;
|
||||
|
||||
/*
|
||||
* I/O Manager routine prototypes
|
||||
*/
|
||||
static errcode_t dos_open(const char *dev, int flags, io_channel *channel);
|
||||
static errcode_t dos_close(io_channel channel);
|
||||
static errcode_t dos_set_blksize(io_channel channel, int blksize);
|
||||
static errcode_t dos_read_blk(io_channel channel, unsigned long block,
|
||||
int count, void *buf);
|
||||
static errcode_t dos_write_blk(io_channel channel, unsigned long block,
|
||||
int count, const void *buf);
|
||||
static errcode_t dos_flush(io_channel channel);
|
||||
|
||||
static struct struct_io_manager struct_dos_manager = {
|
||||
.magic = EXT2_ET_MAGIC_IO_MANAGER,
|
||||
.name = "DOS I/O Manager",
|
||||
.open = dos_open,
|
||||
.close = dos_close,
|
||||
.set_blksize = dos_set_blksize,
|
||||
.read_blk = dos_read_blk,
|
||||
.write_blk = dos_write_blk,
|
||||
.flush = dos_flush
|
||||
};
|
||||
|
||||
io_manager dos_io_manager = &struct_dos_manager;
|
||||
|
||||
/*
|
||||
* Macro taken from unix_io.c
|
||||
*/
|
||||
/*
|
||||
* For checking structure magic numbers...
|
||||
*/
|
||||
|
||||
#define EXT2_CHECK_MAGIC(struct, code) \
|
||||
if ((struct)->magic != (code)) return (code)
|
||||
|
||||
/*
|
||||
* Calculates a CHS address of a sector from its LBA
|
||||
* offset for the given partition.
|
||||
*/
|
||||
static void lba2chs(unsigned long lba_addr, CHS *chs, PARTITION *part)
|
||||
{
|
||||
unsigned long abss;
|
||||
|
||||
chs->offset = lba_addr & 0x000001FF;
|
||||
abss = (lba_addr >> 9) + part->start;
|
||||
chs->cyl = abss / (part->sects * part->heads);
|
||||
chs->head = (abss / part->sects) % part->heads;
|
||||
chs->sector = (abss % part->sects) + 1;
|
||||
}
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
/*
|
||||
* Scans the passed partition table looking for *pno partition
|
||||
* that has LINUX_EXT2FS type.
|
||||
*
|
||||
* TODO:
|
||||
* For partition numbers >5 Linux uses DOS extended partitions -
|
||||
* dive into them an return an appropriate entry. Also dive into
|
||||
* extended partitions when scanning for a first Linux/ext2fs.
|
||||
*/
|
||||
static PTABLE_ENTRY *scan_partition_table(PTABLE_ENTRY *pentry,
|
||||
unsigned short phys,
|
||||
unsigned char *pno)
|
||||
{
|
||||
unsigned i;
|
||||
|
||||
if(*pno != 0xFF && *pno >= 5)
|
||||
return NULL; /* We don't support extended partitions for now */
|
||||
|
||||
if(*pno != 0xFF)
|
||||
{
|
||||
if(pentry[*pno].type == LINUX_EXT2FS)
|
||||
return &pentry[*pno];
|
||||
else
|
||||
{
|
||||
if(!pentry[*pno].type)
|
||||
*pno = 0xFE;
|
||||
else if(pentry[*pno].type == LINUX_SWAP)
|
||||
*pno = 0xFD;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for(i = 0; i < 4; i++)
|
||||
if(pentry[i].type == LINUX_EXT2FS)
|
||||
{
|
||||
*pno = i;
|
||||
return &pentry[i];
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate libext2fs structures associated with I/O manager
|
||||
*/
|
||||
static io_channel alloc_io_channel(PARTITION *part)
|
||||
{
|
||||
io_channel ioch;
|
||||
|
||||
ioch = (io_channel)malloc(sizeof(struct struct_io_channel));
|
||||
if (!ioch)
|
||||
return NULL;
|
||||
memset(ioch, 0, sizeof(struct struct_io_channel));
|
||||
ioch->magic = EXT2_ET_MAGIC_IO_CHANNEL;
|
||||
ioch->manager = dos_io_manager;
|
||||
ioch->name = (char *)malloc(strlen(part->dev)+1);
|
||||
if (!ioch->name) {
|
||||
free(ioch);
|
||||
return NULL;
|
||||
}
|
||||
strcpy(ioch->name, part->dev);
|
||||
ioch->private_data = part;
|
||||
ioch->block_size = 1024; /* The smallest ext2fs block size */
|
||||
ioch->read_error = 0;
|
||||
ioch->write_error = 0;
|
||||
|
||||
return ioch;
|
||||
}
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
/*
|
||||
* Open the 'name' partition, initialize all information structures
|
||||
* we need to keep and create libext2fs I/O manager.
|
||||
*/
|
||||
static errcode_t dos_open(const char *dev, int flags, io_channel *channel)
|
||||
{
|
||||
unsigned char *tmp, sec[512];
|
||||
PARTITION *part;
|
||||
PTABLE_ENTRY *pent;
|
||||
PARTITION **newparts;
|
||||
|
||||
if(!dev)
|
||||
{
|
||||
_dio_error = ERR_BADDEV;
|
||||
return EXT2_ET_BAD_DEVICE_NAME;
|
||||
}
|
||||
|
||||
/*
|
||||
* First check whether the dev name is OK
|
||||
*/
|
||||
tmp = (unsigned char*)strrchr(dev, '/');
|
||||
if(!tmp)
|
||||
{
|
||||
_dio_error = ERR_BADDEV;
|
||||
return EXT2_ET_BAD_DEVICE_NAME;
|
||||
}
|
||||
*tmp = 0;
|
||||
if(strcmp(dev, "/dev"))
|
||||
{
|
||||
_dio_error = ERR_BADDEV;
|
||||
return EXT2_ET_BAD_DEVICE_NAME;
|
||||
}
|
||||
*tmp++ = '/';
|
||||
|
||||
/*
|
||||
* Check whether the partition data is already in cache
|
||||
*/
|
||||
|
||||
part = (PARTITION*)malloc(sizeof(PARTITION));
|
||||
if (!part)
|
||||
return ENOMEM;
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for(;i < npart; i++)
|
||||
if(!strcmp(partitions[i]->dev, dev))
|
||||
{
|
||||
/* Found it! Make it the active one */
|
||||
active = partitions[i];
|
||||
*channel = alloc_io_channel(active);
|
||||
if (!*channel)
|
||||
return ENOMEM;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Drive number & optionally partn number
|
||||
*/
|
||||
switch(tmp[0])
|
||||
{
|
||||
case 'h':
|
||||
case 's':
|
||||
part->phys = 0x80;
|
||||
part->phys += toupper(tmp[2]) - 'A';
|
||||
/*
|
||||
* Do we have the partition number?
|
||||
*/
|
||||
if(tmp[3])
|
||||
part->pno = isdigit((int)tmp[3]) ? tmp[3] - '0' - 1: 0;
|
||||
else
|
||||
part->pno = 0xFF;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if(tmp[2])
|
||||
part->phys = isdigit((int)tmp[2]) ? tmp[2] - '0' : 0;
|
||||
else
|
||||
part->phys = 0x00; /* We'll assume /dev/fd0 */
|
||||
break;
|
||||
|
||||
default:
|
||||
_dio_error = ERR_BADDEV;
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
if(part->phys < 0x80)
|
||||
{
|
||||
/* We don't support floppies for now */
|
||||
_dio_error = ERR_NOTSUPP;
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
part->dev = strdup(dev);
|
||||
|
||||
/*
|
||||
* Get drive's geometry
|
||||
*/
|
||||
_dio_hw_error = biosdisk(DISK_GET_GEOMETRY,
|
||||
part->phys,
|
||||
0, /* head */
|
||||
0, /* cylinder */
|
||||
1, /* sector */
|
||||
1, /* just one sector */
|
||||
sec);
|
||||
|
||||
if(!HW_OK())
|
||||
{
|
||||
_dio_error = ERR_HARDWARE;
|
||||
free(part->dev);
|
||||
free(part);
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the geometry
|
||||
*/
|
||||
part->cyls = (unsigned short)(((sec[0] >> 6) << 8) + sec[1] + 1);
|
||||
part->heads = sec[3] + 1;
|
||||
part->sects = sec[0] & 0x3F;
|
||||
|
||||
/*
|
||||
* Now that we know all we need, let's look for the partition
|
||||
*/
|
||||
_dio_hw_error = biosdisk(DISK_READ, part->phys, 0, 0, 1, 1, sec);
|
||||
|
||||
if(!HW_OK())
|
||||
{
|
||||
_dio_error = ERR_HARDWARE;
|
||||
free(part->dev);
|
||||
free(part);
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
pent = (PTABLE_ENTRY*)&sec[0x1BE];
|
||||
pent = scan_partition_table(pent, part->phys, &part->pno);
|
||||
|
||||
if(!pent)
|
||||
{
|
||||
_dio_error = part->pno == 0xFE ? ERR_EMPTYPART :
|
||||
part->pno == 0xFD ? ERR_LINUXSWAP : ERR_NOTEXT2FS;
|
||||
free(part->dev);
|
||||
free(part);
|
||||
return ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the remaining figures
|
||||
*/
|
||||
{
|
||||
unsigned long fsec, fhead, fcyl;
|
||||
|
||||
fsec = (unsigned long)(pent->start_sec & 0x3F);
|
||||
fhead = (unsigned long)pent->start_head;
|
||||
fcyl = ((pent->start_sec >> 6) << 8) + pent->start_cyl;
|
||||
part->start = fsec + fhead * part->sects + fcyl *
|
||||
(part->heads * part->sects) - 1;
|
||||
part->len = pent->size;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add the partition to the table
|
||||
*/
|
||||
newparts = (PARTITION**)realloc(partitions, sizeof(PARTITION) * npart);
|
||||
if (!newparts) {
|
||||
free(part);
|
||||
return ENOMEM;
|
||||
}
|
||||
partitions = newparts;
|
||||
partitions[npart++] = active = part;
|
||||
|
||||
/*
|
||||
* Now alloc all libe2fs structures
|
||||
*/
|
||||
*channel = alloc_io_channel(active);
|
||||
if (!*channel)
|
||||
return ENOMEM;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t dos_close(io_channel channel)
|
||||
{
|
||||
free(channel->name);
|
||||
free(channel);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t dos_set_blksize(io_channel channel, int blksize)
|
||||
{
|
||||
channel->block_size = blksize;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t dos_read_blk(io_channel channel, unsigned long block,
|
||||
int count, void *buf)
|
||||
{
|
||||
PARTITION *part;
|
||||
size_t size;
|
||||
ext2_loff_t loc;
|
||||
CHS chs;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
part = (PARTITION*)channel->private_data;
|
||||
|
||||
size = (size_t)((count < 0) ? -count : count * channel->block_size);
|
||||
loc = (ext2_loff_t) block * channel->block_size;
|
||||
|
||||
lba2chs(loc, &chs, part);
|
||||
/*
|
||||
* Potential bug here:
|
||||
* If DJGPP is used then reads of >18 sectors will fail!
|
||||
* Have to rewrite biosdisk.
|
||||
*/
|
||||
_dio_hw_error = biosdisk(DISK_READ,
|
||||
part->phys,
|
||||
chs.head,
|
||||
chs.cyl,
|
||||
chs.sector,
|
||||
size < 512 ? 1 : size/512,
|
||||
buf);
|
||||
|
||||
if(!HW_OK())
|
||||
{
|
||||
_dio_error = ERR_HARDWARE;
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t dos_write_blk(io_channel channel, unsigned long block,
|
||||
int count, const void *buf)
|
||||
{
|
||||
PARTITION *part;
|
||||
size_t size;
|
||||
ext2_loff_t loc;
|
||||
CHS chs;
|
||||
|
||||
EXT2_CHECK_MAGIC(channel, EXT2_ET_MAGIC_IO_CHANNEL);
|
||||
part = (PARTITION*)channel->private_data;
|
||||
|
||||
if(count == 1)
|
||||
size = (size_t)channel->block_size;
|
||||
else
|
||||
{
|
||||
if (count < 0)
|
||||
size = (size_t)-count;
|
||||
else
|
||||
size = (size_t)(count * channel->block_size);
|
||||
}
|
||||
|
||||
loc = (ext2_loff_t)block * channel->block_size;
|
||||
lba2chs(loc, &chs, part);
|
||||
_dio_hw_error = biosdisk(DISK_WRITE,
|
||||
part->phys,
|
||||
chs.head,
|
||||
chs.cyl,
|
||||
chs.sector,
|
||||
size < 512 ? 1 : size/512,
|
||||
(void*)buf);
|
||||
|
||||
if(!HW_OK())
|
||||
{
|
||||
_dio_error = ERR_HARDWARE;
|
||||
return EFAULT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
static errcode_t dos_flush(io_channel channel)
|
||||
{
|
||||
/*
|
||||
* No buffers, no flush...
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
122
jni/e2fsprogs/lib/ext2fs/dupfs.c
Executable file
122
jni/e2fsprogs/lib/ext2fs/dupfs.c
Executable file
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* dupfs.c --- duplicate a ext2 filesystem handle
|
||||
*
|
||||
* Copyright (C) 1997, 1998, 2001, 2003, 2005 by 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest)
|
||||
{
|
||||
ext2_filsys fs;
|
||||
errcode_t retval;
|
||||
|
||||
EXT2_CHECK_MAGIC(src, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
*fs = *src;
|
||||
fs->device_name = 0;
|
||||
fs->super = 0;
|
||||
fs->orig_super = 0;
|
||||
fs->group_desc = 0;
|
||||
fs->inode_map = 0;
|
||||
fs->block_map = 0;
|
||||
fs->badblocks = 0;
|
||||
fs->dblist = 0;
|
||||
fs->mmp_buf = 0;
|
||||
fs->mmp_cmp = 0;
|
||||
fs->mmp_fd = -1;
|
||||
|
||||
io_channel_bumpcount(fs->io);
|
||||
if (fs->icache)
|
||||
fs->icache->refcount++;
|
||||
|
||||
retval = ext2fs_get_mem(strlen(src->device_name)+1, &fs->device_name);
|
||||
if (retval)
|
||||
goto errout;
|
||||
strcpy(fs->device_name, src->device_name);
|
||||
|
||||
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->super);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(fs->super, src->super, SUPERBLOCK_SIZE);
|
||||
|
||||
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &fs->orig_super);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(fs->orig_super, src->orig_super, SUPERBLOCK_SIZE);
|
||||
|
||||
retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
|
||||
&fs->group_desc);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(fs->group_desc, src->group_desc,
|
||||
(size_t) fs->desc_blocks * fs->blocksize);
|
||||
|
||||
if (src->inode_map) {
|
||||
retval = ext2fs_copy_bitmap(src->inode_map, &fs->inode_map);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
if (src->block_map) {
|
||||
retval = ext2fs_copy_bitmap(src->block_map, &fs->block_map);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
if (src->badblocks) {
|
||||
retval = ext2fs_badblocks_copy(src->badblocks, &fs->badblocks);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
if (src->dblist) {
|
||||
retval = ext2fs_copy_dblist(src->dblist, &fs->dblist);
|
||||
if (retval)
|
||||
goto errout;
|
||||
}
|
||||
if (src->mmp_buf) {
|
||||
retval = ext2fs_get_mem(src->blocksize, &fs->mmp_buf);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(fs->mmp_buf, src->mmp_buf, src->blocksize);
|
||||
}
|
||||
if (src->mmp_fd >= 0) {
|
||||
fs->mmp_fd = dup(src->mmp_fd);
|
||||
if (fs->mmp_fd < 0) {
|
||||
retval = EXT2_ET_MMP_OPEN_DIRECT;
|
||||
goto errout;
|
||||
}
|
||||
}
|
||||
if (src->mmp_cmp) {
|
||||
int align = ext2fs_get_dio_alignment(src->mmp_fd);
|
||||
|
||||
retval = ext2fs_get_memalign(src->blocksize, align,
|
||||
&fs->mmp_cmp);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memcpy(fs->mmp_cmp, src->mmp_cmp, src->blocksize);
|
||||
}
|
||||
*dest = fs;
|
||||
return 0;
|
||||
errout:
|
||||
ext2fs_free(fs);
|
||||
return retval;
|
||||
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/dupfs.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/dupfs.o
Executable file
Binary file not shown.
143
jni/e2fsprogs/lib/ext2fs/expanddir.c
Executable file
143
jni/e2fsprogs/lib/ext2fs/expanddir.c
Executable file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* expand.c --- expand an ext2fs directory
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct expand_dir_struct {
|
||||
int done;
|
||||
int newblocks;
|
||||
blk64_t goal;
|
||||
errcode_t err;
|
||||
ext2_ino_t dir;
|
||||
};
|
||||
|
||||
static int expand_dir_proc(ext2_filsys fs,
|
||||
blk64_t *blocknr,
|
||||
e2_blkcnt_t blockcnt,
|
||||
blk64_t ref_block EXT2FS_ATTR((unused)),
|
||||
int ref_offset EXT2FS_ATTR((unused)),
|
||||
void *priv_data)
|
||||
{
|
||||
struct expand_dir_struct *es = (struct expand_dir_struct *) priv_data;
|
||||
blk64_t new_blk;
|
||||
char *block;
|
||||
errcode_t retval;
|
||||
|
||||
if (*blocknr) {
|
||||
if (blockcnt >= 0)
|
||||
es->goal = *blocknr;
|
||||
return 0;
|
||||
}
|
||||
if (blockcnt &&
|
||||
(EXT2FS_B2C(fs, es->goal) == EXT2FS_B2C(fs, es->goal+1)))
|
||||
new_blk = es->goal+1;
|
||||
else {
|
||||
es->goal &= ~EXT2FS_CLUSTER_MASK(fs);
|
||||
retval = ext2fs_new_block2(fs, es->goal, 0, &new_blk);
|
||||
if (retval) {
|
||||
es->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
es->newblocks++;
|
||||
ext2fs_block_alloc_stats2(fs, new_blk, +1);
|
||||
}
|
||||
if (blockcnt > 0) {
|
||||
retval = ext2fs_new_dir_block(fs, 0, 0, &block);
|
||||
if (retval) {
|
||||
es->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
es->done = 1;
|
||||
retval = ext2fs_write_dir_block4(fs, new_blk, block, 0,
|
||||
es->dir);
|
||||
ext2fs_free_mem(&block);
|
||||
} else
|
||||
retval = ext2fs_zero_blocks2(fs, new_blk, 1, NULL, NULL);
|
||||
if (blockcnt >= 0)
|
||||
es->goal = new_blk;
|
||||
if (retval) {
|
||||
es->err = retval;
|
||||
return BLOCK_ABORT;
|
||||
}
|
||||
*blocknr = new_blk;
|
||||
|
||||
if (es->done)
|
||||
return (BLOCK_CHANGED | BLOCK_ABORT);
|
||||
else
|
||||
return BLOCK_CHANGED;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_expand_dir(ext2_filsys fs, ext2_ino_t dir)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct expand_dir_struct es;
|
||||
struct ext2_inode inode;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
if (!(fs->flags & EXT2_FLAG_RW))
|
||||
return EXT2_ET_RO_FILSYS;
|
||||
|
||||
if (!fs->block_map)
|
||||
return EXT2_ET_NO_BLOCK_BITMAP;
|
||||
|
||||
retval = ext2fs_check_directory(fs, dir);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_read_inode(fs, dir, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
es.done = 0;
|
||||
es.err = 0;
|
||||
es.goal = ext2fs_find_inode_goal(fs, dir, &inode, 0);
|
||||
es.newblocks = 0;
|
||||
es.dir = dir;
|
||||
|
||||
retval = ext2fs_block_iterate3(fs, dir, BLOCK_FLAG_APPEND,
|
||||
0, expand_dir_proc, &es);
|
||||
if (retval == EXT2_ET_INLINE_DATA_CANT_ITERATE)
|
||||
return ext2fs_inline_data_expand(fs, dir);
|
||||
|
||||
if (es.err)
|
||||
return es.err;
|
||||
if (!es.done)
|
||||
return EXT2_ET_EXPAND_DIR_ERR;
|
||||
|
||||
/*
|
||||
* Update the size and block count fields in the inode.
|
||||
*/
|
||||
retval = ext2fs_read_inode(fs, dir, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_inode_size_set(fs, &inode,
|
||||
EXT2_I_SIZE(&inode) + fs->blocksize);
|
||||
if (retval)
|
||||
return retval;
|
||||
ext2fs_iblk_add_blocks(fs, &inode, es.newblocks);
|
||||
|
||||
retval = ext2fs_write_inode(fs, dir, &inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
return 0;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/expanddir.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/expanddir.o
Executable file
Binary file not shown.
237
jni/e2fsprogs/lib/ext2fs/ext2_err.c
Executable file
237
jni/e2fsprogs/lib/ext2fs/ext2_err.c
Executable file
@@ -0,0 +1,237 @@
|
||||
/*
|
||||
* ext2_err.c:
|
||||
* This file is automatically generated; please do not edit it.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#define N_(a) a
|
||||
|
||||
static const char * const text[] = {
|
||||
N_( "EXT2FS Library version android-t-qpr1-beta-2-gpl-369-g8ed4b2673"),
|
||||
N_( "Wrong magic number for ext2_filsys structure"),
|
||||
N_( "Wrong magic number for badblocks_list structure"),
|
||||
N_( "Wrong magic number for badblocks_iterate structure"),
|
||||
N_( "Wrong magic number for inode_scan structure"),
|
||||
N_( "Wrong magic number for io_channel structure"),
|
||||
N_( "Wrong magic number for unix io_channel structure"),
|
||||
N_( "Wrong magic number for io_manager structure"),
|
||||
N_( "Wrong magic number for block_bitmap structure"),
|
||||
N_( "Wrong magic number for inode_bitmap structure"),
|
||||
N_( "Wrong magic number for generic_bitmap structure"),
|
||||
N_( "Wrong magic number for test io_channel structure"),
|
||||
N_( "Wrong magic number for directory block list structure"),
|
||||
N_( "Wrong magic number for icount structure"),
|
||||
N_( "Wrong magic number for Powerquest io_channel structure"),
|
||||
N_( "Wrong magic number for ext2 file structure"),
|
||||
N_( "Wrong magic number for Ext2 Image Header"),
|
||||
N_( "Wrong magic number for inode io_channel structure"),
|
||||
N_( "Wrong magic number for ext4 extent handle"),
|
||||
N_( "Bad magic number in super-block"),
|
||||
N_( "Filesystem revision too high"),
|
||||
N_( "Attempt to write to filesystem opened read-only"),
|
||||
N_( "Can't read group descriptors"),
|
||||
N_( "Can't write group descriptors"),
|
||||
N_( "Corrupt group descriptor: bad block for block bitmap"),
|
||||
N_( "Corrupt group descriptor: bad block for inode bitmap"),
|
||||
N_( "Corrupt group descriptor: bad block for inode table"),
|
||||
N_( "Can't write an inode bitmap"),
|
||||
N_( "Can't read an inode bitmap"),
|
||||
N_( "Can't write a block bitmap"),
|
||||
N_( "Can't read a block bitmap"),
|
||||
N_( "Can't write an inode table"),
|
||||
N_( "Can't read an inode table"),
|
||||
N_( "Can't read next inode"),
|
||||
N_( "Filesystem has unexpected block size"),
|
||||
N_( "EXT2 directory corrupted"),
|
||||
N_( "Attempt to read block from filesystem resulted in short read"),
|
||||
N_( "Attempt to write block to filesystem resulted in short write"),
|
||||
N_( "No free space in the directory"),
|
||||
N_( "Inode bitmap not loaded"),
|
||||
N_( "Block bitmap not loaded"),
|
||||
N_( "Illegal inode number"),
|
||||
N_( "Illegal block number"),
|
||||
N_( "Internal error in ext2fs_expand_dir"),
|
||||
N_( "Not enough space to build proposed filesystem"),
|
||||
N_( "Illegal block number passed to ext2fs_mark_block_bitmap"),
|
||||
N_( "Illegal block number passed to ext2fs_unmark_block_bitmap"),
|
||||
N_( "Illegal block number passed to ext2fs_test_block_bitmap"),
|
||||
N_( "Illegal inode number passed to ext2fs_mark_inode_bitmap"),
|
||||
N_( "Illegal inode number passed to ext2fs_unmark_inode_bitmap"),
|
||||
N_( "Illegal inode number passed to ext2fs_test_inode_bitmap"),
|
||||
N_( "Attempt to fudge end of block bitmap past the real end"),
|
||||
N_( "Attempt to fudge end of inode bitmap past the real end"),
|
||||
N_( "Illegal indirect block found" ),
|
||||
N_( "Illegal doubly indirect block found" ),
|
||||
N_( "Illegal triply indirect block found" ),
|
||||
N_( "Block bitmaps are not the same"),
|
||||
N_( "Inode bitmaps are not the same"),
|
||||
N_( "Illegal or malformed device name"),
|
||||
N_( "A block group is missing an inode table"),
|
||||
N_( "The ext2 superblock is corrupt"),
|
||||
N_( "Illegal generic bit number passed to ext2fs_mark_generic_bitmap"),
|
||||
N_( "Illegal generic bit number passed to ext2fs_unmark_generic_bitmap"),
|
||||
N_( "Illegal generic bit number passed to ext2fs_test_generic_bitmap"),
|
||||
N_( "Too many symbolic links encountered."),
|
||||
N_( "The callback function will not handle this case"),
|
||||
N_( "The inode is from a bad block in the inode table"),
|
||||
N_( "Filesystem has unsupported feature(s)"),
|
||||
N_( "Filesystem has unsupported read-only feature(s)"),
|
||||
N_( "IO Channel failed to seek on read or write"),
|
||||
N_( "Memory allocation failed"),
|
||||
N_( "Invalid argument passed to ext2 library"),
|
||||
N_( "Could not allocate block in ext2 filesystem"),
|
||||
N_( "Could not allocate inode in ext2 filesystem"),
|
||||
N_( "Ext2 inode is not a directory"),
|
||||
N_( "Too many references in table"),
|
||||
N_( "File not found by ext2_lookup"),
|
||||
N_( "File open read-only"),
|
||||
N_( "Ext2 directory block not found"),
|
||||
N_( "Ext2 directory already exists"),
|
||||
N_( "Unimplemented ext2 library function"),
|
||||
N_( "User cancel requested"),
|
||||
N_( "Ext2 file too big"),
|
||||
N_( "Supplied journal device not a block device"),
|
||||
N_( "Journal superblock not found"),
|
||||
N_( "Journal must be at least 1024 blocks"),
|
||||
N_( "Unsupported journal version"),
|
||||
N_( "Error loading external journal"),
|
||||
N_( "Journal not found"),
|
||||
N_( "Directory hash unsupported"),
|
||||
N_( "Illegal extended attribute block number"),
|
||||
N_( "Cannot create filesystem with requested number of inodes"),
|
||||
N_( "E2image snapshot not in use"),
|
||||
N_( "Too many reserved group descriptor blocks"),
|
||||
N_( "Resize inode is corrupt"),
|
||||
N_( "Tried to set block bmap with missing indirect block"),
|
||||
N_( "TDB: Success"),
|
||||
N_( "TDB: Corrupt database"),
|
||||
N_( "TDB: IO Error"),
|
||||
N_( "TDB: Locking error"),
|
||||
N_( "TDB: Out of memory"),
|
||||
N_( "TDB: Record exists"),
|
||||
N_( "TDB: Lock exists on other keys"),
|
||||
N_( "TDB: Invalid parameter"),
|
||||
N_( "TDB: Record does not exist"),
|
||||
N_( "TDB: Write not permitted"),
|
||||
N_( "Ext2fs directory block list is empty"),
|
||||
N_( "Attempt to modify a block mapping via a read-only block iterator"),
|
||||
N_( "Wrong magic number for ext4 extent saved path"),
|
||||
N_( "Wrong magic number for 64-bit generic bitmap"),
|
||||
N_( "Wrong magic number for 64-bit block bitmap"),
|
||||
N_( "Wrong magic number for 64-bit inode bitmap"),
|
||||
N_( "Wrong magic number --- RESERVED_13"),
|
||||
N_( "Wrong magic number --- RESERVED_14"),
|
||||
N_( "Wrong magic number --- RESERVED_15"),
|
||||
N_( "Wrong magic number --- RESERVED_16"),
|
||||
N_( "Wrong magic number --- RESERVED_17"),
|
||||
N_( "Wrong magic number --- RESERVED_18"),
|
||||
N_( "Wrong magic number --- RESERVED_19"),
|
||||
N_( "Corrupt extent header"),
|
||||
N_( "Corrupt extent index"),
|
||||
N_( "Corrupt extent"),
|
||||
N_( "No free space in extent map"),
|
||||
N_( "Inode does not use extents"),
|
||||
N_( "No 'next' extent"),
|
||||
N_( "No 'previous' extent"),
|
||||
N_( "No 'up' extent"),
|
||||
N_( "No 'down' extent"),
|
||||
N_( "No current node"),
|
||||
N_( "Ext2fs operation not supported"),
|
||||
N_( "No room to insert extent in node"),
|
||||
N_( "Splitting would result in empty node"),
|
||||
N_( "Extent not found"),
|
||||
N_( "Operation not supported for inodes containing extents"),
|
||||
N_( "Extent length is invalid"),
|
||||
N_( "I/O Channel does not support 64-bit block numbers"),
|
||||
N_( "Can't check if filesystem is mounted due to missing mtab file"),
|
||||
N_( "Filesystem too large to use legacy bitmaps"),
|
||||
N_( "MMP: invalid magic number"),
|
||||
N_( "MMP: device currently active"),
|
||||
N_( "MMP: e2fsck being run"),
|
||||
N_( "MMP: block number beyond filesystem range"),
|
||||
N_( "MMP: undergoing an unknown operation"),
|
||||
N_( "MMP: filesystem still in use"),
|
||||
N_( "MMP: open with O_DIRECT failed"),
|
||||
N_( "Block group descriptor size incorrect"),
|
||||
N_( "Inode checksum does not match inode"),
|
||||
N_( "Inode bitmap checksum does not match bitmap"),
|
||||
N_( "Extent block checksum does not match extent block"),
|
||||
N_( "Directory block does not have space for checksum"),
|
||||
N_( "Directory block checksum does not match directory block"),
|
||||
N_( "Extended attribute block checksum does not match block"),
|
||||
N_( "Superblock checksum does not match superblock"),
|
||||
N_( "Unknown checksum algorithm"),
|
||||
N_( "MMP block checksum does not match"),
|
||||
N_( "Ext2 file already exists"),
|
||||
N_( "Block bitmap checksum does not match bitmap"),
|
||||
N_( "Cannot iterate data blocks of an inode containing inline data"),
|
||||
N_( "Extended attribute has an invalid name length"),
|
||||
N_( "Extended attribute has an invalid value length"),
|
||||
N_( "Extended attribute has an incorrect hash"),
|
||||
N_( "Extended attribute block has a bad header"),
|
||||
N_( "Extended attribute key not found"),
|
||||
N_( "Insufficient space to store extended attribute data"),
|
||||
N_( "Filesystem is missing ext_attr or inline_data feature"),
|
||||
N_( "Inode doesn't have inline data"),
|
||||
N_( "No block for an inode with inline data"),
|
||||
N_( "No free space in inline data"),
|
||||
N_( "Wrong magic number for extended attribute structure"),
|
||||
N_( "Inode seems to contain garbage"),
|
||||
N_( "Extended attribute has an invalid value offset"),
|
||||
N_( "Journal flags inconsistent"),
|
||||
N_( "Undo file corrupt"),
|
||||
N_( "Wrong undo file for this filesystem"),
|
||||
N_( "File system is corrupted"),
|
||||
N_( "Bad CRC detected in file system"),
|
||||
N_( "The journal superblock is corrupt"),
|
||||
N_( "Inode is corrupted"),
|
||||
N_( "Inode containing extended attribute value is corrupted"),
|
||||
N_( "Group descriptors not loaded"),
|
||||
N_( "The internal ext2_filsys data structure appears to be corrupted"),
|
||||
N_( "Found cyclic loop in extent tree"),
|
||||
N_( "Operation not supported on an external journal"),
|
||||
0
|
||||
};
|
||||
|
||||
struct error_table {
|
||||
char const * const * msgs;
|
||||
long base;
|
||||
int n_msgs;
|
||||
};
|
||||
struct et_list {
|
||||
struct et_list *next;
|
||||
const struct error_table * table;
|
||||
};
|
||||
extern struct et_list *_et_list;
|
||||
|
||||
const struct error_table et_ext2_error_table = { text, 2133571328L, 183 };
|
||||
|
||||
static struct et_list link = { 0, 0 };
|
||||
|
||||
void initialize_ext2_error_table_r(struct et_list **list);
|
||||
void initialize_ext2_error_table(void);
|
||||
|
||||
void initialize_ext2_error_table(void) {
|
||||
initialize_ext2_error_table_r(&_et_list);
|
||||
}
|
||||
|
||||
/* For Heimdal compatibility */
|
||||
void initialize_ext2_error_table_r(struct et_list **list)
|
||||
{
|
||||
struct et_list *et, **end;
|
||||
|
||||
for (end = list, et = *list; et; end = &et->next, et = et->next)
|
||||
if (et->table->msgs == text)
|
||||
return;
|
||||
et = malloc(sizeof(struct et_list));
|
||||
if (et == 0) {
|
||||
if (!link.table)
|
||||
et = &link;
|
||||
else
|
||||
return;
|
||||
}
|
||||
et->table = &et_ext2_error_table;
|
||||
et->next = 0;
|
||||
*end = et;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/ext2_err.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/ext2_err.o
Executable file
Binary file not shown.
1777
jni/e2fsprogs/lib/ext2fs/ext_attr.c
Executable file
1777
jni/e2fsprogs/lib/ext2fs/ext_attr.c
Executable file
File diff suppressed because it is too large
Load Diff
BIN
jni/e2fsprogs/lib/ext2fs/ext_attr.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/ext_attr.o
Executable file
Binary file not shown.
1877
jni/e2fsprogs/lib/ext2fs/extent.c
Executable file
1877
jni/e2fsprogs/lib/ext2fs/extent.c
Executable file
File diff suppressed because it is too large
Load Diff
BIN
jni/e2fsprogs/lib/ext2fs/extent.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/extent.o
Executable file
Binary file not shown.
873
jni/e2fsprogs/lib/ext2fs/fallocate.c
Executable file
873
jni/e2fsprogs/lib/ext2fs/fallocate.c
Executable file
@@ -0,0 +1,873 @@
|
||||
/*
|
||||
* fallocate.c -- Allocate large chunks of file.
|
||||
*
|
||||
* Copyright (C) 2014 Oracle.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#define min(a, b) ((a) < (b) ? (a) : (b))
|
||||
|
||||
#undef DEBUG
|
||||
|
||||
#ifdef DEBUG
|
||||
# define dbg_printf(f, a...) do {printf(f, ## a); fflush(stdout); } while (0)
|
||||
#else
|
||||
# define dbg_printf(f, a...)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Extent-based fallocate code.
|
||||
*
|
||||
* Find runs of unmapped logical blocks by starting at start and walking the
|
||||
* extents until we reach the end of the range we want.
|
||||
*
|
||||
* For each run of unmapped blocks, try to find the extents on either side of
|
||||
* the range. If there's a left extent that can grow by at least a cluster and
|
||||
* there are lblocks between start and the next lcluster after start, see if
|
||||
* there's an implied cluster allocation; if so, zero the blocks (if the left
|
||||
* extent is initialized) and adjust the extent. Ditto for the blocks between
|
||||
* the end of the last full lcluster and end, if there's a right extent.
|
||||
*
|
||||
* Try to attach as much as we can to the left extent, then try to attach as
|
||||
* much as we can to the right extent. For the remainder, try to allocate the
|
||||
* whole range; map in whatever we get; and repeat until we're done.
|
||||
*
|
||||
* To attach to a left extent, figure out the maximum amount we can add to the
|
||||
* extent and try to allocate that much, and append if successful. To attach
|
||||
* to a right extent, figure out the max we can add to the extent, try to
|
||||
* allocate that much, and prepend if successful.
|
||||
*
|
||||
* We need an alloc_range function that tells us how much we can allocate given
|
||||
* a maximum length and one of a suggested start, a fixed start, or a fixed end
|
||||
* point.
|
||||
*
|
||||
* Every time we modify the extent tree we also need to update the block stats.
|
||||
*
|
||||
* At the end, update i_blocks and i_size appropriately.
|
||||
*/
|
||||
|
||||
static void dbg_print_extent(const char *desc EXT2FS_ATTR((unused)),
|
||||
const struct ext2fs_extent *extent EXT2FS_ATTR((unused)))
|
||||
{
|
||||
#ifdef DEBUG
|
||||
if (desc)
|
||||
printf("%s: ", desc);
|
||||
printf("extent: lblk %llu--%llu, len %u, pblk %llu, flags: ",
|
||||
extent->e_lblk, extent->e_lblk + extent->e_len - 1,
|
||||
extent->e_len, extent->e_pblk);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_LEAF)
|
||||
fputs("LEAF ", stdout);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fputs("UNINIT ", stdout);
|
||||
if (extent->e_flags & EXT2_EXTENT_FLAGS_SECOND_VISIT)
|
||||
fputs("2ND_VISIT ", stdout);
|
||||
if (!extent->e_flags)
|
||||
fputs("(none)", stdout);
|
||||
fputc('\n', stdout);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
|
||||
static errcode_t claim_range(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t blk, blk64_t len)
|
||||
{
|
||||
blk64_t clusters;
|
||||
|
||||
clusters = (len + EXT2FS_CLUSTER_RATIO(fs) - 1) /
|
||||
EXT2FS_CLUSTER_RATIO(fs);
|
||||
ext2fs_block_alloc_stats_range(fs, blk,
|
||||
clusters * EXT2FS_CLUSTER_RATIO(fs), +1);
|
||||
return ext2fs_iblk_add_blocks(fs, inode, clusters);
|
||||
}
|
||||
|
||||
static errcode_t ext_falloc_helper(ext2_filsys fs,
|
||||
int flags,
|
||||
ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
ext2_extent_handle_t handle,
|
||||
struct ext2fs_extent *left_ext,
|
||||
struct ext2fs_extent *right_ext,
|
||||
blk64_t range_start, blk64_t range_len,
|
||||
blk64_t alloc_goal)
|
||||
{
|
||||
struct ext2fs_extent newex, ex;
|
||||
int op;
|
||||
blk64_t fillable, pblk, plen, x, y;
|
||||
blk64_t eof_blk = 0, cluster_fill = 0;
|
||||
errcode_t err;
|
||||
blk_t max_extent_len, max_uninit_len, max_init_len;
|
||||
|
||||
#ifdef DEBUG
|
||||
printf("%s: ", __func__);
|
||||
if (left_ext)
|
||||
printf("left_ext=%llu--%llu, ", left_ext->e_lblk,
|
||||
left_ext->e_lblk + left_ext->e_len - 1);
|
||||
if (right_ext)
|
||||
printf("right_ext=%llu--%llu, ", right_ext->e_lblk,
|
||||
right_ext->e_lblk + right_ext->e_len - 1);
|
||||
printf("start=%llu len=%llu, goal=%llu\n", range_start, range_len,
|
||||
alloc_goal);
|
||||
fflush(stdout);
|
||||
#endif
|
||||
/* Can't create initialized extents past EOF? */
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF))
|
||||
eof_blk = EXT2_I_SIZE(inode) / fs->blocksize;
|
||||
|
||||
/* The allocation goal must be as far into a cluster as range_start. */
|
||||
alloc_goal = (alloc_goal & ~EXT2FS_CLUSTER_MASK(fs)) |
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
|
||||
max_uninit_len = EXT_UNINIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
max_init_len = EXT_INIT_MAX_LEN & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
|
||||
/* We must lengthen the left extent to the end of the cluster */
|
||||
if (left_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
/* How many more blocks can be attached to left_ext? */
|
||||
if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - left_ext->e_len;
|
||||
else
|
||||
fillable = max_init_len - left_ext->e_len;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto expand_right;
|
||||
|
||||
/*
|
||||
* If range_start isn't on a cluster boundary, try an
|
||||
* implied cluster allocation for left_ext.
|
||||
*/
|
||||
cluster_fill = EXT2FS_CLUSTER_RATIO(fs) -
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
cluster_fill &= EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill == 0)
|
||||
goto expand_right;
|
||||
|
||||
if (cluster_fill > fillable)
|
||||
cluster_fill = fillable;
|
||||
|
||||
/* Don't expand an initialized left_ext beyond EOF */
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) {
|
||||
x = left_ext->e_lblk + left_ext->e_len - 1;
|
||||
dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n",
|
||||
__func__, x, x + cluster_fill, eof_blk);
|
||||
if (eof_blk >= x && eof_blk <= x + cluster_fill)
|
||||
cluster_fill = eof_blk - x;
|
||||
if (cluster_fill == 0)
|
||||
goto expand_right;
|
||||
}
|
||||
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto expand_right;
|
||||
left_ext->e_len += cluster_fill;
|
||||
range_start += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
alloc_goal += cluster_fill;
|
||||
|
||||
dbg_print_extent("ext_falloc clus left+", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) {
|
||||
err = ext2fs_zero_blocks2(fs, left_ext->e_pblk +
|
||||
left_ext->e_len -
|
||||
cluster_fill, cluster_fill,
|
||||
NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
expand_right:
|
||||
/* We must lengthen the right extent to the beginning of the cluster */
|
||||
if (right_ext && EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
/* How much can we attach to right_ext? */
|
||||
if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - right_ext->e_len;
|
||||
else
|
||||
fillable = max_init_len - right_ext->e_len;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto try_merge;
|
||||
|
||||
/*
|
||||
* If range_end isn't on a cluster boundary, try an implied
|
||||
* cluster allocation for right_ext.
|
||||
*/
|
||||
cluster_fill = right_ext->e_lblk & EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill == 0)
|
||||
goto try_merge;
|
||||
|
||||
err = ext2fs_extent_goto(handle, right_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (cluster_fill > fillable)
|
||||
cluster_fill = fillable;
|
||||
right_ext->e_lblk -= cluster_fill;
|
||||
right_ext->e_pblk -= cluster_fill;
|
||||
right_ext->e_len += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
|
||||
dbg_print_extent("ext_falloc clus right+", right_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, right_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) {
|
||||
err = ext2fs_zero_blocks2(fs, right_ext->e_pblk,
|
||||
cluster_fill, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_merge:
|
||||
/* Merge both extents together, perhaps? */
|
||||
if (left_ext && right_ext) {
|
||||
/* Are the two extents mergeable? */
|
||||
if ((left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) !=
|
||||
(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT))
|
||||
goto try_left;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_left;
|
||||
|
||||
/*
|
||||
* Skip initialized extent unless user wants to zero blocks
|
||||
* or requires init extent.
|
||||
*/
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(!(flags & EXT2_FALLOCATE_ZERO_BLOCKS) ||
|
||||
!(flags & EXT2_FALLOCATE_FORCE_INIT)))
|
||||
goto try_left;
|
||||
|
||||
/* Will it even fit? */
|
||||
x = left_ext->e_len + range_len + right_ext->e_len;
|
||||
if (x > (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT ?
|
||||
max_uninit_len : max_init_len))
|
||||
goto try_left;
|
||||
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto try_left;
|
||||
|
||||
/* Allocate blocks */
|
||||
y = left_ext->e_pblk + left_ext->e_len;
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH, y,
|
||||
right_ext->e_pblk - y + 1, NULL,
|
||||
&pblk, &plen);
|
||||
if (err)
|
||||
goto try_left;
|
||||
if (pblk + plen != right_ext->e_pblk)
|
||||
goto try_left;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify extents */
|
||||
left_ext->e_len = x;
|
||||
dbg_print_extent("ext_falloc merge", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_delete(handle, 0);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
*right_ext = *left_ext;
|
||||
|
||||
/* Zero blocks */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, range_start, range_len,
|
||||
NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
try_left:
|
||||
/* Extend the left extent */
|
||||
if (left_ext) {
|
||||
/* How many more blocks can be attached to left_ext? */
|
||||
if (left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - left_ext->e_len;
|
||||
else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS)
|
||||
fillable = max_init_len - left_ext->e_len;
|
||||
else
|
||||
fillable = 0;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_right;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
|
||||
/* Don't expand an initialized left_ext beyond EOF */
|
||||
x = left_ext->e_lblk + left_ext->e_len - 1;
|
||||
if (!(flags & EXT2_FALLOCATE_INIT_BEYOND_EOF)) {
|
||||
dbg_printf("%s: lend=%llu newlend=%llu eofblk=%llu\n",
|
||||
__func__, x, x + fillable, eof_blk);
|
||||
if (eof_blk >= x && eof_blk <= x + fillable)
|
||||
fillable = eof_blk - x;
|
||||
}
|
||||
|
||||
if (fillable == 0)
|
||||
goto try_right;
|
||||
|
||||
/* Test if the right edge of the range is already mapped? */
|
||||
if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode,
|
||||
x + fillable, &pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk)
|
||||
fillable -= 1 + ((x + fillable)
|
||||
& EXT2FS_CLUSTER_MASK(fs));
|
||||
if (fillable == 0)
|
||||
goto try_right;
|
||||
}
|
||||
|
||||
/* Allocate range of blocks */
|
||||
x = left_ext->e_pblk + left_ext->e_len;
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH,
|
||||
x, fillable, NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto try_right;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify left_ext */
|
||||
err = ext2fs_extent_goto(handle, left_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
range_start += plen;
|
||||
range_len -= plen;
|
||||
left_ext->e_len += plen;
|
||||
dbg_print_extent("ext_falloc left+", left_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, left_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(left_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_right:
|
||||
/* Extend the right extent */
|
||||
if (right_ext) {
|
||||
/* How much can we attach to right_ext? */
|
||||
if (right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)
|
||||
fillable = max_uninit_len - right_ext->e_len;
|
||||
else if (flags & EXT2_FALLOCATE_ZERO_BLOCKS)
|
||||
fillable = max_init_len - right_ext->e_len;
|
||||
else
|
||||
fillable = 0;
|
||||
|
||||
/* User requires init/uninit but extent is uninit/init. */
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)) ||
|
||||
((flags & EXT2_FALLOCATE_FORCE_UNINIT) &&
|
||||
!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT)))
|
||||
goto try_anywhere;
|
||||
|
||||
if (fillable > range_len)
|
||||
fillable = range_len;
|
||||
if (fillable == 0)
|
||||
goto try_anywhere;
|
||||
|
||||
/* Test if the left edge of the range is already mapped? */
|
||||
if (EXT2FS_CLUSTER_RATIO(fs) > 1) {
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode,
|
||||
right_ext->e_lblk - fillable, &pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk)
|
||||
fillable -= EXT2FS_CLUSTER_RATIO(fs) -
|
||||
((right_ext->e_lblk - fillable)
|
||||
& EXT2FS_CLUSTER_MASK(fs));
|
||||
if (fillable == 0)
|
||||
goto try_anywhere;
|
||||
}
|
||||
|
||||
/*
|
||||
* FIXME: It would be nice if we could handle allocating a
|
||||
* variable range from a fixed end point instead of just
|
||||
* skipping to the general allocator if the whole range is
|
||||
* unavailable.
|
||||
*/
|
||||
err = ext2fs_new_range(fs, EXT2_NEWRANGE_FIXED_GOAL |
|
||||
EXT2_NEWRANGE_MIN_LENGTH,
|
||||
right_ext->e_pblk - fillable,
|
||||
fillable, NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto try_anywhere;
|
||||
err = claim_range(fs, inode,
|
||||
pblk & ~EXT2FS_CLUSTER_MASK(fs),
|
||||
plen + (pblk & EXT2FS_CLUSTER_MASK(fs)));
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Modify right_ext */
|
||||
err = ext2fs_extent_goto(handle, right_ext->e_lblk);
|
||||
if (err)
|
||||
goto out;
|
||||
range_len -= plen;
|
||||
right_ext->e_lblk -= plen;
|
||||
right_ext->e_pblk -= plen;
|
||||
right_ext->e_len += plen;
|
||||
dbg_print_extent("ext_falloc right+", right_ext);
|
||||
err = ext2fs_extent_replace(handle, 0, right_ext);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Zero blocks if necessary */
|
||||
if (!(right_ext->e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk,
|
||||
plen + cluster_fill, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
try_anywhere:
|
||||
/* Try implied cluster alloc on the left and right ends */
|
||||
if (range_len > 0 && (range_start & EXT2FS_CLUSTER_MASK(fs))) {
|
||||
cluster_fill = EXT2FS_CLUSTER_RATIO(fs) -
|
||||
(range_start & EXT2FS_CLUSTER_MASK(fs));
|
||||
cluster_fill &= EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill > range_len)
|
||||
cluster_fill = range_len;
|
||||
newex.e_lblk = range_start;
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk,
|
||||
&pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk == 0)
|
||||
goto try_right_implied;
|
||||
newex.e_pblk = pblk;
|
||||
newex.e_len = cluster_fill;
|
||||
newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 :
|
||||
EXT2_EXTENT_FLAGS_UNINIT);
|
||||
dbg_print_extent("ext_falloc iclus left+", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, newex.e_pblk,
|
||||
newex.e_len, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
range_start += cluster_fill;
|
||||
range_len -= cluster_fill;
|
||||
}
|
||||
|
||||
try_right_implied:
|
||||
y = range_start + range_len;
|
||||
if (range_len > 0 && (y & EXT2FS_CLUSTER_MASK(fs))) {
|
||||
cluster_fill = y & EXT2FS_CLUSTER_MASK(fs);
|
||||
if (cluster_fill > range_len)
|
||||
cluster_fill = range_len;
|
||||
newex.e_lblk = y & ~EXT2FS_CLUSTER_MASK(fs);
|
||||
err = ext2fs_map_cluster_block(fs, ino, inode, newex.e_lblk,
|
||||
&pblk);
|
||||
if (err)
|
||||
goto out;
|
||||
if (pblk == 0)
|
||||
goto no_implied;
|
||||
newex.e_pblk = pblk;
|
||||
newex.e_len = cluster_fill;
|
||||
newex.e_flags = (flags & EXT2_FALLOCATE_FORCE_INIT ? 0 :
|
||||
EXT2_EXTENT_FLAGS_UNINIT);
|
||||
dbg_print_extent("ext_falloc iclus right+", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, newex.e_pblk,
|
||||
newex.e_len, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
range_len -= cluster_fill;
|
||||
}
|
||||
|
||||
no_implied:
|
||||
if (range_len == 0)
|
||||
return 0;
|
||||
|
||||
newex.e_lblk = range_start;
|
||||
if (flags & EXT2_FALLOCATE_FORCE_INIT) {
|
||||
max_extent_len = max_init_len;
|
||||
newex.e_flags = 0;
|
||||
} else {
|
||||
max_extent_len = max_uninit_len;
|
||||
newex.e_flags = EXT2_EXTENT_FLAGS_UNINIT;
|
||||
}
|
||||
pblk = alloc_goal;
|
||||
y = range_len;
|
||||
for (x = 0; x < y;) {
|
||||
cluster_fill = newex.e_lblk & EXT2FS_CLUSTER_MASK(fs);
|
||||
fillable = min(range_len + cluster_fill, max_extent_len);
|
||||
err = ext2fs_new_range(fs, 0, pblk & ~EXT2FS_CLUSTER_MASK(fs),
|
||||
fillable,
|
||||
NULL, &pblk, &plen);
|
||||
if (err)
|
||||
goto out;
|
||||
err = claim_range(fs, inode, pblk, plen);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
/* Create extent */
|
||||
newex.e_pblk = pblk + cluster_fill;
|
||||
newex.e_len = plen - cluster_fill;
|
||||
dbg_print_extent("ext_falloc create", &newex);
|
||||
ext2fs_extent_goto(handle, newex.e_lblk);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT,
|
||||
&ex);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE)
|
||||
ex.e_lblk = 0;
|
||||
else if (err)
|
||||
goto out;
|
||||
|
||||
if (ex.e_lblk > newex.e_lblk)
|
||||
op = 0; /* insert before */
|
||||
else
|
||||
op = EXT2_EXTENT_INSERT_AFTER;
|
||||
dbg_printf("%s: inserting %s lblk %llu newex=%llu\n",
|
||||
__func__, op ? "after" : "before", ex.e_lblk,
|
||||
newex.e_lblk);
|
||||
err = ext2fs_extent_insert(handle, op, &newex);
|
||||
if (err)
|
||||
goto out;
|
||||
err = ext2fs_extent_fix_parents(handle);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
if (!(newex.e_flags & EXT2_EXTENT_FLAGS_UNINIT) &&
|
||||
(flags & EXT2_FALLOCATE_ZERO_BLOCKS)) {
|
||||
err = ext2fs_zero_blocks2(fs, pblk, plen, NULL, NULL);
|
||||
if (err)
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Update variables at end of loop */
|
||||
x += plen - cluster_fill;
|
||||
range_len -= plen - cluster_fill;
|
||||
newex.e_lblk += plen - cluster_fill;
|
||||
pblk += plen - cluster_fill;
|
||||
if (pblk >= ext2fs_blocks_count(fs->super))
|
||||
pblk = fs->super->s_first_data_block;
|
||||
}
|
||||
|
||||
out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static errcode_t extent_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t goal,
|
||||
blk64_t start, blk64_t len)
|
||||
{
|
||||
ext2_extent_handle_t handle;
|
||||
struct ext2fs_extent left_extent, right_extent;
|
||||
struct ext2fs_extent *left_adjacent, *right_adjacent;
|
||||
errcode_t err;
|
||||
blk64_t range_start, range_end = 0, end, next;
|
||||
blk64_t count, goal_distance;
|
||||
|
||||
end = start + len - 1;
|
||||
err = ext2fs_extent_open2(fs, ino, inode, &handle);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* Find the extent closest to the start of the alloc range. We don't
|
||||
* check the return value because _goto() sets the current node to the
|
||||
* next-lowest extent if 'start' is in a hole; or the next-highest
|
||||
* extent if there aren't any lower ones; or doesn't set a current node
|
||||
* if there was a real error reading the extent tree. In that case,
|
||||
* _get() will error out.
|
||||
*/
|
||||
start_again:
|
||||
ext2fs_extent_goto(handle, start);
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_CURRENT, &left_extent);
|
||||
if (err == EXT2_ET_NO_CURRENT_NODE) {
|
||||
blk64_t max_blocks = ext2fs_blocks_count(fs->super);
|
||||
|
||||
if (goal == ~0ULL)
|
||||
goal = ext2fs_find_inode_goal(fs, ino, inode, start);
|
||||
err = ext2fs_find_first_zero_block_bitmap2(fs->block_map,
|
||||
goal, max_blocks - 1, &goal);
|
||||
goal += start;
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL,
|
||||
NULL, start, len, goal);
|
||||
goto errout;
|
||||
} else if (err)
|
||||
goto errout;
|
||||
|
||||
dbg_print_extent("ext_falloc initial", &left_extent);
|
||||
next = left_extent.e_lblk + left_extent.e_len;
|
||||
if (left_extent.e_lblk > start) {
|
||||
/* The nearest extent we found was beyond start??? */
|
||||
goal = left_extent.e_pblk - (left_extent.e_lblk - start);
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle, NULL,
|
||||
&left_extent, start,
|
||||
left_extent.e_lblk - start, goal);
|
||||
if (err)
|
||||
goto errout;
|
||||
|
||||
goto start_again;
|
||||
} else if (next >= start) {
|
||||
range_start = next;
|
||||
left_adjacent = &left_extent;
|
||||
} else {
|
||||
range_start = start;
|
||||
left_adjacent = NULL;
|
||||
}
|
||||
goal = left_extent.e_pblk + (range_start - left_extent.e_lblk);
|
||||
|
||||
do {
|
||||
err = ext2fs_extent_get(handle, EXT2_EXTENT_NEXT_LEAF,
|
||||
&right_extent);
|
||||
dbg_printf("%s: ino=%d get next =%d\n", __func__, ino,
|
||||
(int)err);
|
||||
dbg_print_extent("ext_falloc next", &right_extent);
|
||||
/* Stop if we've seen this extent before */
|
||||
if (!err && right_extent.e_lblk <= left_extent.e_lblk)
|
||||
err = EXT2_ET_EXTENT_NO_NEXT;
|
||||
|
||||
if (err && err != EXT2_ET_EXTENT_NO_NEXT)
|
||||
goto errout;
|
||||
if (err == EXT2_ET_EXTENT_NO_NEXT ||
|
||||
right_extent.e_lblk > end + 1) {
|
||||
range_end = end;
|
||||
right_adjacent = NULL;
|
||||
} else {
|
||||
/* Handle right_extent.e_lblk <= end */
|
||||
range_end = right_extent.e_lblk - 1;
|
||||
right_adjacent = &right_extent;
|
||||
}
|
||||
goal_distance = range_start - next;
|
||||
if (err != EXT2_ET_EXTENT_NO_NEXT &&
|
||||
goal_distance > (range_end - right_extent.e_lblk))
|
||||
goal = right_extent.e_pblk -
|
||||
(right_extent.e_lblk - range_start);
|
||||
|
||||
dbg_printf("%s: ino=%d rstart=%llu rend=%llu\n", __func__, ino,
|
||||
range_start, range_end);
|
||||
err = 0;
|
||||
if (range_start <= range_end) {
|
||||
count = range_end - range_start + 1;
|
||||
err = ext_falloc_helper(fs, flags, ino, inode, handle,
|
||||
left_adjacent, right_adjacent,
|
||||
range_start, count, goal);
|
||||
if (err)
|
||||
goto errout;
|
||||
}
|
||||
|
||||
if (range_end == end)
|
||||
break;
|
||||
|
||||
err = ext2fs_extent_goto(handle, right_extent.e_lblk);
|
||||
if (err)
|
||||
goto errout;
|
||||
next = right_extent.e_lblk + right_extent.e_len;
|
||||
left_extent = right_extent;
|
||||
left_adjacent = &left_extent;
|
||||
range_start = next;
|
||||
goal = left_extent.e_pblk + (range_start - left_extent.e_lblk);
|
||||
} while (range_end < end);
|
||||
|
||||
errout:
|
||||
ext2fs_extent_free(handle);
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* Map physical blocks to a range of logical blocks within a file. The range
|
||||
* of logical blocks are (start, start + len). If there are already extents,
|
||||
* the mappings will try to extend the mappings; otherwise, it will try to map
|
||||
* start as if logical block 0 points to goal. If goal is ~0ULL, then the goal
|
||||
* is calculated based on the inode group.
|
||||
*
|
||||
* Flags:
|
||||
* - EXT2_FALLOCATE_ZERO_BLOCKS: Zero the blocks that are allocated.
|
||||
* - EXT2_FALLOCATE_FORCE_INIT: Create only initialized extents.
|
||||
* - EXT2_FALLOCATE_FORCE_UNINIT: Create only uninitialized extents.
|
||||
* - EXT2_FALLOCATE_INIT_BEYOND_EOF: Create extents beyond EOF.
|
||||
*
|
||||
* If neither FORCE_INIT nor FORCE_UNINIT are specified, this function will
|
||||
* try to expand any extents it finds, zeroing blocks as necessary.
|
||||
*/
|
||||
errcode_t ext2fs_fallocate(ext2_filsys fs, int flags, ext2_ino_t ino,
|
||||
struct ext2_inode *inode, blk64_t goal,
|
||||
blk64_t start, blk64_t len)
|
||||
{
|
||||
struct ext2_inode inode_buf;
|
||||
blk64_t blk, x, zero_blk, last = 0;
|
||||
int zero_len = 0;
|
||||
errcode_t err;
|
||||
|
||||
if (((flags & EXT2_FALLOCATE_FORCE_INIT) &&
|
||||
(flags & EXT2_FALLOCATE_FORCE_UNINIT)) ||
|
||||
(flags & ~EXT2_FALLOCATE_ALL_FLAGS))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (len > ext2fs_blocks_count(fs->super))
|
||||
return EXT2_ET_BLOCK_ALLOC_FAIL;
|
||||
else if (len == 0)
|
||||
return 0;
|
||||
|
||||
/* Read inode structure if necessary */
|
||||
if (!inode) {
|
||||
err = ext2fs_read_inode(fs, ino, &inode_buf);
|
||||
if (err)
|
||||
return err;
|
||||
inode = &inode_buf;
|
||||
}
|
||||
dbg_printf("%s: ino=%d start=%llu len=%llu goal=%llu\n", __func__, ino,
|
||||
start, len, goal);
|
||||
|
||||
if (inode->i_flags & EXT4_EXTENTS_FL) {
|
||||
err = extent_fallocate(fs, flags, ino, inode, goal, start, len);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* XXX: Allocate a bunch of blocks the slow way */
|
||||
for (blk = start; blk < start + len; blk++) {
|
||||
err = ext2fs_bmap2(fs, ino, inode, NULL, 0, blk, 0, &x);
|
||||
if (err)
|
||||
return err;
|
||||
if (x)
|
||||
continue;
|
||||
|
||||
err = ext2fs_bmap2(fs, ino, inode, NULL, BMAP_ALLOC,
|
||||
blk, 0, &x);
|
||||
if (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;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/fallocate.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/fallocate.o
Executable file
Binary file not shown.
666
jni/e2fsprogs/lib/ext2fs/fileio.c
Executable file
666
jni/e2fsprogs/lib/ext2fs/fileio.c
Executable file
@@ -0,0 +1,666 @@
|
||||
/*
|
||||
* fileio.c --- Simple file I/O routines
|
||||
*
|
||||
* Copyright (C) 1997 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct ext2_file {
|
||||
errcode_t magic;
|
||||
ext2_filsys fs;
|
||||
ext2_ino_t ino;
|
||||
struct ext2_inode inode;
|
||||
int flags;
|
||||
__u64 pos;
|
||||
blk64_t blockno;
|
||||
blk64_t physblock;
|
||||
char *buf;
|
||||
};
|
||||
|
||||
struct block_entry {
|
||||
blk64_t physblock;
|
||||
unsigned char sha[EXT2FS_SHA512_LENGTH];
|
||||
};
|
||||
typedef struct block_entry *block_entry_t;
|
||||
|
||||
#define BMAP_BUFFER (file->buf + fs->blocksize)
|
||||
|
||||
errcode_t ext2fs_file_open2(ext2_filsys fs, ext2_ino_t ino,
|
||||
struct ext2_inode *inode,
|
||||
int flags, ext2_file_t *ret)
|
||||
{
|
||||
ext2_file_t file;
|
||||
errcode_t retval;
|
||||
|
||||
/*
|
||||
* Don't let caller create or open a file for writing if the
|
||||
* filesystem is read-only.
|
||||
*/
|
||||
if ((flags & (EXT2_FILE_WRITE | EXT2_FILE_CREATE)) &&
|
||||
!(fs->flags & EXT2_FLAG_RW))
|
||||
return EXT2_ET_RO_FILSYS;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2_file), &file);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
memset(file, 0, sizeof(struct ext2_file));
|
||||
file->magic = EXT2_ET_MAGIC_EXT2_FILE;
|
||||
file->fs = fs;
|
||||
file->ino = ino;
|
||||
file->flags = flags & EXT2_FILE_MASK;
|
||||
|
||||
if (inode) {
|
||||
memcpy(&file->inode, inode, sizeof(struct ext2_inode));
|
||||
} else {
|
||||
retval = ext2fs_read_inode(fs, ino, &file->inode);
|
||||
if (retval)
|
||||
goto fail;
|
||||
}
|
||||
|
||||
retval = ext2fs_get_array(3, fs->blocksize, &file->buf);
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
*ret = file;
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
if (file->buf)
|
||||
ext2fs_free_mem(&file->buf);
|
||||
ext2fs_free_mem(&file);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_file_open(ext2_filsys fs, ext2_ino_t ino,
|
||||
int flags, ext2_file_t *ret)
|
||||
{
|
||||
return ext2fs_file_open2(fs, ino, NULL, flags, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the filesystem handle of a file from the structure
|
||||
*/
|
||||
ext2_filsys ext2fs_file_get_fs(ext2_file_t file)
|
||||
{
|
||||
if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
|
||||
return 0;
|
||||
return file->fs;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the pointer to the inode of a file from the structure
|
||||
*/
|
||||
struct ext2_inode *ext2fs_file_get_inode(ext2_file_t file)
|
||||
{
|
||||
if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
|
||||
return NULL;
|
||||
return &file->inode;
|
||||
}
|
||||
|
||||
/* This function returns the inode number from the structure */
|
||||
ext2_ino_t ext2fs_file_get_inode_num(ext2_file_t file)
|
||||
{
|
||||
if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
|
||||
return 0;
|
||||
return file->ino;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function flushes the dirty block buffer out to disk if
|
||||
* necessary.
|
||||
*/
|
||||
errcode_t ext2fs_file_flush(ext2_file_t file)
|
||||
{
|
||||
errcode_t retval;
|
||||
ext2_filsys fs;
|
||||
int ret_flags;
|
||||
blk64_t dontcare;
|
||||
|
||||
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
|
||||
fs = file->fs;
|
||||
|
||||
if (!(file->flags & EXT2_FILE_BUF_VALID) ||
|
||||
!(file->flags & EXT2_FILE_BUF_DIRTY))
|
||||
return 0;
|
||||
|
||||
/* Is this an uninit block? */
|
||||
if (file->physblock && file->inode.i_flags & EXT4_EXTENTS_FL) {
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode, BMAP_BUFFER,
|
||||
0, file->blockno, &ret_flags, &dontcare);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (ret_flags & BMAP_RET_UNINIT) {
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
|
||||
BMAP_BUFFER, BMAP_SET,
|
||||
file->blockno, 0,
|
||||
&file->physblock);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, the physical block hasn't been allocated yet.
|
||||
* Allocate it.
|
||||
*/
|
||||
if (!file->physblock) {
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
|
||||
BMAP_BUFFER, file->ino ? BMAP_ALLOC : 0,
|
||||
file->blockno, 0, &file->physblock);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = io_channel_write_blk64(fs->io, file->physblock, 1, file->buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
file->flags &= ~EXT2_FILE_BUF_DIRTY;
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function synchronizes the file's block buffer and the current
|
||||
* file position, possibly invalidating block buffer if necessary
|
||||
*/
|
||||
static errcode_t sync_buffer_position(ext2_file_t file)
|
||||
{
|
||||
blk64_t b;
|
||||
errcode_t retval;
|
||||
|
||||
b = file->pos / file->fs->blocksize;
|
||||
if (b != file->blockno) {
|
||||
retval = ext2fs_file_flush(file);
|
||||
if (retval)
|
||||
return retval;
|
||||
file->flags &= ~EXT2_FILE_BUF_VALID;
|
||||
}
|
||||
file->blockno = b;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function loads the file's block buffer with valid data from
|
||||
* the disk as necessary.
|
||||
*
|
||||
* If dontfill is true, then skip initializing the buffer since we're
|
||||
* going to be replacing its entire contents anyway. If set, then the
|
||||
* function basically only sets file->physblock and EXT2_FILE_BUF_VALID
|
||||
*/
|
||||
#define DONTFILL 1
|
||||
static errcode_t load_buffer(ext2_file_t file, int dontfill)
|
||||
{
|
||||
ext2_filsys fs = file->fs;
|
||||
errcode_t retval;
|
||||
int ret_flags;
|
||||
|
||||
if (!(file->flags & EXT2_FILE_BUF_VALID)) {
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
|
||||
BMAP_BUFFER, 0, file->blockno, &ret_flags,
|
||||
&file->physblock);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (!dontfill) {
|
||||
if (file->physblock &&
|
||||
!(ret_flags & BMAP_RET_UNINIT)) {
|
||||
retval = io_channel_read_blk64(fs->io,
|
||||
file->physblock,
|
||||
1, file->buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
} else
|
||||
memset(file->buf, 0, fs->blocksize);
|
||||
}
|
||||
file->flags |= EXT2_FILE_BUF_VALID;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
errcode_t ext2fs_file_close(ext2_file_t file)
|
||||
{
|
||||
errcode_t retval;
|
||||
|
||||
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
|
||||
|
||||
retval = ext2fs_file_flush(file);
|
||||
|
||||
if (file->buf)
|
||||
ext2fs_free_mem(&file->buf);
|
||||
ext2fs_free_mem(&file);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static errcode_t
|
||||
ext2fs_file_read_inline_data(ext2_file_t file, void *buf,
|
||||
unsigned int wanted, unsigned int *got)
|
||||
{
|
||||
ext2_filsys fs;
|
||||
errcode_t retval;
|
||||
unsigned int count = 0;
|
||||
size_t size;
|
||||
|
||||
fs = file->fs;
|
||||
retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
|
||||
file->buf, &size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (file->pos >= size)
|
||||
goto out;
|
||||
|
||||
count = size - file->pos;
|
||||
if (count > wanted)
|
||||
count = wanted;
|
||||
memcpy(buf, file->buf + file->pos, count);
|
||||
file->pos += count;
|
||||
buf = (char *) buf + count;
|
||||
|
||||
out:
|
||||
if (got)
|
||||
*got = count;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
errcode_t ext2fs_file_read(ext2_file_t file, void *buf,
|
||||
unsigned int wanted, unsigned int *got)
|
||||
{
|
||||
ext2_filsys fs;
|
||||
errcode_t retval = 0;
|
||||
unsigned int start, c, count = 0;
|
||||
__u64 left;
|
||||
char *ptr = (char *) buf;
|
||||
|
||||
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
|
||||
fs = file->fs;
|
||||
|
||||
/* If an inode has inline data, things get complicated. */
|
||||
if (file->inode.i_flags & EXT4_INLINE_DATA_FL)
|
||||
return ext2fs_file_read_inline_data(file, buf, wanted, got);
|
||||
|
||||
while ((file->pos < EXT2_I_SIZE(&file->inode)) && (wanted > 0)) {
|
||||
retval = sync_buffer_position(file);
|
||||
if (retval)
|
||||
goto fail;
|
||||
retval = load_buffer(file, 0);
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
start = file->pos % fs->blocksize;
|
||||
c = fs->blocksize - start;
|
||||
if (c > wanted)
|
||||
c = wanted;
|
||||
left = EXT2_I_SIZE(&file->inode) - file->pos ;
|
||||
if (c > left)
|
||||
c = left;
|
||||
|
||||
memcpy(ptr, file->buf+start, c);
|
||||
file->pos += c;
|
||||
ptr += c;
|
||||
count += c;
|
||||
wanted -= c;
|
||||
}
|
||||
|
||||
fail:
|
||||
if (got)
|
||||
*got = count;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
static errcode_t
|
||||
ext2fs_file_write_inline_data(ext2_file_t file, const void *buf,
|
||||
unsigned int nbytes, unsigned int *written)
|
||||
{
|
||||
ext2_filsys fs;
|
||||
errcode_t retval;
|
||||
unsigned int count = 0;
|
||||
size_t size;
|
||||
|
||||
fs = file->fs;
|
||||
retval = ext2fs_inline_data_get(fs, file->ino, &file->inode,
|
||||
file->buf, &size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (file->pos < size) {
|
||||
count = nbytes - file->pos;
|
||||
memcpy(file->buf + file->pos, buf, count);
|
||||
|
||||
retval = ext2fs_inline_data_set(fs, file->ino, &file->inode,
|
||||
file->buf, count);
|
||||
if (retval == EXT2_ET_INLINE_DATA_NO_SPACE)
|
||||
goto expand;
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
file->pos += count;
|
||||
|
||||
/* Update inode size */
|
||||
if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
|
||||
errcode_t rc;
|
||||
|
||||
rc = ext2fs_file_set_size2(file, file->pos);
|
||||
if (retval == 0)
|
||||
retval = rc;
|
||||
}
|
||||
|
||||
if (written)
|
||||
*written = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
expand:
|
||||
retval = ext2fs_inline_data_expand(fs, file->ino);
|
||||
if (retval)
|
||||
return retval;
|
||||
/*
|
||||
* reload inode and return no space error
|
||||
*
|
||||
* XXX: file->inode could be copied from the outside
|
||||
* in ext2fs_file_open2(). We have no way to modify
|
||||
* the outside inode.
|
||||
*/
|
||||
retval = ext2fs_read_inode(fs, file->ino, &file->inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
return EXT2_ET_INLINE_DATA_NO_SPACE;
|
||||
}
|
||||
|
||||
|
||||
errcode_t ext2fs_file_write(ext2_file_t file, const void *buf,
|
||||
unsigned int nbytes, unsigned int *written)
|
||||
{
|
||||
ext2_filsys fs;
|
||||
errcode_t retval = 0;
|
||||
unsigned int start, c, count = 0;
|
||||
const char *ptr = (const char *) buf;
|
||||
block_entry_t new_block = NULL, old_block = NULL;
|
||||
int bmap_flags = 0;
|
||||
|
||||
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
|
||||
fs = file->fs;
|
||||
|
||||
if (!(file->flags & EXT2_FILE_WRITE))
|
||||
return EXT2_ET_FILE_RO;
|
||||
|
||||
/* If an inode has inline data, things get complicated. */
|
||||
if (file->inode.i_flags & EXT4_INLINE_DATA_FL) {
|
||||
retval = ext2fs_file_write_inline_data(file, buf, nbytes,
|
||||
written);
|
||||
if (retval != EXT2_ET_INLINE_DATA_NO_SPACE)
|
||||
return retval;
|
||||
/* fall through to read data from the block */
|
||||
retval = 0;
|
||||
}
|
||||
|
||||
while (nbytes > 0) {
|
||||
retval = sync_buffer_position(file);
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
start = file->pos % fs->blocksize;
|
||||
c = fs->blocksize - start;
|
||||
if (c > nbytes)
|
||||
c = nbytes;
|
||||
|
||||
/*
|
||||
* We only need to do a read-modify-update cycle if
|
||||
* we're doing a partial write.
|
||||
*/
|
||||
retval = load_buffer(file, (c == fs->blocksize));
|
||||
if (retval)
|
||||
goto fail;
|
||||
|
||||
file->flags |= EXT2_FILE_BUF_DIRTY;
|
||||
memcpy(file->buf+start, ptr, c);
|
||||
|
||||
/*
|
||||
* OK, the physical block hasn't been allocated yet.
|
||||
* Allocate it.
|
||||
*/
|
||||
if (!file->physblock) {
|
||||
bmap_flags = (file->ino ? BMAP_ALLOC : 0);
|
||||
if (fs->flags & EXT2_FLAG_SHARE_DUP) {
|
||||
new_block = calloc(1, sizeof(*new_block));
|
||||
if (!new_block) {
|
||||
retval = EXT2_ET_NO_MEMORY;
|
||||
goto fail;
|
||||
}
|
||||
ext2fs_sha512((const unsigned char*)file->buf,
|
||||
fs->blocksize, new_block->sha);
|
||||
old_block = ext2fs_hashmap_lookup(
|
||||
fs->block_sha_map,
|
||||
new_block->sha,
|
||||
sizeof(new_block->sha));
|
||||
}
|
||||
|
||||
if (old_block) {
|
||||
file->physblock = old_block->physblock;
|
||||
bmap_flags |= BMAP_SET;
|
||||
free(new_block);
|
||||
new_block = NULL;
|
||||
}
|
||||
|
||||
retval = ext2fs_bmap2(fs, file->ino, &file->inode,
|
||||
BMAP_BUFFER,
|
||||
bmap_flags,
|
||||
file->blockno, 0,
|
||||
&file->physblock);
|
||||
if (retval) {
|
||||
free(new_block);
|
||||
new_block = NULL;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (new_block) {
|
||||
new_block->physblock = file->physblock;
|
||||
int ret = ext2fs_hashmap_add(fs->block_sha_map,
|
||||
new_block, new_block->sha,
|
||||
sizeof(new_block->sha));
|
||||
if (ret) {
|
||||
retval = EXT2_ET_NO_MEMORY;
|
||||
free(new_block);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if (bmap_flags & BMAP_SET) {
|
||||
ext2fs_iblk_add_blocks(fs, &file->inode, 1);
|
||||
ext2fs_write_inode(fs, file->ino, &file->inode);
|
||||
}
|
||||
}
|
||||
|
||||
file->pos += c;
|
||||
ptr += c;
|
||||
count += c;
|
||||
nbytes -= c;
|
||||
}
|
||||
|
||||
fail:
|
||||
/* Update inode size */
|
||||
if (count != 0 && EXT2_I_SIZE(&file->inode) < file->pos) {
|
||||
errcode_t rc;
|
||||
|
||||
rc = ext2fs_file_set_size2(file, file->pos);
|
||||
if (retval == 0)
|
||||
retval = rc;
|
||||
}
|
||||
|
||||
if (written)
|
||||
*written = count;
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_file_llseek(ext2_file_t file, __u64 offset,
|
||||
int whence, __u64 *ret_pos)
|
||||
{
|
||||
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
|
||||
|
||||
if (whence == EXT2_SEEK_SET)
|
||||
file->pos = offset;
|
||||
else if (whence == EXT2_SEEK_CUR)
|
||||
file->pos += offset;
|
||||
else if (whence == EXT2_SEEK_END)
|
||||
file->pos = EXT2_I_SIZE(&file->inode) + offset;
|
||||
else
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (ret_pos)
|
||||
*ret_pos = file->pos;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_file_lseek(ext2_file_t file, ext2_off_t offset,
|
||||
int whence, ext2_off_t *ret_pos)
|
||||
{
|
||||
__u64 loffset, ret_loffset = 0;
|
||||
errcode_t retval;
|
||||
|
||||
loffset = offset;
|
||||
retval = ext2fs_file_llseek(file, loffset, whence, &ret_loffset);
|
||||
if (ret_pos)
|
||||
*ret_pos = (ext2_off_t) ret_loffset;
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* This function returns the size of the file, according to the inode
|
||||
*/
|
||||
errcode_t ext2fs_file_get_lsize(ext2_file_t file, __u64 *ret_size)
|
||||
{
|
||||
if (file->magic != EXT2_ET_MAGIC_EXT2_FILE)
|
||||
return EXT2_ET_MAGIC_EXT2_FILE;
|
||||
*ret_size = EXT2_I_SIZE(&file->inode);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function returns the size of the file, according to the inode
|
||||
*/
|
||||
ext2_off_t ext2fs_file_get_size(ext2_file_t file)
|
||||
{
|
||||
__u64 size;
|
||||
|
||||
if (ext2fs_file_get_lsize(file, &size))
|
||||
return 0;
|
||||
if ((size >> 32) != 0)
|
||||
return 0;
|
||||
return size;
|
||||
}
|
||||
|
||||
/* Zero the parts of the last block that are past EOF. */
|
||||
static errcode_t ext2fs_file_zero_past_offset(ext2_file_t file,
|
||||
ext2_off64_t offset)
|
||||
{
|
||||
ext2_filsys fs = file->fs;
|
||||
char *b = NULL;
|
||||
ext2_off64_t off = offset % fs->blocksize;
|
||||
blk64_t blk;
|
||||
int ret_flags;
|
||||
errcode_t retval;
|
||||
|
||||
if (off == 0)
|
||||
return 0;
|
||||
|
||||
retval = sync_buffer_position(file);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Is there an initialized block at the end? */
|
||||
retval = ext2fs_bmap2(fs, file->ino, NULL, NULL, 0,
|
||||
offset / fs->blocksize, &ret_flags, &blk);
|
||||
if (retval)
|
||||
return retval;
|
||||
if ((blk == 0) || (ret_flags & BMAP_RET_UNINIT))
|
||||
return 0;
|
||||
|
||||
/* Zero to the end of the block */
|
||||
retval = ext2fs_get_mem(fs->blocksize, &b);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
/* Read/zero/write block */
|
||||
retval = io_channel_read_blk64(fs->io, blk, 1, b);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
memset(b + off, 0, fs->blocksize - off);
|
||||
|
||||
retval = io_channel_write_blk64(fs->io, blk, 1, b);
|
||||
if (retval)
|
||||
goto out;
|
||||
|
||||
out:
|
||||
ext2fs_free_mem(&b);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function sets the size of the file, truncating it if necessary
|
||||
*
|
||||
*/
|
||||
errcode_t ext2fs_file_set_size2(ext2_file_t file, ext2_off64_t size)
|
||||
{
|
||||
ext2_off64_t old_size;
|
||||
errcode_t retval;
|
||||
blk64_t old_truncate, truncate_block;
|
||||
|
||||
EXT2_CHECK_MAGIC(file, EXT2_ET_MAGIC_EXT2_FILE);
|
||||
|
||||
if (size && ext2fs_file_block_offset_too_big(file->fs, &file->inode,
|
||||
(size - 1) / file->fs->blocksize))
|
||||
return EXT2_ET_FILE_TOO_BIG;
|
||||
truncate_block = ((size + file->fs->blocksize - 1) >>
|
||||
EXT2_BLOCK_SIZE_BITS(file->fs->super));
|
||||
old_size = EXT2_I_SIZE(&file->inode);
|
||||
old_truncate = ((old_size + file->fs->blocksize - 1) >>
|
||||
EXT2_BLOCK_SIZE_BITS(file->fs->super));
|
||||
|
||||
retval = ext2fs_inode_size_set(file->fs, &file->inode, size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (file->ino) {
|
||||
retval = ext2fs_write_inode(file->fs, file->ino, &file->inode);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
|
||||
retval = ext2fs_file_zero_past_offset(file, size);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (truncate_block >= old_truncate)
|
||||
return 0;
|
||||
|
||||
return ext2fs_punch(file->fs, file->ino, &file->inode, 0,
|
||||
truncate_block, ~0ULL);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_file_set_size(ext2_file_t file, ext2_off_t size)
|
||||
{
|
||||
return ext2fs_file_set_size2(file, size);
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/fileio.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/fileio.o
Executable file
Binary file not shown.
218
jni/e2fsprogs/lib/ext2fs/finddev.c
Executable file
218
jni/e2fsprogs/lib/ext2fs/finddev.c
Executable file
@@ -0,0 +1,218 @@
|
||||
/*
|
||||
* finddev.c -- this routine attempts to find a particular device in
|
||||
* /dev
|
||||
*
|
||||
* Copyright (C) 2000 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <dirent.h>
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MKDEV_H
|
||||
#include <sys/mkdev.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_SYSMACROS_H
|
||||
#include <sys/sysmacros.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct dir_list {
|
||||
char *name;
|
||||
struct dir_list *next;
|
||||
};
|
||||
|
||||
/*
|
||||
* This function adds an entry to the directory list
|
||||
*/
|
||||
static void add_to_dirlist(const char *name, struct dir_list **list)
|
||||
{
|
||||
struct dir_list *dp;
|
||||
|
||||
dp = malloc(sizeof(struct dir_list));
|
||||
if (!dp)
|
||||
return;
|
||||
dp->name = malloc(strlen(name)+1);
|
||||
if (!dp->name) {
|
||||
free(dp);
|
||||
return;
|
||||
}
|
||||
strcpy(dp->name, name);
|
||||
dp->next = *list;
|
||||
*list = dp;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function frees a directory list
|
||||
*/
|
||||
static void free_dirlist(struct dir_list **list)
|
||||
{
|
||||
struct dir_list *dp, *next;
|
||||
|
||||
for (dp = *list; dp; dp = next) {
|
||||
next = dp->next;
|
||||
free(dp->name);
|
||||
free(dp);
|
||||
}
|
||||
*list = 0;
|
||||
}
|
||||
|
||||
static int scan_dir(char *dirname, dev_t device, struct dir_list **list,
|
||||
char **ret_path)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *dp;
|
||||
char path[1024], *cp;
|
||||
int dirlen;
|
||||
struct stat st;
|
||||
|
||||
dirlen = strlen(dirname);
|
||||
if ((dir = opendir(dirname)) == NULL)
|
||||
return errno;
|
||||
dp = readdir(dir);
|
||||
while (dp) {
|
||||
if (dirlen + strlen(dp->d_name) + 2 >= sizeof(path))
|
||||
goto skip_to_next;
|
||||
if (dp->d_name[0] == '.' &&
|
||||
((dp->d_name[1] == 0) ||
|
||||
((dp->d_name[1] == '.') && (dp->d_name[2] == 0))))
|
||||
goto skip_to_next;
|
||||
sprintf(path, "%s/%s", dirname, dp->d_name);
|
||||
if (stat(path, &st) < 0)
|
||||
goto skip_to_next;
|
||||
if (S_ISDIR(st.st_mode))
|
||||
add_to_dirlist(path, list);
|
||||
if (ext2fsP_is_disk_device(st.st_mode) &&
|
||||
st.st_rdev == device) {
|
||||
cp = malloc(strlen(path)+1);
|
||||
if (!cp) {
|
||||
closedir(dir);
|
||||
return ENOMEM;
|
||||
}
|
||||
strcpy(cp, path);
|
||||
*ret_path = cp;
|
||||
goto success;
|
||||
}
|
||||
skip_to_next:
|
||||
dp = readdir(dir);
|
||||
}
|
||||
success:
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function finds the pathname to a block device with a given
|
||||
* device number. It returns a pointer to allocated memory to the
|
||||
* pathname on success, and NULL on failure.
|
||||
*/
|
||||
char *ext2fs_find_block_device(dev_t device)
|
||||
{
|
||||
struct dir_list *list = 0, *new_list = 0;
|
||||
struct dir_list *current;
|
||||
char *ret_path = 0;
|
||||
int level = 0;
|
||||
|
||||
/*
|
||||
* Add the starting directories to search...
|
||||
*/
|
||||
add_to_dirlist("/devices", &list);
|
||||
add_to_dirlist("/devfs", &list);
|
||||
add_to_dirlist("/dev", &list);
|
||||
|
||||
while (list) {
|
||||
current = list;
|
||||
list = list->next;
|
||||
#ifdef DEBUG
|
||||
printf("Scanning directory %s\n", current->name);
|
||||
#endif
|
||||
scan_dir(current->name, device, &new_list, &ret_path);
|
||||
free(current->name);
|
||||
free(current);
|
||||
if (ret_path)
|
||||
break;
|
||||
/*
|
||||
* If we're done checking at this level, descend to
|
||||
* the next level of subdirectories. (breadth-first)
|
||||
*/
|
||||
if (list == 0) {
|
||||
list = new_list;
|
||||
new_list = 0;
|
||||
/* Avoid infinite loop */
|
||||
if (++level >= EXT2FS_MAX_NESTED_LINKS)
|
||||
break;
|
||||
}
|
||||
}
|
||||
free_dirlist(&list);
|
||||
free_dirlist(&new_list);
|
||||
return ret_path;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
char *devname, *tmp;
|
||||
int major, minor;
|
||||
dev_t device;
|
||||
const char *errmsg = "Couldn't parse %s: %s\n";
|
||||
|
||||
if ((argc != 2) && (argc != 3)) {
|
||||
fprintf(stderr, "Usage: %s device_number\n", argv[0]);
|
||||
fprintf(stderr, "\t: %s major minor\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
if (argc == 2) {
|
||||
device = strtoul(argv[1], &tmp, 0);
|
||||
if (*tmp) {
|
||||
fprintf(stderr, errmsg, "device number", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
major = strtoul(argv[1], &tmp, 0);
|
||||
if (*tmp) {
|
||||
fprintf(stderr, errmsg, "major number", argv[1]);
|
||||
exit(1);
|
||||
}
|
||||
minor = strtoul(argv[2], &tmp, 0);
|
||||
if (*tmp) {
|
||||
fprintf(stderr, errmsg, "minor number", argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
device = makedev(major, minor);
|
||||
printf("Looking for device 0x%04x (%d:%d)\n", device,
|
||||
major, minor);
|
||||
}
|
||||
devname = ext2fs_find_block_device(device);
|
||||
if (devname) {
|
||||
printf("Found device! %s\n", devname);
|
||||
free(devname);
|
||||
} else {
|
||||
printf("Couldn't find device.\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/finddev.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/finddev.o
Executable file
Binary file not shown.
88
jni/e2fsprogs/lib/ext2fs/flushb.c
Executable file
88
jni/e2fsprogs/lib/ext2fs/flushb.c
Executable file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* flushb.c --- Hides system-dependent information for both syncing a
|
||||
* device to disk and to flush any buffers from disk cache.
|
||||
*
|
||||
* Copyright (C) 2000 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>
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#if HAVE_SYS_MOUNT_H
|
||||
#include <sys/param.h>
|
||||
#include <sys/mount.h> /* This may define BLKFLSBUF */
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* For Linux, define BLKFLSBUF and FDFLUSH if necessary, since
|
||||
* not all portable header file does so for us. This really should be
|
||||
* fixed in the glibc header files. (Recent glibcs appear to define
|
||||
* BLKFLSBUF in sys/mount.h, but FDFLUSH still doesn't seem to be
|
||||
* defined anywhere portable.) Until then....
|
||||
*/
|
||||
#ifdef __linux__
|
||||
#ifndef BLKFLSBUF
|
||||
#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */
|
||||
#endif
|
||||
#ifndef FDFLUSH
|
||||
#define FDFLUSH _IO(2,0x4b) /* flush floppy disk */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function will sync a device/file, and optionally attempt to
|
||||
* flush the buffer cache. The latter is basically only useful for
|
||||
* system benchmarks and for torturing systems in burn-in tests. :)
|
||||
*/
|
||||
errcode_t ext2fs_sync_device(int fd, int flushb)
|
||||
{
|
||||
/*
|
||||
* We always sync the device in case we're running on old
|
||||
* kernels for which we can lose data if we don't. (There
|
||||
* still is a race condition for those kernels, but this
|
||||
* reduces it greatly.)
|
||||
*/
|
||||
#if defined(HAVE_FSYNC)
|
||||
if (fsync (fd) == -1)
|
||||
return errno;
|
||||
#endif
|
||||
|
||||
if (flushb) {
|
||||
errcode_t retval = 0;
|
||||
|
||||
#ifdef BLKFLSBUF
|
||||
if (ioctl (fd, BLKFLSBUF, 0) == 0)
|
||||
return 0;
|
||||
retval = errno;
|
||||
#elif defined(__linux__)
|
||||
#warning BLKFLSBUF not defined
|
||||
#endif
|
||||
#ifdef FDFLUSH
|
||||
/* In case this is a floppy */
|
||||
if (ioctl(fd, FDFLUSH, 0) == 0)
|
||||
return 0;
|
||||
if (retval == 0)
|
||||
retval = errno;
|
||||
#elif defined(__linux__)
|
||||
#warning FDFLUSH not defined
|
||||
#endif
|
||||
return retval;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/flushb.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/flushb.o
Executable file
Binary file not shown.
108
jni/e2fsprogs/lib/ext2fs/freefs.c
Executable file
108
jni/e2fsprogs/lib/ext2fs/freefs.c
Executable file
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* freefs.c --- free an ext2 filesystem
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
#include "hashmap.h"
|
||||
|
||||
void ext2fs_free(ext2_filsys fs)
|
||||
{
|
||||
if (!fs || (fs->magic != EXT2_ET_MAGIC_EXT2FS_FILSYS))
|
||||
return;
|
||||
if (fs->image_io != fs->io) {
|
||||
if (fs->image_io)
|
||||
io_channel_close(fs->image_io);
|
||||
}
|
||||
if (fs->io) {
|
||||
io_channel_close(fs->io);
|
||||
}
|
||||
if (fs->device_name)
|
||||
ext2fs_free_mem(&fs->device_name);
|
||||
if (fs->super)
|
||||
ext2fs_free_mem(&fs->super);
|
||||
if (fs->orig_super)
|
||||
ext2fs_free_mem(&fs->orig_super);
|
||||
if (fs->group_desc)
|
||||
ext2fs_free_mem(&fs->group_desc);
|
||||
if (fs->block_map)
|
||||
ext2fs_free_block_bitmap(fs->block_map);
|
||||
if (fs->inode_map)
|
||||
ext2fs_free_inode_bitmap(fs->inode_map);
|
||||
if (fs->image_header)
|
||||
ext2fs_free_mem(&fs->image_header);
|
||||
|
||||
if (fs->badblocks)
|
||||
ext2fs_badblocks_list_free(fs->badblocks);
|
||||
fs->badblocks = 0;
|
||||
|
||||
if (fs->dblist)
|
||||
ext2fs_free_dblist(fs->dblist);
|
||||
|
||||
if (fs->icache)
|
||||
ext2fs_free_inode_cache(fs->icache);
|
||||
|
||||
if (fs->mmp_buf)
|
||||
ext2fs_free_mem(&fs->mmp_buf);
|
||||
if (fs->mmp_cmp)
|
||||
ext2fs_free_mem(&fs->mmp_cmp);
|
||||
|
||||
if (fs->block_sha_map)
|
||||
ext2fs_hashmap_free(fs->block_sha_map);
|
||||
|
||||
fs->magic = 0;
|
||||
|
||||
ext2fs_zero_blocks2(NULL, 0, 0, NULL, NULL);
|
||||
ext2fs_free_mem(&fs);
|
||||
}
|
||||
|
||||
/*
|
||||
* This procedure frees a badblocks list.
|
||||
*/
|
||||
void ext2fs_u32_list_free(ext2_u32_list bb)
|
||||
{
|
||||
if (bb->magic != EXT2_ET_MAGIC_BADBLOCKS_LIST)
|
||||
return;
|
||||
|
||||
if (bb->list)
|
||||
ext2fs_free_mem(&bb->list);
|
||||
bb->list = 0;
|
||||
ext2fs_free_mem(&bb);
|
||||
}
|
||||
|
||||
void ext2fs_badblocks_list_free(ext2_badblocks_list bb)
|
||||
{
|
||||
ext2fs_u32_list_free((ext2_u32_list) bb);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Free a directory block list
|
||||
*/
|
||||
void ext2fs_free_dblist(ext2_dblist dblist)
|
||||
{
|
||||
if (!dblist || (dblist->magic != EXT2_ET_MAGIC_DBLIST))
|
||||
return;
|
||||
|
||||
if (dblist->list)
|
||||
ext2fs_free_mem(&dblist->list);
|
||||
dblist->list = 0;
|
||||
if (dblist->fs && dblist->fs->dblist == dblist)
|
||||
dblist->fs->dblist = 0;
|
||||
dblist->magic = 0;
|
||||
ext2fs_free_mem(&dblist);
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/freefs.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/freefs.o
Executable file
Binary file not shown.
650
jni/e2fsprogs/lib/ext2fs/gen_bitmap.c
Executable file
650
jni/e2fsprogs/lib/ext2fs/gen_bitmap.c
Executable file
@@ -0,0 +1,650 @@
|
||||
/*
|
||||
* gen_bitmap.c --- Generic (32-bit) bitmap routines
|
||||
*
|
||||
* Copyright (C) 2001 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
struct ext2fs_struct_generic_bitmap_32 {
|
||||
errcode_t magic;
|
||||
ext2_filsys fs;
|
||||
__u32 start, end;
|
||||
__u32 real_end;
|
||||
char * description;
|
||||
char * bitmap;
|
||||
errcode_t base_error_code;
|
||||
__u32 reserved[7];
|
||||
};
|
||||
|
||||
typedef struct ext2fs_struct_generic_bitmap_32 *ext2fs_generic_bitmap_32;
|
||||
|
||||
#define EXT2FS_IS_32_BITMAP(bmap) \
|
||||
(((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) || \
|
||||
((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP) || \
|
||||
((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP))
|
||||
|
||||
#define EXT2FS_IS_64_BITMAP(bmap) \
|
||||
(((bmap)->magic == EXT2_ET_MAGIC_GENERIC_BITMAP64) || \
|
||||
((bmap)->magic == EXT2_ET_MAGIC_BLOCK_BITMAP64) || \
|
||||
((bmap)->magic == EXT2_ET_MAGIC_INODE_BITMAP64))
|
||||
|
||||
/*
|
||||
* Used by previously inlined function, so we have to export this and
|
||||
* not change the function signature
|
||||
*/
|
||||
void ext2fs_warn_bitmap2(ext2fs_generic_bitmap gen_bitmap,
|
||||
int code, unsigned long arg)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (bitmap->description)
|
||||
com_err(0, bitmap->base_error_code+code,
|
||||
"#%lu for %s", arg, bitmap->description);
|
||||
else
|
||||
com_err(0, bitmap->base_error_code + code, "#%lu", arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
static errcode_t check_magic(ext2fs_generic_bitmap bitmap)
|
||||
{
|
||||
if (!bitmap || !((bitmap->magic == EXT2_ET_MAGIC_GENERIC_BITMAP) ||
|
||||
(bitmap->magic == EXT2_ET_MAGIC_INODE_BITMAP) ||
|
||||
(bitmap->magic == EXT2_ET_MAGIC_BLOCK_BITMAP)))
|
||||
return EXT2_ET_MAGIC_GENERIC_BITMAP;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_make_generic_bitmap(errcode_t magic, ext2_filsys fs,
|
||||
__u32 start, __u32 end, __u32 real_end,
|
||||
const char *descr, char *init_map,
|
||||
ext2fs_generic_bitmap *ret)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap;
|
||||
errcode_t retval;
|
||||
size_t size;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2fs_struct_generic_bitmap_32),
|
||||
&bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
bitmap->magic = magic;
|
||||
bitmap->fs = fs;
|
||||
bitmap->start = start;
|
||||
bitmap->end = end;
|
||||
bitmap->real_end = real_end;
|
||||
switch (magic) {
|
||||
case EXT2_ET_MAGIC_INODE_BITMAP:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
|
||||
break;
|
||||
case EXT2_ET_MAGIC_BLOCK_BITMAP:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
|
||||
break;
|
||||
default:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
|
||||
}
|
||||
if (descr) {
|
||||
retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&bitmap);
|
||||
return retval;
|
||||
}
|
||||
strcpy(bitmap->description, descr);
|
||||
} else
|
||||
bitmap->description = 0;
|
||||
|
||||
size = (size_t) (((bitmap->real_end - bitmap->start) / 8) + 1);
|
||||
/* Round up to allow for the BT x86 instruction */
|
||||
size = (size + 7) & ~3;
|
||||
retval = ext2fs_get_mem(size, &bitmap->bitmap);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&bitmap->description);
|
||||
ext2fs_free_mem(&bitmap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (init_map)
|
||||
memcpy(bitmap->bitmap, init_map, size);
|
||||
else
|
||||
memset(bitmap->bitmap, 0, size);
|
||||
*ret = (ext2fs_generic_bitmap) bitmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_allocate_generic_bitmap(__u32 start,
|
||||
__u32 end,
|
||||
__u32 real_end,
|
||||
const char *descr,
|
||||
ext2fs_generic_bitmap *ret)
|
||||
{
|
||||
return ext2fs_make_generic_bitmap(EXT2_ET_MAGIC_GENERIC_BITMAP, 0,
|
||||
start, end, real_end, descr, 0, ret);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_copy_generic_bitmap(ext2fs_generic_bitmap gen_src,
|
||||
ext2fs_generic_bitmap *dest)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 src = (ext2fs_generic_bitmap_32) gen_src;
|
||||
|
||||
return (ext2fs_make_generic_bitmap(src->magic, src->fs,
|
||||
src->start, src->end,
|
||||
src->real_end,
|
||||
src->description, src->bitmap,
|
||||
dest));
|
||||
}
|
||||
|
||||
void ext2fs_free_generic_bitmap(ext2fs_inode_bitmap gen_bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
if (check_magic(gen_bitmap))
|
||||
return;
|
||||
|
||||
bitmap->magic = 0;
|
||||
if (bitmap->description) {
|
||||
ext2fs_free_mem(&bitmap->description);
|
||||
bitmap->description = 0;
|
||||
}
|
||||
if (bitmap->bitmap) {
|
||||
ext2fs_free_mem(&bitmap->bitmap);
|
||||
bitmap->bitmap = 0;
|
||||
}
|
||||
ext2fs_free_mem(&bitmap);
|
||||
}
|
||||
|
||||
int ext2fs_test_generic_bitmap(ext2fs_generic_bitmap bitmap,
|
||||
blk_t bitno)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_test_generic_bmap(bitmap, bitno);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"test_bitmap(%lu)", (unsigned long) bitno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, bitno);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_test_bit(bitno - bitmap32->start, bitmap32->bitmap);
|
||||
}
|
||||
|
||||
int ext2fs_mark_generic_bitmap(ext2fs_generic_bitmap bitmap,
|
||||
__u32 bitno)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_mark_generic_bmap(bitmap, bitno);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"mark_bitmap(%lu)", (unsigned long) bitno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_MARK_ERROR, bitno);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_set_bit(bitno - bitmap32->start, bitmap32->bitmap);
|
||||
}
|
||||
|
||||
int ext2fs_unmark_generic_bitmap(ext2fs_generic_bitmap bitmap,
|
||||
blk_t bitno)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_unmark_generic_bmap(bitmap, bitno);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"mark_bitmap(%lu)", (unsigned long) bitno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((bitno < bitmap32->start) || (bitno > bitmap32->end)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_UNMARK_ERROR, bitno);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_clear_bit(bitno - bitmap32->start, bitmap32->bitmap);
|
||||
}
|
||||
|
||||
__u32 ext2fs_get_generic_bitmap_start(ext2fs_generic_bitmap bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_get_generic_bmap_start(bitmap);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"get_bitmap_start");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bitmap32->start;
|
||||
}
|
||||
|
||||
__u32 ext2fs_get_generic_bitmap_end(ext2fs_generic_bitmap bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
return ext2fs_get_generic_bmap_end(bitmap);
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"get_bitmap_end");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
return bitmap32->end;
|
||||
}
|
||||
|
||||
void ext2fs_clear_generic_bitmap(ext2fs_generic_bitmap bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap32 = (ext2fs_generic_bitmap_32) bitmap;
|
||||
|
||||
if (!EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (EXT2FS_IS_64_BITMAP(bitmap)) {
|
||||
ext2fs_warn_bitmap32(bitmap, __func__);
|
||||
ext2fs_clear_generic_bmap(bitmap);
|
||||
return;
|
||||
}
|
||||
#ifndef OMIT_COM_ERR
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"clear_generic_bitmap");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
memset(bitmap32->bitmap, 0,
|
||||
(size_t) (((bitmap32->real_end - bitmap32->start) / 8) + 1));
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_generic_bitmap_end(ext2fs_inode_bitmap gen_bitmap,
|
||||
errcode_t magic, errcode_t neq,
|
||||
ext2_ino_t end, ext2_ino_t *oend)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
EXT2_CHECK_MAGIC(bitmap, magic);
|
||||
|
||||
if (end > bitmap->real_end)
|
||||
return neq;
|
||||
if (oend)
|
||||
*oend = bitmap->end;
|
||||
bitmap->end = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_generic_bitmap(errcode_t magic,
|
||||
__u32 new_end, __u32 new_real_end,
|
||||
ext2fs_generic_bitmap gen_bmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
|
||||
errcode_t retval;
|
||||
size_t size, new_size;
|
||||
__u32 bitno;
|
||||
|
||||
if (!bmap || (bmap->magic != magic))
|
||||
return magic;
|
||||
|
||||
/*
|
||||
* If we're expanding the bitmap, make sure all of the new
|
||||
* parts of the bitmap are zero.
|
||||
*/
|
||||
if (new_end > bmap->end) {
|
||||
bitno = bmap->real_end;
|
||||
if (bitno > new_end)
|
||||
bitno = new_end;
|
||||
for (; bitno > bmap->end; bitno--)
|
||||
ext2fs_clear_bit(bitno - bmap->start, bmap->bitmap);
|
||||
}
|
||||
if (new_real_end == bmap->real_end) {
|
||||
bmap->end = new_end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size = ((bmap->real_end - bmap->start) / 8) + 1;
|
||||
new_size = ((new_real_end - bmap->start) / 8) + 1;
|
||||
|
||||
if (size != new_size) {
|
||||
retval = ext2fs_resize_mem(size, new_size, &bmap->bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
if (new_size > size)
|
||||
memset(bmap->bitmap + size, 0, new_size - size);
|
||||
|
||||
bmap->end = new_end;
|
||||
bmap->real_end = new_real_end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_compare_generic_bitmap(errcode_t magic, errcode_t neq,
|
||||
ext2fs_generic_bitmap gen_bm1,
|
||||
ext2fs_generic_bitmap gen_bm2)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bm1 = (ext2fs_generic_bitmap_32) gen_bm1;
|
||||
ext2fs_generic_bitmap_32 bm2 = (ext2fs_generic_bitmap_32) gen_bm2;
|
||||
blk_t i;
|
||||
|
||||
if (!bm1 || bm1->magic != magic)
|
||||
return magic;
|
||||
if (!bm2 || bm2->magic != magic)
|
||||
return magic;
|
||||
|
||||
if ((bm1->start != bm2->start) ||
|
||||
(bm1->end != bm2->end) ||
|
||||
(memcmp(bm1->bitmap, bm2->bitmap,
|
||||
(size_t) (bm1->end - bm1->start)/8)))
|
||||
return neq;
|
||||
|
||||
for (i = bm1->end - ((bm1->end - bm1->start) % 8); i <= bm1->end; i++)
|
||||
if (ext2fs_fast_test_block_bitmap(gen_bm1, i) !=
|
||||
ext2fs_fast_test_block_bitmap(gen_bm2, i))
|
||||
return neq;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ext2fs_set_generic_bitmap_padding(ext2fs_generic_bitmap gen_map)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 map = (ext2fs_generic_bitmap_32) gen_map;
|
||||
__u32 i, j;
|
||||
|
||||
/* Protect loop from wrap-around if map->real_end is maxed */
|
||||
for (i=map->end+1, j = i - map->start;
|
||||
i <= map->real_end && i > map->end;
|
||||
i++, j++)
|
||||
ext2fs_set_bit(j, map->bitmap);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_generic_bitmap_range(ext2fs_generic_bitmap gen_bmap,
|
||||
errcode_t magic,
|
||||
__u32 start, __u32 num,
|
||||
void *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
|
||||
|
||||
if (!bmap || (bmap->magic != magic))
|
||||
return magic;
|
||||
|
||||
if ((start < bmap->start) || (start+num-1 > bmap->real_end))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
memcpy(out, bmap->bitmap + ((start - bmap->start) >> 3), (num+7) >> 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_generic_bitmap_range(ext2fs_generic_bitmap gen_bmap,
|
||||
errcode_t magic,
|
||||
__u32 start, __u32 num,
|
||||
void *in)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bmap = (ext2fs_generic_bitmap_32) gen_bmap;
|
||||
|
||||
if (!bmap || (bmap->magic != magic))
|
||||
return magic;
|
||||
|
||||
if ((start < bmap->start) || (start+num-1 > bmap->real_end))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
memcpy(bmap->bitmap + ((start - bmap->start) >> 3), in, (num+7) >> 3);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare @mem to zero buffer by 256 bytes.
|
||||
* Return 1 if @mem is zeroed memory, otherwise return 0.
|
||||
*/
|
||||
int ext2fs_mem_is_zero(const char *mem, size_t len)
|
||||
{
|
||||
static const char zero_buf[256];
|
||||
|
||||
while (len >= sizeof(zero_buf)) {
|
||||
if (memcmp(mem, zero_buf, sizeof(zero_buf)))
|
||||
return 0;
|
||||
len -= sizeof(zero_buf);
|
||||
mem += sizeof(zero_buf);
|
||||
}
|
||||
/* Deal with leftover bytes. */
|
||||
if (len)
|
||||
return !memcmp(mem, zero_buf, len);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if all of the bits in a specified range are clear
|
||||
*/
|
||||
static int ext2fs_test_clear_generic_bitmap_range(ext2fs_generic_bitmap gen_bitmap,
|
||||
unsigned int start,
|
||||
unsigned int len)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
size_t start_byte, len_byte = len >> 3;
|
||||
unsigned int start_bit, len_bit = len % 8;
|
||||
int first_bit = 0;
|
||||
int last_bit = 0;
|
||||
int mark_count = 0;
|
||||
int mark_bit = 0;
|
||||
int i;
|
||||
const char *ADDR = bitmap->bitmap;
|
||||
|
||||
start -= bitmap->start;
|
||||
start_byte = start >> 3;
|
||||
start_bit = start % 8;
|
||||
|
||||
if (start_bit != 0) {
|
||||
/*
|
||||
* The compared start block number or start inode number
|
||||
* is not the first bit in a byte.
|
||||
*/
|
||||
mark_count = 8 - start_bit;
|
||||
if (len < 8 - start_bit) {
|
||||
mark_count = (int)len;
|
||||
mark_bit = len + start_bit - 1;
|
||||
} else
|
||||
mark_bit = 7;
|
||||
|
||||
for (i = mark_count; i > 0; i--, mark_bit--)
|
||||
first_bit |= 1 << mark_bit;
|
||||
|
||||
/*
|
||||
* Compare blocks or inodes in the first byte.
|
||||
* If there is any marked bit, this function returns 0.
|
||||
*/
|
||||
if (first_bit & ADDR[start_byte])
|
||||
return 0;
|
||||
else if (len <= 8 - start_bit)
|
||||
return 1;
|
||||
|
||||
start_byte++;
|
||||
len_bit = (len - mark_count) % 8;
|
||||
len_byte = (len - mark_count) >> 3;
|
||||
}
|
||||
|
||||
/*
|
||||
* The compared start block number or start inode number is
|
||||
* the first bit in a byte.
|
||||
*/
|
||||
if (len_bit != 0) {
|
||||
/*
|
||||
* The compared end block number or end inode number is
|
||||
* not the last bit in a byte.
|
||||
*/
|
||||
for (mark_bit = len_bit - 1; mark_bit >= 0; mark_bit--)
|
||||
last_bit |= 1 << mark_bit;
|
||||
|
||||
/*
|
||||
* Compare blocks or inodes in the last byte.
|
||||
* If there is any marked bit, this function returns 0.
|
||||
*/
|
||||
if (last_bit & ADDR[start_byte + len_byte])
|
||||
return 0;
|
||||
else if (len_byte == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Check whether all bytes are 0 */
|
||||
return ext2fs_mem_is_zero(ADDR + start_byte, len_byte);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_find_first_zero_generic_bitmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u32 start, __u32 end,
|
||||
__u32 *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
blk_t b;
|
||||
|
||||
if (start < bitmap->start || end > bitmap->end || start > end) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
while (start <= end) {
|
||||
b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap);
|
||||
if (!b) {
|
||||
*out = start;
|
||||
return 0;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_find_first_set_generic_bitmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u32 start, __u32 end,
|
||||
__u32 *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
blk_t b;
|
||||
|
||||
if (start < bitmap->start || end > bitmap->end || start > end) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
while (start <= end) {
|
||||
b = ext2fs_test_bit(start - bitmap->start, bitmap->bitmap);
|
||||
if (b) {
|
||||
*out = start;
|
||||
return 0;
|
||||
}
|
||||
start++;
|
||||
}
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
int ext2fs_test_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
|
||||
blk_t block, int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_BLOCK_BITMAP);
|
||||
if ((block < bitmap->start) || (block > bitmap->real_end) ||
|
||||
(block+num-1 > bitmap->real_end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST,
|
||||
block, bitmap->description);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_test_clear_generic_bitmap_range((ext2fs_generic_bitmap)
|
||||
bitmap, block, num);
|
||||
}
|
||||
|
||||
int ext2fs_test_inode_bitmap_range(ext2fs_inode_bitmap gen_bitmap,
|
||||
ext2_ino_t inode, int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
|
||||
EXT2_CHECK_MAGIC(bitmap, EXT2_ET_MAGIC_INODE_BITMAP);
|
||||
if ((inode < bitmap->start) || (inode > bitmap->real_end) ||
|
||||
(inode+num-1 > bitmap->real_end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_INODE_TEST,
|
||||
inode, bitmap->description);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_test_clear_generic_bitmap_range((ext2fs_generic_bitmap)
|
||||
bitmap, inode, num);
|
||||
}
|
||||
|
||||
void ext2fs_mark_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
|
||||
blk_t block, int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
int i;
|
||||
|
||||
if ((block < bitmap->start) || (block > bitmap->end) ||
|
||||
(block+num-1 > bitmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
|
||||
bitmap->description);
|
||||
return;
|
||||
}
|
||||
for (i=0; i < num; i++)
|
||||
ext2fs_fast_set_bit(block + i - bitmap->start, bitmap->bitmap);
|
||||
}
|
||||
|
||||
void ext2fs_unmark_block_bitmap_range(ext2fs_block_bitmap gen_bitmap,
|
||||
blk_t block, int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_32 bitmap = (ext2fs_generic_bitmap_32) gen_bitmap;
|
||||
int i;
|
||||
|
||||
if ((block < bitmap->start) || (block > bitmap->end) ||
|
||||
(block+num-1 > bitmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
|
||||
bitmap->description);
|
||||
return;
|
||||
}
|
||||
for (i=0; i < num; i++)
|
||||
ext2fs_fast_clear_bit(block + i - bitmap->start,
|
||||
bitmap->bitmap);
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/gen_bitmap.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/gen_bitmap.o
Executable file
Binary file not shown.
981
jni/e2fsprogs/lib/ext2fs/gen_bitmap64.c
Executable file
981
jni/e2fsprogs/lib/ext2fs/gen_bitmap64.c
Executable file
@@ -0,0 +1,981 @@
|
||||
/*
|
||||
* gen_bitmap64.c --- routines to read, write, and manipulate the new qinode and
|
||||
* block bitmaps.
|
||||
*
|
||||
* Copyright (C) 2007, 2008 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Public
|
||||
* License.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include <errno.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_TIME_H
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
#include "bmap64.h"
|
||||
|
||||
/*
|
||||
* Design of 64-bit bitmaps
|
||||
*
|
||||
* In order maintain ABI compatibility with programs that don't
|
||||
* understand about 64-bit blocks/inodes,
|
||||
* ext2fs_allocate_inode_bitmap() and ext2fs_allocate_block_bitmap()
|
||||
* will create old-style bitmaps unless the application passes the
|
||||
* flag EXT2_FLAG_64BITS to ext2fs_open(). If this flag is
|
||||
* passed, then we know the application has been recompiled, so we can
|
||||
* use the new-style bitmaps. If it is not passed, we have to return
|
||||
* an error if trying to open a filesystem which needs 64-bit bitmaps.
|
||||
*
|
||||
* The new bitmaps use a new set of structure magic numbers, so that
|
||||
* both the old-style and new-style interfaces can identify which
|
||||
* version of the data structure was used. Both the old-style and
|
||||
* new-style interfaces will support either type of bitmap, although
|
||||
* of course 64-bit operation will only be possible when both the
|
||||
* new-style interface and the new-style bitmap are used.
|
||||
*
|
||||
* For example, the new bitmap interfaces will check the structure
|
||||
* magic numbers and so will be able to detect old-stype bitmap. If
|
||||
* they see an old-style bitmap, they will pass it to the gen_bitmap.c
|
||||
* functions for handling. The same will be true for the old
|
||||
* interfaces as well.
|
||||
*
|
||||
* The new-style interfaces will have several different back-end
|
||||
* implementations, so we can support different encodings that are
|
||||
* appropriate for different applications. In general the default
|
||||
* should be whatever makes sense, and what the application/library
|
||||
* will use. However, e2fsck may need specialized implementations for
|
||||
* its own uses. For example, when doing parent directory pointer
|
||||
* loop detections in pass 3, the bitmap will *always* be sparse, so
|
||||
* e2fsck can request an encoding which is optimized for that.
|
||||
*/
|
||||
|
||||
static void warn_bitmap(ext2fs_generic_bitmap_64 bitmap,
|
||||
int code, __u64 arg)
|
||||
{
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (bitmap->description)
|
||||
com_err(0, bitmap->base_error_code+code,
|
||||
"#%llu for %s", (unsigned long long) arg,
|
||||
bitmap->description);
|
||||
else
|
||||
com_err(0, bitmap->base_error_code + code, "#%llu",
|
||||
(unsigned long long) arg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
#define INC_STAT(map, name) map->stats.name
|
||||
#else
|
||||
#define INC_STAT(map, name) ;;
|
||||
#endif
|
||||
|
||||
|
||||
errcode_t ext2fs_alloc_generic_bmap(ext2_filsys fs, errcode_t magic,
|
||||
int type, __u64 start, __u64 end,
|
||||
__u64 real_end,
|
||||
const char *descr,
|
||||
ext2fs_generic_bitmap *ret)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap;
|
||||
struct ext2_bitmap_ops *ops;
|
||||
ext2_ino_t num_dirs;
|
||||
errcode_t retval;
|
||||
|
||||
if (!type)
|
||||
type = EXT2FS_BMAP64_BITARRAY;
|
||||
|
||||
switch (type) {
|
||||
case EXT2FS_BMAP64_BITARRAY:
|
||||
ops = &ext2fs_blkmap64_bitarray;
|
||||
break;
|
||||
case EXT2FS_BMAP64_RBTREE:
|
||||
ops = &ext2fs_blkmap64_rbtree;
|
||||
break;
|
||||
case EXT2FS_BMAP64_AUTODIR:
|
||||
retval = ext2fs_get_num_dirs(fs, &num_dirs);
|
||||
if (retval || num_dirs > (fs->super->s_inodes_count / 320))
|
||||
ops = &ext2fs_blkmap64_bitarray;
|
||||
else
|
||||
ops = &ext2fs_blkmap64_rbtree;
|
||||
break;
|
||||
default:
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
|
||||
&bitmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
if (gettimeofday(&bitmap->stats.created,
|
||||
(struct timezone *) NULL) == -1) {
|
||||
perror("gettimeofday");
|
||||
ext2fs_free_mem(&bitmap);
|
||||
return 1;
|
||||
}
|
||||
bitmap->stats.type = type;
|
||||
#endif
|
||||
|
||||
/* XXX factor out, repeated in copy_bmap */
|
||||
bitmap->magic = magic;
|
||||
bitmap->fs = fs;
|
||||
bitmap->start = start;
|
||||
bitmap->end = end;
|
||||
bitmap->real_end = real_end;
|
||||
bitmap->bitmap_ops = ops;
|
||||
bitmap->cluster_bits = 0;
|
||||
switch (magic) {
|
||||
case EXT2_ET_MAGIC_INODE_BITMAP64:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_INODE_MARK;
|
||||
break;
|
||||
case EXT2_ET_MAGIC_BLOCK_BITMAP64:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_BLOCK_MARK;
|
||||
bitmap->cluster_bits = fs->cluster_ratio_bits;
|
||||
break;
|
||||
default:
|
||||
bitmap->base_error_code = EXT2_ET_BAD_GENERIC_MARK;
|
||||
}
|
||||
if (descr) {
|
||||
retval = ext2fs_get_mem(strlen(descr)+1, &bitmap->description);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&bitmap);
|
||||
return retval;
|
||||
}
|
||||
strcpy(bitmap->description, descr);
|
||||
} else
|
||||
bitmap->description = 0;
|
||||
|
||||
retval = bitmap->bitmap_ops->new_bmap(fs, bitmap);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&bitmap->description);
|
||||
ext2fs_free_mem(&bitmap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*ret = (ext2fs_generic_bitmap) bitmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
static void ext2fs_print_bmap_statistics(ext2fs_generic_bitmap_64 bitmap)
|
||||
{
|
||||
struct ext2_bmap_statistics *stats = &bitmap->stats;
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
float mark_seq_perc = 0.0, test_seq_perc = 0.0;
|
||||
float mark_back_perc = 0.0, test_back_perc = 0.0;
|
||||
struct timeval now;
|
||||
double inuse;
|
||||
|
||||
if (stats->test_count) {
|
||||
test_seq_perc = ((float)stats->test_seq /
|
||||
stats->test_count) * 100;
|
||||
test_back_perc = ((float)stats->test_back /
|
||||
stats->test_count) * 100;
|
||||
}
|
||||
|
||||
if (stats->mark_count) {
|
||||
mark_seq_perc = ((float)stats->mark_seq /
|
||||
stats->mark_count) * 100;
|
||||
mark_back_perc = ((float)stats->mark_back /
|
||||
stats->mark_count) * 100;
|
||||
}
|
||||
|
||||
if (gettimeofday(&now, (struct timezone *) NULL) == -1) {
|
||||
perror("gettimeofday");
|
||||
return;
|
||||
}
|
||||
|
||||
inuse = (double) now.tv_sec + \
|
||||
(((double) now.tv_usec) * 0.000001);
|
||||
inuse -= (double) stats->created.tv_sec + \
|
||||
(((double) stats->created.tv_usec) * 0.000001);
|
||||
#endif /* ENABLE_BMAP_STATS_OPS */
|
||||
|
||||
fprintf(stderr, "\n[+] %s bitmap (type %d)\n", bitmap->description,
|
||||
stats->type);
|
||||
fprintf(stderr, "=================================================\n");
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
fprintf(stderr, "%16llu bits long\n",
|
||||
bitmap->real_end - bitmap->start);
|
||||
fprintf(stderr, "%16lu copy_bmap\n%16lu resize_bmap\n",
|
||||
stats->copy_count, stats->resize_count);
|
||||
fprintf(stderr, "%16lu mark bmap\n%16lu unmark_bmap\n",
|
||||
stats->mark_count, stats->unmark_count);
|
||||
fprintf(stderr, "%16lu test_bmap\n%16lu mark_bmap_extent\n",
|
||||
stats->test_count, stats->mark_ext_count);
|
||||
fprintf(stderr, "%16lu unmark_bmap_extent\n"
|
||||
"%16lu test_clear_bmap_extent\n",
|
||||
stats->unmark_ext_count, stats->test_ext_count);
|
||||
fprintf(stderr, "%16lu set_bmap_range\n%16lu set_bmap_range\n",
|
||||
stats->set_range_count, stats->get_range_count);
|
||||
fprintf(stderr, "%16lu clear_bmap\n%16lu contiguous bit test (%.2f%%)\n",
|
||||
stats->clear_count, stats->test_seq, test_seq_perc);
|
||||
fprintf(stderr, "%16lu contiguous bit mark (%.2f%%)\n"
|
||||
"%16llu bits tested backwards (%.2f%%)\n",
|
||||
stats->mark_seq, mark_seq_perc,
|
||||
stats->test_back, test_back_perc);
|
||||
fprintf(stderr, "%16llu bits marked backwards (%.2f%%)\n"
|
||||
"%16.2f seconds in use\n",
|
||||
stats->mark_back, mark_back_perc, inuse);
|
||||
#endif /* ENABLE_BMAP_STATS_OPS */
|
||||
}
|
||||
#endif
|
||||
|
||||
void ext2fs_free_generic_bmap(ext2fs_generic_bitmap gen_bmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
|
||||
if (!bmap)
|
||||
return;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
ext2fs_free_generic_bitmap(gen_bmap);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
if (getenv("E2FSPROGS_BITMAP_STATS")) {
|
||||
ext2fs_print_bmap_statistics(bmap);
|
||||
bmap->bitmap_ops->print_stats(bmap);
|
||||
}
|
||||
#endif
|
||||
|
||||
bmap->bitmap_ops->free_bmap(bmap);
|
||||
|
||||
if (bmap->description) {
|
||||
ext2fs_free_mem(&bmap->description);
|
||||
bmap->description = 0;
|
||||
}
|
||||
bmap->magic = 0;
|
||||
ext2fs_free_mem(&bmap);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_copy_generic_bmap(ext2fs_generic_bitmap gen_src,
|
||||
ext2fs_generic_bitmap *dest)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 src = (ext2fs_generic_bitmap_64) gen_src;
|
||||
char *descr, *new_descr;
|
||||
ext2fs_generic_bitmap_64 new_bmap;
|
||||
errcode_t retval;
|
||||
|
||||
if (!src)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(src))
|
||||
return ext2fs_copy_generic_bitmap(gen_src, dest);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(src))
|
||||
return EINVAL;
|
||||
|
||||
/* Allocate a new bitmap struct */
|
||||
retval = ext2fs_get_memzero(sizeof(struct ext2fs_struct_generic_bitmap_64),
|
||||
&new_bmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
src->stats.copy_count++;
|
||||
#endif
|
||||
#ifdef ENABLE_BMAP_STATS
|
||||
if (gettimeofday(&new_bmap->stats.created,
|
||||
(struct timezone *) NULL) == -1) {
|
||||
perror("gettimeofday");
|
||||
ext2fs_free_mem(&new_bmap);
|
||||
return 1;
|
||||
}
|
||||
new_bmap->stats.type = src->stats.type;
|
||||
#endif
|
||||
|
||||
/* Copy all the high-level parts over */
|
||||
new_bmap->magic = src->magic;
|
||||
new_bmap->fs = src->fs;
|
||||
new_bmap->start = src->start;
|
||||
new_bmap->end = src->end;
|
||||
new_bmap->real_end = src->real_end;
|
||||
new_bmap->bitmap_ops = src->bitmap_ops;
|
||||
new_bmap->base_error_code = src->base_error_code;
|
||||
new_bmap->cluster_bits = src->cluster_bits;
|
||||
|
||||
descr = src->description;
|
||||
if (descr) {
|
||||
retval = ext2fs_get_mem(strlen(descr)+10, &new_descr);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&new_bmap);
|
||||
return retval;
|
||||
}
|
||||
strcpy(new_descr, "copy of ");
|
||||
strcat(new_descr, descr);
|
||||
new_bmap->description = new_descr;
|
||||
}
|
||||
|
||||
retval = src->bitmap_ops->copy_bmap(src, new_bmap);
|
||||
if (retval) {
|
||||
ext2fs_free_mem(&new_bmap->description);
|
||||
ext2fs_free_mem(&new_bmap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
*dest = (ext2fs_generic_bitmap) new_bmap;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_resize_generic_bmap(ext2fs_generic_bitmap gen_bmap,
|
||||
__u64 new_end,
|
||||
__u64 new_real_end)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
|
||||
if (!bmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap))
|
||||
return ext2fs_resize_generic_bitmap(gen_bmap->magic, new_end,
|
||||
new_real_end, gen_bmap);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return EINVAL;
|
||||
|
||||
INC_STAT(bmap, resize_count);
|
||||
|
||||
return bmap->bitmap_ops->resize_bmap(bmap, new_end, new_real_end);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_fudge_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap,
|
||||
errcode_t neq,
|
||||
__u64 end, __u64 *oend)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
ext2_ino_t tmp_oend;
|
||||
int retval;
|
||||
|
||||
retval = ext2fs_fudge_generic_bitmap_end(gen_bitmap,
|
||||
bitmap->magic,
|
||||
neq, end, &tmp_oend);
|
||||
if (oend)
|
||||
*oend = tmp_oend;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
if (end > bitmap->real_end)
|
||||
return neq;
|
||||
if (oend)
|
||||
*oend = bitmap->end;
|
||||
bitmap->end = end;
|
||||
return 0;
|
||||
}
|
||||
|
||||
__u64 ext2fs_get_generic_bmap_start(ext2fs_generic_bitmap gen_bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap))
|
||||
return ext2fs_get_generic_bitmap_start(gen_bitmap);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
return bitmap->start;
|
||||
}
|
||||
|
||||
__u64 ext2fs_get_generic_bmap_end(ext2fs_generic_bitmap gen_bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap))
|
||||
return ext2fs_get_generic_bitmap_end(gen_bitmap);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
return bitmap->end;
|
||||
}
|
||||
|
||||
void ext2fs_clear_generic_bmap(ext2fs_generic_bitmap gen_bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap))
|
||||
ext2fs_clear_generic_bitmap(gen_bitmap);
|
||||
else
|
||||
bitmap->bitmap_ops->clear_bmap(bitmap);
|
||||
}
|
||||
|
||||
int ext2fs_mark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u64 arg)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (arg & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap,
|
||||
EXT2FS_MARK_ERROR, 0xffffffff);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_mark_generic_bitmap(gen_bitmap, arg);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return 0;
|
||||
|
||||
arg >>= bitmap->cluster_bits;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
if (arg == bitmap->stats.last_marked + 1)
|
||||
bitmap->stats.mark_seq++;
|
||||
if (arg < bitmap->stats.last_marked)
|
||||
bitmap->stats.mark_back++;
|
||||
bitmap->stats.last_marked = arg;
|
||||
bitmap->stats.mark_count++;
|
||||
#endif
|
||||
|
||||
if ((arg < bitmap->start) || (arg > bitmap->end)) {
|
||||
warn_bitmap(bitmap, EXT2FS_MARK_ERROR, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bitmap->bitmap_ops->mark_bmap(bitmap, arg);
|
||||
}
|
||||
|
||||
int ext2fs_unmark_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u64 arg)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (arg & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_UNMARK_ERROR,
|
||||
0xffffffff);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_unmark_generic_bitmap(gen_bitmap, arg);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return 0;
|
||||
|
||||
arg >>= bitmap->cluster_bits;
|
||||
|
||||
INC_STAT(bitmap, unmark_count);
|
||||
|
||||
if ((arg < bitmap->start) || (arg > bitmap->end)) {
|
||||
warn_bitmap(bitmap, EXT2FS_UNMARK_ERROR, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bitmap->bitmap_ops->unmark_bmap(bitmap, arg);
|
||||
}
|
||||
|
||||
int ext2fs_test_generic_bmap(ext2fs_generic_bitmap gen_bitmap,
|
||||
__u64 arg)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
if (!bitmap)
|
||||
return 0;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
if (arg & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bitmap, EXT2FS_TEST_ERROR,
|
||||
0xffffffff);
|
||||
return 0;
|
||||
}
|
||||
return ext2fs_test_generic_bitmap(gen_bitmap, arg);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return 0;
|
||||
|
||||
arg >>= bitmap->cluster_bits;
|
||||
|
||||
#ifdef ENABLE_BMAP_STATS_OPS
|
||||
bitmap->stats.test_count++;
|
||||
if (arg == bitmap->stats.last_tested + 1)
|
||||
bitmap->stats.test_seq++;
|
||||
if (arg < bitmap->stats.last_tested)
|
||||
bitmap->stats.test_back++;
|
||||
bitmap->stats.last_tested = arg;
|
||||
#endif
|
||||
|
||||
if ((arg < bitmap->start) || (arg > bitmap->end)) {
|
||||
warn_bitmap(bitmap, EXT2FS_TEST_ERROR, arg);
|
||||
return 0;
|
||||
}
|
||||
|
||||
return bitmap->bitmap_ops->test_bmap(bitmap, arg);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_set_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
|
||||
__u64 start, unsigned int num,
|
||||
void *in)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
|
||||
if (!bmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((start+num-1) & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bmap, EXT2FS_UNMARK_ERROR,
|
||||
0xffffffff);
|
||||
return EINVAL;
|
||||
}
|
||||
return ext2fs_set_generic_bitmap_range(gen_bmap, bmap->magic,
|
||||
start, num, in);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return EINVAL;
|
||||
|
||||
INC_STAT(bmap, set_range_count);
|
||||
|
||||
return bmap->bitmap_ops->set_bmap_range(bmap, start, num, in);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_generic_bmap_range(ext2fs_generic_bitmap gen_bmap,
|
||||
__u64 start, unsigned int num,
|
||||
void *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
|
||||
if (!bmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((start+num-1) & ~0xffffffffULL) {
|
||||
ext2fs_warn_bitmap2(gen_bmap,
|
||||
EXT2FS_UNMARK_ERROR, 0xffffffff);
|
||||
return EINVAL;
|
||||
}
|
||||
return ext2fs_get_generic_bitmap_range(gen_bmap, bmap->magic,
|
||||
start, num, out);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return EINVAL;
|
||||
|
||||
INC_STAT(bmap, get_range_count);
|
||||
|
||||
return bmap->bitmap_ops->get_bmap_range(bmap, start, num, out);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_compare_generic_bmap(errcode_t neq,
|
||||
ext2fs_generic_bitmap gen_bm1,
|
||||
ext2fs_generic_bitmap gen_bm2)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bm1 = (ext2fs_generic_bitmap_64) gen_bm1;
|
||||
ext2fs_generic_bitmap_64 bm2 = (ext2fs_generic_bitmap_64) gen_bm2;
|
||||
blk64_t i;
|
||||
|
||||
if (!bm1 || !bm2)
|
||||
return EINVAL;
|
||||
if (bm1->magic != bm2->magic)
|
||||
return EINVAL;
|
||||
|
||||
/* Now we know both bitmaps have the same magic */
|
||||
if (EXT2FS_IS_32_BITMAP(bm1))
|
||||
return ext2fs_compare_generic_bitmap(bm1->magic, neq,
|
||||
gen_bm1, gen_bm2);
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bm1))
|
||||
return EINVAL;
|
||||
|
||||
if ((bm1->start != bm2->start) ||
|
||||
(bm1->end != bm2->end))
|
||||
return neq;
|
||||
|
||||
for (i = bm1->start; i < bm1->end; i++) {
|
||||
int ret1, ret2;
|
||||
ret1 = !!ext2fs_test_generic_bmap(gen_bm1, i);
|
||||
ret2 = !!ext2fs_test_generic_bmap(gen_bm2, i);
|
||||
if (ret1 != ret2) {
|
||||
return neq;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ext2fs_set_generic_bmap_padding(ext2fs_generic_bitmap gen_bmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
__u64 start, num;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
ext2fs_set_generic_bitmap_padding(gen_bmap);
|
||||
return;
|
||||
}
|
||||
|
||||
start = bmap->end + 1;
|
||||
num = bmap->real_end - bmap->end;
|
||||
bmap->bitmap_ops->mark_bmap_extent(bmap, start, num);
|
||||
/* XXX ought to warn on error */
|
||||
}
|
||||
|
||||
int ext2fs_test_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
|
||||
blk64_t block, unsigned int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
__u64 end = block + num;
|
||||
|
||||
if (!bmap)
|
||||
return EINVAL;
|
||||
|
||||
if (num == 1)
|
||||
return !ext2fs_test_generic_bmap((ext2fs_generic_bitmap)
|
||||
bmap, block);
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((block & ~0xffffffffULL) ||
|
||||
((block+num-1) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
|
||||
EXT2FS_UNMARK_ERROR, 0xffffffff);
|
||||
return EINVAL;
|
||||
}
|
||||
return ext2fs_test_block_bitmap_range(
|
||||
(ext2fs_generic_bitmap) bmap, block, num);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return EINVAL;
|
||||
|
||||
INC_STAT(bmap, test_ext_count);
|
||||
|
||||
/* convert to clusters if necessary */
|
||||
block >>= bmap->cluster_bits;
|
||||
end += (1ULL << bmap->cluster_bits) - 1;
|
||||
end >>= bmap->cluster_bits;
|
||||
num = end - block;
|
||||
|
||||
if ((block < bmap->start) || (block > bmap->end) ||
|
||||
(block+num-1 > bmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_TEST, block,
|
||||
bmap->description);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
return bmap->bitmap_ops->test_clear_bmap_extent(bmap, block, num);
|
||||
}
|
||||
|
||||
void ext2fs_mark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
|
||||
blk64_t block, unsigned int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
__u64 end = block + num;
|
||||
|
||||
if (!bmap)
|
||||
return;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((block & ~0xffffffffULL) ||
|
||||
((block+num-1) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
|
||||
EXT2FS_UNMARK_ERROR, 0xffffffff);
|
||||
return;
|
||||
}
|
||||
ext2fs_mark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
|
||||
block, num);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return;
|
||||
|
||||
INC_STAT(bmap, mark_ext_count);
|
||||
|
||||
/* convert to clusters if necessary */
|
||||
block >>= bmap->cluster_bits;
|
||||
end += (1ULL << bmap->cluster_bits) - 1;
|
||||
end >>= bmap->cluster_bits;
|
||||
num = end - block;
|
||||
|
||||
if ((block < bmap->start) || (block > bmap->end) ||
|
||||
(block+num-1 > bmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_MARK, block,
|
||||
bmap->description);
|
||||
return;
|
||||
}
|
||||
|
||||
bmap->bitmap_ops->mark_bmap_extent(bmap, block, num);
|
||||
}
|
||||
|
||||
void ext2fs_unmark_block_bitmap_range2(ext2fs_block_bitmap gen_bmap,
|
||||
blk64_t block, unsigned int num)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap = (ext2fs_generic_bitmap_64) gen_bmap;
|
||||
__u64 end = block + num;
|
||||
|
||||
if (!bmap)
|
||||
return;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bmap)) {
|
||||
if ((block & ~0xffffffffULL) ||
|
||||
((block+num-1) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2((ext2fs_generic_bitmap) bmap,
|
||||
EXT2FS_UNMARK_ERROR, 0xffffffff);
|
||||
return;
|
||||
}
|
||||
ext2fs_unmark_block_bitmap_range((ext2fs_generic_bitmap) bmap,
|
||||
block, num);
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bmap))
|
||||
return;
|
||||
|
||||
INC_STAT(bmap, unmark_ext_count);
|
||||
|
||||
/* convert to clusters if necessary */
|
||||
block >>= bmap->cluster_bits;
|
||||
end += (1ULL << bmap->cluster_bits) - 1;
|
||||
end >>= bmap->cluster_bits;
|
||||
num = end - block;
|
||||
|
||||
if ((block < bmap->start) || (block > bmap->end) ||
|
||||
(block+num-1 > bmap->end)) {
|
||||
ext2fs_warn_bitmap(EXT2_ET_BAD_BLOCK_UNMARK, block,
|
||||
bmap->description);
|
||||
return;
|
||||
}
|
||||
|
||||
bmap->bitmap_ops->unmark_bmap_extent(bmap, block, num);
|
||||
}
|
||||
|
||||
void ext2fs_warn_bitmap32(ext2fs_generic_bitmap gen_bitmap, const char *func)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bitmap = (ext2fs_generic_bitmap_64) gen_bitmap;
|
||||
|
||||
#ifndef OMIT_COM_ERR
|
||||
if (bitmap && bitmap->description)
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"called %s with 64-bit bitmap for %s", func,
|
||||
bitmap->description);
|
||||
else
|
||||
com_err(0, EXT2_ET_MAGIC_GENERIC_BITMAP,
|
||||
"called %s with 64-bit bitmap", func);
|
||||
#endif
|
||||
}
|
||||
|
||||
errcode_t ext2fs_convert_subcluster_bitmap(ext2_filsys fs,
|
||||
ext2fs_block_bitmap *bitmap)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap, cmap;
|
||||
ext2fs_block_bitmap gen_bmap = *bitmap, gen_cmap;
|
||||
errcode_t retval;
|
||||
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))
|
||||
return 0; /* Nothing to do */
|
||||
|
||||
retval = ext2fs_allocate_block_bitmap(fs, "converted cluster bitmap",
|
||||
&gen_cmap);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
cmap = (ext2fs_generic_bitmap_64) gen_cmap;
|
||||
i = bmap->start;
|
||||
b_end = bmap->end;
|
||||
bmap->end = bmap->real_end;
|
||||
c_end = cmap->end;
|
||||
cmap->end = cmap->real_end;
|
||||
while (i < bmap->real_end) {
|
||||
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;
|
||||
ext2fs_free_block_bitmap(gen_bmap);
|
||||
*bitmap = (ext2fs_block_bitmap) cmap;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_find_first_zero_generic_bmap(ext2fs_generic_bitmap bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
|
||||
__u64 cstart, cend, cout;
|
||||
errcode_t retval;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
blk_t blk = 0;
|
||||
|
||||
if (((start) & ~0xffffffffULL) ||
|
||||
((end) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
retval = ext2fs_find_first_zero_generic_bitmap(bitmap, start,
|
||||
end, &blk);
|
||||
if (retval == 0)
|
||||
*out = blk;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
cstart = start >> bmap64->cluster_bits;
|
||||
cend = end >> bmap64->cluster_bits;
|
||||
|
||||
if (cstart < bmap64->start || cend > bmap64->end || start > end) {
|
||||
warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (bmap64->bitmap_ops->find_first_zero) {
|
||||
retval = bmap64->bitmap_ops->find_first_zero(bmap64, cstart,
|
||||
cend, &cout);
|
||||
if (retval)
|
||||
return retval;
|
||||
found:
|
||||
cout <<= bmap64->cluster_bits;
|
||||
*out = (cout >= start) ? cout : start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cout = cstart; cout <= cend; cout++)
|
||||
if (!bmap64->bitmap_ops->test_bmap(bmap64, cout))
|
||||
goto found;
|
||||
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_find_first_set_generic_bmap(ext2fs_generic_bitmap bitmap,
|
||||
__u64 start, __u64 end, __u64 *out)
|
||||
{
|
||||
ext2fs_generic_bitmap_64 bmap64 = (ext2fs_generic_bitmap_64) bitmap;
|
||||
__u64 cstart, cend, cout;
|
||||
errcode_t retval;
|
||||
|
||||
if (!bitmap)
|
||||
return EINVAL;
|
||||
|
||||
if (EXT2FS_IS_32_BITMAP(bitmap)) {
|
||||
blk_t blk = 0;
|
||||
|
||||
if (((start) & ~0xffffffffULL) ||
|
||||
((end) & ~0xffffffffULL)) {
|
||||
ext2fs_warn_bitmap2(bitmap, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
retval = ext2fs_find_first_set_generic_bitmap(bitmap, start,
|
||||
end, &blk);
|
||||
if (retval == 0)
|
||||
*out = blk;
|
||||
return retval;
|
||||
}
|
||||
|
||||
if (!EXT2FS_IS_64_BITMAP(bitmap))
|
||||
return EINVAL;
|
||||
|
||||
cstart = start >> bmap64->cluster_bits;
|
||||
cend = end >> bmap64->cluster_bits;
|
||||
|
||||
if (cstart < bmap64->start || cend > bmap64->end || start > end) {
|
||||
warn_bitmap(bmap64, EXT2FS_TEST_ERROR, start);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (bmap64->bitmap_ops->find_first_set) {
|
||||
retval = bmap64->bitmap_ops->find_first_set(bmap64, cstart,
|
||||
cend, &cout);
|
||||
if (retval)
|
||||
return retval;
|
||||
found:
|
||||
cout <<= bmap64->cluster_bits;
|
||||
*out = (cout >= start) ? cout : start;
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (cout = cstart; cout <= cend; cout++)
|
||||
if (bmap64->bitmap_ops->test_bmap(bmap64, cout))
|
||||
goto found;
|
||||
|
||||
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 = 0;
|
||||
|
||||
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;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/gen_bitmap64.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/gen_bitmap64.o
Executable file
Binary file not shown.
117
jni/e2fsprogs/lib/ext2fs/gen_crc32ctable.c
Executable file
117
jni/e2fsprogs/lib/ext2fs/gen_crc32ctable.c
Executable file
@@ -0,0 +1,117 @@
|
||||
#include <stdio.h>
|
||||
#include "crc32c_defs.h"
|
||||
#include <inttypes.h>
|
||||
|
||||
#define ENTRIES_PER_LINE 4
|
||||
|
||||
#if CRC_LE_BITS > 8
|
||||
# define LE_TABLE_ROWS (CRC_LE_BITS/8)
|
||||
# define LE_TABLE_SIZE 256
|
||||
#else
|
||||
# define LE_TABLE_ROWS 1
|
||||
# define LE_TABLE_SIZE (1 << CRC_LE_BITS)
|
||||
#endif
|
||||
|
||||
#if CRC_BE_BITS > 8
|
||||
# define BE_TABLE_ROWS (CRC_BE_BITS/8)
|
||||
# define BE_TABLE_SIZE 256
|
||||
#else
|
||||
# define BE_TABLE_ROWS 1
|
||||
# define BE_TABLE_SIZE (1 << CRC_BE_BITS)
|
||||
#endif
|
||||
|
||||
static uint32_t crc32table_be[BE_TABLE_ROWS][256];
|
||||
static uint32_t crc32ctable_le[LE_TABLE_ROWS][256];
|
||||
|
||||
/**
|
||||
* crc32init_le() - allocate and initialize LE table data
|
||||
*
|
||||
* crc is the crc of the byte i; other entries are filled in based on the
|
||||
* fact that crctable[i^j] = crctable[i] ^ crctable[j].
|
||||
*
|
||||
*/
|
||||
static void crc32cinit_le(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
uint32_t crc = 1;
|
||||
|
||||
crc32ctable_le[0][0] = 0;
|
||||
|
||||
for (i = LE_TABLE_SIZE >> 1; i; i >>= 1) {
|
||||
crc = (crc >> 1) ^ ((crc & 1) ? CRC32C_POLY_LE : 0);
|
||||
for (j = 0; j < LE_TABLE_SIZE; j += 2 * i)
|
||||
crc32ctable_le[0][i + j] = crc ^ crc32ctable_le[0][j];
|
||||
}
|
||||
for (i = 0; i < LE_TABLE_SIZE; i++) {
|
||||
crc = crc32ctable_le[0][i];
|
||||
for (j = 1; j < LE_TABLE_ROWS; j++) {
|
||||
crc = crc32ctable_le[0][crc & 0xff] ^ (crc >> 8);
|
||||
crc32ctable_le[j][i] = crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* crc32init_be() - allocate and initialize BE table data
|
||||
*/
|
||||
static void crc32init_be(void)
|
||||
{
|
||||
unsigned i, j;
|
||||
uint32_t crc = 0x80000000;
|
||||
|
||||
crc32table_be[0][0] = 0;
|
||||
|
||||
for (i = 1; i < BE_TABLE_SIZE; i <<= 1) {
|
||||
crc = (crc << 1) ^ ((crc & 0x80000000) ? CRCPOLY_BE : 0);
|
||||
for (j = 0; j < i; j++)
|
||||
crc32table_be[0][i + j] = crc ^ crc32table_be[0][j];
|
||||
}
|
||||
for (i = 0; i < BE_TABLE_SIZE; i++) {
|
||||
crc = crc32table_be[0][i];
|
||||
for (j = 1; j < BE_TABLE_ROWS; j++) {
|
||||
crc = crc32table_be[0][(crc >> 24) & 0xff] ^ (crc << 8);
|
||||
crc32table_be[j][i] = crc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void output_table(uint32_t (*table)[256], int rows, int len, char *trans)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (j = 0 ; j < rows; j++) {
|
||||
printf("{");
|
||||
for (i = 0; i < len - 1; i++) {
|
||||
if (i % ENTRIES_PER_LINE == 0)
|
||||
printf("\n");
|
||||
printf("%s(0x%8.8xL), ", trans, table[j][i]);
|
||||
}
|
||||
printf("%s(0x%8.8xL)},\n", trans, table[j][len - 1]);
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
printf("/* this file is generated - do not edit */\n\n");
|
||||
|
||||
if (CRC_BE_BITS > 1) {
|
||||
crc32init_be();
|
||||
printf("static const uint32_t "
|
||||
"crc32table_be[%d][%d] = {",
|
||||
BE_TABLE_ROWS, BE_TABLE_SIZE);
|
||||
output_table(crc32table_be, LE_TABLE_ROWS,
|
||||
BE_TABLE_SIZE, "tobe");
|
||||
printf("};\n");
|
||||
}
|
||||
if (CRC_LE_BITS > 1) {
|
||||
crc32cinit_le();
|
||||
printf("static const uint32_t "
|
||||
"crc32ctable_le[%d][%d] = {",
|
||||
LE_TABLE_ROWS, LE_TABLE_SIZE);
|
||||
output_table(crc32ctable_le, LE_TABLE_ROWS,
|
||||
LE_TABLE_SIZE, "tole");
|
||||
printf("};\n");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
50
jni/e2fsprogs/lib/ext2fs/get_num_dirs.c
Executable file
50
jni/e2fsprogs/lib/ext2fs/get_num_dirs.c
Executable file
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* get_num_dirs.c -- calculate number of directories
|
||||
*
|
||||
* Copyright 1997 by 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fsP.h"
|
||||
|
||||
/*
|
||||
* Returns the number of directories in the filesystem as reported by
|
||||
* the group descriptors. Of course, the group descriptors could be
|
||||
* wrong!
|
||||
*/
|
||||
errcode_t ext2fs_get_num_dirs(ext2_filsys fs, ext2_ino_t *ret_num_dirs)
|
||||
{
|
||||
dgrp_t i;
|
||||
ext2_ino_t num_dirs, max_dirs;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
num_dirs = 0;
|
||||
max_dirs = fs->super->s_inodes_per_group;
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
if (ext2fs_bg_used_dirs_count(fs, i) > max_dirs)
|
||||
num_dirs += max_dirs / 8;
|
||||
else
|
||||
num_dirs += ext2fs_bg_used_dirs_count(fs, i);
|
||||
}
|
||||
if (num_dirs > fs->super->s_inodes_count)
|
||||
num_dirs = fs->super->s_inodes_count;
|
||||
|
||||
*ret_num_dirs = num_dirs;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/get_num_dirs.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/get_num_dirs.o
Executable file
Binary file not shown.
171
jni/e2fsprogs/lib/ext2fs/get_pathname.c
Executable file
171
jni/e2fsprogs/lib/ext2fs/get_pathname.c
Executable file
@@ -0,0 +1,171 @@
|
||||
/*
|
||||
* get_pathname.c --- do directory/inode -> name translation
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
/*
|
||||
*
|
||||
* ext2fs_get_pathname(fs, dir, ino, name)
|
||||
*
|
||||
* This function translates takes two inode numbers into a
|
||||
* string, placing the result in <name>. <dir> is the containing
|
||||
* directory inode, and <ino> is the inode number itself. If
|
||||
* <ino> is zero, then ext2fs_get_pathname will return pathname
|
||||
* of the the directory <dir>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
struct get_pathname_struct {
|
||||
ext2_ino_t search_ino;
|
||||
ext2_ino_t parent;
|
||||
char *name;
|
||||
errcode_t errcode;
|
||||
};
|
||||
|
||||
#ifdef __TURBOC__
|
||||
#pragma argsused
|
||||
#endif
|
||||
static int get_pathname_proc(struct ext2_dir_entry *dirent,
|
||||
int offset EXT2FS_ATTR((unused)),
|
||||
int blocksize EXT2FS_ATTR((unused)),
|
||||
char *buf EXT2FS_ATTR((unused)),
|
||||
void *priv_data)
|
||||
{
|
||||
struct get_pathname_struct *gp;
|
||||
errcode_t retval;
|
||||
int name_len = ext2fs_dirent_name_len(dirent);
|
||||
|
||||
gp = (struct get_pathname_struct *) priv_data;
|
||||
|
||||
if ((name_len == 2) && !strncmp(dirent->name, "..", 2))
|
||||
gp->parent = dirent->inode;
|
||||
if (dirent->inode == gp->search_ino) {
|
||||
retval = ext2fs_get_mem(name_len + 1, &gp->name);
|
||||
if (retval) {
|
||||
gp->errcode = retval;
|
||||
return DIRENT_ABORT;
|
||||
}
|
||||
strncpy(gp->name, dirent->name, name_len);
|
||||
gp->name[name_len] = '\0';
|
||||
return DIRENT_ABORT;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t ext2fs_get_pathname_int(ext2_filsys fs, ext2_ino_t dir,
|
||||
ext2_ino_t ino, int maxdepth,
|
||||
char *buf, char **name)
|
||||
{
|
||||
struct get_pathname_struct gp;
|
||||
char *parent_name = 0, *ret;
|
||||
errcode_t retval;
|
||||
|
||||
if (dir == ino) {
|
||||
retval = ext2fs_get_mem(2, name);
|
||||
if (retval)
|
||||
return retval;
|
||||
strcpy(*name, (dir == EXT2_ROOT_INO) ? "/" : ".");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!dir || (maxdepth < 0)) {
|
||||
retval = ext2fs_get_mem(4, name);
|
||||
if (retval)
|
||||
return retval;
|
||||
strcpy(*name, "...");
|
||||
return 0;
|
||||
}
|
||||
|
||||
gp.search_ino = ino;
|
||||
gp.parent = 0;
|
||||
gp.name = 0;
|
||||
gp.errcode = 0;
|
||||
|
||||
retval = ext2fs_dir_iterate(fs, dir, 0, buf, get_pathname_proc, &gp);
|
||||
if (retval == EXT2_ET_NO_DIRECTORY) {
|
||||
char tmp[32];
|
||||
|
||||
if (ino)
|
||||
snprintf(tmp, sizeof(tmp), "<%u>/<%u>", dir, ino);
|
||||
else
|
||||
snprintf(tmp, sizeof(tmp), "<%u>", dir);
|
||||
retval = ext2fs_get_mem(strlen(tmp)+1, name);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
strcpy(*name, tmp);
|
||||
return 0;
|
||||
} else if (retval)
|
||||
goto cleanup;
|
||||
if (gp.errcode) {
|
||||
retval = gp.errcode;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
retval = ext2fs_get_pathname_int(fs, gp.parent, dir, maxdepth-1,
|
||||
buf, &parent_name);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
if (!ino) {
|
||||
*name = parent_name;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (gp.name)
|
||||
retval = ext2fs_get_mem(strlen(parent_name)+strlen(gp.name)+2,
|
||||
&ret);
|
||||
else
|
||||
retval = ext2fs_get_mem(strlen(parent_name)+5, &ret);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
ret[0] = 0;
|
||||
if (parent_name[1])
|
||||
strcat(ret, parent_name);
|
||||
strcat(ret, "/");
|
||||
if (gp.name)
|
||||
strcat(ret, gp.name);
|
||||
else
|
||||
strcat(ret, "???");
|
||||
*name = ret;
|
||||
retval = 0;
|
||||
|
||||
cleanup:
|
||||
ext2fs_free_mem(&parent_name);
|
||||
ext2fs_free_mem(&gp.name);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino,
|
||||
char **name)
|
||||
{
|
||||
char *buf;
|
||||
errcode_t retval;
|
||||
|
||||
EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS);
|
||||
|
||||
retval = ext2fs_get_mem(fs->blocksize, &buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (dir == ino)
|
||||
ino = 0;
|
||||
retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name);
|
||||
ext2fs_free_mem(&buf);
|
||||
return retval;
|
||||
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/get_pathname.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/get_pathname.o
Executable file
Binary file not shown.
151
jni/e2fsprogs/lib/ext2fs/getsectsize.c
Executable file
151
jni/e2fsprogs/lib/ext2fs/getsectsize.c
Executable file
@@ -0,0 +1,151 @@
|
||||
/*
|
||||
* getsectsize.c --- get the sector size of a device.
|
||||
*
|
||||
* Copyright (C) 1995, 1995 Theodore Ts'o.
|
||||
* Copyright (C) 2003 VMware, Inc.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SYS_DISK_H
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FD_H
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(_IO)
|
||||
#if !defined(BLKSSZGET)
|
||||
#define BLKSSZGET _IO(0x12,104)/* get block device sector size */
|
||||
#endif
|
||||
#if !defined(BLKPBSZGET)
|
||||
#define BLKPBSZGET _IO(0x12,123)/* get block physical sector size */
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* Returns the logical sector size of a device
|
||||
*/
|
||||
errcode_t ext2fs_get_device_sectsize(const char *file, int *sectsize)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
*sectsize = 512; // just guessing
|
||||
return 0;
|
||||
#else // not _WIN32
|
||||
|
||||
int fd;
|
||||
|
||||
fd = ext2fs_open_file(file, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
|
||||
#ifdef BLKSSZGET
|
||||
if (ioctl(fd, BLKSSZGET, sectsize) >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef DIOCGSECTORSIZE
|
||||
if (ioctl(fd, DIOCGSECTORSIZE, sectsize) >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
*sectsize = 0;
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
#endif // ifdef _WIN32
|
||||
}
|
||||
|
||||
/*
|
||||
* Return desired alignment for direct I/O
|
||||
*/
|
||||
int ext2fs_get_dio_alignment(int fd)
|
||||
{
|
||||
int align = 0;
|
||||
|
||||
#ifdef BLKSSZGET
|
||||
if (ioctl(fd, BLKSSZGET, &align) < 0)
|
||||
align = 0;
|
||||
#endif
|
||||
#ifdef DIOCGSECTORSIZE
|
||||
if (align <= 0 &&
|
||||
ioctl(fd, DIOCGSECTORSIZE, &align) < 0)
|
||||
align = 0;
|
||||
#endif
|
||||
|
||||
#ifdef _SC_PAGESIZE
|
||||
if (align <= 0)
|
||||
align = sysconf(_SC_PAGESIZE);
|
||||
#endif
|
||||
#ifdef HAVE_GETPAGESIZE
|
||||
if (align <= 0)
|
||||
align = getpagesize();
|
||||
#endif
|
||||
if (align <= 0)
|
||||
align = 4096;
|
||||
|
||||
return align;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the physical sector size of a device
|
||||
*/
|
||||
errcode_t ext2fs_get_device_phys_sectsize(const char *file, int *sectsize)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
|
||||
return ext2fs_get_device_sectsize(file, sectsize);
|
||||
|
||||
#else // not _WIN32
|
||||
|
||||
int fd;
|
||||
|
||||
fd = ext2fs_open_file(file, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
|
||||
#ifdef BLKPBSZGET
|
||||
if (ioctl(fd, BLKPBSZGET, sectsize) >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
#ifdef DIOCGSECTORSIZE
|
||||
/* This isn't really the physical sector size, but FreeBSD
|
||||
* doesn't seem to have this concept. */
|
||||
if (ioctl(fd, DIOCGSECTORSIZE, sectsize) >= 0) {
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
*sectsize = 0;
|
||||
close(fd);
|
||||
return 0;
|
||||
|
||||
#endif // ifdef _WIN32
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/getsectsize.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/getsectsize.o
Executable file
Binary file not shown.
315
jni/e2fsprogs/lib/ext2fs/getsize.c
Executable file
315
jni/e2fsprogs/lib/ext2fs/getsize.c
Executable file
@@ -0,0 +1,315 @@
|
||||
/*
|
||||
* getsize.c --- get the size of a partition.
|
||||
*
|
||||
* Copyright (C) 1995, 1995 Theodore Ts'o.
|
||||
* Copyright (C) 2003 VMware, Inc.
|
||||
*
|
||||
* Windows version of ext2fs_get_device_size by Chris Li, VMware.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _LARGEFILE_SOURCE
|
||||
#define _LARGEFILE_SOURCE
|
||||
#endif
|
||||
#ifndef _LARGEFILE64_SOURCE
|
||||
#define _LARGEFILE64_SOURCE
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#ifdef HAVE_SYS_IOCTL_H
|
||||
#include <sys/ioctl.h>
|
||||
#endif
|
||||
#ifdef HAVE_LINUX_FD_H
|
||||
#include <linux/fd.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_DISKLABEL_H
|
||||
#include <sys/disklabel.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_DISK_H
|
||||
#include <sys/disk.h>
|
||||
#endif
|
||||
#ifdef __linux__
|
||||
#include <sys/utsname.h>
|
||||
#endif
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#include <ctype.h>
|
||||
|
||||
#if defined(__linux__) && defined(_IO) && !defined(BLKGETSIZE)
|
||||
#define BLKGETSIZE _IO(0x12,96) /* return device size */
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(_IOR) && !defined(BLKGETSIZE64)
|
||||
#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size in bytes (u64 *arg) */
|
||||
#endif
|
||||
|
||||
#ifdef APPLE_DARWIN
|
||||
#define BLKGETSIZE DKIOCGETBLOCKCOUNT32
|
||||
#endif /* APPLE_DARWIN */
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
#if defined(__CYGWIN__) || defined (WIN32)
|
||||
#include "windows.h"
|
||||
#include "winioctl.h"
|
||||
|
||||
#if (_WIN32_WINNT >= 0x0500)
|
||||
#define HAVE_GET_FILE_SIZE_EX 1
|
||||
#endif
|
||||
|
||||
errcode_t ext2fs_get_device_size2(const char *file, int blocksize,
|
||||
blk64_t *retblocks)
|
||||
{
|
||||
int fd;
|
||||
HANDLE h;
|
||||
PARTITION_INFORMATION pi;
|
||||
DISK_GEOMETRY gi;
|
||||
DWORD retbytes;
|
||||
#ifdef HAVE_GET_FILE_SIZE_EX
|
||||
LARGE_INTEGER filesize;
|
||||
#else
|
||||
DWORD filesize;
|
||||
#endif /* HAVE_GET_FILE_SIZE_EX */
|
||||
|
||||
fd = ext2fs_open_file(file, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
h = (HANDLE)_get_osfhandle(fd);
|
||||
if (DeviceIoControl(h, IOCTL_DISK_GET_PARTITION_INFO,
|
||||
&pi, sizeof(PARTITION_INFORMATION),
|
||||
&pi, sizeof(PARTITION_INFORMATION),
|
||||
&retbytes, NULL)) {
|
||||
|
||||
*retblocks = pi.PartitionLength.QuadPart / blocksize;
|
||||
|
||||
} else if (DeviceIoControl(h, IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
||||
&gi, sizeof(DISK_GEOMETRY),
|
||||
&gi, sizeof(DISK_GEOMETRY),
|
||||
&retbytes, NULL)) {
|
||||
|
||||
*retblocks = gi.BytesPerSector *
|
||||
gi.SectorsPerTrack *
|
||||
gi.TracksPerCylinder *
|
||||
gi.Cylinders.QuadPart / blocksize;
|
||||
|
||||
#ifdef HAVE_GET_FILE_SIZE_EX
|
||||
} else if (GetFileSizeEx(h, &filesize)) {
|
||||
*retblocks = filesize.QuadPart / blocksize;
|
||||
}
|
||||
#else
|
||||
} else {
|
||||
filesize = GetFileSize(h, NULL);
|
||||
if (INVALID_FILE_SIZE != filesize) {
|
||||
*retblocks = filesize / blocksize;
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_GET_FILE_SIZE_EX */
|
||||
|
||||
close(fd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static int valid_offset (int fd, ext2_loff_t offset)
|
||||
{
|
||||
char ch;
|
||||
|
||||
if (ext2fs_llseek (fd, offset, 0) < 0)
|
||||
return 0;
|
||||
if (read (fd, &ch, 1) < 1)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of blocks in a partition
|
||||
*/
|
||||
errcode_t ext2fs_get_device_size2(const char *file, int blocksize,
|
||||
blk64_t *retblocks)
|
||||
{
|
||||
int fd, rc = 0;
|
||||
unsigned long long size64;
|
||||
ext2_loff_t high, low;
|
||||
|
||||
fd = ext2fs_open_file(file, O_RDONLY, 0);
|
||||
if (fd < 0)
|
||||
return errno;
|
||||
|
||||
#if defined DKIOCGETBLOCKCOUNT && defined DKIOCGETBLOCKSIZE /* For Apple Darwin */
|
||||
unsigned int size;
|
||||
|
||||
if (ioctl(fd, DKIOCGETBLOCKCOUNT, &size64) >= 0 &&
|
||||
ioctl(fd, DKIOCGETBLOCKSIZE, &size) >= 0) {
|
||||
*retblocks = size64 * size / blocksize;
|
||||
goto out;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BLKGETSIZE64
|
||||
{
|
||||
int valid_blkgetsize64 = 1;
|
||||
#ifdef __linux__
|
||||
struct utsname ut;
|
||||
|
||||
if ((uname(&ut) == 0) &&
|
||||
((ut.release[0] == '2') && (ut.release[1] == '.') &&
|
||||
(ut.release[2] < '6') && (ut.release[3] == '.')))
|
||||
valid_blkgetsize64 = 0;
|
||||
#endif
|
||||
if (valid_blkgetsize64 &&
|
||||
ioctl(fd, BLKGETSIZE64, &size64) >= 0) {
|
||||
*retblocks = size64 / blocksize;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif /* BLKGETSIZE64 */
|
||||
|
||||
#ifdef BLKGETSIZE
|
||||
{
|
||||
unsigned long size;
|
||||
|
||||
if (ioctl(fd, BLKGETSIZE, &size) >= 0) {
|
||||
*retblocks = size / (blocksize / 512);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef FDGETPRM
|
||||
{
|
||||
struct floppy_struct this_floppy;
|
||||
|
||||
if (ioctl(fd, FDGETPRM, &this_floppy) >= 0) {
|
||||
*retblocks = this_floppy.size / (blocksize / 512);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_SYS_DISKLABEL_H
|
||||
{
|
||||
int part;
|
||||
struct disklabel lab;
|
||||
struct partition *pp;
|
||||
char ch;
|
||||
|
||||
#if defined(DIOCGMEDIASIZE)
|
||||
{
|
||||
off_t ms;
|
||||
u_int bs;
|
||||
if (ioctl(fd, DIOCGMEDIASIZE, &ms) >= 0) {
|
||||
*retblocks = ms / blocksize;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#elif defined(DIOCGDINFO)
|
||||
/* old disklabel interface */
|
||||
part = strlen(file) - 1;
|
||||
if (part >= 0) {
|
||||
ch = file[part];
|
||||
if (isdigit(ch))
|
||||
part = 0;
|
||||
else if (ch >= 'a' && ch <= 'h')
|
||||
part = ch - 'a';
|
||||
else
|
||||
part = -1;
|
||||
}
|
||||
if (part >= 0 && (ioctl(fd, DIOCGDINFO, (char *)&lab) >= 0)) {
|
||||
pp = &lab.d_partitions[part];
|
||||
if (pp->p_size) {
|
||||
*retblocks = pp->p_size / (blocksize / 512);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif /* defined(DIOCG*) */
|
||||
}
|
||||
#endif /* HAVE_SYS_DISKLABEL_H */
|
||||
|
||||
{
|
||||
ext2fs_struct_stat st;
|
||||
|
||||
if (ext2fs_fstat(fd, &st) == 0)
|
||||
if (S_ISREG(st.st_mode)) {
|
||||
*retblocks = st.st_size / blocksize;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, we couldn't figure it out by using a specialized ioctl,
|
||||
* which is generally the best way. So do binary search to
|
||||
* find the size of the partition.
|
||||
*/
|
||||
low = 0;
|
||||
for (high = 1024; valid_offset(fd, high); high *= 2)
|
||||
low = high;
|
||||
while (low < high - 1) {
|
||||
const ext2_loff_t mid = (low + high) / 2;
|
||||
|
||||
if (valid_offset (fd, mid))
|
||||
low = mid;
|
||||
else
|
||||
high = mid;
|
||||
}
|
||||
valid_offset(fd, 0);
|
||||
size64 = low + 1;
|
||||
*retblocks = size64 / blocksize;
|
||||
out:
|
||||
close(fd);
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* WIN32 */
|
||||
|
||||
errcode_t ext2fs_get_device_size(const char *file, int blocksize,
|
||||
blk_t *retblocks)
|
||||
{
|
||||
errcode_t retval;
|
||||
blk64_t blocks;
|
||||
|
||||
retval = ext2fs_get_device_size2(file, blocksize, &blocks);
|
||||
if (retval)
|
||||
return retval;
|
||||
if (blocks >= (1ULL << 32))
|
||||
return EFBIG;
|
||||
*retblocks = (blk_t) blocks;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
blk64_t blocks;
|
||||
int retval;
|
||||
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: %s device\n", argv[0]);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
retval = ext2fs_get_device_size2(argv[1], 1024, &blocks);
|
||||
if (retval) {
|
||||
com_err(argv[0], retval,
|
||||
"while calling ext2fs_get_device_size");
|
||||
exit(1);
|
||||
}
|
||||
printf("Device %s has %llu 1k blocks.\n", argv[1],
|
||||
(unsigned long long) locks);
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/getsize.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/getsize.o
Executable file
Binary file not shown.
109
jni/e2fsprogs/lib/ext2fs/hashmap.c
Executable file
109
jni/e2fsprogs/lib/ext2fs/hashmap.c
Executable file
@@ -0,0 +1,109 @@
|
||||
#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;
|
||||
const char *s = str;
|
||||
uint32_t hash = 5381;
|
||||
|
||||
while (size-- > 0) {
|
||||
c = *s++;
|
||||
hash = ((hash << 5) + hash) + c;
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
struct ext2fs_hashmap *ext2fs_hashmap_create(
|
||||
uint32_t(*hash_fct)(const void*, size_t),
|
||||
void(*free_fct)(void*), size_t size)
|
||||
{
|
||||
struct ext2fs_hashmap *h = calloc(sizeof(struct ext2fs_hashmap) +
|
||||
sizeof(struct ext2fs_hashmap_entry) * size, 1);
|
||||
if (!h)
|
||||
return NULL;
|
||||
|
||||
h->size = size;
|
||||
h->free = free_fct;
|
||||
h->hash = hash_fct;
|
||||
h->first = h->last = NULL;
|
||||
return h;
|
||||
}
|
||||
|
||||
int ext2fs_hashmap_add(struct ext2fs_hashmap *h,
|
||||
void *data, const void *key, size_t key_len)
|
||||
{
|
||||
uint32_t hash = h->hash(key, key_len) % h->size;
|
||||
struct ext2fs_hashmap_entry *e = malloc(sizeof(*e));
|
||||
|
||||
if (!e)
|
||||
return -1;
|
||||
|
||||
e->data = data;
|
||||
e->key = key;
|
||||
e->key_len = key_len;
|
||||
e->next = h->entries[hash];
|
||||
h->entries[hash] = e;
|
||||
|
||||
e->list_prev = NULL;
|
||||
e->list_next = h->first;
|
||||
if (h->first)
|
||||
h->first->list_prev = e;
|
||||
h->first = e;
|
||||
if (!h->last)
|
||||
h->last = e;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *ext2fs_hashmap_lookup(struct ext2fs_hashmap *h, const void *key,
|
||||
size_t key_len)
|
||||
{
|
||||
struct ext2fs_hashmap_entry *iter;
|
||||
uint32_t hash = h->hash(key, key_len) % h->size;
|
||||
|
||||
for (iter = h->entries[hash]; iter; iter = iter->next)
|
||||
if (iter->key_len == key_len && !memcmp(iter->key, key, key_len))
|
||||
return iter->data;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *ext2fs_hashmap_iter_in_order(struct ext2fs_hashmap *h,
|
||||
struct ext2fs_hashmap_entry **it)
|
||||
{
|
||||
*it = *it ? (*it)->list_next : h->first;
|
||||
return *it ? (*it)->data : NULL;
|
||||
}
|
||||
|
||||
void ext2fs_hashmap_free(struct ext2fs_hashmap *h)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < h->size; ++i) {
|
||||
struct ext2fs_hashmap_entry *it = h->entries[i];
|
||||
while (it) {
|
||||
struct ext2fs_hashmap_entry *tmp = it->next;
|
||||
if (h->free)
|
||||
h->free(it->data);
|
||||
free(it);
|
||||
it = tmp;
|
||||
}
|
||||
}
|
||||
free(h);
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/hashmap.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/hashmap.o
Executable file
Binary file not shown.
90
jni/e2fsprogs/lib/ext2fs/i_block.c
Executable file
90
jni/e2fsprogs/lib/ext2fs/i_block.c
Executable file
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* i_block.c --- Manage the i_block field for i_blocks
|
||||
*
|
||||
* Copyright (C) 2008 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
errcode_t ext2fs_iblk_add_blocks(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t num_blocks)
|
||||
{
|
||||
unsigned long long b = inode->i_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
|
||||
|
||||
if (!ext2fs_has_feature_huge_file(fs->super) ||
|
||||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
|
||||
num_blocks *= fs->blocksize / 512;
|
||||
num_blocks *= EXT2FS_CLUSTER_RATIO(fs);
|
||||
|
||||
b += num_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
|
||||
else if (b > 0xFFFFFFFF)
|
||||
return EOVERFLOW;
|
||||
inode->i_blocks = b & 0xFFFFFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_iblk_sub_blocks(ext2_filsys fs, struct ext2_inode *inode,
|
||||
blk64_t num_blocks)
|
||||
{
|
||||
unsigned long long b = inode->i_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
b += ((long long) inode->osd2.linux2.l_i_blocks_hi) << 32;
|
||||
|
||||
if (!ext2fs_has_feature_huge_file(fs->super) ||
|
||||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
|
||||
num_blocks *= fs->blocksize / 512;
|
||||
num_blocks *= EXT2FS_CLUSTER_RATIO(fs);
|
||||
|
||||
if (num_blocks > b)
|
||||
return EOVERFLOW;
|
||||
|
||||
b -= num_blocks;
|
||||
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
|
||||
inode->i_blocks = b & 0xFFFFFFFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_iblk_set(ext2_filsys fs, struct ext2_inode *inode, blk64_t b)
|
||||
{
|
||||
if (!ext2fs_has_feature_huge_file(fs->super) ||
|
||||
!(inode->i_flags & EXT4_HUGE_FILE_FL))
|
||||
b *= fs->blocksize / 512;
|
||||
b *= EXT2FS_CLUSTER_RATIO(fs);
|
||||
|
||||
inode->i_blocks = b & 0xFFFFFFFF;
|
||||
if (ext2fs_has_feature_huge_file(fs->super))
|
||||
inode->osd2.linux2.l_i_blocks_hi = b >> 32;
|
||||
else if (b >> 32)
|
||||
return EOVERFLOW;
|
||||
return 0;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/i_block.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/i_block.o
Executable file
Binary file not shown.
921
jni/e2fsprogs/lib/ext2fs/icount.c
Executable file
921
jni/e2fsprogs/lib/ext2fs/icount.c
Executable file
@@ -0,0 +1,921 @@
|
||||
/*
|
||||
* icount.c --- an efficient inode count abstraction
|
||||
*
|
||||
* Copyright (C) 1997 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"
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
#include "tdb.h"
|
||||
|
||||
/*
|
||||
* The data storage strategy used by icount relies on the observation
|
||||
* that most inode counts are either zero (for non-allocated inodes),
|
||||
* one (for most files), and only a few that are two or more
|
||||
* (directories and files that are linked to more than one directory).
|
||||
*
|
||||
* Also, e2fsck tends to load the icount data sequentially.
|
||||
*
|
||||
* So, we use an inode bitmap to indicate which inodes have a count of
|
||||
* one, and then use a sorted list to store the counts for inodes
|
||||
* which are greater than one.
|
||||
*
|
||||
* We also use an optional bitmap to indicate which inodes are already
|
||||
* in the sorted list, to speed up the use of this abstraction by
|
||||
* e2fsck's pass 2. Pass 2 increments inode counts as it finds them,
|
||||
* so this extra bitmap avoids searching the sorted list to see if a
|
||||
* particular inode is on the sorted list already.
|
||||
*/
|
||||
|
||||
struct ext2_icount_el {
|
||||
ext2_ino_t ino;
|
||||
__u32 count;
|
||||
};
|
||||
|
||||
struct ext2_icount {
|
||||
errcode_t magic;
|
||||
ext2fs_inode_bitmap single;
|
||||
ext2fs_inode_bitmap multiple;
|
||||
ext2_ino_t count;
|
||||
ext2_ino_t size;
|
||||
ext2_ino_t num_inodes;
|
||||
ext2_ino_t cursor;
|
||||
struct ext2_icount_el *list;
|
||||
struct ext2_icount_el *last_lookup;
|
||||
#ifdef CONFIG_TDB
|
||||
char *tdb_fn;
|
||||
TDB_CONTEXT *tdb;
|
||||
#endif
|
||||
__u16 *fullmap;
|
||||
};
|
||||
|
||||
/*
|
||||
* We now use a 32-bit counter field because it doesn't cost us
|
||||
* anything extra for the in-memory data structure, due to alignment
|
||||
* padding. But there's no point changing the interface if most of
|
||||
* the time we only care if the number is bigger than 65,000 or not.
|
||||
* So use the following translation function to return a 16-bit count.
|
||||
*/
|
||||
#define icount_16_xlate(x) (((x) > 65500) ? 65500 : (x))
|
||||
|
||||
void ext2fs_free_icount(ext2_icount_t icount)
|
||||
{
|
||||
if (!icount)
|
||||
return;
|
||||
|
||||
icount->magic = 0;
|
||||
if (icount->list)
|
||||
ext2fs_free_mem(&icount->list);
|
||||
if (icount->single)
|
||||
ext2fs_free_inode_bitmap(icount->single);
|
||||
if (icount->multiple)
|
||||
ext2fs_free_inode_bitmap(icount->multiple);
|
||||
#ifdef CONFIG_TDB
|
||||
if (icount->tdb)
|
||||
tdb_close(icount->tdb);
|
||||
if (icount->tdb_fn) {
|
||||
(void) unlink(icount->tdb_fn);
|
||||
free(icount->tdb_fn);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (icount->fullmap)
|
||||
ext2fs_free_mem(&icount->fullmap);
|
||||
|
||||
ext2fs_free_mem(&icount);
|
||||
}
|
||||
|
||||
static errcode_t alloc_icount(ext2_filsys fs, int flags, ext2_icount_t *ret)
|
||||
{
|
||||
ext2_icount_t icount;
|
||||
errcode_t retval;
|
||||
|
||||
*ret = 0;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct ext2_icount), &icount);
|
||||
if (retval)
|
||||
return retval;
|
||||
memset(icount, 0, sizeof(struct ext2_icount));
|
||||
icount->magic = EXT2_ET_MAGIC_ICOUNT;
|
||||
icount->num_inodes = fs->super->s_inodes_count;
|
||||
|
||||
if ((flags & EXT2_ICOUNT_OPT_FULLMAP) &&
|
||||
(flags & EXT2_ICOUNT_OPT_INCREMENT)) {
|
||||
unsigned sz = sizeof(*icount->fullmap) * icount->num_inodes;
|
||||
|
||||
retval = ext2fs_get_mem(sz, &icount->fullmap);
|
||||
/* If we can't allocate, fall back */
|
||||
if (!retval) {
|
||||
memset(icount->fullmap, 0, sz);
|
||||
*ret = icount;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
retval = ext2fs_allocate_inode_bitmap(fs, "icount", &icount->single);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
if (flags & EXT2_ICOUNT_OPT_INCREMENT) {
|
||||
retval = ext2fs_allocate_inode_bitmap(fs, "icount_inc",
|
||||
&icount->multiple);
|
||||
if (retval)
|
||||
goto errout;
|
||||
} else
|
||||
icount->multiple = 0;
|
||||
|
||||
*ret = icount;
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
ext2fs_free_icount(icount);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TDB
|
||||
struct uuid {
|
||||
__u32 time_low;
|
||||
__u16 time_mid;
|
||||
__u16 time_hi_and_version;
|
||||
__u16 clock_seq;
|
||||
__u8 node[6];
|
||||
};
|
||||
|
||||
static void unpack_uuid(void *in, struct uuid *uu)
|
||||
{
|
||||
__u8 *ptr = in;
|
||||
__u32 tmp;
|
||||
|
||||
tmp = *ptr++;
|
||||
tmp = (tmp << 8) | *ptr++;
|
||||
tmp = (tmp << 8) | *ptr++;
|
||||
tmp = (tmp << 8) | *ptr++;
|
||||
uu->time_low = tmp;
|
||||
|
||||
tmp = *ptr++;
|
||||
tmp = (tmp << 8) | *ptr++;
|
||||
uu->time_mid = tmp;
|
||||
|
||||
tmp = *ptr++;
|
||||
tmp = (tmp << 8) | *ptr++;
|
||||
uu->time_hi_and_version = tmp;
|
||||
|
||||
tmp = *ptr++;
|
||||
tmp = (tmp << 8) | *ptr++;
|
||||
uu->clock_seq = tmp;
|
||||
|
||||
memcpy(uu->node, ptr, 6);
|
||||
}
|
||||
|
||||
static void uuid_unparse(void *uu, char *out)
|
||||
{
|
||||
struct uuid uuid;
|
||||
|
||||
unpack_uuid(uu, &uuid);
|
||||
sprintf(out,
|
||||
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
uuid.time_low, uuid.time_mid, uuid.time_hi_and_version,
|
||||
uuid.clock_seq >> 8, uuid.clock_seq & 0xFF,
|
||||
uuid.node[0], uuid.node[1], uuid.node[2],
|
||||
uuid.node[3], uuid.node[4], uuid.node[5]);
|
||||
}
|
||||
#endif
|
||||
|
||||
errcode_t ext2fs_create_icount_tdb(ext2_filsys fs EXT2FS_NO_TDB_UNUSED,
|
||||
char *tdb_dir EXT2FS_NO_TDB_UNUSED,
|
||||
int flags EXT2FS_NO_TDB_UNUSED,
|
||||
ext2_icount_t *ret EXT2FS_NO_TDB_UNUSED)
|
||||
{
|
||||
#ifdef CONFIG_TDB
|
||||
ext2_icount_t icount;
|
||||
errcode_t retval;
|
||||
char *fn, uuid[40];
|
||||
ext2_ino_t num_inodes;
|
||||
mode_t save_umask;
|
||||
int fd;
|
||||
|
||||
retval = alloc_icount(fs, flags, &icount);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = ext2fs_get_mem(strlen(tdb_dir) + 64, &fn);
|
||||
if (retval)
|
||||
goto errout;
|
||||
uuid_unparse(fs->super->s_uuid, uuid);
|
||||
sprintf(fn, "%s/%s-icount-XXXXXX", tdb_dir, uuid);
|
||||
save_umask = umask(077);
|
||||
fd = mkstemp(fn);
|
||||
if (fd < 0) {
|
||||
retval = errno;
|
||||
ext2fs_free_mem(&fn);
|
||||
goto errout;
|
||||
}
|
||||
icount->tdb_fn = fn;
|
||||
umask(save_umask);
|
||||
/*
|
||||
* This is an overestimate of the size that we will need; the
|
||||
* ideal value is the number of used inodes with a count
|
||||
* greater than 1. OTOH the times when we really need this is
|
||||
* with the backup programs that use lots of hard links, in
|
||||
* which case the number of inodes in use approaches the ideal
|
||||
* value.
|
||||
*/
|
||||
num_inodes = fs->super->s_inodes_count - fs->super->s_free_inodes_count;
|
||||
|
||||
icount->tdb = tdb_open(fn, num_inodes, TDB_NOLOCK | TDB_NOSYNC,
|
||||
O_RDWR | O_CREAT | O_TRUNC, 0600);
|
||||
close(fd);
|
||||
if (icount->tdb == NULL) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
*ret = icount;
|
||||
return 0;
|
||||
errout:
|
||||
ext2fs_free_icount(icount);
|
||||
return(retval);
|
||||
#else
|
||||
return EXT2_ET_UNIMPLEMENTED;
|
||||
#endif
|
||||
}
|
||||
|
||||
errcode_t ext2fs_create_icount2(ext2_filsys fs, int flags, unsigned int size,
|
||||
ext2_icount_t hint, ext2_icount_t *ret)
|
||||
{
|
||||
ext2_icount_t icount;
|
||||
errcode_t retval;
|
||||
size_t bytes;
|
||||
ext2_ino_t i;
|
||||
|
||||
if (hint) {
|
||||
EXT2_CHECK_MAGIC(hint, EXT2_ET_MAGIC_ICOUNT);
|
||||
if (hint->size > size)
|
||||
size = (size_t) hint->size;
|
||||
}
|
||||
|
||||
retval = alloc_icount(fs, flags, &icount);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
if (icount->fullmap)
|
||||
goto successout;
|
||||
|
||||
if (size) {
|
||||
icount->size = size;
|
||||
} else {
|
||||
/*
|
||||
* Figure out how many special case inode counts we will
|
||||
* have. We know we will need one for each directory;
|
||||
* we also need to reserve some extra room for file links
|
||||
*/
|
||||
retval = ext2fs_get_num_dirs(fs, &icount->size);
|
||||
if (retval)
|
||||
goto errout;
|
||||
icount->size += fs->super->s_inodes_count / 50;
|
||||
}
|
||||
|
||||
bytes = (size_t) (icount->size * sizeof(struct ext2_icount_el));
|
||||
#if 0
|
||||
printf("Icount allocated %u entries, %d bytes.\n",
|
||||
icount->size, bytes);
|
||||
#endif
|
||||
retval = ext2fs_get_array(icount->size, sizeof(struct ext2_icount_el),
|
||||
&icount->list);
|
||||
if (retval)
|
||||
goto errout;
|
||||
memset(icount->list, 0, bytes);
|
||||
|
||||
icount->count = 0;
|
||||
icount->cursor = 0;
|
||||
|
||||
/*
|
||||
* Populate the sorted list with those entries which were
|
||||
* found in the hint icount (since those are ones which will
|
||||
* likely need to be in the sorted list this time around).
|
||||
*/
|
||||
if (hint) {
|
||||
for (i=0; i < hint->count; i++)
|
||||
icount->list[i].ino = hint->list[i].ino;
|
||||
icount->count = hint->count;
|
||||
}
|
||||
|
||||
successout:
|
||||
*ret = icount;
|
||||
return 0;
|
||||
|
||||
errout:
|
||||
ext2fs_free_icount(icount);
|
||||
return(retval);
|
||||
}
|
||||
|
||||
errcode_t ext2fs_create_icount(ext2_filsys fs, int flags,
|
||||
unsigned int size,
|
||||
ext2_icount_t *ret)
|
||||
{
|
||||
return ext2fs_create_icount2(fs, flags, size, 0, ret);
|
||||
}
|
||||
|
||||
/*
|
||||
* insert_icount_el() --- Insert a new entry into the sorted list at a
|
||||
* specified position.
|
||||
*/
|
||||
static struct ext2_icount_el *insert_icount_el(ext2_icount_t icount,
|
||||
ext2_ino_t ino, int pos)
|
||||
{
|
||||
struct ext2_icount_el *el;
|
||||
errcode_t retval;
|
||||
ext2_ino_t new_size = 0;
|
||||
int num;
|
||||
|
||||
if (icount->last_lookup && icount->last_lookup->ino == ino)
|
||||
return icount->last_lookup;
|
||||
|
||||
if (icount->count >= icount->size) {
|
||||
if (icount->count) {
|
||||
new_size = icount->list[(unsigned)icount->count-1].ino;
|
||||
new_size = (ext2_ino_t) (icount->count *
|
||||
((float) icount->num_inodes / new_size));
|
||||
}
|
||||
if (new_size < (icount->size + 100))
|
||||
new_size = icount->size + 100;
|
||||
#if 0
|
||||
printf("Reallocating icount %u entries...\n", new_size);
|
||||
#endif
|
||||
retval = ext2fs_resize_mem((size_t) icount->size *
|
||||
sizeof(struct ext2_icount_el),
|
||||
(size_t) new_size *
|
||||
sizeof(struct ext2_icount_el),
|
||||
&icount->list);
|
||||
if (retval)
|
||||
return 0;
|
||||
icount->size = new_size;
|
||||
}
|
||||
num = (int) icount->count - pos;
|
||||
if (num < 0)
|
||||
return 0; /* should never happen */
|
||||
if (num) {
|
||||
memmove(&icount->list[pos+1], &icount->list[pos],
|
||||
sizeof(struct ext2_icount_el) * num);
|
||||
}
|
||||
icount->count++;
|
||||
el = &icount->list[pos];
|
||||
el->count = 0;
|
||||
el->ino = ino;
|
||||
icount->last_lookup = el;
|
||||
return el;
|
||||
}
|
||||
|
||||
/*
|
||||
* get_icount_el() --- given an inode number, try to find icount
|
||||
* information in the sorted list. If the create flag is set,
|
||||
* and we can't find an entry, create one in the sorted list.
|
||||
*/
|
||||
static struct ext2_icount_el *get_icount_el(ext2_icount_t icount,
|
||||
ext2_ino_t ino, int create)
|
||||
{
|
||||
int low, high, mid;
|
||||
|
||||
if (!icount || !icount->list)
|
||||
return 0;
|
||||
|
||||
if (create && ((icount->count == 0) ||
|
||||
(ino > icount->list[(unsigned)icount->count-1].ino))) {
|
||||
return insert_icount_el(icount, ino, (unsigned) icount->count);
|
||||
}
|
||||
if (icount->count == 0)
|
||||
return 0;
|
||||
|
||||
if (icount->cursor >= icount->count)
|
||||
icount->cursor = 0;
|
||||
if (ino == icount->list[icount->cursor].ino)
|
||||
return &icount->list[icount->cursor++];
|
||||
#if 0
|
||||
printf("Non-cursor get_icount_el: %u\n", ino);
|
||||
#endif
|
||||
low = 0;
|
||||
high = (int) icount->count-1;
|
||||
while (low <= high) {
|
||||
mid = ((unsigned)low + (unsigned)high) >> 1;
|
||||
if (ino == icount->list[mid].ino) {
|
||||
icount->cursor = mid+1;
|
||||
return &icount->list[mid];
|
||||
}
|
||||
if (ino < icount->list[mid].ino)
|
||||
high = mid-1;
|
||||
else
|
||||
low = mid+1;
|
||||
}
|
||||
/*
|
||||
* If we need to create a new entry, it should be right at
|
||||
* low (where high will be left at low-1).
|
||||
*/
|
||||
if (create)
|
||||
return insert_icount_el(icount, ino, low);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t set_inode_count(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u32 count)
|
||||
{
|
||||
struct ext2_icount_el *el;
|
||||
#ifdef CONFIG_TDB
|
||||
TDB_DATA key, data;
|
||||
|
||||
if (icount->tdb) {
|
||||
key.dptr = (unsigned char *) &ino;
|
||||
key.dsize = sizeof(ext2_ino_t);
|
||||
data.dptr = (unsigned char *) &count;
|
||||
data.dsize = sizeof(__u32);
|
||||
if (count) {
|
||||
if (tdb_store(icount->tdb, key, data, TDB_REPLACE))
|
||||
return tdb_error(icount->tdb) +
|
||||
EXT2_ET_TDB_SUCCESS;
|
||||
} else {
|
||||
if (tdb_delete(icount->tdb, key))
|
||||
return tdb_error(icount->tdb) +
|
||||
EXT2_ET_TDB_SUCCESS;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (icount->fullmap) {
|
||||
icount->fullmap[ino] = icount_16_xlate(count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
el = get_icount_el(icount, ino, 1);
|
||||
if (!el)
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
|
||||
el->count = count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static errcode_t get_inode_count(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u32 *count)
|
||||
{
|
||||
struct ext2_icount_el *el;
|
||||
#ifdef CONFIG_TDB
|
||||
TDB_DATA key, data;
|
||||
|
||||
if (icount->tdb) {
|
||||
key.dptr = (unsigned char *) &ino;
|
||||
key.dsize = sizeof(ext2_ino_t);
|
||||
|
||||
data = tdb_fetch(icount->tdb, key);
|
||||
if (data.dptr == NULL) {
|
||||
*count = 0;
|
||||
return tdb_error(icount->tdb) + EXT2_ET_TDB_SUCCESS;
|
||||
}
|
||||
|
||||
*count = *((__u32 *) data.dptr);
|
||||
free(data.dptr);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
if (icount->fullmap) {
|
||||
*count = icount->fullmap[ino];
|
||||
return 0;
|
||||
}
|
||||
|
||||
el = get_icount_el(icount, ino, 0);
|
||||
if (!el) {
|
||||
*count = 0;
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
*count = el->count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_icount_validate(ext2_icount_t icount, FILE *out)
|
||||
{
|
||||
errcode_t ret = 0;
|
||||
unsigned int i;
|
||||
const char *bad = "bad icount";
|
||||
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (icount->count > icount->size) {
|
||||
fprintf(out, "%s: count > size\n", bad);
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
}
|
||||
for (i=1; i < icount->count; i++) {
|
||||
if (icount->list[i-1].ino >= icount->list[i].ino) {
|
||||
fprintf(out, "%s: list[%d].ino=%u, list[%d].ino=%u\n",
|
||||
bad, i-1, icount->list[i-1].ino,
|
||||
i, icount->list[i].ino);
|
||||
ret = EXT2_ET_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_icount_fetch(ext2_icount_t icount, ext2_ino_t ino, __u16 *ret)
|
||||
{
|
||||
__u32 val;
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (!ino || (ino > icount->num_inodes))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (!icount->fullmap) {
|
||||
if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
|
||||
*ret = 1;
|
||||
return 0;
|
||||
}
|
||||
if (icount->multiple &&
|
||||
!ext2fs_test_inode_bitmap2(icount->multiple, ino)) {
|
||||
*ret = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
get_inode_count(icount, ino, &val);
|
||||
*ret = icount_16_xlate(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_icount_increment(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u16 *ret)
|
||||
{
|
||||
__u32 curr_value;
|
||||
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (!ino || (ino > icount->num_inodes))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
if (icount->fullmap) {
|
||||
curr_value = icount_16_xlate(icount->fullmap[ino] + 1);
|
||||
icount->fullmap[ino] = curr_value;
|
||||
} else if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
|
||||
/*
|
||||
* If the existing count is 1, then we know there is
|
||||
* no entry in the list.
|
||||
*/
|
||||
if (set_inode_count(icount, ino, 2))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
curr_value = 2;
|
||||
ext2fs_unmark_inode_bitmap2(icount->single, ino);
|
||||
} else if (icount->multiple) {
|
||||
/*
|
||||
* The count is either zero or greater than 1; if the
|
||||
* inode is set in icount->multiple, then there should
|
||||
* be an entry in the list, so we need to fix it.
|
||||
*/
|
||||
if (ext2fs_test_inode_bitmap2(icount->multiple, ino)) {
|
||||
get_inode_count(icount, ino, &curr_value);
|
||||
curr_value++;
|
||||
if (set_inode_count(icount, ino, curr_value))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
} else {
|
||||
/*
|
||||
* The count was zero; mark the single bitmap
|
||||
* and return.
|
||||
*/
|
||||
ext2fs_mark_inode_bitmap2(icount->single, ino);
|
||||
if (ret)
|
||||
*ret = 1;
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* The count is either zero or greater than 1; try to
|
||||
* find an entry in the list to determine which.
|
||||
*/
|
||||
get_inode_count(icount, ino, &curr_value);
|
||||
curr_value++;
|
||||
if (set_inode_count(icount, ino, curr_value))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
}
|
||||
if (icount->multiple)
|
||||
ext2fs_mark_inode_bitmap2(icount->multiple, ino);
|
||||
if (ret)
|
||||
*ret = icount_16_xlate(curr_value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_icount_decrement(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u16 *ret)
|
||||
{
|
||||
__u32 curr_value;
|
||||
|
||||
if (!ino || (ino > icount->num_inodes))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (icount->fullmap) {
|
||||
if (!icount->fullmap[ino])
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
curr_value = --icount->fullmap[ino];
|
||||
if (ret)
|
||||
*ret = icount_16_xlate(curr_value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (ext2fs_test_inode_bitmap2(icount->single, ino)) {
|
||||
ext2fs_unmark_inode_bitmap2(icount->single, ino);
|
||||
if (icount->multiple)
|
||||
ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
|
||||
else {
|
||||
set_inode_count(icount, ino, 0);
|
||||
}
|
||||
if (ret)
|
||||
*ret = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (icount->multiple &&
|
||||
!ext2fs_test_inode_bitmap2(icount->multiple, ino))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
get_inode_count(icount, ino, &curr_value);
|
||||
if (!curr_value)
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
curr_value--;
|
||||
if (set_inode_count(icount, ino, curr_value))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
|
||||
if (curr_value == 1)
|
||||
ext2fs_mark_inode_bitmap2(icount->single, ino);
|
||||
if ((curr_value == 0) && icount->multiple)
|
||||
ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
|
||||
|
||||
if (ret)
|
||||
*ret = icount_16_xlate(curr_value);
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_icount_store(ext2_icount_t icount, ext2_ino_t ino,
|
||||
__u16 count)
|
||||
{
|
||||
if (!ino || (ino > icount->num_inodes))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
EXT2_CHECK_MAGIC(icount, EXT2_ET_MAGIC_ICOUNT);
|
||||
|
||||
if (icount->fullmap)
|
||||
return set_inode_count(icount, ino, count);
|
||||
|
||||
if (count == 1) {
|
||||
ext2fs_mark_inode_bitmap2(icount->single, ino);
|
||||
if (icount->multiple)
|
||||
ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
|
||||
return 0;
|
||||
}
|
||||
if (count == 0) {
|
||||
ext2fs_unmark_inode_bitmap2(icount->single, ino);
|
||||
if (icount->multiple) {
|
||||
/*
|
||||
* If the icount->multiple bitmap is enabled,
|
||||
* we can just clear both bitmaps and we're done
|
||||
*/
|
||||
ext2fs_unmark_inode_bitmap2(icount->multiple, ino);
|
||||
} else
|
||||
set_inode_count(icount, ino, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (set_inode_count(icount, ino, count))
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
ext2fs_unmark_inode_bitmap2(icount->single, ino);
|
||||
if (icount->multiple)
|
||||
ext2fs_mark_inode_bitmap2(icount->multiple, ino);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ext2_ino_t ext2fs_get_icount_size(ext2_icount_t icount)
|
||||
{
|
||||
if (!icount || icount->magic != EXT2_ET_MAGIC_ICOUNT)
|
||||
return 0;
|
||||
|
||||
return icount->size;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
|
||||
ext2_filsys test_fs;
|
||||
ext2_icount_t icount;
|
||||
|
||||
#define EXIT 0x00
|
||||
#define FETCH 0x01
|
||||
#define STORE 0x02
|
||||
#define INCREMENT 0x03
|
||||
#define DECREMENT 0x04
|
||||
|
||||
struct test_program {
|
||||
int cmd;
|
||||
ext2_ino_t ino;
|
||||
__u16 arg;
|
||||
__u16 expected;
|
||||
};
|
||||
|
||||
struct test_program prog[] = {
|
||||
{ STORE, 42, 42, 42 },
|
||||
{ STORE, 1, 1, 1 },
|
||||
{ STORE, 2, 2, 2 },
|
||||
{ STORE, 3, 3, 3 },
|
||||
{ STORE, 10, 1, 1 },
|
||||
{ STORE, 42, 0, 0 },
|
||||
{ INCREMENT, 5, 0, 1 },
|
||||
{ INCREMENT, 5, 0, 2 },
|
||||
{ INCREMENT, 5, 0, 3 },
|
||||
{ INCREMENT, 5, 0, 4 },
|
||||
{ DECREMENT, 5, 0, 3 },
|
||||
{ DECREMENT, 5, 0, 2 },
|
||||
{ DECREMENT, 5, 0, 1 },
|
||||
{ DECREMENT, 5, 0, 0 },
|
||||
{ FETCH, 10, 0, 1 },
|
||||
{ FETCH, 1, 0, 1 },
|
||||
{ FETCH, 2, 0, 2 },
|
||||
{ FETCH, 3, 0, 3 },
|
||||
{ INCREMENT, 1, 0, 2 },
|
||||
{ DECREMENT, 2, 0, 1 },
|
||||
{ DECREMENT, 2, 0, 0 },
|
||||
{ FETCH, 12, 0, 0 },
|
||||
{ EXIT, 0, 0, 0 }
|
||||
};
|
||||
|
||||
struct test_program extended[] = {
|
||||
{ STORE, 1, 1, 1 },
|
||||
{ STORE, 2, 2, 2 },
|
||||
{ STORE, 3, 3, 3 },
|
||||
{ STORE, 4, 4, 4 },
|
||||
{ STORE, 5, 5, 5 },
|
||||
{ STORE, 6, 1, 1 },
|
||||
{ STORE, 7, 2, 2 },
|
||||
{ STORE, 8, 3, 3 },
|
||||
{ STORE, 9, 4, 4 },
|
||||
{ STORE, 10, 5, 5 },
|
||||
{ STORE, 11, 1, 1 },
|
||||
{ STORE, 12, 2, 2 },
|
||||
{ STORE, 13, 3, 3 },
|
||||
{ STORE, 14, 4, 4 },
|
||||
{ STORE, 15, 5, 5 },
|
||||
{ STORE, 16, 1, 1 },
|
||||
{ STORE, 17, 2, 2 },
|
||||
{ STORE, 18, 3, 3 },
|
||||
{ STORE, 19, 4, 4 },
|
||||
{ STORE, 20, 5, 5 },
|
||||
{ STORE, 21, 1, 1 },
|
||||
{ STORE, 22, 2, 2 },
|
||||
{ STORE, 23, 3, 3 },
|
||||
{ STORE, 24, 4, 4 },
|
||||
{ STORE, 25, 5, 5 },
|
||||
{ STORE, 26, 1, 1 },
|
||||
{ STORE, 27, 2, 2 },
|
||||
{ STORE, 28, 3, 3 },
|
||||
{ STORE, 29, 4, 4 },
|
||||
{ STORE, 30, 5, 5 },
|
||||
{ EXIT, 0, 0, 0 }
|
||||
};
|
||||
|
||||
/*
|
||||
* Setup the variables for doing the inode scan test.
|
||||
*/
|
||||
static void setup(void)
|
||||
{
|
||||
errcode_t retval;
|
||||
struct ext2_super_block param;
|
||||
|
||||
initialize_ext2_error_table();
|
||||
|
||||
memset(¶m, 0, sizeof(param));
|
||||
ext2fs_blocks_count_set(¶m, 12000);
|
||||
|
||||
retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, ¶m,
|
||||
test_io_manager, &test_fs);
|
||||
if (retval) {
|
||||
com_err("setup", retval,
|
||||
"while initializing filesystem");
|
||||
exit(1);
|
||||
}
|
||||
retval = ext2fs_allocate_tables(test_fs);
|
||||
if (retval) {
|
||||
com_err("setup", retval,
|
||||
"while allocating tables for test filesystem");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
int run_test(int flags, int size, char *dir, struct test_program *prog)
|
||||
{
|
||||
errcode_t retval;
|
||||
ext2_icount_t icount;
|
||||
struct test_program *pc;
|
||||
__u16 result;
|
||||
int problem = 0;
|
||||
|
||||
if (dir) {
|
||||
#ifdef CONFIG_TDB
|
||||
retval = ext2fs_create_icount_tdb(test_fs, dir,
|
||||
flags, &icount);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while creating icount using tdb");
|
||||
exit(1);
|
||||
}
|
||||
#else
|
||||
printf("Skipped\n");
|
||||
return 0;
|
||||
#endif
|
||||
} else {
|
||||
retval = ext2fs_create_icount2(test_fs, flags, size, 0,
|
||||
&icount);
|
||||
if (retval) {
|
||||
com_err("run_test", retval, "while creating icount");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
for (pc = prog; pc->cmd != EXIT; pc++) {
|
||||
switch (pc->cmd) {
|
||||
case FETCH:
|
||||
printf("icount_fetch(%u) = ", pc->ino);
|
||||
break;
|
||||
case STORE:
|
||||
retval = ext2fs_icount_store(icount, pc->ino, pc->arg);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while calling icount_store");
|
||||
exit(1);
|
||||
}
|
||||
printf("icount_store(%u, %u) = ", pc->ino, pc->arg);
|
||||
break;
|
||||
case INCREMENT:
|
||||
retval = ext2fs_icount_increment(icount, pc->ino, 0);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while calling icount_increment");
|
||||
exit(1);
|
||||
}
|
||||
printf("icount_increment(%u) = ", pc->ino);
|
||||
break;
|
||||
case DECREMENT:
|
||||
retval = ext2fs_icount_decrement(icount, pc->ino, 0);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while calling icount_decrement");
|
||||
exit(1);
|
||||
}
|
||||
printf("icount_decrement(%u) = ", pc->ino);
|
||||
break;
|
||||
}
|
||||
retval = ext2fs_icount_fetch(icount, pc->ino, &result);
|
||||
if (retval) {
|
||||
com_err("run_test", retval,
|
||||
"while calling icount_fetch");
|
||||
exit(1);
|
||||
}
|
||||
printf("%u (%s)\n", result, (result == pc->expected) ?
|
||||
"OK" : "NOT OK");
|
||||
if (result != pc->expected)
|
||||
problem++;
|
||||
}
|
||||
printf("icount size is %u\n", ext2fs_get_icount_size(icount));
|
||||
retval = ext2fs_icount_validate(icount, stdout);
|
||||
if (retval) {
|
||||
com_err("run_test", retval, "while calling icount_validate");
|
||||
exit(1);
|
||||
}
|
||||
ext2fs_free_icount(icount);
|
||||
return problem;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int failed = 0;
|
||||
|
||||
setup();
|
||||
printf("Standard icount run:\n");
|
||||
failed += run_test(0, 0, 0, prog);
|
||||
printf("\nMultiple bitmap test:\n");
|
||||
failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, 0, prog);
|
||||
printf("\nResizing icount:\n");
|
||||
failed += run_test(0, 3, 0, extended);
|
||||
printf("\nStandard icount run with tdb:\n");
|
||||
failed += run_test(0, 0, ".", prog);
|
||||
printf("\nMultiple bitmap test with tdb:\n");
|
||||
failed += run_test(EXT2_ICOUNT_OPT_INCREMENT, 0, ".", prog);
|
||||
if (failed)
|
||||
printf("FAILED!\n");
|
||||
return failed;
|
||||
}
|
||||
#endif
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/icount.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/icount.o
Executable file
Binary file not shown.
470
jni/e2fsprogs/lib/ext2fs/imager.c
Executable file
470
jni/e2fsprogs/lib/ext2fs/imager.c
Executable file
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
* image.c --- writes out the critical parts of the filesystem as a
|
||||
* flat file.
|
||||
*
|
||||
* Copyright (C) 2000 Theodore Ts'o.
|
||||
*
|
||||
* Note: this uses the POSIX IO interfaces, unlike most of the other
|
||||
* functions in this library. So sue me.
|
||||
*
|
||||
* %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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#if HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
#ifndef HAVE_TYPE_SSIZE_T
|
||||
typedef int ssize_t;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This function returns 1 if the specified block is all zeros
|
||||
*/
|
||||
static int check_zero_block(char *buf, int blocksize)
|
||||
{
|
||||
char *cp = buf;
|
||||
int left = blocksize;
|
||||
|
||||
while (left > 0) {
|
||||
if (*cp++)
|
||||
return 0;
|
||||
left--;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the inode table out as a single block.
|
||||
*/
|
||||
#define BUF_BLOCKS 32
|
||||
|
||||
errcode_t ext2fs_image_inode_write(ext2_filsys fs, int fd, int flags)
|
||||
{
|
||||
dgrp_t group;
|
||||
ssize_t left, c, d;
|
||||
char *buf, *cp;
|
||||
blk64_t blk;
|
||||
ssize_t actual;
|
||||
errcode_t retval;
|
||||
ext2_loff_t r;
|
||||
|
||||
buf = malloc(fs->blocksize * BUF_BLOCKS);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
for (group = 0; group < fs->group_desc_count; group++) {
|
||||
blk = ext2fs_inode_table_loc(fs, group);
|
||||
if (!blk) {
|
||||
retval = EXT2_ET_MISSING_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
left = fs->inode_blocks_per_group;
|
||||
if ((blk < fs->super->s_first_data_block) ||
|
||||
(blk + left - 1 >= ext2fs_blocks_count(fs->super))) {
|
||||
retval = EXT2_ET_GDESC_BAD_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
while (left) {
|
||||
c = BUF_BLOCKS;
|
||||
if (c > left)
|
||||
c = left;
|
||||
retval = io_channel_read_blk64(fs->io, blk, c, buf);
|
||||
if (retval)
|
||||
goto errout;
|
||||
cp = buf;
|
||||
while (c) {
|
||||
if (!(flags & IMAGER_FLAG_SPARSEWRITE)) {
|
||||
d = c;
|
||||
goto skip_sparse;
|
||||
}
|
||||
/* Skip zero blocks */
|
||||
if (check_zero_block(cp, fs->blocksize)) {
|
||||
c--;
|
||||
blk++;
|
||||
left--;
|
||||
cp += fs->blocksize;
|
||||
r = ext2fs_llseek(fd, fs->blocksize,
|
||||
SEEK_CUR);
|
||||
if (r < 0) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
/* Find non-zero blocks */
|
||||
for (d = 1; d < c; d++) {
|
||||
if (check_zero_block(cp +
|
||||
d * fs->blocksize,
|
||||
fs->blocksize))
|
||||
break;
|
||||
}
|
||||
skip_sparse:
|
||||
actual = write(fd, cp, d * fs->blocksize);
|
||||
if (actual == -1) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
if (actual != d * fs->blocksize) {
|
||||
retval = EXT2_ET_SHORT_WRITE;
|
||||
goto errout;
|
||||
}
|
||||
blk += d;
|
||||
left -= d;
|
||||
cp += d * fs->blocksize;
|
||||
c -= d;
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
|
||||
errout:
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read in the inode table and stuff it into place
|
||||
*/
|
||||
errcode_t ext2fs_image_inode_read(ext2_filsys fs, int fd,
|
||||
int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
dgrp_t group;
|
||||
ssize_t c, left;
|
||||
char *buf;
|
||||
blk64_t blk;
|
||||
ssize_t actual;
|
||||
errcode_t retval;
|
||||
|
||||
buf = malloc(fs->blocksize * BUF_BLOCKS);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
for (group = 0; group < fs->group_desc_count; group++) {
|
||||
blk = ext2fs_inode_table_loc(fs, group);
|
||||
if (!blk) {
|
||||
retval = EXT2_ET_MISSING_INODE_TABLE;
|
||||
goto errout;
|
||||
}
|
||||
left = fs->inode_blocks_per_group;
|
||||
while (left) {
|
||||
c = BUF_BLOCKS;
|
||||
if (c > left)
|
||||
c = left;
|
||||
actual = read(fd, buf, fs->blocksize * c);
|
||||
if (actual == -1) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
if (actual != fs->blocksize * c) {
|
||||
retval = EXT2_ET_SHORT_READ;
|
||||
goto errout;
|
||||
}
|
||||
retval = io_channel_write_blk64(fs->io, blk, c, buf);
|
||||
if (retval)
|
||||
goto errout;
|
||||
|
||||
blk += c;
|
||||
left -= c;
|
||||
}
|
||||
}
|
||||
retval = ext2fs_flush_icache(fs);
|
||||
|
||||
errout:
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out superblock and group descriptors
|
||||
*/
|
||||
errcode_t ext2fs_image_super_write(ext2_filsys fs, int fd,
|
||||
int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
char *buf, *cp;
|
||||
ssize_t actual;
|
||||
errcode_t retval;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
unsigned int groups_per_block;
|
||||
struct ext2_group_desc *gdp;
|
||||
int j;
|
||||
#endif
|
||||
|
||||
if (fs->group_desc == NULL)
|
||||
return EXT2_ET_NO_GDESC;
|
||||
|
||||
buf = malloc(fs->blocksize);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
/*
|
||||
* Write out the superblock
|
||||
*/
|
||||
memset(buf, 0, fs->blocksize);
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
/*
|
||||
* We're writing out superblock so let's convert
|
||||
* it to little endian and then back if needed
|
||||
*/
|
||||
ext2fs_swap_super(fs->super);
|
||||
memcpy(buf, fs->super, SUPERBLOCK_SIZE);
|
||||
ext2fs_swap_super(fs->super);
|
||||
#else
|
||||
memcpy(buf, fs->super, SUPERBLOCK_SIZE);
|
||||
#endif
|
||||
actual = write(fd, buf, fs->blocksize);
|
||||
if (actual == -1) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
if (actual != (ssize_t) fs->blocksize) {
|
||||
retval = EXT2_ET_SHORT_WRITE;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now write out the block group descriptors
|
||||
*/
|
||||
|
||||
cp = (char *) fs->group_desc;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
/*
|
||||
* Convert group descriptors to little endian and back
|
||||
* if needed
|
||||
*/
|
||||
groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
|
||||
gdp = ext2fs_group_desc(fs, fs->group_desc, j);
|
||||
if (gdp)
|
||||
ext2fs_swap_group_desc2(fs, gdp);
|
||||
}
|
||||
#endif
|
||||
|
||||
actual = write(fd, cp, (ssize_t)fs->blocksize * fs->desc_blocks);
|
||||
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
groups_per_block = EXT2_DESC_PER_BLOCK(fs->super);
|
||||
for (j=0; j < groups_per_block*fs->desc_blocks; j++) {
|
||||
gdp = ext2fs_group_desc(fs, fs->group_desc, j);
|
||||
if (gdp)
|
||||
ext2fs_swap_group_desc2(fs, gdp);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (actual == -1) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
if (actual != (ssize_t)(fs->blocksize * fs->desc_blocks)) {
|
||||
retval = EXT2_ET_SHORT_WRITE;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
retval = 0;
|
||||
|
||||
errout:
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read the superblock and group descriptors and overwrite them.
|
||||
*/
|
||||
errcode_t ext2fs_image_super_read(ext2_filsys fs, int fd,
|
||||
int flags EXT2FS_ATTR((unused)))
|
||||
{
|
||||
char *buf;
|
||||
ssize_t actual, size;
|
||||
errcode_t retval;
|
||||
|
||||
size = (ssize_t)fs->blocksize * (fs->group_desc_count + 1);
|
||||
buf = malloc(size);
|
||||
if (!buf)
|
||||
return ENOMEM;
|
||||
|
||||
/*
|
||||
* Read it all in.
|
||||
*/
|
||||
actual = read(fd, buf, size);
|
||||
if (actual == -1) {
|
||||
retval = errno;
|
||||
goto errout;
|
||||
}
|
||||
if (actual != size) {
|
||||
retval = EXT2_ET_SHORT_READ;
|
||||
goto errout;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now copy in the superblock and group descriptors
|
||||
*/
|
||||
memcpy(fs->super, buf, SUPERBLOCK_SIZE);
|
||||
|
||||
memcpy(fs->group_desc, buf + fs->blocksize,
|
||||
(ssize_t)fs->blocksize * fs->group_desc_count);
|
||||
|
||||
retval = 0;
|
||||
|
||||
errout:
|
||||
free(buf);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
* Write the block/inode bitmaps.
|
||||
*/
|
||||
errcode_t ext2fs_image_bitmap_write(ext2_filsys fs, int fd, int flags)
|
||||
{
|
||||
ext2fs_generic_bitmap bmap;
|
||||
errcode_t retval;
|
||||
ssize_t actual;
|
||||
size_t c;
|
||||
__u64 itr, cnt, size, total_size;
|
||||
char buf[1024];
|
||||
|
||||
if (flags & IMAGER_FLAG_INODEMAP) {
|
||||
if (!fs->inode_map) {
|
||||
retval = ext2fs_read_inode_bitmap(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
bmap = fs->inode_map;
|
||||
itr = 1;
|
||||
cnt = (__u64)EXT2_INODES_PER_GROUP(fs->super) *
|
||||
fs->group_desc_count;
|
||||
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
|
||||
} else {
|
||||
if (!fs->block_map) {
|
||||
retval = ext2fs_read_block_bitmap(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
bmap = fs->block_map;
|
||||
itr = fs->super->s_first_data_block;
|
||||
cnt = EXT2_GROUPS_TO_CLUSTERS(fs->super, fs->group_desc_count);
|
||||
size = EXT2_CLUSTERS_PER_GROUP(fs->super) / 8;
|
||||
}
|
||||
total_size = size * fs->group_desc_count;
|
||||
|
||||
while (cnt > 0) {
|
||||
size = sizeof(buf);
|
||||
if (size > (cnt >> 3))
|
||||
size = (cnt >> 3);
|
||||
if (size == 0)
|
||||
break;
|
||||
|
||||
retval = ext2fs_get_generic_bmap_range(bmap, itr,
|
||||
size << 3, buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
actual = write(fd, buf, size);
|
||||
if (actual == -1)
|
||||
return errno;
|
||||
if (actual != (int) size)
|
||||
return EXT2_ET_SHORT_READ;
|
||||
|
||||
itr += size << 3;
|
||||
cnt -= size << 3;
|
||||
}
|
||||
|
||||
size = total_size % fs->blocksize;
|
||||
memset(buf, 0, sizeof(buf));
|
||||
if (size) {
|
||||
size = fs->blocksize - size;
|
||||
while (size) {
|
||||
c = size;
|
||||
if (c > (int) sizeof(buf))
|
||||
c = sizeof(buf);
|
||||
actual = write(fd, buf, c);
|
||||
if (actual < 0)
|
||||
return errno;
|
||||
if ((size_t) actual != c)
|
||||
return EXT2_ET_SHORT_WRITE;
|
||||
size -= c;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read the block/inode bitmaps.
|
||||
*/
|
||||
errcode_t ext2fs_image_bitmap_read(ext2_filsys fs, int fd, int flags)
|
||||
{
|
||||
ext2fs_generic_bitmap bmap;
|
||||
errcode_t retval;
|
||||
__u64 itr, cnt;
|
||||
char buf[1024];
|
||||
unsigned int size;
|
||||
ssize_t actual;
|
||||
|
||||
if (flags & IMAGER_FLAG_INODEMAP) {
|
||||
if (!fs->inode_map) {
|
||||
retval = ext2fs_read_inode_bitmap(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
bmap = fs->inode_map;
|
||||
itr = 1;
|
||||
cnt = (__u64)EXT2_INODES_PER_GROUP(fs->super) *
|
||||
fs->group_desc_count;
|
||||
size = (EXT2_INODES_PER_GROUP(fs->super) / 8);
|
||||
} else {
|
||||
if (!fs->block_map) {
|
||||
retval = ext2fs_read_block_bitmap(fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
bmap = fs->block_map;
|
||||
itr = fs->super->s_first_data_block;
|
||||
cnt = EXT2_GROUPS_TO_BLOCKS(fs->super, fs->group_desc_count);
|
||||
size = EXT2_BLOCKS_PER_GROUP(fs->super) / 8;
|
||||
}
|
||||
|
||||
while (cnt > 0) {
|
||||
size = sizeof(buf);
|
||||
if (size > (cnt >> 3))
|
||||
size = (cnt >> 3);
|
||||
if (size == 0)
|
||||
break;
|
||||
|
||||
actual = read(fd, buf, size);
|
||||
if (actual == -1)
|
||||
return errno;
|
||||
if (actual != (int) size)
|
||||
return EXT2_ET_SHORT_READ;
|
||||
|
||||
retval = ext2fs_set_generic_bmap_range(bmap, itr,
|
||||
size << 3, buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
itr += size << 3;
|
||||
cnt -= size << 3;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/imager.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/imager.o
Executable file
Binary file not shown.
67
jni/e2fsprogs/lib/ext2fs/ind_block.c
Executable file
67
jni/e2fsprogs/lib/ext2fs/ind_block.c
Executable file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* ind_block.c --- indirect block I/O routines
|
||||
*
|
||||
* Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
|
||||
* 2001, 2002, 2003, 2004, 2005 by 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
errcode_t ext2fs_read_ind_block(ext2_filsys fs, blk_t blk, void *buf)
|
||||
{
|
||||
errcode_t retval;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
blk_t *block_nr;
|
||||
int i;
|
||||
int limit = fs->blocksize >> 2;
|
||||
#endif
|
||||
|
||||
if ((fs->flags & EXT2_FLAG_IMAGE_FILE) &&
|
||||
(fs->io != fs->image_io))
|
||||
memset(buf, 0, fs->blocksize);
|
||||
else {
|
||||
retval = io_channel_read_blk(fs->io, blk, 1, buf);
|
||||
if (retval)
|
||||
return retval;
|
||||
}
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
block_nr = (blk_t *) buf;
|
||||
for (i = 0; i < limit; i++, block_nr++)
|
||||
*block_nr = ext2fs_swab32(*block_nr);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf)
|
||||
{
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
blk_t *block_nr;
|
||||
int i;
|
||||
int limit = fs->blocksize >> 2;
|
||||
#endif
|
||||
|
||||
if (fs->flags & EXT2_FLAG_IMAGE_FILE)
|
||||
return 0;
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
block_nr = (blk_t *) buf;
|
||||
for (i = 0; i < limit; i++, block_nr++)
|
||||
*block_nr = ext2fs_swab32(*block_nr);
|
||||
#endif
|
||||
return io_channel_write_blk(fs->io, blk, 1, buf);
|
||||
}
|
||||
|
||||
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/ind_block.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/ind_block.o
Executable file
Binary file not shown.
671
jni/e2fsprogs/lib/ext2fs/initialize.c
Executable file
671
jni/e2fsprogs/lib/ext2fs/initialize.c
Executable file
@@ -0,0 +1,671 @@
|
||||
/*
|
||||
* initialize.c --- initialize a filesystem handle given superblock
|
||||
* parameters. Used by mke2fs when initializing a filesystem.
|
||||
*
|
||||
* Copyright (C) 1994, 1995, 1996 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>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#include "ext2fs.h"
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) && defined(EXT2_OS_LINUX)
|
||||
#define CREATOR_OS EXT2_OS_LINUX
|
||||
#else
|
||||
#if defined(__GNU__) && defined(EXT2_OS_HURD)
|
||||
#define CREATOR_OS EXT2_OS_HURD
|
||||
#else
|
||||
#if defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD)
|
||||
#define CREATOR_OS EXT2_OS_FREEBSD
|
||||
#else
|
||||
#if defined(LITES) && defined(EXT2_OS_LITES)
|
||||
#define CREATOR_OS EXT2_OS_LITES
|
||||
#else
|
||||
#define CREATOR_OS EXT2_OS_LINUX /* by default */
|
||||
#endif /* defined(LITES) && defined(EXT2_OS_LITES) */
|
||||
#endif /* defined(__FreeBSD__) && defined(EXT2_OS_FREEBSD) */
|
||||
#endif /* defined(__GNU__) && defined(EXT2_OS_HURD) */
|
||||
#endif /* defined(__linux__) && defined(EXT2_OS_LINUX) */
|
||||
|
||||
/*
|
||||
* Calculate the number of GDT blocks to reserve for online filesystem growth.
|
||||
* The absolute maximum number of GDT blocks we can reserve is determined by
|
||||
* the number of block pointers that can fit into a single block.
|
||||
*/
|
||||
static unsigned int calc_reserved_gdt_blocks(ext2_filsys fs)
|
||||
{
|
||||
struct ext2_super_block *sb = fs->super;
|
||||
unsigned long bpg = sb->s_blocks_per_group;
|
||||
unsigned int gdpb = EXT2_DESC_PER_BLOCK(sb);
|
||||
unsigned long max_blocks = 0xffffffff;
|
||||
unsigned long rsv_groups;
|
||||
unsigned int rsv_gdb;
|
||||
|
||||
/* We set it at 1024x the current filesystem size, or
|
||||
* the upper block count limit (2^32), whichever is lower.
|
||||
*/
|
||||
if (ext2fs_blocks_count(sb) < max_blocks / 1024)
|
||||
max_blocks = ext2fs_blocks_count(sb) * 1024;
|
||||
/*
|
||||
* ext2fs_div64_ceil() is unnecessary because max_blocks is
|
||||
* max _GDT_ blocks, which is limited to 32 bits.
|
||||
*/
|
||||
rsv_groups = ext2fs_div_ceil(max_blocks - sb->s_first_data_block, bpg);
|
||||
rsv_gdb = ext2fs_div_ceil(rsv_groups, gdpb) - fs->desc_blocks;
|
||||
if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb))
|
||||
rsv_gdb = EXT2_ADDR_PER_BLOCK(sb);
|
||||
#ifdef RES_GDT_DEBUG
|
||||
printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %u\n",
|
||||
max_blocks, rsv_groups, rsv_gdb);
|
||||
#endif
|
||||
|
||||
return rsv_gdb;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_initialize(const char *name, int flags,
|
||||
struct ext2_super_block *param,
|
||||
io_manager manager, ext2_filsys *ret_fs)
|
||||
{
|
||||
ext2_filsys fs;
|
||||
errcode_t retval;
|
||||
struct ext2_super_block *super;
|
||||
unsigned int rem;
|
||||
unsigned int overhead = 0;
|
||||
unsigned int ipg;
|
||||
dgrp_t i;
|
||||
blk64_t free_blocks;
|
||||
blk_t numblocks;
|
||||
int rsv_gdt;
|
||||
int csum_flag;
|
||||
int bigalloc_flag;
|
||||
int io_flags;
|
||||
int has_bg;
|
||||
unsigned reserved_inos;
|
||||
char *buf = 0;
|
||||
char c;
|
||||
double reserved_ratio;
|
||||
char *time_env;
|
||||
|
||||
if (!param || !ext2fs_blocks_count(param))
|
||||
return EXT2_ET_INVALID_ARGUMENT;
|
||||
|
||||
retval = ext2fs_get_mem(sizeof(struct struct_ext2_filsys), &fs);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
memset(fs, 0, sizeof(struct struct_ext2_filsys));
|
||||
fs->magic = EXT2_ET_MAGIC_EXT2FS_FILSYS;
|
||||
fs->flags = flags | EXT2_FLAG_RW;
|
||||
fs->umask = 022;
|
||||
fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE;
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
fs->flags |= EXT2_FLAG_SWAP_BYTES;
|
||||
#endif
|
||||
|
||||
time_env = getenv("E2FSPROGS_FAKE_TIME");
|
||||
if (time_env)
|
||||
fs->now = strtoul(time_env, NULL, 0);
|
||||
|
||||
io_flags = IO_FLAG_RW;
|
||||
if (flags & EXT2_FLAG_EXCLUSIVE)
|
||||
io_flags |= IO_FLAG_EXCLUSIVE;
|
||||
if (flags & EXT2_FLAG_DIRECT_IO)
|
||||
io_flags |= IO_FLAG_DIRECT_IO;
|
||||
io_flags |= O_BINARY;
|
||||
retval = manager->open(name, io_flags, &fs->io);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
fs->image_io = fs->io;
|
||||
fs->io->app_data = fs;
|
||||
retval = ext2fs_get_mem(strlen(name)+1, &fs->device_name);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
strcpy(fs->device_name, name);
|
||||
retval = ext2fs_get_mem(SUPERBLOCK_SIZE, &super);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
fs->super = super;
|
||||
|
||||
memset(super, 0, SUPERBLOCK_SIZE);
|
||||
|
||||
#define set_field(field, default) (super->field = param->field ? \
|
||||
param->field : (default))
|
||||
#define assign_field(field) (super->field = param->field)
|
||||
|
||||
super->s_magic = EXT2_SUPER_MAGIC;
|
||||
super->s_state = EXT2_VALID_FS;
|
||||
|
||||
bigalloc_flag = ext2fs_has_feature_bigalloc(param);
|
||||
|
||||
assign_field(s_log_block_size);
|
||||
|
||||
if (bigalloc_flag) {
|
||||
set_field(s_log_cluster_size, super->s_log_block_size+4);
|
||||
if (super->s_log_block_size > super->s_log_cluster_size) {
|
||||
retval = EXT2_ET_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
} else
|
||||
super->s_log_cluster_size = super->s_log_block_size;
|
||||
|
||||
set_field(s_first_data_block, super->s_log_cluster_size ? 0 : 1);
|
||||
set_field(s_max_mnt_count, 0);
|
||||
set_field(s_errors, EXT2_ERRORS_DEFAULT);
|
||||
set_field(s_feature_compat, 0);
|
||||
set_field(s_feature_incompat, 0);
|
||||
set_field(s_feature_ro_compat, 0);
|
||||
set_field(s_default_mount_opts, 0);
|
||||
set_field(s_first_meta_bg, 0);
|
||||
set_field(s_raid_stride, 0); /* default stride size: 0 */
|
||||
set_field(s_raid_stripe_width, 0); /* default stripe width: 0 */
|
||||
set_field(s_log_groups_per_flex, 0);
|
||||
set_field(s_flags, 0);
|
||||
assign_field(s_backup_bgs[0]);
|
||||
assign_field(s_backup_bgs[1]);
|
||||
|
||||
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;
|
||||
}
|
||||
if (super->s_feature_ro_compat & ~EXT2_LIB_FEATURE_RO_COMPAT_SUPP) {
|
||||
retval = EXT2_ET_RO_UNSUPP_FEATURE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
set_field(s_rev_level, EXT2_GOOD_OLD_REV);
|
||||
if (super->s_rev_level >= EXT2_DYNAMIC_REV) {
|
||||
set_field(s_first_ino, EXT2_GOOD_OLD_FIRST_INO);
|
||||
set_field(s_inode_size, EXT2_GOOD_OLD_INODE_SIZE);
|
||||
if (super->s_inode_size >= sizeof(struct ext2_inode_large)) {
|
||||
int extra_isize = sizeof(struct ext2_inode_large) -
|
||||
EXT2_GOOD_OLD_INODE_SIZE;
|
||||
set_field(s_min_extra_isize, extra_isize);
|
||||
set_field(s_want_extra_isize, extra_isize);
|
||||
}
|
||||
} else {
|
||||
super->s_first_ino = EXT2_GOOD_OLD_FIRST_INO;
|
||||
super->s_inode_size = EXT2_GOOD_OLD_INODE_SIZE;
|
||||
}
|
||||
|
||||
set_field(s_checkinterval, 0);
|
||||
super->s_mkfs_time = super->s_lastcheck = fs->now ? fs->now : time(NULL);
|
||||
|
||||
super->s_creator_os = CREATOR_OS;
|
||||
|
||||
fs->fragsize = fs->blocksize = EXT2_BLOCK_SIZE(super);
|
||||
fs->cluster_ratio_bits = super->s_log_cluster_size -
|
||||
super->s_log_block_size;
|
||||
|
||||
if (bigalloc_flag) {
|
||||
unsigned long long bpg;
|
||||
|
||||
if (param->s_blocks_per_group &&
|
||||
param->s_clusters_per_group &&
|
||||
((param->s_clusters_per_group * EXT2FS_CLUSTER_RATIO(fs)) !=
|
||||
param->s_blocks_per_group)) {
|
||||
retval = EXT2_ET_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
if (param->s_clusters_per_group)
|
||||
assign_field(s_clusters_per_group);
|
||||
else if (param->s_blocks_per_group)
|
||||
super->s_clusters_per_group =
|
||||
param->s_blocks_per_group /
|
||||
EXT2FS_CLUSTER_RATIO(fs);
|
||||
else if (super->s_log_cluster_size + 15 < 32)
|
||||
super->s_clusters_per_group = fs->blocksize * 8;
|
||||
else
|
||||
super->s_clusters_per_group = (fs->blocksize - 1) * 8;
|
||||
if (super->s_clusters_per_group > EXT2_MAX_CLUSTERS_PER_GROUP(super))
|
||||
super->s_clusters_per_group = EXT2_MAX_CLUSTERS_PER_GROUP(super);
|
||||
bpg = EXT2FS_C2B(fs,
|
||||
(unsigned long long) super->s_clusters_per_group);
|
||||
if (bpg >= (((unsigned long long) 1) << 32)) {
|
||||
retval = EXT2_ET_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
super->s_blocks_per_group = bpg;
|
||||
} else {
|
||||
set_field(s_blocks_per_group, fs->blocksize * 8);
|
||||
if (super->s_blocks_per_group > EXT2_MAX_BLOCKS_PER_GROUP(super))
|
||||
super->s_blocks_per_group = EXT2_MAX_BLOCKS_PER_GROUP(super);
|
||||
super->s_clusters_per_group = super->s_blocks_per_group;
|
||||
}
|
||||
|
||||
ext2fs_blocks_count_set(super, ext2fs_blocks_count(param) &
|
||||
~((blk64_t) EXT2FS_CLUSTER_MASK(fs)));
|
||||
ext2fs_r_blocks_count_set(super, ext2fs_r_blocks_count(param));
|
||||
if (ext2fs_r_blocks_count(super) >= ext2fs_blocks_count(param)) {
|
||||
retval = EXT2_ET_INVALID_ARGUMENT;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
set_field(s_mmp_update_interval, 0);
|
||||
|
||||
/*
|
||||
* If we're creating an external journal device, we don't need
|
||||
* to bother with the rest.
|
||||
*/
|
||||
if (ext2fs_has_feature_journal_dev(super)) {
|
||||
fs->group_desc_count = 0;
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
*ret_fs = fs;
|
||||
return 0;
|
||||
}
|
||||
|
||||
retry:
|
||||
fs->group_desc_count = (dgrp_t) ext2fs_div64_ceil(
|
||||
ext2fs_blocks_count(super) - super->s_first_data_block,
|
||||
EXT2_BLOCKS_PER_GROUP(super));
|
||||
if (fs->group_desc_count == 0) {
|
||||
retval = EXT2_ET_TOOSMALL;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
set_field(s_desc_size,
|
||||
ext2fs_has_feature_64bit(super) ?
|
||||
EXT2_MIN_DESC_SIZE_64BIT : 0);
|
||||
|
||||
fs->desc_blocks = ext2fs_div_ceil(fs->group_desc_count,
|
||||
EXT2_DESC_PER_BLOCK(super));
|
||||
|
||||
i = fs->blocksize >= 4096 ? 1 : 4096 / fs->blocksize;
|
||||
|
||||
if (ext2fs_has_feature_64bit(super) &&
|
||||
(ext2fs_blocks_count(super) / i) >= (1ULL << 32))
|
||||
set_field(s_inodes_count, ~0U);
|
||||
else
|
||||
set_field(s_inodes_count, ext2fs_blocks_count(super) / i);
|
||||
|
||||
/*
|
||||
* Make sure we have at least EXT2_FIRST_INO + 1 inodes, so
|
||||
* that we have enough inodes for the filesystem(!)
|
||||
*/
|
||||
if (super->s_inodes_count < EXT2_FIRST_INODE(super)+1)
|
||||
super->s_inodes_count = EXT2_FIRST_INODE(super)+1;
|
||||
|
||||
/*
|
||||
* There should be at least as many inodes as the user
|
||||
* requested. Figure out how many inodes per group that
|
||||
* should be. But make sure that we don't allocate more than
|
||||
* one bitmap's worth of inodes each group.
|
||||
*/
|
||||
ipg = ext2fs_div_ceil(super->s_inodes_count, fs->group_desc_count);
|
||||
if (ipg > fs->blocksize * 8) {
|
||||
if (!bigalloc_flag && super->s_blocks_per_group >= 256) {
|
||||
/* Try again with slightly different parameters */
|
||||
super->s_blocks_per_group -= 8;
|
||||
ext2fs_blocks_count_set(super,
|
||||
ext2fs_blocks_count(param));
|
||||
super->s_clusters_per_group = super->s_blocks_per_group;
|
||||
goto retry;
|
||||
} else {
|
||||
retval = EXT2_ET_TOO_MANY_INODES;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
if (ipg > (unsigned) EXT2_MAX_INODES_PER_GROUP(super))
|
||||
ipg = EXT2_MAX_INODES_PER_GROUP(super);
|
||||
|
||||
ipg_retry:
|
||||
super->s_inodes_per_group = ipg;
|
||||
|
||||
/*
|
||||
* Make sure the number of inodes per group completely fills
|
||||
* the inode table blocks in the descriptor. If not, add some
|
||||
* additional inodes/group. Waste not, want not...
|
||||
*/
|
||||
fs->inode_blocks_per_group = (((super->s_inodes_per_group *
|
||||
EXT2_INODE_SIZE(super)) +
|
||||
EXT2_BLOCK_SIZE(super) - 1) /
|
||||
EXT2_BLOCK_SIZE(super));
|
||||
super->s_inodes_per_group = ((fs->inode_blocks_per_group *
|
||||
EXT2_BLOCK_SIZE(super)) /
|
||||
EXT2_INODE_SIZE(super));
|
||||
/*
|
||||
* Finally, make sure the number of inodes per group is a
|
||||
* multiple of 8. This is needed to simplify the bitmap
|
||||
* splicing code.
|
||||
*/
|
||||
if (super->s_inodes_per_group < 8)
|
||||
super->s_inodes_per_group = 8;
|
||||
super->s_inodes_per_group &= ~7;
|
||||
fs->inode_blocks_per_group = (((super->s_inodes_per_group *
|
||||
EXT2_INODE_SIZE(super)) +
|
||||
EXT2_BLOCK_SIZE(super) - 1) /
|
||||
EXT2_BLOCK_SIZE(super));
|
||||
|
||||
/*
|
||||
* adjust inode count to reflect the adjusted inodes_per_group
|
||||
*/
|
||||
if ((__u64)super->s_inodes_per_group * fs->group_desc_count > ~0U) {
|
||||
ipg--;
|
||||
goto ipg_retry;
|
||||
}
|
||||
super->s_inodes_count = super->s_inodes_per_group *
|
||||
fs->group_desc_count;
|
||||
super->s_free_inodes_count = super->s_inodes_count;
|
||||
|
||||
/*
|
||||
* check the number of reserved group descriptor table blocks
|
||||
*/
|
||||
if (ext2fs_has_feature_resize_inode(super))
|
||||
rsv_gdt = calc_reserved_gdt_blocks(fs);
|
||||
else
|
||||
rsv_gdt = 0;
|
||||
set_field(s_reserved_gdt_blocks, rsv_gdt);
|
||||
if (super->s_reserved_gdt_blocks > EXT2_ADDR_PER_BLOCK(super)) {
|
||||
retval = EXT2_ET_RES_GDT_BLOCKS;
|
||||
goto cleanup;
|
||||
}
|
||||
/* Enable meta_bg if we'd lose more than 3/4 of a BG to GDT blocks. */
|
||||
if (super->s_reserved_gdt_blocks + fs->desc_blocks >
|
||||
super->s_blocks_per_group * 3 / 4) {
|
||||
ext2fs_set_feature_meta_bg(fs->super);
|
||||
ext2fs_clear_feature_resize_inode(fs->super);
|
||||
set_field(s_reserved_gdt_blocks, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate the maximum number of bookkeeping blocks per
|
||||
* group. It includes the superblock, the block group
|
||||
* descriptors, the block bitmap, the inode bitmap, the inode
|
||||
* table, and the reserved gdt blocks.
|
||||
*/
|
||||
overhead = (int) (3 + fs->inode_blocks_per_group +
|
||||
super->s_reserved_gdt_blocks);
|
||||
|
||||
if (ext2fs_has_feature_meta_bg(fs->super))
|
||||
overhead++;
|
||||
else
|
||||
overhead += fs->desc_blocks;
|
||||
|
||||
/* This can only happen if the user requested too many inodes */
|
||||
if (overhead > super->s_blocks_per_group) {
|
||||
retval = EXT2_ET_TOO_MANY_INODES;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/*
|
||||
* See if the last group is big enough to support the
|
||||
* necessary data structures. If not, we need to get rid of
|
||||
* it. We need to recalculate the overhead for the last block
|
||||
* group, since it might or might not have a superblock
|
||||
* backup.
|
||||
*/
|
||||
overhead = (int) (2 + fs->inode_blocks_per_group);
|
||||
has_bg = 0;
|
||||
if (ext2fs_has_feature_sparse_super2(super)) {
|
||||
/*
|
||||
* We have to do this manually since
|
||||
* super->s_backup_bgs hasn't been set up yet.
|
||||
*/
|
||||
if (fs->group_desc_count == 2)
|
||||
has_bg = param->s_backup_bgs[0] != 0;
|
||||
else
|
||||
has_bg = param->s_backup_bgs[1] != 0;
|
||||
} else
|
||||
has_bg = ext2fs_bg_has_super(fs, fs->group_desc_count - 1);
|
||||
if (has_bg)
|
||||
overhead += 1 + fs->desc_blocks + super->s_reserved_gdt_blocks;
|
||||
rem = ((ext2fs_blocks_count(super) - super->s_first_data_block) %
|
||||
super->s_blocks_per_group);
|
||||
if ((fs->group_desc_count == 1) && rem && (rem < overhead)) {
|
||||
retval = EXT2_ET_TOOSMALL;
|
||||
goto cleanup;
|
||||
}
|
||||
if (rem && (rem < overhead+50)) {
|
||||
ext2fs_blocks_count_set(super, ext2fs_blocks_count(super) -
|
||||
rem);
|
||||
/*
|
||||
* If blocks count is changed, we need to recalculate
|
||||
* reserved blocks count not to exceed 50%.
|
||||
*/
|
||||
reserved_ratio = 100.0 * ext2fs_r_blocks_count(param) /
|
||||
ext2fs_blocks_count(param);
|
||||
ext2fs_r_blocks_count_set(super, reserved_ratio *
|
||||
ext2fs_blocks_count(super) / 100.0);
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point we know how big the filesystem will be. So
|
||||
* we can do any and all allocations that depend on the block
|
||||
* count.
|
||||
*/
|
||||
|
||||
/* Set up the locations of the backup superblocks */
|
||||
if (ext2fs_has_feature_sparse_super2(super)) {
|
||||
if (super->s_backup_bgs[0] >= fs->group_desc_count)
|
||||
super->s_backup_bgs[0] = fs->group_desc_count - 1;
|
||||
if (super->s_backup_bgs[1] >= fs->group_desc_count)
|
||||
super->s_backup_bgs[1] = fs->group_desc_count - 1;
|
||||
if (super->s_backup_bgs[0] == super->s_backup_bgs[1])
|
||||
super->s_backup_bgs[1] = 0;
|
||||
if (super->s_backup_bgs[0] > super->s_backup_bgs[1]) {
|
||||
__u32 t = super->s_backup_bgs[0];
|
||||
super->s_backup_bgs[0] = super->s_backup_bgs[1];
|
||||
super->s_backup_bgs[1] = t;
|
||||
}
|
||||
}
|
||||
|
||||
retval = ext2fs_get_mem(strlen(fs->device_name) + 80, &buf);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
strcpy(buf, "block bitmap for ");
|
||||
strcat(buf, fs->device_name);
|
||||
retval = ext2fs_allocate_subcluster_bitmap(fs, buf, &fs->block_map);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
strcpy(buf, "inode bitmap for ");
|
||||
strcat(buf, fs->device_name);
|
||||
retval = ext2fs_allocate_inode_bitmap(fs, buf, &fs->inode_map);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
ext2fs_free_mem(&buf);
|
||||
|
||||
retval = ext2fs_get_array(fs->desc_blocks, fs->blocksize,
|
||||
&fs->group_desc);
|
||||
if (retval)
|
||||
goto cleanup;
|
||||
|
||||
memset(fs->group_desc, 0, (size_t) fs->desc_blocks * fs->blocksize);
|
||||
|
||||
/*
|
||||
* Reserve the superblock and group descriptors for each
|
||||
* group, and fill in the correct group statistics for group.
|
||||
* Note that although the block bitmap, inode bitmap, and
|
||||
* inode table have not been allocated (and in fact won't be
|
||||
* by this routine), they are accounted for nevertheless.
|
||||
*
|
||||
* If FLEX_BG meta-data grouping is used, only account for the
|
||||
* superblock and group descriptors (the inode tables and
|
||||
* bitmaps will be accounted for when allocated).
|
||||
*/
|
||||
free_blocks = 0;
|
||||
csum_flag = ext2fs_has_group_desc_csum(fs);
|
||||
reserved_inos = super->s_first_ino;
|
||||
for (i = 0; i < fs->group_desc_count; i++) {
|
||||
/*
|
||||
* Don't set the BLOCK_UNINIT group for the last group
|
||||
* because the block bitmap needs to be padded.
|
||||
*/
|
||||
if (csum_flag) {
|
||||
if (i != fs->group_desc_count - 1)
|
||||
ext2fs_bg_flags_set(fs, i,
|
||||
EXT2_BG_BLOCK_UNINIT);
|
||||
ext2fs_bg_flags_set(fs, i, EXT2_BG_INODE_UNINIT);
|
||||
numblocks = super->s_inodes_per_group;
|
||||
if (reserved_inos) {
|
||||
if (numblocks > reserved_inos) {
|
||||
numblocks -= reserved_inos;
|
||||
reserved_inos = 0;
|
||||
} else {
|
||||
reserved_inos -= numblocks;
|
||||
numblocks = 0;
|
||||
}
|
||||
}
|
||||
ext2fs_bg_itable_unused_set(fs, i, numblocks);
|
||||
}
|
||||
numblocks = ext2fs_reserve_super_and_bgd(fs, i, fs->block_map);
|
||||
if (fs->super->s_log_groups_per_flex)
|
||||
numblocks += 2 + fs->inode_blocks_per_group;
|
||||
|
||||
free_blocks += numblocks;
|
||||
ext2fs_bg_free_blocks_count_set(fs, i, numblocks);
|
||||
ext2fs_bg_free_inodes_count_set(fs, i, fs->super->s_inodes_per_group);
|
||||
ext2fs_bg_used_dirs_count_set(fs, i, 0);
|
||||
ext2fs_group_desc_csum_set(fs, i);
|
||||
}
|
||||
free_blocks &= ~EXT2FS_CLUSTER_MASK(fs);
|
||||
ext2fs_free_blocks_count_set(super, free_blocks);
|
||||
|
||||
c = (char) 255;
|
||||
if (((int) c) == -1) {
|
||||
super->s_flags |= EXT2_FLAGS_SIGNED_HASH;
|
||||
} else {
|
||||
super->s_flags |= EXT2_FLAGS_UNSIGNED_HASH;
|
||||
}
|
||||
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
ext2fs_mark_bb_dirty(fs);
|
||||
ext2fs_mark_ib_dirty(fs);
|
||||
|
||||
io_channel_set_blksize(fs->io, fs->blocksize);
|
||||
|
||||
*ret_fs = fs;
|
||||
return 0;
|
||||
cleanup:
|
||||
free(buf);
|
||||
ext2fs_free(fs);
|
||||
return retval;
|
||||
}
|
||||
|
||||
errcode_t ext2fs_calculate_summary_stats(ext2_filsys fs, int super_only)
|
||||
{
|
||||
blk64_t blk;
|
||||
ext2_ino_t ino;
|
||||
unsigned int group = 0;
|
||||
unsigned int count = 0;
|
||||
int total_free = 0;
|
||||
int group_free = 0;
|
||||
int last_allocated = 0;
|
||||
int uninit;
|
||||
|
||||
/*
|
||||
* First calculate the block statistics
|
||||
*/
|
||||
uninit = 1;
|
||||
for (blk = fs->super->s_first_data_block;
|
||||
blk < ext2fs_blocks_count(fs->super); blk++) {
|
||||
if (!ext2fs_fast_test_block_bitmap2(fs->block_map, blk)) {
|
||||
group_free++;
|
||||
total_free++;
|
||||
} else {
|
||||
uninit = 0;
|
||||
}
|
||||
count++;
|
||||
if ((count == fs->super->s_blocks_per_group) ||
|
||||
(blk == ext2fs_blocks_count(fs->super)-1)) {
|
||||
ext2fs_bg_free_blocks_count_set(fs, group,
|
||||
group_free);
|
||||
if (!super_only) {
|
||||
if (uninit && blk !=
|
||||
ext2fs_blocks_count(fs->super) - 1)
|
||||
ext2fs_bg_flags_set(fs, group,
|
||||
EXT2_BG_BLOCK_UNINIT);
|
||||
else
|
||||
ext2fs_bg_flags_clear(fs, group,
|
||||
EXT2_BG_BLOCK_UNINIT);
|
||||
}
|
||||
count = 0;
|
||||
group_free = 0;
|
||||
uninit = 1;
|
||||
group++;
|
||||
}
|
||||
}
|
||||
total_free = EXT2FS_C2B(fs, total_free);
|
||||
ext2fs_free_blocks_count_set(fs->super, total_free);
|
||||
|
||||
/*
|
||||
* Next, calculate the inode statistics
|
||||
*/
|
||||
group_free = 0;
|
||||
total_free = 0;
|
||||
last_allocated = 0;
|
||||
count = 0;
|
||||
group = 0;
|
||||
|
||||
/* Protect loop from wrap-around if s_inodes_count maxed */
|
||||
for (ino = 1; ino <= fs->super->s_inodes_count && ino > 0; ino++) {
|
||||
if (!ext2fs_test_inode_bitmap2(fs->inode_map, ino)) {
|
||||
group_free++;
|
||||
total_free++;
|
||||
} else {
|
||||
last_allocated = ino;
|
||||
}
|
||||
count++;
|
||||
if ((count == fs->super->s_inodes_per_group) ||
|
||||
(ino == fs->super->s_inodes_count)) {
|
||||
if (!super_only) {
|
||||
if (last_allocated) {
|
||||
ext2fs_bg_flags_clear(fs, group,
|
||||
EXT2_BG_INODE_UNINIT);
|
||||
ext2fs_bg_itable_unused_set(fs, group,
|
||||
fs->super->s_inodes_per_group -
|
||||
(last_allocated %
|
||||
fs->super->s_inodes_per_group));
|
||||
} else {
|
||||
ext2fs_bg_flags_set(fs, group,
|
||||
EXT2_BG_INODE_UNINIT);
|
||||
ext2fs_bg_itable_unused_set(fs, group,
|
||||
0);
|
||||
}
|
||||
ext2fs_bg_free_inodes_count_set(fs, group,
|
||||
group_free);
|
||||
}
|
||||
group++;
|
||||
count = 0;
|
||||
group_free = 0;
|
||||
last_allocated = 0;
|
||||
}
|
||||
}
|
||||
fs->super->s_free_inodes_count = total_free;
|
||||
ext2fs_mark_super_dirty(fs);
|
||||
return 0;
|
||||
}
|
||||
BIN
jni/e2fsprogs/lib/ext2fs/initialize.o
Executable file
BIN
jni/e2fsprogs/lib/ext2fs/initialize.o
Executable file
Binary file not shown.
118
jni/e2fsprogs/lib/ext2fs/inline.c
Executable file
118
jni/e2fsprogs/lib/ext2fs/inline.c
Executable file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* inline.c --- Includes the inlined functions defined in the header
|
||||
* files as standalone functions, in case the application program
|
||||
* is compiled with inlining turned off.
|
||||
*
|
||||
* Copyright (C) 1993, 1994 Theodore Ts'o.
|
||||
*
|
||||
* %Begin-Header%
|
||||
* This file may be redistributed under the terms of the GNU Library
|
||||
* General Public License, version 2.
|
||||
* %End-Header%
|
||||
*/
|
||||
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 600 /* for posix_memalign() */
|
||||
#endif
|
||||
|
||||
#include "config.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#if HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#if HAVE_SYS_STAT_H
|
||||
#include <sys/stat.h>
|
||||
#endif
|
||||
#if HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
#if HAVE_MALLOC_H
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#include "ext2_fs.h"
|
||||
#define INCLUDE_INLINE_FUNCS
|
||||
#include "ext2fs.h"
|
||||
|
||||
/*
|
||||
* We used to define this as an inline, but since we are now using
|
||||
* autoconf-defined #ifdef's, we need to export this as a
|
||||
* library-provided function exclusively.
|
||||
*/
|
||||
errcode_t ext2fs_get_memalign(unsigned long size,
|
||||
unsigned long align, void *ptr)
|
||||
{
|
||||
errcode_t retval = 0;
|
||||
void **p = ptr;
|
||||
|
||||
if (align < 8)
|
||||
align = 8;
|
||||
#ifdef HAVE_POSIX_MEMALIGN
|
||||
retval = posix_memalign(p, align, size);
|
||||
if (retval == ENOMEM)
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
#else /* !HAVE_POSIX_MEMALIGN */
|
||||
#ifdef HAVE_MEMALIGN
|
||||
*p = memalign(align, size);
|
||||
if (*p == NULL) {
|
||||
if (errno)
|
||||
return errno;
|
||||
else
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
}
|
||||
#else /* !HAVE_MEMALIGN */
|
||||
#ifdef HAVE_VALLOC
|
||||
if (align > sizeof(long long))
|
||||
*p = valloc(size);
|
||||
else
|
||||
#endif
|
||||
*p = malloc(size);
|
||||
if ((uintptr_t) *p & (align - 1)) {
|
||||
free(*p);
|
||||
*p = 0;
|
||||
}
|
||||
if (*p == 0)
|
||||
return EXT2_ET_NO_MEMORY;
|
||||
#endif /* HAVE_MEMALIGN */
|
||||
#endif /* HAVE_POSIX_MEMALIGN */
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static int isaligned(void *ptr, unsigned long align)
|
||||
{
|
||||
return (((unsigned long) ptr & (align - 1)) == 0);
|
||||
}
|
||||
|
||||
static errcode_t test_memalign(unsigned long align)
|
||||
{
|
||||
void *ptr = 0;
|
||||
errcode_t retval;
|
||||
|
||||
retval = ext2fs_get_memalign(32, align, &ptr);
|
||||
if (!retval && !isaligned(ptr, align))
|
||||
retval = EINVAL;
|
||||
free(ptr);
|
||||
printf("tst_memalign(%lu) is %s\n", align,
|
||||
retval ? error_message(retval) : "OK");
|
||||
return retval;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (test_memalign(4))
|
||||
err++;
|
||||
if (test_memalign(32))
|
||||
err++;
|
||||
if (test_memalign(1024))
|
||||
err++;
|
||||
if (test_memalign(4096))
|
||||
err++;
|
||||
return err;
|
||||
}
|
||||
#endif
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user