Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a bug and add corresponding unit tests #355

Merged
merged 3 commits into from
Dec 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/overlaybd/tar/erofs/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ include(FetchContent)
FetchContent_Declare(
erofs-utils
GIT_REPOSITORY https://git.kernel.org/pub/scm/linux/kernel/git/xiang/erofs-utils.git
GIT_TAG 654e8b8a8f1a87b0746ff47db00dec1afc05fbc9
GIT_TAG 80156068eb4980342c0ad3ee47ac7261acce5caf
)

FetchContent_MakeAvailable(erofs-utils)
Expand Down
44 changes: 44 additions & 0 deletions src/overlaybd/tar/erofs/erofs_fs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,50 @@ int ErofsFile::fiemap(struct photon::fs::fiemap *map)
return 0;
}

ssize_t ErofsFile::pread(void *buf, size_t count, off_t offset)
{
struct erofs_inode *inode = &file_private->inode;
struct erofs_map_blocks map;
erofs_off_t ptr = offset;
ssize_t read = 0;
int ret;

map.index = UINT_MAX;
while (ptr < offset + count) {
char *estart = (char*)buf + ptr - offset;
erofs_off_t eend, moff = 0;
map.m_la = ptr;
ret = erofs_map_blocks(inode, &map, 0);
if (ret || map.m_plen != map.m_llen)
LOG_ERROR_RETURN(0, -1, "[erofs_fs] fail to map blocks");
eend = std::min(offset + count, map.m_la + map.m_llen);
if (ptr < map.m_la)
LOG_ERROR_RETURN(0, -1, "[erofs_fs] invalid read offset");
if (!(map.m_flags & EROFS_MAP_MAPPED)) {
if (!map.m_llen) {
/* reached EOF */
memset((void*)estart, 0, offset + count - ptr);
ptr = offset + count;
continue;
}
memset((void*)estart, 0, eend - ptr);
ptr = eend;
continue;;
}
if (ptr > map.m_la) {
moff = ptr - map.m_la;
map.m_la = ptr;
}
ret = erofs_read_one_data(inode, &map, estart, moff,
eend - map.m_la);
if (ret)
return ret;
read += eend - map.m_la;
ptr = eend;
}
return read;
}

