Skip to content

Commit 222aa97

Browse files
authored
Merge pull request #371 from runloopai/adam/zstd
Add zstd decompression support for overlaybd-apply
2 parents 0253222 + a618d27 commit 222aa97

File tree

5 files changed

+144
-1
lines changed

5 files changed

+144
-1
lines changed

src/overlaybd/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
add_subdirectory(registryfs)
22
add_subdirectory(lsmt)
33
add_subdirectory(zfile)
4+
add_subdirectory(zstd)
45
add_subdirectory(cache)
56
add_subdirectory(tar)
67
add_subdirectory(gzip)
@@ -16,6 +17,7 @@ target_link_libraries(overlaybd_lib INTERFACE
1617
registryfs_lib
1718
lsmt_lib
1819
zfile_lib
20+
zstd_lib
1921
cache_lib
2022
tar_lib
2123
gzip_lib

src/overlaybd/zstd/CMakeLists.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
file(GLOB SOURCE_ZSTD "*.cpp")
2+
3+
add_library(zstd_lib STATIC ${SOURCE_ZSTD})
4+
5+
target_include_directories(zstd_lib PUBLIC
6+
${PHOTON_INCLUDE_DIR}
7+
)
8+
9+
target_link_libraries(zstd_lib photon_static ${LIBZSTD})

src/overlaybd/zstd/zstdfile.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
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 "zstdfile.h"
18+
19+
#include <vector>
20+
21+
#include <fcntl.h>
22+
#include <zstd.h>
23+
#include <photon/common/alog.h>
24+
#include <photon/fs/filesystem.h>
25+
#include <photon/fs/virtual-file.h>
26+
27+
class ZStdAdaptorFile : public photon::fs::VirtualReadOnlyFile {
28+
public:
29+
ZStdAdaptorFile(photon::fs::IFile* file, bool ownership)
30+
: m_file(file)
31+
, m_ownership(ownership)
32+
, m_stream(ZSTD_createDStream())
33+
, m_buffer(ZSTD_DStreamInSize())
34+
, m_input({m_buffer.data(), 0, 0}) {
35+
}
36+
37+
~ZStdAdaptorFile() {
38+
ZSTD_freeDStream(m_stream);
39+
if (m_ownership) {
40+
delete m_file;
41+
}
42+
}
43+
44+
ssize_t read(void *buf, size_t count) override {
45+
ssize_t bytes_read = 0;
46+
ZSTD_outBuffer output = { buf, count, 0 };
47+
while (output.pos < output.size) {
48+
// Output buffer is not filled, read more.
49+
if (m_input.pos == m_input.size) {
50+
// Reached the end of the input buffer, read more compressed data.
51+
ssize_t read_compressed_bytes = m_file->read(m_buffer.data(), m_buffer.size());
52+
if (read_compressed_bytes == 0) {
53+
// EOF reached.
54+
return bytes_read;
55+
}
56+
if (read_compressed_bytes < 0 || read_compressed_bytes > (ssize_t) m_buffer.size()) {
57+
// Error reading file.
58+
LOG_ERRNO_RETURN(EIO, -1, "read buffer error");
59+
}
60+
m_input.size = read_compressed_bytes;
61+
m_input.pos = 0;
62+
}
63+
const size_t prev_pos = output.pos;
64+
const size_t ret = ZSTD_decompressStream(m_stream, &output, &m_input);
65+
if (ZSTD_isError(ret)) {
66+
LOG_ERRNO_RETURN(EIO, -1, "failed to decompress zstd frame");
67+
}
68+
bytes_read += output.pos - prev_pos;
69+
if (ret == 0) {
70+
// End of this ZSTD frame, set up for the next one (if there is one).
71+
ZSTD_initDStream(m_stream);
72+
}
73+
}
74+
return bytes_read;
75+
}
76+
77+
int fstat(struct stat *buf) override {
78+
return m_file->fstat(buf);
79+
}
80+
81+
UNIMPLEMENTED_POINTER(photon::fs::IFileSystem *filesystem() override);
82+
UNIMPLEMENTED(off_t lseek(off_t offset, int whence) override);
83+
UNIMPLEMENTED(ssize_t readv(const struct iovec *iov, int iovcnt) override);
84+
UNIMPLEMENTED(ssize_t preadv(const struct iovec *iov, int iovcnt, off_t offset) override);
85+
private:
86+
photon::fs::IFile* m_file;
87+
bool m_ownership; // whether we own m_file and should delete it.
88+
ZSTD_DStream* m_stream;
89+
90+
std::vector<uint8_t> m_buffer;
91+
ZSTD_inBuffer m_input;
92+
};
93+
94+
photon::fs::IFile *open_zstdfile_adaptor(photon::fs::IFile* file, bool ownership) {
95+
return new ZStdAdaptorFile(file, ownership);
96+
}
97+
98+
const uint8_t ZSTD_MAGIC_HEADER[4] = {0x28, 0xB5, 0x2F, 0xFD};
99+
100+
bool is_zstdfile(photon::fs::IFile* file) {
101+
char buf[4] = {0};
102+
ssize_t readn = file->read(buf, 4);
103+
file->lseek(0, 0);
104+
return readn == 4 && memcmp(buf, ZSTD_MAGIC_HEADER, 4) == 0;
105+
}

src/overlaybd/zstd/zstdfile.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
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+
#pragma once
18+
19+
#include <photon/fs/virtual-file.h>
20+
21+
// Opens a ZSTD compressed file and provides a view of the decompressed data.
22+
// Takes ownership of `file` when `ownership` is true (default).
23+
photon::fs::IFile* open_zstdfile_adaptor(photon::fs::IFile* file, bool ownership = true);
24+
25+
bool is_zstdfile(photon::fs::IFile* file);

src/tools/overlaybd-apply.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "../overlaybd/tar/libtar.h"
2626
#include "../overlaybd/gzindex/gzfile.h"
2727
#include "../overlaybd/gzip/gz.h"
28+
#include "../overlaybd/zstd/zstdfile.h"
2829
#include <errno.h>
2930
#include <fcntl.h>
3031
#include <inttypes.h>
@@ -100,7 +101,6 @@ int main(int argc, char **argv) {
100101
photon::init(photon::INIT_EVENT_DEFAULT, photon::INIT_IO_DEFAULT);
101102
DEFER({photon::fini();});
102103

103-
104104
ImageService *imgservice = nullptr;
105105
photon::fs::IFile *imgfile = nullptr;
106106
if (raw) {
@@ -141,6 +141,8 @@ int main(int argc, char **argv) {
141141
tarf->lseek(0, 0);
142142
}
143143
src_file = open_gzfile_adaptor(input_path.c_str());
144+
} else if (is_zstdfile(tarf)) {
145+
src_file = open_zstdfile_adaptor(tarf, /*ownership=*/false);
144146
} else {
145147
src_file = tarf;
146148
}

0 commit comments

Comments
 (0)