Skip to content

Commit b2262fe

Browse files
authored
Merge pull request #350 from hsiangkao/turbooci-erofs-fix
[bugfix] workaround if some SegmentMapping refers to end of tar
2 parents 0911a9b + dc073b2 commit b2262fe

File tree

4 files changed

+295
-3
lines changed

4 files changed

+295
-3
lines changed

src/overlaybd/lsmt/file.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -573,9 +573,19 @@ class LSMTReadOnlyFile : public IFileRW {
573573
// LOG_DEBUG("offset: `, length: `", m.moffset, size);
574574
ssize_t ret = m_files[m.tag]->pread(buf, size, m.moffset * ALIGNMENT);
575575
if (ret < size) {
576-
LOG_ERRNO_RETURN(0, (int)ret,
577-
"failed to read from `-th file ( ` pread return: ` < size: `)",
578-
m.tag, m_files[m.tag], ret, size);
576+
if (ret < 0) {
577+
LOG_ERRNO_RETURN(0, -1,
578+
"failed to read from `-th file ( ` pread return: ` < size: `)",
579+
m.tag, m_files[m.tag], ret, size);
580+
}
581+
size_t ret2 = m_files[m.tag]->pread((char *)buf + ret, size - ret, m.moffset * ALIGNMENT + ret);
582+
if (ret2) {
583+
LOG_ERRNO_RETURN(0, (int)ret,
584+
"failed to read from `-th file ( ` pread return: ` < size: `)",
585+
m.tag, m_files[m.tag], ret, size);
586+
} else {
587+
memset((char *)buf + ret, 0, size - ret);
588+
}
579589
}
580590
lsmt_io_size += ret;
581591
lsmt_io_cnt++;

src/overlaybd/tar/erofs/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,7 @@ target_include_directories(erofs_lib PRIVATE
3939

4040
target_compile_options(erofs_lib PRIVATE "-include${EROFS_CONFIG_FILE}")
4141
target_link_libraries(erofs_lib PRIVATE ${EROFS_LIB_STATIC})
42+
43+
if(BUILD_TESTING)
44+
add_subdirectory(test)
45+
endif()
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
include_directories($ENV{GFLAGS}/include)
2+
link_directories($ENV{GFLAGS}/lib)
3+
4+
include_directories($ENV{GTEST}/googletest/include)
5+
link_directories($ENV{GTEST}/lib)
6+
7+
add_executable(erofs_test test.cpp)
8+
target_include_directories(erofs_test PUBLIC ${PHOTON_INCLUDE_DIR})
9+
target_link_libraries(erofs_test gtest gtest_main pthread photon_static
10+
tar_lib lsmt_lib gzip_lib gzindex_lib checksum_lib)
11+
12+
add_test(
13+
NAME erofs_test
14+
COMMAND ${EXECUTABLE_OUTPUT_PATH}/erofs_test
15+
)
Lines changed: 263 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,263 @@
1+
/*
2+
Copyright The Overlaybd Authors
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
#include <zlib.h>
18+
#include <gtest/gtest.h>
19+
#include <fcntl.h>
20+
#include <photon/photon.h>
21+
#include <photon/fs/localfs.h>
22+
#include <photon/fs/subfs.h>
23+
#include <photon/fs/extfs/extfs.h>
24+
#include <photon/common/alog.h>
25+
#include <photon/common/alog-stdstring.h>
26+
#include <vector>
27+
#include "../../../gzindex/gzfile.h"
28+
#include "../../../lsmt/file.h"
29+
#include "../liberofs.h"
30+
#include "../../tar_file.cpp"
31+
#include "../../../gzip/gz.h"
32+
#include "../../../../tools/sha256file.h"
33+
34+
35+
#define FILE_SIZE (2 * 1024 * 1024)
36+
#define IMAGE_SIZE 512UL<<20
37+
class ErofsTest : public ::testing::Test {
38+
protected:
39+
virtual void SetUp() override{
40+
fs = photon::fs::new_localfs_adaptor();
41+
42+
ASSERT_NE(nullptr, fs);
43+
if (fs->access(workdir.c_str(), 0) != 0) {
44+
auto ret = fs->mkdir(workdir.c_str(), 0755);
45+
ASSERT_EQ(0, ret);
46+
}
47+
48+
fs = photon::fs::new_subfs(fs, workdir.c_str(), true);
49+
ASSERT_NE(nullptr, fs);
50+
}
51+
virtual void TearDown() override{
52+
for (auto fn : filelist){
53+
fs->unlink(fn.c_str());
54+
}
55+
if (fs)
56+
delete fs;
57+
}
58+
59+
int download(const std::string &url, std::string out = "") {
60+
if (out == "") {
61+
out = workdir + "/" + std::string(basename(url.c_str()));
62+
}
63+
if (fs->access(out.c_str(), 0) == 0)
64+
return 0;
65+
// download file
66+
std::string cmd = "curl -s -o " + out + " " + url;
67+
LOG_INFO(VALUE(cmd.c_str()));
68+
auto ret = system(cmd.c_str());
69+
if (ret != 0) {
70+
LOG_ERRNO_RETURN(0, -1, "download failed: `", url.c_str());
71+
}
72+
return 0;
73+
}
74+
75+
int download_decomp(const std::string &url) {
76+
// download file
77+
std::string cmd = "wget -q -O - " + url +" | gzip -d -c >" +
78+
workdir + "/test.tar";
79+
LOG_INFO(VALUE(cmd.c_str()));
80+
auto ret = system(cmd.c_str());
81+
if (ret != 0) {
82+
LOG_ERRNO_RETURN(0, -1, "download failed: `", url.c_str());
83+
}
84+
return 0;
85+
}
86+
87+
int inflate(unsigned char *data, unsigned int size) {
88+
unsigned char out[65536];
89+
z_stream strm;
90+
int ret;
91+
/* allocate inflate state */
92+
strm.zalloc = Z_NULL;
93+
strm.zfree = Z_NULL;
94+
strm.opaque = Z_NULL;
95+
strm.avail_in = 0;
96+
strm.next_in = Z_NULL;
97+
ret = inflateInit2(&strm, 31);
98+
if (ret != Z_OK)
99+
return ret;
100+
DEFER((void)inflateEnd(&strm));
101+
strm.avail_in = size;
102+
strm.next_in = data;
103+
int fd = open(std::string(workdir + "/test.tar").c_str(), O_WRONLY | O_TRUNC | O_CREAT, 0644);
104+
if (fd < 0)
105+
return fd;
106+
DEFER(close(fd));
107+
do {
108+
strm.avail_out = sizeof(out);
109+
strm.next_out = out;
110+
ret = ::inflate(&strm, Z_NO_FLUSH);
111+
switch (ret) {
112+
case Z_NEED_DICT:
113+
case Z_DATA_ERROR:
114+
case Z_MEM_ERROR:
115+
return -1;
116+
}
117+
int have = sizeof(out) - strm.avail_out;
118+
if (write(fd, out, have) != have) {
119+
return -1;
120+
}
121+
} while (strm.avail_out == 0);
122+
return 0;
123+
}
124+
int write_file(photon::fs::IFile *file) {
125+
std::string bb = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01";
126+
ssize_t size = 0;
127+
ssize_t ret;
128+
struct stat st;
129+
LOG_INFO(VALUE(bb.size()));
130+
while (size < FILE_SIZE) {
131+
ret = file->write(bb.data(), bb.size());
132+
EXPECT_EQ(bb.size(), ret);
133+
ret = file->fstat(&st);
134+
EXPECT_EQ(0, ret);
135+
ret = file->lseek(0, SEEK_CUR);
136+
EXPECT_EQ(st.st_size, ret);
137+
size += bb.size();
138+
}
139+
LOG_INFO("write ` byte", size);
140+
EXPECT_EQ(FILE_SIZE, size);
141+
return 0;
142+
}
143+
144+
IFile *createDevice(const char *fn, IFile *target_file, size_t virtual_size = IMAGE_SIZE){
145+
auto fn_idx = std::string(fn)+".idx";
146+
auto fn_meta = std::string(fn)+".meta";
147+
DEFER({
148+
filelist.push_back(fn_idx);
149+
filelist.push_back(fn_meta);
150+
});
151+
auto fmeta = fs->open(fn_idx.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
152+
auto findex = fs->open(fn_meta.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRWXU);
153+
LSMT::WarpFileArgs args(findex, fmeta, target_file);
154+
args.virtual_size = virtual_size;
155+
return create_warpfile(args, false);
156+
}
157+
158+
int do_verify(IFile *verify, IFile *test, off_t offset = 0, ssize_t count = -1) {
159+
160+
if (count == -1) {
161+
count = verify->lseek(0, SEEK_END);
162+
auto len = test->lseek(0, SEEK_END);
163+
if (count != len) {
164+
LOG_ERROR("check logical length failed");
165+
return -1;
166+
}
167+
}
168+
LOG_INFO("start verify, virtual size: `", count);
169+
170+
ssize_t LEN = 1UL<<20;
171+
char vbuf[1UL<<20], tbuf[1UL<<20];
172+
// set_log_output_level(0);
173+
for (off_t i = 0; i < count; i+=LEN) {
174+
LOG_DEBUG("`", i);
175+
auto ret_v = verify->pread(vbuf, LEN, i);
176+
auto ret_t = test->pread(tbuf, LEN, i);
177+
if (ret_v == -1 || ret_t == -1) {
178+
LOG_ERROR_RETURN(0, -1, "pread(`,`) failed. (ret_v: `, ret_t: `)",
179+
i, LEN, ret_v, ret_v);
180+
}
181+
if (ret_v != ret_t) {
182+
LOG_ERROR_RETURN(0, -1, "compare pread(`,`) return code failed. ret:` / `(expected)",
183+
i, LEN, ret_t, ret_v);
184+
}
185+
if (memcmp(vbuf, tbuf, ret_v)!= 0){
186+
LOG_ERROR_RETURN(0, -1, "compare pread(`,`) buffer failed.", i, LEN);
187+
}
188+
}
189+
return 0;
190+
}
191+
192+
std::string workdir = "/tmp/tar_test";
193+
photon::fs::IFileSystem *fs;
194+
std::vector<std::string> filelist;
195+
};
196+
197+
TEST_F(ErofsTest, tar_meta) {
198+
unsigned char tar_zipped[249] = {
199+
0x1f, 0x8b, 0x08, 0x08, 0x7d, 0x06, 0x12, 0x67, 0x00, 0x03, 0x74,
200+
0x65, 0x73, 0x74, 0x2e, 0x74, 0x61, 0x72, 0x00, 0xed, 0xd7, 0x31,
201+
0x0e, 0xc2, 0x30, 0x0c, 0x85, 0xe1, 0xce, 0x9c, 0xa2, 0x47, 0x48,
202+
0x52, 0x27, 0x86, 0xe3, 0x14, 0xc4, 0x05, 0x68, 0xb8, 0x3f, 0x35,
203+
0xe9, 0xc0, 0xea, 0xc1, 0x2e, 0x92, 0xdf, 0xbf, 0x54, 0xea, 0xf2,
204+
0xb2, 0x7c, 0x52, 0xd2, 0x9f, 0x5b, 0x9f, 0x8c, 0x4b, 0x7b, 0x8d,
205+
0x48, 0xbe, 0x99, 0x6b, 0xfa, 0xfd, 0x1e, 0xd1, 0x94, 0x89, 0x13,
206+
0x51, 0xca, 0x39, 0xcb, 0xff, 0xd6, 0x5a, 0x99, 0xe6, 0x64, 0x7d,
207+
0x30, 0xe9, 0xbd, 0xf5, 0xf5, 0x35, 0xcf, 0x1e, 0x53, 0xff, 0xd8,
208+
0x7a, 0x7f, 0x5c, 0xce, 0x3e, 0x03, 0x3a, 0xaf, 0xbe, 0xfb, 0x2f,
209+
0xc6, 0x1b, 0x0a, 0xff, 0x85, 0x4b, 0x16, 0xff, 0x5c, 0x2b, 0xfc,
210+
0x7b, 0x04, 0xff, 0xb1, 0x13, 0xff, 0x8b, 0xf1, 0x86, 0xce, 0x3f,
211+
0x7f, 0xfd, 0x37, 0x82, 0x7f, 0x8f, 0xe0, 0x3f, 0x76, 0xe2, 0x9f,
212+
0x8c, 0x37, 0x54, 0xfe, 0x17, 0x1a, 0xfe, 0x17, 0xf8, 0xf7, 0x08,
213+
0xfe, 0x63, 0x27, 0xfe, 0xab, 0xf1, 0x86, 0xca, 0x3f, 0x8f, 0xfb,
214+
0x7f, 0xc3, 0xfd, 0xdf, 0x25, 0xf8, 0x8f, 0x9d, 0xf8, 0x6f, 0xc6,
215+
0x1b, 0x0a, 0xff, 0x4b, 0x2a, 0x65, 0xbc, 0xff, 0x71, 0xff, 0x77,
216+
0x09, 0xfe, 0x63, 0x27, 0xfe, 0xd9, 0x78, 0x43, 0xe7, 0x7f, 0xdc,
217+
0xff, 0x2b, 0xc3, 0xbf, 0x47, 0xf0, 0x1f, 0x3b, 0xf1, 0x7f, 0x35,
218+
0xde, 0x50, 0xf9, 0xdf, 0x1f, 0xfe, 0x78, 0xff, 0xfb, 0x05, 0xff,
219+
0xb1, 0x13, 0xff, 0x37, 0xe3, 0x0d, 0x8d, 0xff, 0x9c, 0x0f, 0xff,
220+
0x09, 0xfe, 0x3d, 0x82, 0x7f, 0x84, 0x10, 0x8a, 0xd9, 0x07, 0xbf,
221+
0x49, 0x1c, 0x0f, 0x00, 0x28, 0x00, 0x00
222+
};
223+
// set_log_output_level(0);
224+
ASSERT_EQ(0, inflate(tar_zipped, sizeof(tar_zipped)));
225+
226+
auto src_file = fs->open("test.tar", O_RDONLY, 0666);
227+
ASSERT_NE(nullptr, src_file);
228+
DEFER(delete src_file);
229+
auto verify_dev = createDevice("verify", src_file);
230+
auto tar = new LibErofs(verify_dev, 4096, false);
231+
ASSERT_EQ(0, tar->extract_tar(src_file, true, true));
232+
delete tar;
233+
234+
src_file->lseek(0, 0);
235+
236+
auto tar_idx = fs->open("test.tar.meta", O_TRUNC | O_CREAT | O_RDWR, 0644);
237+
auto imgfile = createDevice("mock", src_file);
238+
DEFER(delete imgfile;);
239+
auto tar2 = new UnTar(src_file, nullptr, 0, 4096, nullptr, true);
240+
auto obj_count = tar2->dump_tar_headers(tar_idx);
241+
EXPECT_NE(-1, obj_count);
242+
LOG_INFO("objects count: `", obj_count);
243+
tar_idx->lseek(0,0);
244+
delete tar2;
245+
246+
auto tar3 = new LibErofs(imgfile, 4096, true);
247+
ASSERT_EQ(0, tar3->extract_tar(tar_idx, true, true));
248+
delete tar3;
249+
EXPECT_EQ(0, do_verify(verify_dev, imgfile));
250+
delete tar_idx;
251+
}
252+
253+
int main(int argc, char **argv) {
254+
255+
::testing::InitGoogleTest(&argc, argv);
256+
photon::init(photon::INIT_EVENT_DEFAULT, photon::INIT_IO_DEFAULT);
257+
set_log_output_level(1);
258+
259+
auto ret = RUN_ALL_TESTS();
260+
(void)ret;
261+
262+
return 0;
263+
}

0 commit comments

Comments
 (0)