From b6afefb5d12dbed4801272dae3048588dfc1cb9a Mon Sep 17 00:00:00 2001 From: fishsoupisgood Date: Sat, 12 May 2018 17:10:22 +0100 Subject: first working version --- src/clone_extents.c | 200 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 200 insertions(+) create mode 100644 src/clone_extents.c (limited to 'src/clone_extents.c') diff --git a/src/clone_extents.c b/src/clone_extents.c new file mode 100644 index 0000000..09c639b --- /dev/null +++ b/src/clone_extents.c @@ -0,0 +1,200 @@ +#include "project.h" + + +static int allocate_extent (ext2_filsys fs, ext2_ino_t i_num, ext2_extent_handle_t eh, blk64_t l_start, blk64_t len, __u32 flags) +{ + blk64_t goal, start, size, want,max; + dgrp_t group; + int ret; + struct ext2fs_extent e; + + group = ext2fs_group_of_ino (fs, i_num); + goal = ext2fs_group_first_block2 (fs, group); + + + max = (flags & EXT2_EXTENT_FLAGS_UNINIT) ? EXT_UNINIT_MAX_LEN:EXT_INIT_MAX_LEN; + + ret = 0; + + while (len) { + + want = (len > max) ? max : len; + + EXT2_MOAN_FAIL (ret, ext2fs_new_range (fs, 0, goal, want, + fs->block_map, &start, &size)); + + if (ret) + break; + + if (size > want) size = want; + + ext2fs_block_alloc_stats_range (fs, start, size, +1); + + + e.e_pblk = start; + e.e_lblk = l_start; + e.e_len = size; + e.e_flags = flags; + + + EXT2_MOAN_FAIL (ret, ext2fs_extent_insert (eh, EXT2_EXTENT_INSERT_AFTER, &e)); + + if (ret) { + + fprintf(stderr,"Failed extent was:\n"); + fprintf(stderr," e.e_pblk = %lld\n",(long long int) e.e_pblk); + fprintf(stderr," e.e_lblk = %lld\n",(long long int) e.e_lblk); + fprintf(stderr," e.e_len = %lld\n",(long long int) e.e_len); + fprintf(stderr," e.e_flags = 0x%llx\n",(long long int) e.e_flags); + break; + } + + len -= size; + + } + + return ret; +} + + +int clone_extents (ext2_filsys src_fs, ext2_filsys dst_fs, ext2_ino_t i_num, struct ext2_inode *src_i, struct ext2_inode *dst_i) +{ + ext2_extent_handle_t src_e = NULL, dst_e = NULL; + // struct ext2_extent_info info; + struct ext2fs_extent e; + int ret; + blk64_t l_start = 0; + blk64_t l_len = 0; + __u32 flags; + + + do { + EXT2_MOAN_FAIL (ret, ext2fs_extent_open2 (src_fs, i_num, src_i, &src_e)); + + if (ret) + break; + + + EXT2_MOAN_FAIL (ret, ext2fs_extent_open2 (dst_fs, i_num, dst_i, &dst_e)); + + if (ret) + break; + + + ret = ext2fs_extent_get (src_e, EXT2_EXTENT_ROOT, &e); + + if (ret == EXT2_ET_EXTENT_NO_NEXT) { + EXT2_MOAN_FAIL (ret, ext2fs_write_inode (dst_fs, i_num, dst_i)); + break; + } + + if (ret) { + EXT2_MOAN (ret, "ext2fs_extent_get (src_e, EXT2_EXTENT_ROOT, &e)"); + break; + } + + + + for (;;) { + + if (e.e_flags & EXT2_EXTENT_FLAGS_LEAF) { + + if (!l_len) + flags = e.e_flags; + + if (((l_start + l_len) != e.e_lblk) || (flags != e.e_flags) ) { + ret = allocate_extent (dst_fs, i_num, dst_e, l_start, l_len, flags); + + if (ret) break; + + dst_i->i_blocks += l_len * (dst_fs->blocksize / 512); + + l_start = e.e_lblk; + l_len = e.e_len; + flags = e.e_flags; + } else + l_len += e.e_len; + + } + + ret = ext2fs_extent_get (src_e, EXT2_EXTENT_NEXT_LEAF, &e); + + if (ret == EXT2_ET_EXTENT_NO_NEXT) { + ret = 0; + break; + } + + if (ret) { + EXT2_MOAN (ret, "ext2fs_extent_get (src_e, EXT2_EXTENT_NEXT_LEAF, &e)"); + break; + } + } + + if (l_len) + ret = allocate_extent (dst_fs, i_num, dst_e, l_start, l_len, flags); + + if (ret) break; + + dst_i->i_blocks += l_len * (dst_fs->blocksize / 512); + + if (dst_e) + ext2fs_extent_free (dst_e); + + dst_e = NULL; + + EXT2_MOAN_FAIL (ret, ext2fs_write_inode (dst_fs, i_num, dst_i)); + + if (ret) + break; + + EXT2_MOAN_FAIL (ret, ext2fs_extent_get (src_e, EXT2_EXTENT_ROOT, &e)); + + if (ret) + break; + + + for (;;) { + uint64_t file_offset, file_len; + + + if ((e.e_flags & EXT2_EXTENT_FLAGS_LEAF) && ! (e.e_flags & EXT2_EXTENT_FLAGS_UNINIT)) { + + file_offset = e.e_lblk; + file_len = e.e_len; + + file_offset *= src_fs->blocksize; + file_len *= src_fs->blocksize; + + if (clone_data (src_fs, dst_fs, i_num, src_i, dst_i, file_offset, file_len)) { + ret = 1; + break; + } + } + + ret = ext2fs_extent_get (src_e, EXT2_EXTENT_NEXT_LEAF, &e); + + if (ret == EXT2_ET_EXTENT_NO_NEXT) { + ret = 0; + break; + } + + if (ret) { + EXT2_MOAN (ret, "ext2fs_extent_get (src_e, EXT2_EXTENT_NEXT_LEAF, &e)"); + break; + } + } + + } while (0); + + if (dst_e) + ext2fs_extent_free (dst_e); + + if (src_e) + ext2fs_extent_free (src_e); + + + return ret; +} + + + -- cgit v1.2.3