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