static int populate_file_details_from_inode()

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