Directory: | cvmfs/ |
---|---|
File: | cvmfs/compression.cc |
Date: | 2024-05-05 02:33:21 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 412 | 530 | 77.7% |
Branches: | 221 | 448 | 49.3% |
Line | Branch | Exec | Source |
---|---|---|---|
1 | /** | ||
2 | * This file is part of the CernVM File System. | ||
3 | * | ||
4 | * This is a wrapper around zlib. It provides | ||
5 | * a set of functions to conveniently compress and decompress stuff. | ||
6 | * Almost all of the functions return true on success, otherwise false. | ||
7 | * | ||
8 | * TODO: think about code deduplication | ||
9 | */ | ||
10 | |||
11 | #include "cvmfs_config.h" | ||
12 | #include "compression.h" | ||
13 | |||
14 | #include <alloca.h> | ||
15 | #include <stdlib.h> | ||
16 | #include <sys/stat.h> | ||
17 | |||
18 | #include <algorithm> | ||
19 | #include <cassert> | ||
20 | #include <cstring> | ||
21 | |||
22 | #include "crypto/hash.h" | ||
23 | #include "util/exception.h" | ||
24 | #include "util/logging.h" | ||
25 | #include "util/platform.h" | ||
26 | #include "util/posix.h" | ||
27 | #include "util/smalloc.h" | ||
28 | |||
29 | using namespace std; // NOLINT | ||
30 | |||
31 | |||
32 | 8 | static bool CopyFile2File(FILE *fsrc, FILE *fdest) { | |
33 | unsigned char buf[1024]; | ||
34 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | rewind(fsrc); |
35 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | rewind(fdest); |
36 | |||
37 | size_t have; | ||
38 | do { | ||
39 |
1/2✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
|
23 | have = fread(buf, 1, 1024, fsrc); |
40 |
2/4✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 23 times.
|
23 | if (fwrite(buf, 1, have, fdest) != have) |
41 | ✗ | return false; | |
42 |
2/2✓ Branch 0 taken 15 times.
✓ Branch 1 taken 8 times.
|
23 | } while (have == 1024); |
43 | 8 | return true; | |
44 | } | ||
45 | |||
46 | 3 | bool CopyPath2File(const std::string &src, FILE *fdest) { | |
47 | 3 | int retval = -1; | |
48 | platform_stat64 info; | ||
49 | |||
50 |
1/2✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
|
3 | FILE *fsrc = fopen(src.c_str(), "r"); |
51 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
|
3 | if (!fsrc) goto file_copy_final; |
52 | |||
53 |
2/4✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 3 times.
|
3 | if (!CopyFile2File(fsrc, fdest)) goto file_copy_final; |
54 | 3 | retval = platform_fstat(fileno(fsrc), &info); | |
55 | 3 | retval |= fchmod(fileno(fdest), info.st_mode); | |
56 | |||
57 | 3 | file_copy_final: | |
58 |
2/4✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
|
3 | if (fsrc) fclose(fsrc); |
59 | 3 | return retval == 0; | |
60 | } | ||
61 | |||
62 | |||
63 | 5 | bool CopyPath2Path(const string &src, const string &dest) { | |
64 | 5 | FILE *fsrc = NULL; | |
65 | 5 | FILE *fdest = NULL; | |
66 | 5 | int retval = -1; | |
67 | platform_stat64 info; | ||
68 | |||
69 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | fsrc = fopen(src.c_str(), "r"); |
70 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (!fsrc) goto file_copy_final; |
71 | |||
72 |
1/2✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
|
5 | fdest = fopen(dest.c_str(), "w"); |
73 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | if (!fdest) goto file_copy_final; |
74 | |||
75 |
2/4✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
|
5 | if (!CopyFile2File(fsrc, fdest)) goto file_copy_final; |
76 | 5 | retval = platform_fstat(fileno(fsrc), &info); | |
77 | 5 | retval |= fchmod(fileno(fdest), info.st_mode); | |
78 | |||
79 | 5 | file_copy_final: | |
80 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | if (fsrc) fclose(fsrc); |
81 |
2/4✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 5 times.
✗ Branch 4 not taken.
|
5 | if (fdest) fclose(fdest); |
82 | 5 | return retval == 0; | |
83 | } | ||
84 | |||
85 | |||
86 | ✗ | bool CopyMem2File(const unsigned char *buffer, const unsigned buffer_size, | |
87 | FILE *fdest) | ||
88 | { | ||
89 | ✗ | int written = fwrite(buffer, 1, buffer_size, fdest); | |
90 | ✗ | return (written >=0) && (unsigned(written) == buffer_size); | |
91 | } | ||
92 | |||
93 | |||
94 | 49 | bool CopyMem2Path(const unsigned char *buffer, const unsigned buffer_size, | |
95 | const string &path) | ||
96 | { | ||
97 | 49 | int fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, kDefaultFileMode); | |
98 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 49 times.
|
49 | if (fd < 0) |
99 | ✗ | return false; | |
100 | |||
101 | 49 | int written = write(fd, buffer, buffer_size); | |
102 | 49 | close(fd); | |
103 | |||
104 |
2/4✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 49 times.
✗ Branch 3 not taken.
|
49 | return (written >=0) && (unsigned(written) == buffer_size); |
105 | } | ||
106 | |||
107 | |||
108 | 1 | bool CopyPath2Mem(const string &path, | |
109 | unsigned char **buffer, unsigned *buffer_size) | ||
110 | { | ||
111 | 1 | const int fd = open(path.c_str(), O_RDONLY); | |
112 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (fd < 0) |
113 | ✗ | return false; | |
114 | |||
115 | 1 | *buffer_size = 512; | |
116 | 1 | *buffer = reinterpret_cast<unsigned char *>(smalloc(*buffer_size)); | |
117 | 1 | unsigned total_bytes = 0; | |
118 | while (true) { | ||
119 | 2 | int num_bytes = read(fd, *buffer + total_bytes, *buffer_size - total_bytes); | |
120 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (num_bytes == 0) |
121 | 1 | break; | |
122 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (num_bytes < 0) { |
123 | ✗ | close(fd); | |
124 | ✗ | free(*buffer); | |
125 | ✗ | *buffer_size = 0; | |
126 | ✗ | return false; | |
127 | } | ||
128 | 1 | total_bytes += num_bytes; | |
129 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (total_bytes >= *buffer_size) { |
130 | ✗ | *buffer_size *= 2; | |
131 | ✗ | *buffer = | |
132 | ✗ | reinterpret_cast<unsigned char *>(srealloc(*buffer, *buffer_size)); | |
133 | } | ||
134 | 1 | } | |
135 | |||
136 | 1 | close(fd); | |
137 | 1 | *buffer_size = total_bytes; | |
138 | 1 | return true; | |
139 | } | ||
140 | |||
141 | namespace zlib { | ||
142 | |||
143 | const unsigned kBufferSize = 32768; | ||
144 | |||
145 | /** | ||
146 | * Aborts if string doesn't match any of the algorithms. | ||
147 | */ | ||
148 | ✗ | Algorithms ParseCompressionAlgorithm(const std::string &algorithm_option) { | |
149 | ✗ | if ((algorithm_option == "default") || (algorithm_option == "zlib")) | |
150 | ✗ | return kZlibDefault; | |
151 | ✗ | if (algorithm_option == "none") | |
152 | ✗ | return kNoCompression; | |
153 | ✗ | PANIC(kLogStderr, "unknown compression algorithms: %s", | |
154 | algorithm_option.c_str()); | ||
155 | } | ||
156 | |||
157 | |||
158 | ✗ | std::string AlgorithmName(const zlib::Algorithms alg) { | |
159 | ✗ | switch (alg) { | |
160 | ✗ | case kZlibDefault: | |
161 | ✗ | return "zlib"; | |
162 | break; | ||
163 | ✗ | case kNoCompression: | |
164 | ✗ | return "none"; | |
165 | break; | ||
166 | // Purposely did not add a 'default' statement here: this will | ||
167 | // cause the compiler to generate a warning if a new algorithm | ||
168 | // is added but this function is not updated. | ||
169 | } | ||
170 | ✗ | return "unknown"; | |
171 | } | ||
172 | |||
173 | |||
174 | 227 | void CompressInit(z_stream *strm) { | |
175 | 227 | strm->zalloc = Z_NULL; | |
176 | 227 | strm->zfree = Z_NULL; | |
177 | 227 | strm->opaque = Z_NULL; | |
178 | 227 | strm->next_in = Z_NULL; | |
179 | 227 | strm->avail_in = 0; | |
180 | 227 | int retval = deflateInit(strm, Z_DEFAULT_COMPRESSION); | |
181 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 227 times.
|
227 | assert(retval == 0); |
182 | 227 | } | |
183 | |||
184 | |||
185 | 236 | void DecompressInit(z_stream *strm) { | |
186 | 236 | strm->zalloc = Z_NULL; | |
187 | 236 | strm->zfree = Z_NULL; | |
188 | 236 | strm->opaque = Z_NULL; | |
189 | 236 | strm->avail_in = 0; | |
190 | 236 | strm->next_in = Z_NULL; | |
191 | 236 | int retval = inflateInit(strm); | |
192 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
|
236 | assert(retval == 0); |
193 | 236 | } | |
194 | |||
195 | |||
196 | 227 | void CompressFini(z_stream *strm) { | |
197 | 227 | (void)deflateEnd(strm); | |
198 | 227 | } | |
199 | |||
200 | |||
201 | 230 | void DecompressFini(z_stream *strm) { | |
202 | 230 | (void)inflateEnd(strm); | |
203 | 230 | } | |
204 | |||
205 | |||
206 | 4 | StreamStates CompressZStream2Null( | |
207 | const void *buf, | ||
208 | const int64_t size, | ||
209 | const bool eof, | ||
210 | z_stream *strm, | ||
211 | shash::ContextPtr *hash_context) | ||
212 | { | ||
213 | unsigned char out[kZChunk]; | ||
214 | int z_ret; | ||
215 | |||
216 | 4 | strm->avail_in = size; | |
217 | 4 | strm->next_in = static_cast<unsigned char *>(const_cast<void *>(buf)); | |
218 | // Run deflate() on input until output buffer not full, finish | ||
219 | // compression if all of source has been read in | ||
220 | do { | ||
221 | 4 | strm->avail_out = kZChunk; | |
222 | 4 | strm->next_out = out; | |
223 |
3/4✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
|
4 | z_ret = deflate(strm, eof ? Z_FINISH : Z_NO_FLUSH); // no bad return value |
224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (z_ret == Z_STREAM_ERROR) |
225 | ✗ | return kStreamDataError; | |
226 | 4 | size_t have = kZChunk - strm->avail_out; | |
227 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | shash::Update(out, have, *hash_context); |
228 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | } while (strm->avail_out == 0); |
229 | |||
230 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | return (z_ret == Z_STREAM_END ? kStreamEnd : kStreamContinue); |
231 | } | ||
232 | |||
233 | |||
234 | 124 | StreamStates DecompressZStream2Sink( | |
235 | const void *buf, | ||
236 | const int64_t size, | ||
237 | z_stream *strm, | ||
238 | cvmfs::Sink *sink) | ||
239 | { | ||
240 | unsigned char out[kZChunk]; | ||
241 | int z_ret; | ||
242 | 124 | int64_t pos = 0; | |
243 | |||
244 | do { | ||
245 | 124 | strm->avail_in = (kZChunk > (size-pos)) ? size-pos : kZChunk; | |
246 | 124 | strm->next_in = ((unsigned char *)buf)+pos; | |
247 | |||
248 | // Run inflate() on input until output buffer not full | ||
249 | do { | ||
250 | 201 | strm->avail_out = kZChunk; | |
251 | 201 | strm->next_out = out; | |
252 |
1/2✓ Branch 1 taken 201 times.
✗ Branch 2 not taken.
|
201 | z_ret = inflate(strm, Z_NO_FLUSH); |
253 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 201 times.
|
201 | switch (z_ret) { |
254 | ✗ | case Z_NEED_DICT: | |
255 | ✗ | z_ret = Z_DATA_ERROR; // and fall through | |
256 | ✗ | case Z_STREAM_ERROR: | |
257 | case Z_DATA_ERROR: | ||
258 | ✗ | return kStreamDataError; | |
259 | ✗ | case Z_MEM_ERROR: | |
260 | ✗ | return kStreamIOError; | |
261 | } | ||
262 | 201 | size_t have = kZChunk - strm->avail_out; | |
263 |
1/2✓ Branch 1 taken 201 times.
✗ Branch 2 not taken.
|
201 | int64_t written = sink->Write(out, have); |
264 |
2/4✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 201 times.
|
201 | if ((written < 0) || (static_cast<uint64_t>(written) != have)) |
265 | ✗ | return kStreamIOError; | |
266 |
2/2✓ Branch 0 taken 77 times.
✓ Branch 1 taken 124 times.
|
201 | } while (strm->avail_out == 0); |
267 | |||
268 | 124 | pos += kZChunk; | |
269 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 124 times.
|
124 | } while (pos < size); |
270 | |||
271 |
2/2✓ Branch 0 taken 119 times.
✓ Branch 1 taken 5 times.
|
124 | return (z_ret == Z_STREAM_END ? kStreamEnd : kStreamContinue); |
272 | } | ||
273 | |||
274 | |||
275 | 8 | StreamStates DecompressZStream2File( | |
276 | const void *buf, | ||
277 | const int64_t size, | ||
278 | z_stream *strm, | ||
279 | FILE *f) | ||
280 | { | ||
281 | unsigned char out[kZChunk]; | ||
282 | int z_ret; | ||
283 | 8 | int64_t pos = 0; | |
284 | |||
285 | do { | ||
286 | 8 | strm->avail_in = (kZChunk > (size-pos)) ? size-pos : kZChunk; | |
287 | 8 | strm->next_in = ((unsigned char *)buf)+pos; | |
288 | |||
289 | // Run inflate() on input until output buffer not full | ||
290 | do { | ||
291 | 11 | strm->avail_out = kZChunk; | |
292 | 11 | strm->next_out = out; | |
293 |
1/2✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
11 | z_ret = inflate(strm, Z_NO_FLUSH); |
294 |
1/4✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
|
11 | switch (z_ret) { |
295 | ✗ | case Z_NEED_DICT: | |
296 | ✗ | z_ret = Z_DATA_ERROR; // and fall through | |
297 | ✗ | case Z_STREAM_ERROR: | |
298 | case Z_DATA_ERROR: | ||
299 | ✗ | return kStreamDataError; | |
300 | ✗ | case Z_MEM_ERROR: | |
301 | ✗ | return kStreamIOError; | |
302 | } | ||
303 | 11 | size_t have = kZChunk - strm->avail_out; | |
304 |
4/9✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 11 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 11 times.
|
11 | if (fwrite(out, 1, have, f) != have || ferror(f)) { |
305 | ✗ | LogCvmfs(kLogCompress, kLogDebug, "Inflate to file failed with %s " | |
306 | ✗ | "(errno=%d)", strerror(errno), errno); | |
307 | ✗ | return kStreamIOError; | |
308 | } | ||
309 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 8 times.
|
11 | } while (strm->avail_out == 0); |
310 | |||
311 | 8 | pos += kZChunk; | |
312 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | } while (pos < size); |
313 | |||
314 |
1/2✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
|
8 | return (z_ret == Z_STREAM_END ? kStreamEnd : kStreamContinue); |
315 | } | ||
316 | |||
317 | |||
318 | 44 | bool CompressPath2Path(const string &src, const string &dest) { | |
319 | 44 | FILE *fsrc = fopen(src.c_str(), "r"); | |
320 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (!fsrc) { |
321 | ✗ | LogCvmfs(kLogCompress, kLogDebug, "open %s as compression source failed", | |
322 | src.c_str()); | ||
323 | ✗ | return false; | |
324 | } | ||
325 | |||
326 | 44 | FILE *fdest = fopen(dest.c_str(), "w"); | |
327 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (!fdest) { |
328 | ✗ | LogCvmfs(kLogCompress, kLogDebug, "open %s as compression destination " | |
329 | ✗ | "failed with errno=%d", dest.c_str(), errno); | |
330 | ✗ | fclose(fsrc); | |
331 | ✗ | return false; | |
332 | } | ||
333 | |||
334 | 44 | LogCvmfs(kLogCompress, kLogDebug, "opened %s and %s for compression", | |
335 | src.c_str(), dest.c_str()); | ||
336 | 44 | const bool result = CompressFile2File(fsrc, fdest); | |
337 | |||
338 | 44 | fclose(fsrc); | |
339 | 44 | fclose(fdest); | |
340 | 44 | return result; | |
341 | } | ||
342 | |||
343 | |||
344 | 102 | bool CompressPath2Path(const string &src, const string &dest, | |
345 | shash::Any *compressed_hash) | ||
346 | { | ||
347 |
1/2✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
|
102 | FILE *fsrc = fopen(src.c_str(), "r"); |
348 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | if (!fsrc) { |
349 | ✗ | LogCvmfs(kLogCompress, kLogDebug, "open %s as compression source failed", | |
350 | src.c_str()); | ||
351 | ✗ | return false; | |
352 | } | ||
353 | |||
354 |
1/2✓ Branch 2 taken 102 times.
✗ Branch 3 not taken.
|
102 | FILE *fdest = fopen(dest.c_str(), "w"); |
355 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | if (!fdest) { |
356 | ✗ | LogCvmfs(kLogCompress, kLogDebug, "open %s as compression destination " | |
357 | ✗ | "failed with errno=%d", dest.c_str(), errno); | |
358 | ✗ | fclose(fsrc); | |
359 | ✗ | return false; | |
360 | } | ||
361 | |||
362 |
1/2✓ Branch 3 taken 102 times.
✗ Branch 4 not taken.
|
102 | LogCvmfs(kLogCompress, kLogDebug, "opened %s and %s for compression", |
363 | src.c_str(), dest.c_str()); | ||
364 | 102 | bool result = false; | |
365 |
2/4✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 102 times.
|
102 | if (!CompressFile2File(fsrc, fdest, compressed_hash)) |
366 | ✗ | goto compress_path2path_final; | |
367 | platform_stat64 info; | ||
368 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
|
102 | if (platform_fstat(fileno(fsrc), &info) != 0) goto compress_path2path_final; |
369 | // TODO(jakob): open in the right mode from the beginning | ||
370 |
1/2✗ Branch 2 not taken.
✓ Branch 3 taken 102 times.
|
102 | if (fchmod(fileno(fdest), info.st_mode) != 0) goto compress_path2path_final; |
371 | |||
372 | 102 | result = true; | |
373 | |||
374 | 102 | compress_path2path_final: | |
375 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | fclose(fsrc); |
376 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | fclose(fdest); |
377 | 102 | return result; | |
378 | } | ||
379 | |||
380 | |||
381 | ✗ | bool DecompressPath2Path(const string &src, const string &dest) { | |
382 | ✗ | FILE *fsrc = NULL; | |
383 | ✗ | FILE *fdest = NULL; | |
384 | ✗ | int result = false; | |
385 | |||
386 | ✗ | fsrc = fopen(src.c_str(), "r"); | |
387 | ✗ | if (!fsrc) goto decompress_path2path_final; | |
388 | |||
389 | ✗ | fdest = fopen(dest.c_str(), "w"); | |
390 | ✗ | if (!fdest) goto decompress_path2path_final; | |
391 | |||
392 | ✗ | result = DecompressFile2File(fsrc, fdest); | |
393 | |||
394 | ✗ | decompress_path2path_final: | |
395 | ✗ | if (fsrc) fclose(fsrc); | |
396 | ✗ | if (fdest) fclose(fdest); | |
397 | ✗ | return result; | |
398 | } | ||
399 | |||
400 | |||
401 | 44 | bool CompressFile2Null(FILE *fsrc, shash::Any *compressed_hash) { | |
402 | 44 | int z_ret = 0; | |
403 | 44 | int flush = 0; | |
404 | 44 | bool result = -1; | |
405 | unsigned have; | ||
406 | z_stream strm; | ||
407 | unsigned char in[kZChunk]; | ||
408 | unsigned char out[kZChunk]; | ||
409 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | shash::ContextPtr hash_context(compressed_hash->algorithm); |
410 | |||
411 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | CompressInit(&strm); |
412 | 44 | hash_context.buffer = alloca(hash_context.size); | |
413 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | shash::Init(hash_context); |
414 | |||
415 | // Compress until end of file | ||
416 | do { | ||
417 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | strm.avail_in = fread(in, 1, kZChunk, fsrc); |
418 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if (ferror(fsrc)) goto compress_file2null_final; |
419 | |||
420 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | flush = feof(fsrc) ? Z_FINISH : Z_NO_FLUSH; |
421 | 44 | strm.next_in = in; | |
422 | |||
423 | // Run deflate() on input until output buffer not full, finish | ||
424 | // compression if all of source has been read in | ||
425 | do { | ||
426 | 44 | strm.avail_out = kZChunk; | |
427 | 44 | strm.next_out = out; | |
428 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | z_ret = deflate(&strm, flush); // no bad return value |
429 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (z_ret == Z_STREAM_ERROR) |
430 | ✗ | goto compress_file2null_final; // state not clobbered | |
431 | 44 | have = kZChunk - strm.avail_out; | |
432 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | shash::Update(out, have, hash_context); |
433 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | } while (strm.avail_out == 0); |
434 | |||
435 | // Done when last data in file processed | ||
436 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | } while (flush != Z_FINISH); |
437 | |||
438 | // stream will be complete | ||
439 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (z_ret != Z_STREAM_END) goto compress_file2null_final; |
440 | |||
441 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | shash::Final(hash_context, compressed_hash); |
442 | 44 | result = true; | |
443 | |||
444 | // Clean up and return | ||
445 | 44 | compress_file2null_final: | |
446 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | CompressFini(&strm); |
447 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d", |
448 | result); | ||
449 | 44 | return result; | |
450 | } | ||
451 | |||
452 | |||
453 | 2 | bool CompressFd2Null(int fd_src, shash::Any *compressed_hash, | |
454 | uint64_t *processed_bytes) { | ||
455 | 2 | int z_ret = 0; | |
456 | 2 | int flush = 0; | |
457 | 2 | bool result = false; | |
458 | unsigned have; | ||
459 | z_stream strm; | ||
460 | unsigned char in[kZChunk]; | ||
461 | unsigned char out[kZChunk]; | ||
462 | 2 | off_t cksum_bytes = 0; | |
463 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | shash::ContextPtr hash_context(compressed_hash->algorithm); |
464 | |||
465 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | CompressInit(&strm); |
466 | 2 | hash_context.buffer = alloca(hash_context.size); | |
467 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | shash::Init(hash_context); |
468 | |||
469 | // Compress until end of file | ||
470 | do { | ||
471 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | ssize_t bytes_read = read(fd_src, in, kZChunk); |
472 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (bytes_read < 0) { |
473 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (errno == EINTR) {continue;} |
474 | 1 | goto compress_fd2null_final; | |
475 | } | ||
476 | 1 | cksum_bytes += bytes_read; | |
477 | 1 | strm.avail_in = bytes_read; | |
478 | |||
479 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | flush = (static_cast<size_t>(bytes_read) < kZChunk) ? Z_FINISH : Z_NO_FLUSH; |
480 | 1 | strm.next_in = in; | |
481 | |||
482 | // Run deflate() on input until output buffer not full, finish | ||
483 | // compression if all of source has been read in | ||
484 | do { | ||
485 | 1 | strm.avail_out = kZChunk; | |
486 | 1 | strm.next_out = out; | |
487 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | z_ret = deflate(&strm, flush); // no bad return value |
488 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (z_ret == Z_STREAM_ERROR) |
489 | ✗ | goto compress_fd2null_final; // state not clobbered | |
490 | 1 | have = kZChunk - strm.avail_out; | |
491 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | shash::Update(out, have, hash_context); |
492 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } while (strm.avail_out == 0); |
493 | |||
494 | // Done when last data in file processed | ||
495 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } while (flush != Z_FINISH); |
496 | |||
497 | // stream will be complete | ||
498 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (z_ret != Z_STREAM_END) goto compress_fd2null_final; |
499 | |||
500 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | shash::Final(hash_context, compressed_hash); |
501 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (processed_bytes) { |
502 | 1 | *processed_bytes = cksum_bytes; | |
503 | } | ||
504 | 1 | result = true; | |
505 | |||
506 | // Clean up and return | ||
507 | 2 | compress_fd2null_final: | |
508 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | CompressFini(&strm); |
509 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d", |
510 | result); | ||
511 | 2 | return result; | |
512 | } | ||
513 | |||
514 | |||
515 | 44 | bool CompressPath2Null(const string &src, shash::Any *compressed_hash) { | |
516 | 44 | FILE *fsrc = fopen(src.c_str(), "r"); | |
517 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (fsrc == NULL) |
518 | ✗ | return false; | |
519 | 44 | bool retval = CompressFile2Null(fsrc, compressed_hash); | |
520 | 44 | fclose(fsrc); | |
521 | 44 | return retval; | |
522 | } | ||
523 | |||
524 | |||
525 | 44 | bool CompressFile2File(FILE *fsrc, FILE *fdest) { | |
526 | 44 | int z_ret = 0; | |
527 | 44 | int flush = 0; | |
528 | 44 | bool result = false; | |
529 | unsigned have; | ||
530 | z_stream strm; | ||
531 | unsigned char in[kZChunk]; | ||
532 | unsigned char out[kZChunk]; | ||
533 | |||
534 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | CompressInit(&strm); |
535 | |||
536 | // Compress until end of file | ||
537 | do { | ||
538 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | strm.avail_in = fread(in, 1, kZChunk, fsrc); |
539 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 44 times.
|
44 | if (ferror(fsrc)) goto compress_file2file_final; |
540 | |||
541 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | flush = feof(fsrc) ? Z_FINISH : Z_NO_FLUSH; |
542 | 44 | strm.next_in = in; | |
543 | |||
544 | // Run deflate() on input until output buffer not full, finish | ||
545 | // compression if all of source has been read in | ||
546 | do { | ||
547 | 44 | strm.avail_out = kZChunk; | |
548 | 44 | strm.next_out = out; | |
549 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | z_ret = deflate(&strm, flush); // no bad return value |
550 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (z_ret == Z_STREAM_ERROR) |
551 | ✗ | goto compress_file2file_final; // state not clobbered | |
552 | 44 | have = kZChunk - strm.avail_out; | |
553 |
4/9✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 44 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 44 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 44 times.
|
44 | if (fwrite(out, 1, have, fdest) != have || ferror(fdest)) |
554 | ✗ | goto compress_file2file_final; | |
555 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | } while (strm.avail_out == 0); |
556 | |||
557 | // Done when last data in file processed | ||
558 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | } while (flush != Z_FINISH); |
559 | |||
560 | // stream will be complete | ||
561 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
|
44 | if (z_ret != Z_STREAM_END) goto compress_file2file_final; |
562 | |||
563 | 44 | result = true; | |
564 | |||
565 | // Clean up and return | ||
566 | 44 | compress_file2file_final: | |
567 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | CompressFini(&strm); |
568 |
1/2✓ Branch 1 taken 44 times.
✗ Branch 2 not taken.
|
44 | LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d", |
569 | result); | ||
570 | 44 | return result; | |
571 | } | ||
572 | |||
573 | ✗ | bool CompressPath2File(const string &src, FILE *fdest, | |
574 | shash::Any *compressed_hash) | ||
575 | { | ||
576 | ✗ | FILE *fsrc = fopen(src.c_str(), "r"); | |
577 | ✗ | if (!fsrc) | |
578 | ✗ | return false; | |
579 | |||
580 | ✗ | bool retval = CompressFile2File(fsrc, fdest, compressed_hash); | |
581 | ✗ | fclose(fsrc); | |
582 | ✗ | return retval; | |
583 | } | ||
584 | |||
585 | |||
586 | 102 | bool CompressFile2File(FILE *fsrc, FILE *fdest, shash::Any *compressed_hash) { | |
587 | 102 | int z_ret = 0; | |
588 | 102 | int flush = 0; | |
589 | 102 | bool result = false; | |
590 | unsigned have; | ||
591 | z_stream strm; | ||
592 | unsigned char in[kZChunk]; | ||
593 | unsigned char out[kZChunk]; | ||
594 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | shash::ContextPtr hash_context(compressed_hash->algorithm); |
595 | |||
596 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | CompressInit(&strm); |
597 | 102 | hash_context.buffer = alloca(hash_context.size); | |
598 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | shash::Init(hash_context); |
599 | |||
600 | // Compress until end of file | ||
601 | do { | ||
602 |
1/2✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
|
144 | strm.avail_in = fread(in, 1, kZChunk, fsrc); |
603 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 144 times.
|
144 | if (ferror(fsrc)) goto compress_file2file_hashed_final; |
604 | |||
605 |
2/2✓ Branch 1 taken 102 times.
✓ Branch 2 taken 42 times.
|
144 | flush = feof(fsrc) ? Z_FINISH : Z_NO_FLUSH; |
606 | 144 | strm.next_in = in; | |
607 | |||
608 | // Run deflate() on input until output buffer not full, finish | ||
609 | // compression if all of source has been read in | ||
610 | do { | ||
611 | 144 | strm.avail_out = kZChunk; | |
612 | 144 | strm.next_out = out; | |
613 |
1/2✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
|
144 | z_ret = deflate(&strm, flush); // no bad return value |
614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
|
144 | if (z_ret == Z_STREAM_ERROR) |
615 | ✗ | goto compress_file2file_hashed_final; // state not clobbered | |
616 | 144 | have = kZChunk - strm.avail_out; | |
617 |
4/9✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 144 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 144 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 144 times.
|
144 | if (fwrite(out, 1, have, fdest) != have || ferror(fdest)) |
618 | ✗ | goto compress_file2file_hashed_final; | |
619 |
1/2✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
|
144 | shash::Update(out, have, hash_context); |
620 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
|
144 | } while (strm.avail_out == 0); |
621 | |||
622 | // Done when last data in file processed | ||
623 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 102 times.
|
144 | } while (flush != Z_FINISH); |
624 | |||
625 | // Stream will be complete | ||
626 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 102 times.
|
102 | if (z_ret != Z_STREAM_END) goto compress_file2file_hashed_final; |
627 | |||
628 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | shash::Final(hash_context, compressed_hash); |
629 | 102 | result = true; | |
630 | |||
631 | // Clean up and return | ||
632 | 102 | compress_file2file_hashed_final: | |
633 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | CompressFini(&strm); |
634 |
1/2✓ Branch 1 taken 102 times.
✗ Branch 2 not taken.
|
102 | LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d", |
635 | result); | ||
636 | 102 | return result; | |
637 | } | ||
638 | |||
639 | |||
640 | 10 | bool DecompressFile2File(FILE *fsrc, FILE *fdest) { | |
641 | 10 | bool result = false; | |
642 | 10 | StreamStates stream_state = kStreamIOError; | |
643 | z_stream strm; | ||
644 | size_t have; | ||
645 | unsigned char buf[kBufferSize]; | ||
646 | |||
647 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | DecompressInit(&strm); |
648 | |||
649 |
3/4✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✓ Branch 4 taken 10 times.
|
18 | while ((have = fread(buf, 1, kBufferSize, fsrc)) > 0) { |
650 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | stream_state = DecompressZStream2File(buf, have, &strm, fdest); |
651 |
2/4✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
|
8 | if ((stream_state == kStreamDataError) || (stream_state == kStreamIOError)) |
652 | ✗ | goto decompress_file2file_final; | |
653 | } | ||
654 |
1/2✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
10 | LogCvmfs(kLogCompress, kLogDebug, "end of decompression, state=%d, error=%d", |
655 | stream_state, ferror(fsrc)); | ||
656 |
5/6✓ Branch 0 taken 8 times.
✓ Branch 1 taken 2 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 8 times.
|
10 | if ((stream_state != kStreamEnd) || ferror(fsrc)) |
657 | 2 | goto decompress_file2file_final; | |
658 | |||
659 | 8 | result = true; | |
660 | |||
661 | 10 | decompress_file2file_final: | |
662 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | DecompressFini(&strm); |
663 | 10 | return result; | |
664 | } | ||
665 | |||
666 | |||
667 | 10 | bool DecompressPath2File(const string &src, FILE *fdest) { | |
668 | 10 | FILE *fsrc = fopen(src.c_str(), "r"); | |
669 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (!fsrc) |
670 | ✗ | return false; | |
671 | |||
672 | 10 | bool retval = DecompressFile2File(fsrc, fdest); | |
673 | 10 | fclose(fsrc); | |
674 | 10 | return retval; | |
675 | } | ||
676 | |||
677 | |||
678 | 1 | bool CompressMem2File(const unsigned char *buf, const size_t size, | |
679 | FILE *fdest, shash::Any *compressed_hash) { | ||
680 | 1 | int z_ret = 0; | |
681 | 1 | int flush = 0; | |
682 | 1 | bool result = false; | |
683 | unsigned have; | ||
684 | z_stream strm; | ||
685 | 1 | size_t offset = 0; | |
686 | 1 | size_t used = 0; | |
687 | unsigned char out[kZChunk]; | ||
688 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | shash::ContextPtr hash_context(compressed_hash->algorithm); |
689 | |||
690 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | CompressInit(&strm); |
691 | 1 | hash_context.buffer = alloca(hash_context.size); | |
692 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | shash::Init(hash_context); |
693 | |||
694 | // Compress the given memory buffer | ||
695 | do { | ||
696 | 5 | used = min(static_cast<size_t>(kZChunk), size - offset); | |
697 | 5 | strm.avail_in = used; | |
698 | |||
699 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
|
5 | flush = (strm.avail_in < kZChunk) ? Z_FINISH : Z_NO_FLUSH; |
700 | 5 | strm.next_in = const_cast<unsigned char*>(buf + offset); | |
701 | |||
702 | // Run deflate() on input until output buffer not full, finish | ||
703 | // compression if all of source has been read in | ||
704 | do { | ||
705 | 8 | strm.avail_out = kZChunk; | |
706 | 8 | strm.next_out = out; | |
707 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | z_ret = deflate(&strm, flush); // no bad return value |
708 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (z_ret == Z_STREAM_ERROR) |
709 | ✗ | goto compress_file2file_hashed_final; // state not clobbered | |
710 | 8 | have = kZChunk - strm.avail_out; | |
711 |
4/9✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 8 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 8 times.
|
8 | if (fwrite(out, 1, have, fdest) != have || ferror(fdest)) |
712 | ✗ | goto compress_file2file_hashed_final; | |
713 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | shash::Update(out, have, hash_context); |
714 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
|
8 | } while (strm.avail_out == 0); |
715 | |||
716 | 5 | offset += used; | |
717 | |||
718 | // Done when last data in file processed | ||
719 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
|
5 | } while (flush != Z_FINISH); |
720 | |||
721 | // Stream will be complete | ||
722 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (z_ret != Z_STREAM_END) goto compress_file2file_hashed_final; |
723 | |||
724 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | shash::Final(hash_context, compressed_hash); |
725 | 1 | result = true; | |
726 | |||
727 | // Clean up and return | ||
728 | 1 | compress_file2file_hashed_final: | |
729 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | CompressFini(&strm); |
730 |
1/2✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
1 | LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d", |
731 | result); | ||
732 | 1 | return result; | |
733 | } | ||
734 | |||
735 | |||
736 | /** | ||
737 | * User of this function has to free out_buf. | ||
738 | */ | ||
739 | 30 | bool CompressMem2Mem(const void *buf, const int64_t size, | |
740 | void **out_buf, uint64_t *out_size) | ||
741 | { | ||
742 | unsigned char out[kZChunk]; | ||
743 | int z_ret; | ||
744 | int flush; | ||
745 | z_stream strm; | ||
746 | 30 | int64_t pos = 0; | |
747 | 30 | uint64_t alloc_size = kZChunk; | |
748 | |||
749 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | CompressInit(&strm); |
750 | 30 | *out_buf = smalloc(alloc_size); | |
751 | 30 | *out_size = 0; | |
752 | |||
753 | do { | ||
754 | 1053 | strm.avail_in = (kZChunk > (size-pos)) ? size-pos : kZChunk; | |
755 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 1023 times.
|
1053 | flush = (pos + kZChunk) >= size ? Z_FINISH : Z_NO_FLUSH; |
756 | 1053 | strm.next_in = ((unsigned char *)buf) + pos; | |
757 | |||
758 | // Run deflate() on input until output buffer not full | ||
759 | do { | ||
760 | 1069 | strm.avail_out = kZChunk; | |
761 | 1069 | strm.next_out = out; | |
762 |
1/2✓ Branch 1 taken 1069 times.
✗ Branch 2 not taken.
|
1069 | z_ret = deflate(&strm, flush); |
763 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1069 times.
|
1069 | if (z_ret == Z_STREAM_ERROR) { |
764 | ✗ | CompressFini(&strm); | |
765 | ✗ | free(*out_buf); | |
766 | ✗ | *out_buf = NULL; | |
767 | ✗ | *out_size = 0; | |
768 | ✗ | return false; | |
769 | } | ||
770 | 1069 | size_t have = kZChunk - strm.avail_out; | |
771 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1064 times.
|
1069 | if (*out_size+have > alloc_size) { |
772 | 5 | alloc_size *= 2; | |
773 | 5 | *out_buf = srealloc(*out_buf, alloc_size); | |
774 | } | ||
775 | 1069 | memcpy(static_cast<unsigned char *>(*out_buf) + *out_size, out, have); | |
776 | 1069 | *out_size += have; | |
777 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 1053 times.
|
1069 | } while (strm.avail_out == 0); |
778 | |||
779 | 1053 | pos += kZChunk; | |
780 |
2/2✓ Branch 0 taken 1023 times.
✓ Branch 1 taken 30 times.
|
1053 | } while (flush != Z_FINISH); |
781 | |||
782 |
1/2✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
|
30 | CompressFini(&strm); |
783 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (z_ret != Z_STREAM_END) { |
784 | ✗ | free(*out_buf); | |
785 | ✗ | *out_buf = NULL; | |
786 | ✗ | *out_size = 0; | |
787 | ✗ | return false; | |
788 | } else { | ||
789 | 30 | return true; | |
790 | } | ||
791 | } | ||
792 | |||
793 | |||
794 | /** | ||
795 | * User of this function has to free out_buf. | ||
796 | */ | ||
797 | 91 | bool DecompressMem2Mem(const void *buf, const int64_t size, | |
798 | void **out_buf, uint64_t *out_size) | ||
799 | { | ||
800 | unsigned char out[kZChunk]; | ||
801 | int z_ret; | ||
802 | z_stream strm; | ||
803 | 91 | int64_t pos = 0; | |
804 | 91 | uint64_t alloc_size = kZChunk; | |
805 | |||
806 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | DecompressInit(&strm); |
807 | 91 | *out_buf = smalloc(alloc_size); | |
808 | 91 | *out_size = 0; | |
809 | |||
810 | do { | ||
811 | 92 | strm.avail_in = (kZChunk > (size-pos)) ? size-pos : kZChunk; | |
812 | 92 | strm.next_in = ((unsigned char *)buf)+pos; | |
813 | |||
814 | // Run inflate() on input until output buffer not full | ||
815 | do { | ||
816 | 1371 | strm.avail_out = kZChunk; | |
817 | 1371 | strm.next_out = out; | |
818 |
1/2✓ Branch 1 taken 1371 times.
✗ Branch 2 not taken.
|
1371 | z_ret = inflate(&strm, Z_NO_FLUSH); |
819 |
1/3✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1371 times.
|
1371 | switch (z_ret) { |
820 | ✗ | case Z_NEED_DICT: | |
821 | ✗ | z_ret = Z_DATA_ERROR; // and fall through | |
822 | ✗ | case Z_STREAM_ERROR: | |
823 | case Z_DATA_ERROR: | ||
824 | case Z_MEM_ERROR: | ||
825 | ✗ | DecompressFini(&strm); | |
826 | ✗ | free(*out_buf); | |
827 | ✗ | *out_buf = NULL; | |
828 | ✗ | *out_size = 0; | |
829 | ✗ | return false; | |
830 | } | ||
831 | 1371 | size_t have = kZChunk - strm.avail_out; | |
832 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1360 times.
|
1371 | if (*out_size+have > alloc_size) { |
833 | 11 | alloc_size *= 2; | |
834 | 11 | *out_buf = srealloc(*out_buf, alloc_size); | |
835 | } | ||
836 | 1371 | memcpy(static_cast<unsigned char *>(*out_buf) + *out_size, out, have); | |
837 | 1371 | *out_size += have; | |
838 |
2/2✓ Branch 0 taken 1279 times.
✓ Branch 1 taken 92 times.
|
1371 | } while (strm.avail_out == 0); |
839 | |||
840 | 92 | pos += kZChunk; | |
841 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 91 times.
|
92 | } while (pos < size); |
842 | |||
843 |
1/2✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
|
91 | DecompressFini(&strm); |
844 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
|
91 | if (z_ret != Z_STREAM_END) { |
845 | ✗ | free(*out_buf); | |
846 | ✗ | *out_buf = NULL; | |
847 | ✗ | *out_size = 0; | |
848 | ✗ | return false; | |
849 | } | ||
850 | |||
851 | 91 | return true; | |
852 | } | ||
853 | |||
854 | |||
855 | //------------------------------------------------------------------------------ | ||
856 | |||
857 | |||
858 | 1 | void Compressor::RegisterPlugins() { | |
859 | 1 | RegisterPlugin<ZlibCompressor>(); | |
860 | 1 | RegisterPlugin<EchoCompressor>(); | |
861 | 1 | } | |
862 | |||
863 | |||
864 | //------------------------------------------------------------------------------ | ||
865 | |||
866 | |||
867 | 249548 | bool ZlibCompressor::WillHandle(const zlib::Algorithms &alg) { | |
868 | 249548 | return alg == kZlibDefault; | |
869 | } | ||
870 | |||
871 | |||
872 | 249481 | ZlibCompressor::ZlibCompressor(const Algorithms &alg) | |
873 | 249481 | : Compressor(alg) | |
874 | { | ||
875 | 249518 | stream_.zalloc = Z_NULL; | |
876 | 249518 | stream_.zfree = Z_NULL; | |
877 | 249518 | stream_.opaque = Z_NULL; | |
878 | 249518 | stream_.next_in = Z_NULL; | |
879 | 249518 | stream_.avail_in = 0; | |
880 |
1/2✓ Branch 1 taken 250414 times.
✗ Branch 2 not taken.
|
249518 | const int zlib_retval = deflateInit(&stream_, Z_DEFAULT_COMPRESSION); |
881 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 250414 times.
|
250414 | assert(zlib_retval == 0); |
882 | 250414 | } | |
883 | |||
884 | |||
885 | ✗ | Compressor* ZlibCompressor::Clone() { | |
886 | ✗ | ZlibCompressor* other = new ZlibCompressor(zlib::kZlibDefault); | |
887 | ✗ | assert(stream_.avail_in == 0); | |
888 | // Delete the other stream | ||
889 | ✗ | int retcode = deflateEnd(&other->stream_); | |
890 | ✗ | assert(retcode == Z_OK); | |
891 | ✗ | retcode = deflateCopy(const_cast<z_streamp>(&other->stream_), &stream_); | |
892 | ✗ | assert(retcode == Z_OK); | |
893 | ✗ | return other; | |
894 | } | ||
895 | |||
896 | 648933 | bool ZlibCompressor::Deflate( | |
897 | const bool flush, | ||
898 | unsigned char **inbuf, size_t *inbufsize, | ||
899 | unsigned char **outbuf, size_t *outbufsize) | ||
900 | { | ||
901 | // Adding compression | ||
902 | 648933 | stream_.avail_in = *inbufsize; | |
903 | 648933 | stream_.next_in = *inbuf; | |
904 |
2/2✓ Branch 0 taken 250719 times.
✓ Branch 1 taken 398214 times.
|
648933 | const int flush_int = (flush) ? Z_FINISH : Z_NO_FLUSH; |
905 | 648933 | int retcode = 0; | |
906 | |||
907 | // TODO(jblomer) Figure out what exactly behaves differently with zlib 1.2.10 | ||
908 | // if ((*inbufsize == 0) && !flush) | ||
909 | // return true; | ||
910 | |||
911 | 648933 | stream_.avail_out = *outbufsize; | |
912 | 648933 | stream_.next_out = *outbuf; | |
913 | |||
914 | // Deflate in zlib! | ||
915 | 648933 | retcode = deflate(&stream_, flush_int); | |
916 |
3/4✓ Branch 0 taken 250414 times.
✓ Branch 1 taken 400121 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 250414 times.
|
650535 | assert(retcode == Z_OK || retcode == Z_STREAM_END); |
917 | |||
918 | 650535 | *outbufsize -= stream_.avail_out; | |
919 | 650535 | *inbuf = stream_.next_in; | |
920 | 650535 | *inbufsize = stream_.avail_in; | |
921 | |||
922 |
3/4✓ Branch 0 taken 399513 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67579 times.
✓ Branch 3 taken 331934 times.
|
399510 | return (flush_int == Z_NO_FLUSH && retcode == Z_OK && stream_.avail_in == 0) |
923 |
6/6✓ Branch 0 taken 399510 times.
✓ Branch 1 taken 251025 times.
✓ Branch 2 taken 250986 times.
✓ Branch 3 taken 67615 times.
✓ Branch 4 taken 250022 times.
✓ Branch 5 taken 964 times.
|
1050045 | || (flush_int == Z_FINISH && retcode == Z_STREAM_END); |
924 | } | ||
925 | |||
926 | |||
927 | 999114 | ZlibCompressor::~ZlibCompressor() { | |
928 | 499490 | int retcode = deflateEnd(&stream_); | |
929 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 250378 times.
|
500756 | assert(retcode == Z_OK); |
930 | 1000380 | } | |
931 | |||
932 | |||
933 | 1 | size_t ZlibCompressor::DeflateBound(const size_t bytes) { | |
934 | // Call zlib's deflate bound | ||
935 | 1 | return deflateBound(&stream_, bytes); | |
936 | } | ||
937 | |||
938 | |||
939 | //------------------------------------------------------------------------------ | ||
940 | |||
941 | |||
942 | 3 | EchoCompressor::EchoCompressor(const zlib::Algorithms &alg): | |
943 | 3 | Compressor(alg) | |
944 | { | ||
945 | 3 | } | |
946 | |||
947 | |||
948 | 3 | bool EchoCompressor::WillHandle(const zlib::Algorithms &alg) { | |
949 | 3 | return alg == kNoCompression; | |
950 | } | ||
951 | |||
952 | |||
953 | ✗ | Compressor* EchoCompressor::Clone() { | |
954 | ✗ | return new EchoCompressor(zlib::kNoCompression); | |
955 | } | ||
956 | |||
957 | |||
958 | 209718 | bool EchoCompressor::Deflate( | |
959 | const bool flush, | ||
960 | unsigned char **inbuf, size_t *inbufsize, | ||
961 | unsigned char **outbuf, size_t *outbufsize) | ||
962 | { | ||
963 | 209718 | size_t bytes_to_copy = min(*outbufsize, *inbufsize); | |
964 | 209718 | memcpy(*outbuf, *inbuf, bytes_to_copy); | |
965 | 209718 | const bool done = (bytes_to_copy == *inbufsize); | |
966 | |||
967 | // Update the return variables | ||
968 | 209718 | *inbuf += bytes_to_copy; | |
969 | 209718 | *outbufsize = bytes_to_copy; | |
970 | 209718 | *inbufsize -= bytes_to_copy; | |
971 | |||
972 | 209718 | return done; | |
973 | } | ||
974 | |||
975 | |||
976 | 1 | size_t EchoCompressor::DeflateBound(const size_t bytes) { | |
977 | // zero bytes as an upper bound is no good because some callers want to | ||
978 | // allocate buffers according to this value | ||
979 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | return (bytes == 0) ? 1 : bytes; |
980 | } | ||
981 | |||
982 | } // namespace zlib | ||
983 |