in src/native/tools/dumpextfs/load_ext4.cpp [133:244]
static int populate_file_details_from_inode(ext2_filsys fs, int ino, file_details *details)
{
struct ext2_inode inode;
int retval = ext2fs_read_inode(fs, ino, &inode);
if (retval)
{
printf("ext2fs_read_inode() failed: %d\n", retval);
return retval;
}
if (inode.i_flags & EXT4_INLINE_DATA_FL)
{
// TODO: Implement handling of inline data?
// May not be worth it since these files are small and the diff won't
// be very valuable
return 0;
}
if (ext2fs_is_fast_symlink(&inode))
{
return 0;
}
__u64 file_size = EXT2_I_SIZE(&inode);
__u64 read = 0;
details->length = file_size;
unsigned int blocksize = fs->blocksize;
unsigned int got;
bool current_block_all_zeroes{true};
ext2_file_t e2_file;
retval = ext2fs_file_open(fs, ino, 0, &e2_file);
if (retval)
{
printf("ext2fs_file_open() failed: %d\n", retval);
return retval;
}
std::vector<char> buf;
buf.reserve(blocksize);
blk64_t prev_physblock = std::numeric_limits<blk64_t>::max();
__u64 offset = std::numeric_limits<__u64>::max();
__u64 length = 0;
archive_diff::hashing::hasher hasher_sha256(archive_diff::hashing::algorithm::sha256);
archive_diff::hashing::hasher hasher_sha256_region(archive_diff::hashing::algorithm::sha256);
while (read < file_size)
{
retval = ext2fs_file_read(e2_file, const_cast<char *>(buf.data()), blocksize, &got);
if (retval == EXT2_ET_SHORT_READ)
{
// Very small files are probably not worth diffing
return 0;
}
else if (retval)
{
printf("ext2fs_file_read() failed: %d\n", retval);
return retval;
}
unsigned char *ubuf = reinterpret_cast<unsigned char *>(buf.data());
hasher_sha256.hash_data(ubuf, got);
blk64_t current_physblock = ext2fs_file_get_current_physblock(e2_file);
bool no_valid_previous = prev_physblock == std::numeric_limits<blk64_t>::max();
if (no_valid_previous || (current_physblock != (prev_physblock + 1)))
{
if (length)
{
auto offset_value = current_block_all_zeroes ? std::nullopt : std::optional<uint64_t>{offset};
details->regions.emplace_back(
file_region{
offset_value, length, current_block_all_zeroes, hasher_sha256_region.get_hash_string()});
hasher_sha256_region.reset();
}
offset = blocksize * current_physblock;
length = 0;
current_block_all_zeroes = true;
}
hasher_sha256_region.hash_data(ubuf, got);
if (current_block_all_zeroes)
{
current_block_all_zeroes = is_all_zeroes(ubuf, got);
}
length += got;
prev_physblock = current_physblock;
read += got;
}
if (length)
{
auto offset_value = current_block_all_zeroes ? std::nullopt : std::optional<uint64_t>{offset};
details->regions.emplace_back(
file_region{offset_value, length, current_block_all_zeroes, hasher_sha256_region.get_hash_string()});
}
details->hash_sha256_string = hasher_sha256.get_hash_string();
return 0;
}