GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/compression/compression.cc
Date: 2026-10-11 02:40:02
Exec Total Coverage
Lines: 409 547 74.8%
Branches: 220 448 49.1%

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 182 static bool CopyFile2File(FILE *fsrc, FILE *fdest) {
33 unsigned char buf[1024];
34
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
182 rewind(fsrc);
35
1/2
✓ Branch 1 taken 182 times.
✗ Branch 2 not taken.
182 rewind(fdest);
36
37 size_t have;
38 do {
39
1/2
✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
197 have = fread(buf, 1, 1024, fsrc);
40
2/4
✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 197 times.
197 if (fwrite(buf, 1, have, fdest) != have)
41 ✗ return false;
42
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 182 times.
197 } while (have == 1024);
43 182 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)
52 ✗ goto file_copy_final;
53
54
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))
55 ✗ goto file_copy_final;
56 3 retval = platform_fstat(fileno(fsrc), &info);
57 3 retval |= fchmod(fileno(fdest), info.st_mode);
58
59 3 file_copy_final:
60
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (fsrc)
61
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 fclose(fsrc);
62 3 return retval == 0;
63 }
64
65
66 179 bool CopyPath2Path(const string &src, const string &dest) {
67 179 FILE *fsrc = NULL;
68 179 FILE *fdest = NULL;
69 179 int retval = -1;
70 platform_stat64 info;
71
72
1/2
✓ Branch 2 taken 179 times.
✗ Branch 3 not taken.
179 fsrc = fopen(src.c_str(), "r");
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 179 times.
179 if (!fsrc)
74 ✗ goto file_copy_final;
75
76
1/2
✓ Branch 2 taken 179 times.
✗ Branch 3 not taken.
179 fdest = fopen(dest.c_str(), "w");
77
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 179 times.
179 if (!fdest)
78 ✗ goto file_copy_final;
79
80
2/4
✓ Branch 1 taken 179 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 179 times.
179 if (!CopyFile2File(fsrc, fdest))
81 ✗ goto file_copy_final;
82 179 retval = platform_fstat(fileno(fsrc), &info);
83 179 retval |= fchmod(fileno(fdest), info.st_mode);
84
85 179 file_copy_final:
86
1/2
✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
179 if (fsrc)
87
1/2
✓ Branch 1 taken 179 times.
✗ Branch 2 not taken.
179 fclose(fsrc);
88
1/2
✓ Branch 0 taken 179 times.
✗ Branch 1 not taken.
179 if (fdest)
89
1/2
✓ Branch 1 taken 179 times.
✗ Branch 2 not taken.
179 fclose(fdest);
90 179 return retval == 0;
91 }
92
93
94 ✗ bool CopyMem2File(const unsigned char *buffer, const unsigned buffer_size,
95 FILE *fdest) {
96 ✗ int const written = fwrite(buffer, 1, buffer_size, fdest);
97 ✗ return (written >= 0) && (unsigned(written) == buffer_size);
98 }
99
100
101 931 bool CopyMem2Path(const unsigned char *buffer, const unsigned buffer_size,
102 const string &path) {
103 931 int const fd = open(path.c_str(), O_WRONLY | O_CREAT | O_TRUNC, kDefaultFileMode);
104
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 931 times.
931 if (fd < 0)
105 ✗ return false;
106
107 931 int const written = write(fd, buffer, buffer_size);
108 931 close(fd);
109
110
2/4
✓ Branch 0 taken 931 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 931 times.
✗ Branch 3 not taken.
931 return (written >= 0) && (unsigned(written) == buffer_size);
111 }
112
113
114 46 bool CopyPath2Mem(const string &path, unsigned char **buffer,
115 unsigned *buffer_size) {
116 46 const int fd = open(path.c_str(), O_RDONLY);
117
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (fd < 0)
118 ✗ return false;
119
120 46 *buffer_size = 512;
121 46 *buffer = reinterpret_cast<unsigned char *>(smalloc(*buffer_size));
122 46 unsigned total_bytes = 0;
123 while (true) {
124 92 int const num_bytes = read(fd, *buffer + total_bytes, *buffer_size - total_bytes);
125
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 46 times.
92 if (num_bytes == 0)
126 46 break;
127
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (num_bytes < 0) {
128 ✗ close(fd);
129 ✗ free(*buffer);
130 ✗ *buffer_size = 0;
131 ✗ return false;
132 }
133 46 total_bytes += num_bytes;
134
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46 times.
46 if (total_bytes >= *buffer_size) {
135 ✗ *buffer_size *= 2;
136 ✗ *buffer = reinterpret_cast<unsigned char *>(
137 ✗ srealloc(*buffer, *buffer_size));
138 }
139 46 }
140
141 46 close(fd);
142 46 *buffer_size = total_bytes;
143 46 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 5479 void CompressInit(z_stream *strm) {
180 5479 strm->zalloc = Z_NULL;
181 5479 strm->zfree = Z_NULL;
182 5479 strm->opaque = Z_NULL;
183 5479 strm->next_in = Z_NULL;
184 5479 strm->avail_in = 0;
185 5479 int const retval = deflateInit(strm, Z_DEFAULT_COMPRESSION);
186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5479 times.
5479 assert(retval == 0);
187 5479 }
188
189
190 4198 void DecompressInit(z_stream *strm) {
191 4198 strm->zalloc = Z_NULL;
192 4198 strm->zfree = Z_NULL;
193 4198 strm->opaque = Z_NULL;
194 4198 strm->avail_in = 0;
195 4198 strm->next_in = Z_NULL;
196 4198 int const retval = inflateInit(strm);
197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4198 times.
4198 assert(retval == 0);
198 4198 }
199
200
201 5479 void CompressFini(z_stream *strm) { (void)deflateEnd(strm); }
202
203
204 3978 void DecompressFini(z_stream *strm) { (void)inflateEnd(strm); }
205
206
207 196 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 196 strm->avail_in = size;
216 196 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 196 strm->avail_out = kZChunk;
221 196 strm->next_out = out;
222
3/4
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 49 times.
✓ Branch 3 taken 196 times.
✗ Branch 4 not taken.
196 z_ret = deflate(strm, eof ? Z_FINISH : Z_NO_FLUSH); // no bad return value
223
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196 times.
196 if (z_ret == Z_STREAM_ERROR)
224 ✗ return kStreamDataError;
225 196 size_t const have = kZChunk - strm->avail_out;
226
1/2
✓ Branch 1 taken 196 times.
✗ Branch 2 not taken.
196 shash::Update(out, have, *hash_context);
227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 196 times.
196 } while (strm->avail_out == 0);
228
229
2/2
✓ Branch 0 taken 147 times.
✓ Branch 1 taken 49 times.
196 return (z_ret == Z_STREAM_END ? kStreamEnd : kStreamContinue);
230 }
231
232
233 3397 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 3397 int64_t pos = 0;
240
241 do {
242 3397 strm->avail_in = (kZChunk > (size - pos)) ? size - pos : kZChunk;
243 3397 strm->next_in = ((unsigned char *)buf) + pos;
244
245 // Run inflate() on input until output buffer not full
246 do {
247 5370 strm->avail_out = kZChunk;
248 5370 strm->next_out = out;
249
1/2
✓ Branch 1 taken 5370 times.
✗ Branch 2 not taken.
5370 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 5370 times.
5370 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 5370 size_t const have = kZChunk - strm->avail_out;
260
1/2
✓ Branch 1 taken 5370 times.
✗ Branch 2 not taken.
5370 int64_t const written = sink->Write(out, have);
261
2/4
✓ Branch 0 taken 5370 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5370 times.
5370 if ((written < 0) || (static_cast<uint64_t>(written) != have))
262 ✗ return kStreamIOError;
263
2/2
✓ Branch 0 taken 1973 times.
✓ Branch 1 taken 3397 times.
5370 } while (strm->avail_out == 0);
264
265 3397 pos += kZChunk;
266
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3397 times.
3397 } while (pos < size);
267
268
2/2
✓ Branch 0 taken 3234 times.
✓ Branch 1 taken 163 times.
3397 return (z_ret == Z_STREAM_END ? kStreamEnd : kStreamContinue);
269 }
270
271
272 8 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 8 int64_t pos = 0;
279
280 do {
281 8 strm->avail_in = (kZChunk > (size - pos)) ? size - pos : kZChunk;
282 8 strm->next_in = ((unsigned char *)buf) + pos;
283
284 // Run inflate() on input until output buffer not full
285 do {
286 11 strm->avail_out = kZChunk;
287 11 strm->next_out = out;
288
1/2
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
11 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 11 times.
11 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 11 size_t const have = kZChunk - strm->avail_out;
299
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)) {
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 3 times.
✓ Branch 1 taken 8 times.
11 } while (strm->avail_out == 0);
307
308 8 pos += kZChunk;
309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 } while (pos < size);
310
311
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 return (z_ret == Z_STREAM_END ? kStreamEnd : kStreamContinue);
312 }
313
314
315 1200 bool CompressPath2Path(const string &src, const string &dest) {
316 1200 FILE *fsrc = fopen(src.c_str(), "r");
317
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 if (!fsrc) {
318 ✗ LogCvmfs(kLogCompress, kLogDebug, "open %s as compression source failed",
319 src.c_str());
320 ✗ return false;
321 }
322
323 1200 FILE *fdest = fopen(dest.c_str(), "w");
324
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 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 1200 LogCvmfs(kLogCompress, kLogDebug, "opened %s and %s for compression",
334 src.c_str(), dest.c_str());
335 1200 const bool result = CompressFile2File(fsrc, fdest);
336
337 1200 fclose(fsrc);
338 1200 fclose(fdest);
339 1200 return result;
340 }
341
342
343 2080 bool CompressPath2Path(const string &src, const string &dest,
344 shash::Any *compressed_hash) {
345
1/2
✓ Branch 2 taken 2080 times.
✗ Branch 3 not taken.
2080 FILE *fsrc = fopen(src.c_str(), "r");
346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2080 times.
2080 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 2080 times.
✗ Branch 3 not taken.
2080 FILE *fdest = fopen(dest.c_str(), "w");
353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2080 times.
2080 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 2080 times.
✗ Branch 4 not taken.
2080 LogCvmfs(kLogCompress, kLogDebug, "opened %s and %s for compression",
363 src.c_str(), dest.c_str());
364 2080 bool result = false;
365
2/4
✓ Branch 1 taken 2080 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 2080 times.
2080 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 2080 times.
2080 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 2080 times.
2080 if (fchmod(fileno(fdest), info.st_mode) != 0)
372 ✗ goto compress_path2path_final;
373
374 2080 result = true;
375
376 2080 compress_path2path_final:
377
1/2
✓ Branch 1 taken 2080 times.
✗ Branch 2 not taken.
2080 fclose(fsrc);
378
1/2
✓ Branch 1 taken 2080 times.
✗ Branch 2 not taken.
2080 fclose(fdest);
379 2080 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 1200 bool CompressFile2Null(FILE *fsrc, shash::Any *compressed_hash) {
408 1200 int z_ret = 0;
409 1200 int flush = 0;
410 1200 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 1200 times.
✗ Branch 2 not taken.
1200 shash::ContextPtr hash_context(compressed_hash->algorithm);
416
417
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 CompressInit(&strm);
418 1200 hash_context.buffer = alloca(hash_context.size);
419
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 shash::Init(hash_context);
420
421 // Compress until end of file
422 do {
423
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 strm.avail_in = fread(in, 1, kZChunk, fsrc);
424
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1200 times.
1200 if (ferror(fsrc))
425 ✗ goto compress_file2null_final;
426
427
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 flush = feof(fsrc) ? Z_FINISH : Z_NO_FLUSH;
428 1200 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 1200 strm.avail_out = kZChunk;
434 1200 strm.next_out = out;
435
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 z_ret = deflate(&strm, flush); // no bad return value
436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 if (z_ret == Z_STREAM_ERROR)
437 ✗ goto compress_file2null_final; // state not clobbered
438 1200 have = kZChunk - strm.avail_out;
439
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 shash::Update(out, have, hash_context);
440
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 } while (strm.avail_out == 0);
441
442 // Done when last data in file processed
443
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 } while (flush != Z_FINISH);
444
445 // stream will be complete
446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 if (z_ret != Z_STREAM_END)
447 ✗ goto compress_file2null_final;
448
449
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 shash::Final(hash_context, compressed_hash);
450 1200 result = true;
451
452 // Clean up and return
453 1200 compress_file2null_final:
454
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 CompressFini(&strm);
455
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d",
456 result);
457 1200 return result;
458 }
459
460
461 16 bool CompressFd2Null(int fd_src, shash::Any *compressed_hash,
462 uint64_t *processed_bytes) {
463 16 int z_ret = 0;
464 16 int flush = 0;
465 16 bool result = false;
466 unsigned have;
467 z_stream strm;
468 unsigned char in[kZChunk];
469 unsigned char out[kZChunk];
470 16 off_t cksum_bytes = 0;
471
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 shash::ContextPtr hash_context(compressed_hash->algorithm);
472
473
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 CompressInit(&strm);
474 16 hash_context.buffer = alloca(hash_context.size);
475
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 shash::Init(hash_context);
476
477 // Compress until end of file
478 do {
479
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 ssize_t const bytes_read = read(fd_src, in, kZChunk);
480
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
16 if (bytes_read < 0) {
481
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (errno == EINTR) {
482 ✗ continue;
483 }
484 8 goto compress_fd2null_final;
485 }
486 8 cksum_bytes += bytes_read;
487 8 strm.avail_in = bytes_read;
488
489
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 flush = (static_cast<size_t>(bytes_read) < kZChunk) ? Z_FINISH : Z_NO_FLUSH;
490 8 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 8 strm.avail_out = kZChunk;
496 8 strm.next_out = out;
497
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 z_ret = deflate(&strm, flush); // no bad return value
498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (z_ret == Z_STREAM_ERROR)
499 ✗ goto compress_fd2null_final; // state not clobbered
500 8 have = kZChunk - strm.avail_out;
501
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 shash::Update(out, have, hash_context);
502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 } while (strm.avail_out == 0);
503
504 // Done when last data in file processed
505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 } while (flush != Z_FINISH);
506
507 // stream will be complete
508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (z_ret != Z_STREAM_END)
509 ✗ goto compress_fd2null_final;
510
511
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 shash::Final(hash_context, compressed_hash);
512
1/2
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
8 if (processed_bytes) {
513 8 *processed_bytes = cksum_bytes;
514 }
515 8 result = true;
516
517 // Clean up and return
518 16 compress_fd2null_final:
519
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 CompressFini(&strm);
520
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d",
521 result);
522 16 return result;
523 }
524
525
526 1200 bool CompressPath2Null(const string &src, shash::Any *compressed_hash) {
527 1200 FILE *fsrc = fopen(src.c_str(), "r");
528
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 if (fsrc == NULL)
529 ✗ return false;
530 1200 bool const retval = CompressFile2Null(fsrc, compressed_hash);
531 1200 fclose(fsrc);
532 1200 return retval;
533 }
534
535
536 1200 bool CompressFile2File(FILE *fsrc, FILE *fdest) {
537 1200 int z_ret = 0;
538 1200 int flush = 0;
539 1200 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 1200 times.
✗ Branch 2 not taken.
1200 CompressInit(&strm);
546
547 // Compress until end of file
548 do {
549
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 strm.avail_in = fread(in, 1, kZChunk, fsrc);
550
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1200 times.
1200 if (ferror(fsrc))
551 ✗ goto compress_file2file_final;
552
553
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 flush = feof(fsrc) ? Z_FINISH : Z_NO_FLUSH;
554 1200 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 1200 strm.avail_out = kZChunk;
560 1200 strm.next_out = out;
561
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 z_ret = deflate(&strm, flush); // no bad return value
562
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 if (z_ret == Z_STREAM_ERROR)
563 ✗ goto compress_file2file_final; // state not clobbered
564 1200 have = kZChunk - strm.avail_out;
565
4/9
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1200 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 1200 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 1200 times.
1200 if (fwrite(out, 1, have, fdest) != have || ferror(fdest))
566 ✗ goto compress_file2file_final;
567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 } while (strm.avail_out == 0);
568
569 // Done when last data in file processed
570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 } while (flush != Z_FINISH);
571
572 // stream will be complete
573
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1200 times.
1200 if (z_ret != Z_STREAM_END)
574 ✗ goto compress_file2file_final;
575
576 1200 result = true;
577
578 // Clean up and return
579 1200 compress_file2file_final:
580
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 CompressFini(&strm);
581
1/2
✓ Branch 1 taken 1200 times.
✗ Branch 2 not taken.
1200 LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d",
582 result);
583 1200 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 const retval = CompressFile2File(fsrc, fdest, compressed_hash);
593 ✗ fclose(fsrc);
594 ✗ return retval;
595 }
596
597
598 2080 bool CompressFile2File(FILE *fsrc, FILE *fdest, shash::Any *compressed_hash) {
599 2080 int z_ret = 0;
600 2080 int flush = 0;
601 2080 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 2080 times.
✗ Branch 2 not taken.
2080 shash::ContextPtr hash_context(compressed_hash->algorithm);
607
608
1/2
✓ Branch 1 taken 2080 times.
✗ Branch 2 not taken.
2080 CompressInit(&strm);
609 2080 hash_context.buffer = alloca(hash_context.size);
610
1/2
✓ Branch 1 taken 2080 times.
✗ Branch 2 not taken.
2080 shash::Init(hash_context);
611
612 // Compress until end of file
613 do {
614
1/2
✓ Branch 1 taken 3050 times.
✗ Branch 2 not taken.
3050 strm.avail_in = fread(in, 1, kZChunk, fsrc);
615
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3050 times.
3050 if (ferror(fsrc))
616 ✗ goto compress_file2file_hashed_final;
617
618
2/2
✓ Branch 1 taken 2080 times.
✓ Branch 2 taken 970 times.
3050 flush = feof(fsrc) ? Z_FINISH : Z_NO_FLUSH;
619 3050 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 3050 strm.avail_out = kZChunk;
625 3050 strm.next_out = out;
626
1/2
✓ Branch 1 taken 3050 times.
✗ Branch 2 not taken.
3050 z_ret = deflate(&strm, flush); // no bad return value
627
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3050 times.
3050 if (z_ret == Z_STREAM_ERROR)
628 ✗ goto compress_file2file_hashed_final; // state not clobbered
629 3050 have = kZChunk - strm.avail_out;
630
4/9
✓ Branch 1 taken 3050 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3050 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 3050 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 3050 times.
3050 if (fwrite(out, 1, have, fdest) != have || ferror(fdest))
631 ✗ goto compress_file2file_hashed_final;
632
1/2
✓ Branch 1 taken 3050 times.
✗ Branch 2 not taken.
3050 shash::Update(out, have, hash_context);
633
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3050 times.
3050 } while (strm.avail_out == 0);
634
635 // Done when last data in file processed
636
2/2
✓ Branch 0 taken 970 times.
✓ Branch 1 taken 2080 times.
3050 } while (flush != Z_FINISH);
637
638 // Stream will be complete
639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2080 times.
2080 if (z_ret != Z_STREAM_END)
640 ✗ goto compress_file2file_hashed_final;
641
642
1/2
✓ Branch 1 taken 2080 times.
✗ Branch 2 not taken.
2080 shash::Final(hash_context, compressed_hash);
643 2080 result = true;
644
645 // Clean up and return
646 2080 compress_file2file_hashed_final:
647
1/2
✓ Branch 1 taken 2080 times.
✗ Branch 2 not taken.
2080 CompressFini(&strm);
648
1/2
✓ Branch 1 taken 2080 times.
✗ Branch 2 not taken.
2080 LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d",
649 result);
650 2080 return result;
651 }
652
653
654 10 bool DecompressFile2File(FILE *fsrc, FILE *fdest) {
655 10 bool result = false;
656 10 StreamStates stream_state = kStreamIOError;
657 z_stream strm;
658 size_t have;
659 unsigned char buf[kBufferSize];
660
661
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 DecompressInit(&strm);
662
663
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) {
664
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 stream_state = DecompressZStream2File(buf, have, &strm, fdest);
665
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))
666 ✗ goto decompress_file2file_final;
667 }
668
1/2
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
10 LogCvmfs(kLogCompress, kLogDebug, "end of decompression, state=%d, error=%d",
669 stream_state, ferror(fsrc));
670
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))
671 2 goto decompress_file2file_final;
672
673 8 result = true;
674
675 10 decompress_file2file_final:
676
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 DecompressFini(&strm);
677 10 return result;
678 }
679
680
681 10 bool DecompressPath2File(const string &src, FILE *fdest) {
682 10 FILE *fsrc = fopen(src.c_str(), "r");
683
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (!fsrc)
684 ✗ return false;
685
686 10 bool const retval = DecompressFile2File(fsrc, fdest);
687 10 fclose(fsrc);
688 10 return retval;
689 }
690
691
692 36 bool CompressMem2File(const unsigned char *buf, const size_t size, FILE *fdest,
693 shash::Any *compressed_hash) {
694 36 int z_ret = 0;
695 36 int flush = 0;
696 36 bool result = false;
697 unsigned have;
698 z_stream strm;
699 36 size_t offset = 0;
700 36 size_t used = 0;
701 unsigned char out[kZChunk];
702
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 shash::ContextPtr hash_context(compressed_hash->algorithm);
703
704
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 CompressInit(&strm);
705 36 hash_context.buffer = alloca(hash_context.size);
706
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 shash::Init(hash_context);
707
708 // Compress the given memory buffer
709 do {
710 180 used = min(static_cast<size_t>(kZChunk), size - offset);
711 180 strm.avail_in = used;
712
713
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 144 times.
180 flush = (strm.avail_in < kZChunk) ? Z_FINISH : Z_NO_FLUSH;
714 180 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 288 strm.avail_out = kZChunk;
720 288 strm.next_out = out;
721
1/2
✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
288 z_ret = deflate(&strm, flush); // no bad return value
722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 288 times.
288 if (z_ret == Z_STREAM_ERROR)
723 ✗ goto compress_file2file_hashed_final; // state not clobbered
724 288 have = kZChunk - strm.avail_out;
725
4/9
✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 288 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 288 times.
✗ Branch 8 not taken.
✓ Branch 9 taken 288 times.
288 if (fwrite(out, 1, have, fdest) != have || ferror(fdest))
726 ✗ goto compress_file2file_hashed_final;
727
1/2
✓ Branch 1 taken 288 times.
✗ Branch 2 not taken.
288 shash::Update(out, have, hash_context);
728
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 180 times.
288 } while (strm.avail_out == 0);
729
730 180 offset += used;
731
732 // Done when last data in file processed
733
2/2
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 36 times.
180 } while (flush != Z_FINISH);
734
735 // Stream will be complete
736
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 36 times.
36 if (z_ret != Z_STREAM_END)
737 ✗ goto compress_file2file_hashed_final;
738
739
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 shash::Final(hash_context, compressed_hash);
740 36 result = true;
741
742 // Clean up and return
743 36 compress_file2file_hashed_final:
744
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 CompressFini(&strm);
745
1/2
✓ Branch 1 taken 36 times.
✗ Branch 2 not taken.
36 LogCvmfs(kLogCompress, kLogDebug, "file compression finished with result %d",
746 result);
747 36 return result;
748 }
749
750
751 /**
752 * User of this function has to free out_buf.
753 */
754 751 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 751 int64_t pos = 0;
761 751 uint64_t alloc_size = kZChunk;
762
763
1/2
✓ Branch 1 taken 751 times.
✗ Branch 2 not taken.
751 CompressInit(&strm);
764 751 *out_buf = smalloc(alloc_size);
765 751 *out_size = 0;
766
767 do {
768 44740 strm.avail_in = (kZChunk > (size - pos)) ? size - pos : kZChunk;
769
2/2
✓ Branch 0 taken 751 times.
✓ Branch 1 taken 43989 times.
44740 flush = (pos + kZChunk) >= size ? Z_FINISH : Z_NO_FLUSH;
770 44740 strm.next_in = ((unsigned char *)buf) + pos;
771
772 // Run deflate() on input until output buffer not full
773 do {
774 45428 strm.avail_out = kZChunk;
775 45428 strm.next_out = out;
776
1/2
✓ Branch 1 taken 45428 times.
✗ Branch 2 not taken.
45428 z_ret = deflate(&strm, flush);
777
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 45428 times.
45428 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 45428 size_t const have = kZChunk - strm.avail_out;
785
2/2
✓ Branch 0 taken 215 times.
✓ Branch 1 taken 45213 times.
45428 if (*out_size + have > alloc_size) {
786 215 alloc_size *= 2;
787 215 *out_buf = srealloc(*out_buf, alloc_size);
788 }
789 45428 memcpy(static_cast<unsigned char *>(*out_buf) + *out_size, out, have);
790 45428 *out_size += have;
791
2/2
✓ Branch 0 taken 688 times.
✓ Branch 1 taken 44740 times.
45428 } while (strm.avail_out == 0);
792
793 44740 pos += kZChunk;
794
2/2
✓ Branch 0 taken 43989 times.
✓ Branch 1 taken 751 times.
44740 } while (flush != Z_FINISH);
795
796
1/2
✓ Branch 1 taken 751 times.
✗ Branch 2 not taken.
751 CompressFini(&strm);
797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 751 times.
751 if (z_ret != Z_STREAM_END) {
798 ✗ free(*out_buf);
799 ✗ *out_buf = NULL;
800 ✗ *out_size = 0;
801 ✗ return false;
802 } else {
803 751 return true;
804 }
805 }
806
807
808 /**
809 * User of this function has to free out_buf.
810 */
811 435 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 435 int64_t pos = 0;
817 435 uint64_t alloc_size = kZChunk;
818
819
1/2
✓ Branch 1 taken 435 times.
✗ Branch 2 not taken.
435 DecompressInit(&strm);
820 435 *out_buf = smalloc(alloc_size);
821 435 *out_size = 0;
822
823 do {
824 55475 strm.avail_in = (kZChunk > (size - pos)) ? size - pos : kZChunk;
825 55475 strm.next_in = ((unsigned char *)buf) + pos;
826
827 // Run inflate() on input until output buffer not full
828 do {
829 55475 strm.avail_out = kZChunk;
830 55475 strm.next_out = out;
831
1/2
✓ Branch 1 taken 55475 times.
✗ Branch 2 not taken.
55475 z_ret = inflate(&strm, Z_NO_FLUSH);
832
1/3
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 55475 times.
55475 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 55475 size_t const have = kZChunk - strm.avail_out;
845
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 55002 times.
55475 if (*out_size + have > alloc_size) {
846 473 alloc_size *= 2;
847 473 *out_buf = srealloc(*out_buf, alloc_size);
848 }
849 55475 memcpy(static_cast<unsigned char *>(*out_buf) + *out_size, out, have);
850 55475 *out_size += have;
851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55475 times.
55475 } while (strm.avail_out == 0);
852
853 55475 pos += kZChunk;
854
2/2
✓ Branch 0 taken 55040 times.
✓ Branch 1 taken 435 times.
55475 } while (pos < size);
855
856
1/2
✓ Branch 1 taken 435 times.
✗ Branch 2 not taken.
435 DecompressFini(&strm);
857
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 435 times.
435 if (z_ret != Z_STREAM_END) {
858 ✗ free(*out_buf);
859 ✗ *out_buf = NULL;
860 ✗ *out_size = 0;
861 ✗ return false;
862 }
863
864 435 return true;
865 }
866
867
868 //------------------------------------------------------------------------------
869
870
871 44 void Compressor::RegisterPlugins() {
872 44 RegisterPlugin<ZlibCompressor>();
873 44 RegisterPlugin<EchoCompressor>();
874 44 }
875
876
877 //------------------------------------------------------------------------------
878
879
880 4504670 bool ZlibCompressor::WillHandle(const zlib::Algorithms &alg) {
881 4504670 return alg == kZlibDefault;
882 }
883
884
885 4505441 ZlibCompressor::ZlibCompressor(const Algorithms &alg) : Compressor(alg) {
886 4505783 stream_.zalloc = Z_NULL;
887 4505783 stream_.zfree = Z_NULL;
888 4505783 stream_.opaque = Z_NULL;
889 4505783 stream_.next_in = Z_NULL;
890 4505783 stream_.avail_in = 0;
891
1/2
✓ Branch 1 taken 4509347 times.
✗ Branch 2 not taken.
4505783 const int zlib_retval = deflateInit(&stream_, Z_DEFAULT_COMPRESSION);
892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4509347 times.
4509347 assert(zlib_retval == 0);
893 4509347 }
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 20744576 bool ZlibCompressor::Deflate(const bool flush, unsigned char **inbuf,
908 size_t *inbufsize, unsigned char **outbuf,
909 size_t *outbufsize) {
910 // Adding compression
911 20744576 stream_.avail_in = *inbufsize;
912 20744576 stream_.next_in = *inbuf;
913
2/2
✓ Branch 0 taken 13538053 times.
✓ Branch 1 taken 7206523 times.
20744576 const int flush_int = (flush) ? Z_FINISH : Z_NO_FLUSH;
914 20744576 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 20744576 stream_.avail_out = *outbufsize;
921 20744576 stream_.next_out = *outbuf;
922
923 // Deflate in zlib!
924 20744576 retcode = deflate(&stream_, flush_int);
925
3/4
✓ Branch 0 taken 4508249 times.
✓ Branch 1 taken 16232295 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4508249 times.
20740544 assert(retcode == Z_OK || retcode == Z_STREAM_END);
926
927 20740544 *outbufsize -= stream_.avail_out;
928 20740544 *inbuf = stream_.next_in;
929 20740544 *inbufsize = stream_.avail_in;
930
931
3/4
✓ Branch 0 taken 7205569 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1217208 times.
✓ Branch 3 taken 5988361 times.
7205551 return (flush_int == Z_NO_FLUSH && retcode == Z_OK && stream_.avail_in == 0)
932
6/6
✓ Branch 0 taken 7205551 times.
✓ Branch 1 taken 13534993 times.
✓ Branch 2 taken 13537063 times.
✓ Branch 3 taken 1215120 times.
✓ Branch 4 taken 4505657 times.
✓ Branch 5 taken 9031406 times.
27946095 || (flush_int == Z_FINISH && retcode == Z_STREAM_END);
933 }
934
935
936 18028784 ZlibCompressor::~ZlibCompressor() {
937 9014302 int const retcode = deflateEnd(&stream_);
938
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4508951 times.
9017902 assert(retcode == Z_OK);
939 18032384 }
940
941
942 43 size_t ZlibCompressor::DeflateBound(const size_t bytes) {
943 // Call zlib's deflate bound
944 43 return deflateBound(&stream_, bytes);
945 }
946
947
948 //------------------------------------------------------------------------------
949
950
951 129 EchoCompressor::EchoCompressor(const zlib::Algorithms &alg)
952 129 : Compressor(alg) { }
953
954
955 129 bool EchoCompressor::WillHandle(const zlib::Algorithms &alg) {
956 129 return alg == kNoCompression;
957 }
958
959
960 ✗ Compressor *EchoCompressor::Clone() {
961 ✗ return new EchoCompressor(zlib::kNoCompression);
962 }
963
964
965 9017874 bool EchoCompressor::Deflate(const bool flush, unsigned char **inbuf,
966 size_t *inbufsize, unsigned char **outbuf,
967 size_t *outbufsize) {
968 9017874 size_t const bytes_to_copy = min(*outbufsize, *inbufsize);
969 9017874 memcpy(*outbuf, *inbuf, bytes_to_copy);
970 9017874 const bool done = (bytes_to_copy == *inbufsize);
971
972 // Update the return variables
973 9017874 *inbuf += bytes_to_copy;
974 9017874 *outbufsize = bytes_to_copy;
975 9017874 *inbufsize -= bytes_to_copy;
976
977 9017874 return done;
978 }
979
980
981 43 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 43 times.
✗ Branch 1 not taken.
43 return (bytes == 0) ? 1 : bytes;
985 }
986
987 } // namespace zlib
988