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