1 //===-- CompressionStream.cpp --------------------------------------------===//
2 //
3 //                     The KLEE Symbolic Virtual Machine
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 #include "klee/Config/config.h"
10 #include "klee/Config/Version.h"
11 #ifdef HAVE_ZLIB_H
12 #include "klee/Support/CompressionStream.h"
13 
14 #include "llvm/Support/FileSystem.h"
15 
16 #include <fcntl.h>
17 #include <errno.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 
22 namespace klee {
23 
compressed_fd_ostream(const std::string & Filename,std::string & ErrorInfo)24 compressed_fd_ostream::compressed_fd_ostream(const std::string &Filename,
25                                              std::string &ErrorInfo)
26     : llvm::raw_ostream(), pos(0) {
27   ErrorInfo = "";
28   // Open file in binary mode
29 #if LLVM_VERSION_CODE >= LLVM_VERSION(7, 0)
30   std::error_code EC =
31       llvm::sys::fs::openFileForWrite(Filename, FD);
32 #else
33   std::error_code EC =
34       llvm::sys::fs::openFileForWrite(Filename, FD, llvm::sys::fs::F_None);
35 #endif
36   if (EC) {
37     ErrorInfo = EC.message();
38     FD = -1;
39     return;
40   }
41   // Initialize the compression library
42   strm.zalloc = Z_NULL;
43   strm.zfree = Z_NULL;
44   strm.opaque = Z_NULL;
45   strm.next_in = Z_NULL;
46   strm.next_out = buffer;
47   strm.avail_in = 0;
48   strm.avail_out = BUFSIZE;
49 
50   const auto ret = deflateInit2(&strm, Z_BEST_COMPRESSION, Z_DEFLATED, 31,
51                                 8 /* memory usage default, 0 smallest, 9 highest*/,
52                                 Z_DEFAULT_STRATEGY);
53   if (ret != Z_OK)
54     ErrorInfo = "Deflate initialisation returned with error: " + std::to_string(ret);
55 }
56 
writeFullCompressedData()57 void compressed_fd_ostream::writeFullCompressedData() {
58   // Check if no space available and write the buffer
59   if (strm.avail_out == 0) {
60     write_file(reinterpret_cast<const char *>(buffer), BUFSIZE);
61     strm.next_out = buffer;
62     strm.avail_out = BUFSIZE;
63   }
64 }
65 
flush_compressed_data()66 void compressed_fd_ostream::flush_compressed_data() {
67   // flush data from the raw buffer
68   flush();
69 
70   // write the remaining data
71   int deflate_res = Z_OK;
72   while (deflate_res == Z_OK) {
73     // Check if no space available and write the buffer
74     writeFullCompressedData();
75     deflate_res = deflate(&strm, Z_FINISH);
76   }
77   assert(deflate_res == Z_STREAM_END);
78   write_file(reinterpret_cast<const char *>(buffer), BUFSIZE - strm.avail_out);
79 }
80 
~compressed_fd_ostream()81 compressed_fd_ostream::~compressed_fd_ostream() {
82   if (FD >= 0) {
83     // write the remaining data
84     flush_compressed_data();
85     close(FD);
86   }
87   deflateEnd(&strm);
88 }
89 
write_impl(const char * Ptr,size_t Size)90 void compressed_fd_ostream::write_impl(const char *Ptr, size_t Size) {
91   strm.next_in =
92       const_cast<unsigned char *>(reinterpret_cast<const unsigned char *>(Ptr));
93   strm.avail_in = Size;
94 
95   // Check if there is still data to compress
96   while (strm.avail_in != 0) {
97     // compress data
98     const auto res __attribute__ ((unused)) = deflate(&strm, Z_NO_FLUSH);
99     assert(res == Z_OK);
100     writeFullCompressedData();
101   }
102 }
103 
write_file(const char * Ptr,size_t Size)104 void compressed_fd_ostream::write_file(const char *Ptr, size_t Size) {
105   pos += Size;
106   assert(FD >= 0 && "File already closed");
107   do {
108     ssize_t ret = ::write(FD, Ptr, Size);
109     if (ret < 0) {
110       if (errno == EINTR || errno == EAGAIN)
111         continue;
112       assert(0 && "Could not write to file");
113       break;
114     }
115 
116     Ptr += ret;
117     Size -= ret;
118   } while (Size > 0);
119 }
120 }
121 #endif
122