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