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