aboutsummaryrefslogtreecommitdiffstats
path: root/src/clone_extents.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/clone_extents.c')
-rw-r--r--src/clone_extents.c200
1 files changed, 200 insertions, 0 deletions
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;
+}
+
+
+