| 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 |