// ErofsFileSystem
EROFS_UNIMPLEMENTED_FUNC(photon::fs::IFile*, ErofsFileSystem, open(const char *pathname, int flags, mode_t mode), NULL)
EROFS_UNIMPLEMENTED_FUNC(photon::fs::IFile*, ErofsFileSystem, creat(const char *pathname, mode_t mode), NULL)
Expand Down
1 change: 1 addition & 0 deletions src/overlaybd/tar/erofs/erofs_fs.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class ErofsFile: public photon::fs::VirtualReadOnlyFile {
photon::fs::IFileSystem *filesystem();
int fstat(struct stat *buf);
int fiemap(struct photon::fs::fiemap *map);
ssize_t pread(void *buf, size_t count, off_t offset);
private:
ErofsFileSystem *fs;
struct ErofsFileInt;
Expand Down
304 changes: 304 additions & 0 deletions src/overlaybd/tar/erofs/test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -782,6 +782,310 @@ TEST_F(ErofsCacheTest, erofs_cache) {
#undef round_up_blk
}

/* test for building in clean and incremental mode */
class ErofsTestCleanIncremental: public ::testing::Test {
protected:
photon::fs::IFileSystem *host_fs;
std::string workdir = "/tmp/erofs_clean_incrementtal";
/* layer0 */
std::string layer0_src = workdir + "/layer0.tar";
std::string layer0_idx = workdir + "/layer0.idx";
std::string layer0_meta = workdir + "/layer0.meta";
std::string layer0_content = workdir + "/layer0_content";
/* layer1 */
std::string layer1_src = workdir + "/layer1.tar";
std::string layer1_idx = workdir + "/layer1.idx";
std::string layer1_meta = workdir + "/layer1.meta";
std::string layer1_content = workdir + "/layer1_content";

virtual void SetUp() override{
host_fs = photon::fs::new_localfs_adaptor();
ASSERT_NE(nullptr, host_fs);
if (host_fs->access(workdir.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->mkdir(workdir.c_str(), 0755));
}
}

virtual void TearDown() override{
ASSERT_NE(nullptr, host_fs);
/* layer 0 */
if (host_fs->access(layer0_src.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->unlink(layer0_src.c_str()));
}
if (host_fs->access(layer0_idx.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->unlink(layer0_idx.c_str()));
}
if (host_fs->access(layer0_meta.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->unlink(layer0_meta.c_str()));
}
if (host_fs->access(layer0_content.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->unlink(layer0_content.c_str()));
}

/* layer 1 */
if (host_fs->access(layer1_src.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->unlink(layer1_src.c_str()));
}
if (host_fs->access(layer1_idx.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->unlink(layer0_idx.c_str()));
}
if (host_fs->access(layer1_meta.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->unlink(layer0_meta.c_str()));
}
if (host_fs->access(layer1_content.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->unlink(layer1_content.c_str()));
}

if (host_fs->access(workdir.c_str(), 0) != 0) {
ASSERT_EQ(0, host_fs->rmdir(workdir.c_str()));
}
delete host_fs;
}

int traverse_fs(photon::fs::IFileSystem *fs, photon::fs::IFile *out) {
std::vector<string> items;

items.emplace_back("/");
while (!items.empty()) {
std::string tmp = items.front();
struct stat st;

out->write(tmp.c_str(), tmp.size());
items.erase(items.begin());
if (fs->stat(tmp.c_str(), &st))
LOG_ERRNO_RETURN(0, -1, "fail to stat file `", tmp);
/* handle dirs */
if (S_ISDIR(st.st_mode)) {
auto dir = fs->opendir(tmp.c_str());
do {
dirent *dent = dir->get();
items.emplace_back(tmp + "/" + std::string(dent->d_name));
} while (dir->next());
dir->closedir();
delete dir;
} else if (S_ISREG(st.st_mode)) { /* handle regular files */
photon::fs::IFile *file;
size_t left = st.st_size;
off_t offset = 0;
char buf[4096];
int len;

file = fs->open(tmp.c_str(), O_RDONLY);
if (!file)
LOG_ERRNO_RETURN(0, -1, "fail to open file `", tmp);
while (left > 0) {
len = std::min((size_t)4096, left);
if ((len = file->pread(buf, len, offset)) < 0) {
LOG_ERROR_RETURN(0, len, "fail to pread file `", tmp);
} else if (len == 0)
LOG_ERROR_RETURN(0, len, "fail to pread file `", tmp);
if (out->write(buf, len) != len)
LOG_ERRNO_RETURN(0, -1, "fail to write content to out file");
left -= len;
offset += len;
}
delete file;
}
}
return 0;
}
};

/*
* There are two layers, whose structures are:
*
* layer0 (root)
* ├── [ 4.0K] dir1
* │ ├── [ 4.0K] dir1_1.txt
* │ ├── [ 8.0K] dir1_2.txt
* │ └── [ 4.9K] dir1_3.txt
* ├── [ 4.0K] dir2
* │ ├── [ 4.0K] dir2_1.txt
* │ ├── [ 8.0K] dir2_2.txt
* │ └── [ 4.9K] dir2_3.txt
* ├── [ 4.0K] dir3
* │ ├── [ 4.0K] dir3_1.txt
* │ ├── [ 8.0K] dir3_2.txt
* │ └── [ 4.9K] dir3_3.txt
* └── [ 512] dirx (** a regular file **)
*
* layer1 (root)
* ├── [ 4.0K] dir1
* │ ├── [ 8.0K] dir1_1.txt
* │ └── [ 512] dir1_4.txt
* ├── [ 4.0K] dir3
* │ └── [ 36K] dir3_3.txt
* ├── [ 4.0K] dir4
* │ ├── [ 4.0K] dir4_1.txt
* │ └── [ 32K] dir4_2.txt
* ├── [ 4.0K] dirx (** a directory **)
* │ ├── [ 4.9K] dirx_1.txt
* │ ├── [ 8.0K] dirx_2.txt
* │ └── [ 32K] dirx_3.txt
* └── [ 0] .wh.dir2
*/
TEST_F(ErofsTestCleanIncremental, clean_incremental_mode) {
/* test for the clean mode */
static const unsigned char layer0_zipped[482] = {
0x1f, 0x8b, 0x08, 0x08, 0x26, 0x47, 0x40, 0x67, 0x00, 0x03, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x30,
0x2e, 0x74, 0x61, 0x72, 0x00, 0xed, 0xdd, 0xd1, 0x6a, 0xdb, 0x30, 0x14, 0x06, 0x60, 0x3f, 0x4a,
0x9e, 0x20, 0xb5, 0x64, 0x4b, 0x7a, 0x9c, 0x91, 0x6d, 0x37, 0xbd, 0x2a, 0x64, 0x19, 0xf4, 0xf1,
0x67, 0x3b, 0x81, 0xb9, 0x85, 0x75, 0x85, 0xce, 0x92, 0xd7, 0x7c, 0xdf, 0x85, 0x13, 0xec, 0x40,
0x1c, 0x8e, 0xac, 0xc0, 0x8f, 0x7c, 0x7c, 0x7c, 0xe8, 0x36, 0xd7, 0x4f, 0x4a, 0x4a, 0xcb, 0xeb,
0xe4, 0xf5, 0xeb, 0xf2, 0x3e, 0x8c, 0x25, 0xf6, 0xfd, 0x18, 0x42, 0x18, 0xa6, 0xfd, 0xa5, 0xf4,
0xb1, 0x3b, 0xa4, 0xed, 0x4f, 0xad, 0xeb, 0x7e, 0xfe, 0xb8, 0x9c, 0xce, 0x87, 0x43, 0x77, 0x7e,
0x7a, 0xba, 0xbc, 0xf5, 0xb9, 0xbf, 0x1d, 0xff, 0x4f, 0x1d, 0x1f, 0xbe, 0x3f, 0x9e, 0x9f, 0xb7,
0xfd, 0x8e, 0xb9, 0xc0, 0x79, 0x1c, 0xff, 0x54, 0xff, 0xb0, 0xaa, 0x7f, 0x9f, 0x4b, 0xec, 0xa6,
0x3d, 0xa9, 0x0c, 0xdd, 0xa1, 0xdf, 0xf6, 0xb4, 0xae, 0xee, 0xbc, 0xfe, 0x27, 0xee, 0xda, 0x72,
0xfd, 0xc7, 0x6d, 0xff, 0x04, 0xde, 0x39, 0xff, 0x87, 0x3c, 0x5d, 0xf7, 0xb9, 0x4f, 0xcb, 0xf5,
0x9f, 0xb2, 0xf9, 0xbf, 0x86, 0x5b, 0xfd, 0xe7, 0xcd, 0x97, 0xe1, 0x78, 0x79, 0xde, 0xe2, 0x37,
0xbe, 0x3d, 0xff, 0x87, 0xb9, 0xee, 0xaf, 0xea, 0x1f, 0xc7, 0xe9, 0xb0, 0xf9, 0xbf, 0x82, 0xaf,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xe6, 0x5a, 0xe5, 0x7f, 0xeb, 0xfc, 0x37, 0x36, 0xc9, 0x7f, 0xe3,
0x8b, 0xfc, 0x3f, 0xe5, 0x32, 0xe7, 0xbf, 0x43, 0x29, 0xf2, 0xdf, 0x1a, 0x5a, 0x8f, 0x7b, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0xe3, 0xd6, 0xeb, 0x3f, 0x42, 0x9b, 0xfb, 0xff, 0x5e,
0xae, 0xff, 0x48, 0x61, 0x59, 0xff, 0x91, 0xb3, 0xf5, 0x1f, 0x35, 0xb4, 0x1e, 0x7f, 0x00, 0x00,
0x00, 0xc0, 0xf6, 0x96, 0xfc, 0x67, 0xd8, 0x51, 0xff, 0xaf, 0x32, 0x2c, 0xfd, 0xbf, 0xf2, 0xa8,
0xff, 0x57, 0x0d, 0xb7, 0xfa, 0xcf, 0x9b, 0x5d, 0xe4, 0x7f, 0x79, 0xb8, 0xdd, 0xff, 0x95, 0xe4,
0x7f, 0x35, 0x7c, 0x03, 0x00, 0x00, 0x00, 0x3e, 0xbd, 0x75, 0xfe, 0xb3, 0x8b, 0xfe, 0xef, 0x4b,
0xfe, 0x17, 0xc7, 0x5e, 0xff, 0x9f, 0x2a, 0x5a, 0x8f, 0x3f, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x07,
0xad, 0xf2, 0xbf, 0x75, 0xfe, 0xdb, 0xae, 0xff, 0x7b, 0xf8, 0x9d, 0xff, 0xa6, 0x51, 0xff, 0xf7,
0x8a, 0x5a, 0x8f, 0x7b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f, 0x68, 0xbd, 0x00,
0x81, 0xa6, 0x96, 0xf5, 0x3f, 0x61, 0x27, 0xfd, 0xdf, 0x62, 0x4e, 0x7d, 0x89, 0xd7, 0xfe, 0x6f,
0x51, 0xff, 0xb7, 0x1a, 0x6e, 0xf5, 0x9f, 0x37, 0xbb, 0xe8, 0xff, 0x36, 0x8c, 0xfd, 0xf5, 0xf9,
0x0f, 0xbd, 0xf5, 0x5f, 0x35, 0x9c, 0x00, 0x00, 0x00, 0x80, 0x4f, 0x6f, 0x9d, 0xff, 0xec, 0xa1,
0xff, 0xdb, 0x18, 0xcb, 0xb5, 0xff, 0x9b, 0xfc, 0xa7, 0x8a, 0xd6, 0xe3, 0x0f, 0x00, 0x00, 0x00,
0x00, 0xee, 0x41, 0xab, 0xfc, 0x6f, 0x9d, 0xff, 0xb6, 0xe9, 0xff, 0x16, 0xca, 0x64, 0x95, 0xff,
0x5e, 0x9f, 0xff, 0x11, 0xf4, 0x7f, 0xab, 0xa2, 0xf5, 0xb8, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3e, 0xac, 0xf5, 0xf2, 0x03, 0xa0, 0xa1, 0x5f, 0xeb, 0xed, 0xa4, 0x5a, 0x00, 0xf0,
0x00, 0x00
};

// prepare layer0 tar
ASSERT_EQ(0, ErofsTest::inflate(layer0_src,
const_cast<unsigned char*>(layer0_zipped),
sizeof(layer0_zipped)));

// create device
auto layer0_src_file = host_fs->open(layer0_src.c_str(), O_RDONLY, 0666);
ASSERT_NE(nullptr, layer0_src_file);
DEFER(delete layer0_src_file);
auto layer0_findex = host_fs->open(layer0_idx.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
auto layer0_fmeta = host_fs->open(layer0_meta.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
LSMT::WarpFileArgs layer0_args(layer0_findex, layer0_fmeta, layer0_src_file);
layer0_args.virtual_size = IMAGE_SIZE;
auto layer0_erofs_device = create_warpfile(layer0_args, false);
ASSERT_NE(layer0_erofs_device, nullptr);
DEFER(delete layer0_erofs_device);

// create erofs image
auto layer0_tar = new LibErofs(layer0_erofs_device, 4096, false);
ASSERT_EQ(0, layer0_tar->extract_tar(layer0_src_file, true, true));
delete layer0_tar;

// setup erofs fs
auto erofs_fs_layer0 = create_erofs_fs(layer0_erofs_device, 4096);
ASSERT_NE(erofs_fs_layer0, nullptr);

// traverse the fs tree
std::string layer0_sha256_std = "sha256:6af847069dbebf41654dbb4f39de074e1d593eae3050b21eaedf09a2d53494f7";
auto layer0_out = host_fs->open(layer0_content.c_str(), O_RDWR | O_CREAT | O_TRUNC);
ASSERT_NE(nullptr, layer0_out);
ASSERT_EQ(0, traverse_fs(erofs_fs_layer0, layer0_out));
layer0_out->lseek(0, SEEK_SET);
auto layer0_sha256file = new_sha256_file(layer0_out, false);
ASSERT_STREQ(layer0_sha256_std.c_str(), layer0_sha256file->sha256_checksum().c_str());
delete layer0_out;
delete layer0_sha256file;
delete erofs_fs_layer0;

/* test for the incremental mode */
static const unsigned char layer1_zipped[720] = {
0x1f, 0x8b, 0x08, 0x08, 0x67, 0x4c, 0x40, 0x67, 0x00, 0x03, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x31,
0x2e, 0x74, 0x61, 0x72, 0x00, 0xed, 0xdb, 0xc1, 0x6e, 0xa3, 0x3a, 0x14, 0x06, 0x60, 0x3f, 0x0a,
0x4f, 0x40, 0x6c, 0x63, 0xcc, 0xe3, 0x54, 0xd5, 0xcd, 0x62, 0xba, 0x8a, 0x44, 0xa9, 0x26, 0x8f,
0x7f, 0x09, 0x8d, 0x66, 0x3a, 0xa9, 0xda, 0xce, 0x86, 0x90, 0x4e, 0xbe, 0x6f, 0x61, 0x23, 0x40,
0xc2, 0xe8, 0x27, 0x5e, 0x1c, 0x9d, 0xb4, 0xbb, 0xb0, 0xba, 0x38, 0x1b, 0xfa, 0x7e, 0x99, 0x67,
0x97, 0xf3, 0x72, 0x9c, 0xca, 0x90, 0x63, 0xec, 0x6a, 0x9f, 0x4f, 0xf7, 0x0d, 0x43, 0xea, 0x43,
0xd3, 0xaf, 0xbf, 0xb4, 0x10, 0x5e, 0x9e, 0xa7, 0xc7, 0xb1, 0x69, 0xc2, 0x78, 0x38, 0x4c, 0x9f,
0xdd, 0xf7, 0xd5, 0xf5, 0x6f, 0xaa, 0xdd, 0xed, 0x9f, 0xc6, 0xe3, 0xba, 0x1f, 0xc1, 0xdf, 0xe7,
0x5f, 0x6a, 0xcc, 0x35, 0xc4, 0x14, 0x6b, 0x8d, 0xf2, 0xbf, 0x86, 0x73, 0xfe, 0xa7, 0xe1, 0x21,
0xb7, 0xd3, 0x71, 0x8d, 0x77, 0x3c, 0x05, 0x5c, 0x4b, 0xf9, 0x20, 0xff, 0x39, 0xf6, 0xd8, 0xfd,
0xfa, 0xfd, 0xd7, 0x21, 0xcf, 0xf9, 0xe7, 0x9a, 0x52, 0x68, 0xe2, 0x0a, 0x6b, 0x79, 0xe7, 0xce,
0xf3, 0xdf, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x82, 0xad, 0x5b, 0x10, 0xd8,
0xd0, 0xdb, 0xfe, 0x9f, 0x6e, 0x8b, 0xfe, 0x9f, 0xb4, 0x0c, 0xbf, 0xfa, 0x7f, 0x86, 0x14, 0x97,
0xfe, 0x9f, 0xf9, 0xb2, 0xfe, 0x9f, 0x2b, 0xd8, 0x7a, 0xf3, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x9b, 0x10, 0xb8, 0x67, 0xed, 0x6e,
0xff, 0x34, 0x1e, 0x97, 0xe1, 0x21, 0xb5, 0xd3, 0x71, 0x5a, 0xe1, 0x19, 0x71, 0x56, 0x4b, 0x59,
0xe6, 0xd9, 0xc5, 0x9c, 0x52, 0x4d, 0x31, 0xa4, 0x32, 0xe4, 0x18, 0xbb, 0x5a, 0x4b, 0x1f, 0x62,
0xca, 0x35, 0x95, 0xd0, 0xc4, 0x15, 0xd6, 0xf2, 0xce, 0xcb, 0xf3, 0xf4, 0x38, 0x36, 0x4d, 0x18,
0x0f, 0x87, 0x4f, 0xdf, 0xfd, 0xab, 0xeb, 0xdf, 0xd4, 0xd6, 0xdb, 0x0f, 0x00, 0x00, 0x00, 0x00,
0xdc, 0x83, 0xad, 0xea, 0x7f, 0x4b, 0xfd, 0xb7, 0xdb, 0xad, 0xfa, 0x8c, 0x53, 0x95, 0x77, 0xe8,
0xfb, 0x0f, 0xea, 0xbf, 0xaf, 0xc7, 0xa9, 0x0c, 0xa9, 0x76, 0xb1, 0x96, 0x61, 0x3e, 0x9f, 0x62,
0x5f, 0x73, 0x68, 0xfa, 0x55, 0x57, 0x75, 0x76, 0xe7, 0xf5, 0xdf, 0x73, 0xfe, 0xa7, 0xe1, 0xa1,
0xdb, 0xa2, 0xfe, 0x9f, 0xe6, 0x4f, 0x63, 0x48, 0x17, 0xf9, 0xe7, 0x92, 0x93, 0xfa, 0xff, 0x35,
0xfc, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x6b, 0x0a, 0xb7, 0xa1, 0xdd, 0xed, 0x9f, 0xc6, 0xb4, 0x5b, 0xf5,
0x19, 0x71, 0x36, 0xf4, 0xfd, 0x32, 0xcf, 0x2e, 0xe7, 0xe5, 0x38, 0x95, 0x21, 0xd5, 0x3c, 0xd4,
0x3e, 0xe6, 0x10, 0x53, 0xec, 0x6b, 0x0e, 0x4d, 0xbf, 0xea, 0xaa, 0xce, 0x5e, 0x9e, 0xa7, 0xc7,
0xb1, 0x69, 0xc2, 0x78, 0x38, 0x4c, 0x9f, 0xdd, 0xf7, 0xd5, 0xf5, 0x6f, 0xea, 0x9c, 0xff, 0x69,
0x78, 0x48, 0xed, 0x74, 0x5c, 0xe3, 0x1d, 0x4f, 0x01, 0xd7, 0x52, 0x3e, 0xc8, 0x3f, 0xff, 0x91,
0x7f, 0x29, 0x75, 0xce, 0x3f, 0x97, 0x98, 0x42, 0x13, 0x57, 0x58, 0xcb, 0x3b, 0x77, 0x9e, 0xff,
0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xed, 0xbd, 0xed, 0xff, 0x28, 0x9b, 0xf4,
0x7f, 0xc4, 0xf4, 0xbe, 0xff, 0x27, 0x77, 0x43, 0xd1, 0xff, 0x71, 0x0d, 0x5b, 0x7f, 0x7f, 0x6c,
0x6b, 0xf9, 0xfd, 0x97, 0x1b, 0xe9, 0xff, 0xeb, 0x62, 0x9d, 0xf7, 0x80, 0xd7, 0xfe, 0xbf, 0x41,
0xff, 0xdf, 0x35, 0x9c, 0xf3, 0x3f, 0x0d, 0x1b, 0xf5, 0xff, 0x9d, 0xb6, 0xff, 0xf4, 0x3b, 0xff,
0xd8, 0xd9, 0xff, 0xaf, 0x68, 0x0f, 0x00, 0x00, 0x00, 0xfc, 0xfb, 0xb6, 0x2e, 0x40, 0xb0, 0xa9,
0xb7, 0xf5, 0xbf, 0xbc, 0x45, 0xfd, 0x2f, 0xc5, 0x3f, 0xeb, 0x7f, 0xa9, 0x7f, 0xfd, 0xff, 0x6f,
0x54, 0xff, 0xbb, 0x86, 0xad, 0xb7, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb8, 0x09, 0x81, 0x7b, 0xd6, 0xee, 0xda, 0x9f, 0x3f, 0xda,
0xfd, 0xd3, 0x98, 0xd7, 0x7b, 0x46, 0x9c, 0xd5, 0x52, 0x96, 0x79, 0x76, 0x39, 0x2f, 0xc7, 0xa9,
0x0c, 0xa9, 0x76, 0xb1, 0x76, 0xc3, 0x7c, 0x3e, 0xa5, 0x54, 0x4b, 0x68, 0xe2, 0x7a, 0x4b, 0xfa,
0xed, 0xe5, 0x79, 0x7a, 0x1c, 0x9b, 0x26, 0x8c, 0x87, 0xc3, 0xf4, 0xd9, 0x7d, 0x5f, 0x5d, 0x07,
0x00, 0x00, 0x00, 0x00, 0x80, 0x1b, 0xf2, 0x3f, 0xe2, 0x43, 0x75, 0xe6, 0x00, 0x30, 0x02, 0x00
};

// prepare layer1 tar
ASSERT_EQ(0, ErofsTest::inflate(layer1_src,
const_cast<unsigned char*>(layer1_zipped),
sizeof(layer1_zipped)));
// create device
auto layer1_src_file = host_fs->open(layer1_src.c_str(), O_RDONLY, 0666);
ASSERT_NE(nullptr, layer1_src_file);
DEFER(delete layer1_src_file);
auto layer1_findex = host_fs->open(layer1_idx.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
auto layer1_fmeta = host_fs->open(layer1_meta.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
LSMT::WarpFileArgs layser1_args(layer1_findex, layer1_fmeta, layer1_src_file);
auto layer1_erofs_device = create_warpfile(layser1_args, false);
ASSERT_NE(layer1_erofs_device, nullptr);
DEFER(delete layer1_erofs_device);

// merge lower and upper
LSMT::IFileRW *merged_view = stack_files(layer1_erofs_device, layer0_erofs_device, false, false);
ASSERT_NE(nullptr, merged_view);

// setup erofs fs
auto layer1_tar = new LibErofs(merged_view, 4096, false);
ASSERT_EQ(0, layer1_tar->extract_tar(layer1_src_file, true, false));
delete layer1_tar;
auto erofs_fs_layer1 = create_erofs_fs(merged_view, 4096);
ASSERT_NE(erofs_fs_layer1, nullptr);

// traverse the fs tree
std::string layer1_sha256_std = "sha256:a57cc5bf4d47dbd098a4d019364bd9af559063d48b7033b7322147332c132b04";
auto layer1_out = host_fs->open(layer1_content.c_str(), O_RDWR | O_CREAT | O_TRUNC);
ASSERT_NE(nullptr, layer1_out);
ASSERT_EQ(0, traverse_fs(erofs_fs_layer1, layer1_out));
layer1_out->lseek(0, SEEK_SET);
auto layer1_sha256file = new_sha256_file(layer1_out, false);
ASSERT_STREQ(layer1_sha256_std.c_str(), layer1_sha256file->sha256_checksum().c_str());
delete layer1_out;
delete layer1_sha256file;
delete erofs_fs_layer1;
}

int main(int argc, char **argv) {

::testing::InitGoogleTest(&argc, argv);
Expand Down