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