pmt: initial 2.9.1 update

This commit is contained in:
2024-10-02 21:37:57 +03:00
parent 82bd2939cd
commit 7259d451c4
459 changed files with 86355 additions and 2404 deletions

554
jni/e2fsprogs/lib/ext2fs/alloc.c Executable file
View 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

Binary file not shown.

View 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 ;
}

Binary file not shown.

View 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;
}

Binary file not shown.

View 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;
}

Binary file not shown.

116
jni/e2fsprogs/lib/ext2fs/atexit.c Executable file
View 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

Binary file not shown.

View 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;
}

Binary file not shown.

View 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);
}

View 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;
}

Binary file not shown.

View 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));
}

Binary file not shown.

148
jni/e2fsprogs/lib/ext2fs/bitops.c Executable file
View 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

Binary file not shown.

View 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
};

Binary file not shown.

View 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,
};

Binary file not shown.

606
jni/e2fsprogs/lib/ext2fs/blknum.c Executable file
View 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

Binary file not shown.

659
jni/e2fsprogs/lib/ext2fs/block.c Executable file
View 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

Binary file not shown.

499
jni/e2fsprogs/lib/ext2fs/bmap.c Executable file
View 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

Binary file not shown.

167
jni/e2fsprogs/lib/ext2fs/bmove.c Executable file
View 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;
}

View 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;
}

View 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;
}

Binary file not shown.

View 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;
}

Binary file not shown.

View 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

Binary file not shown.

938
jni/e2fsprogs/lib/ext2fs/crc32c.c Executable file
View 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

Binary file not shown.

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

Binary file not shown.

403
jni/e2fsprogs/lib/ext2fs/dblist.c Executable file
View 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

Binary file not shown.

View 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;
}

Binary file not shown.

View 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 */

Binary file not shown.

View 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;
}

Binary file not shown.

View 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);
}

Binary file not shown.

View 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);
}

Binary file not shown.

459
jni/e2fsprogs/lib/ext2fs/dosio.c Executable file
View 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
View 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

Binary file not shown.

View 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;
}

Binary file not shown.

View 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;
}

Binary file not shown.

File diff suppressed because it is too large Load Diff

Binary file not shown.

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

Binary file not shown.

View 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;
}

Binary file not shown.

666
jni/e2fsprogs/lib/ext2fs/fileio.c Executable file
View 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

Binary file not shown.

View 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

Binary file not shown.

View 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

Binary file not shown.

108
jni/e2fsprogs/lib/ext2fs/freefs.c Executable file
View 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

Binary file not shown.

View 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);
}

Binary file not shown.

View 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;
}

Binary file not shown.

View 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;
}

View 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;
}

Binary file not shown.

View 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;
}

Binary file not shown.

View 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
}

Binary file not shown.

View 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

Binary file not shown.

View 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);
}

Binary file not shown.

View 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;
}

Binary file not shown.

921
jni/e2fsprogs/lib/ext2fs/icount.c Executable file
View 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(&param, 0, sizeof(param));
ext2fs_blocks_count_set(&param, 12000);
retval = ext2fs_initialize("test fs", EXT2_FLAG_64BITS, &param,
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

Binary file not shown.

470
jni/e2fsprogs/lib/ext2fs/imager.c Executable file
View 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

Binary file not shown.

View 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);
}

Binary file not shown.

View 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;
}

Binary file not shown.

118
jni/e2fsprogs/lib/ext2fs/inline.c Executable file
View 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