• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "entry_name_utils-inl.h"
18 #include "zip_archive_common.h"
19 #include "ziparchive/zip_writer.h"
20 
21 #include <utils/Log.h>
22 
23 #include <sys/param.h>
24 
25 #include <cassert>
26 #include <cstdio>
27 #include <memory>
28 #include <vector>
29 #include <zlib.h>
30 #define DEF_MEM_LEVEL 8                // normally in zutil.h?
31 
32 #if !defined(powerof2)
33 #define powerof2(x) ((((x)-1)&(x))==0)
34 #endif
35 
36 /* Zip compression methods we support */
37 enum {
38   kCompressStored     = 0,        // no compression
39   kCompressDeflated   = 8,        // standard deflate
40 };
41 
42 // Size of the output buffer used for compression.
43 static const size_t kBufSize = 32768u;
44 
45 // No error, operation completed successfully.
46 static const int32_t kNoError = 0;
47 
48 // The ZipWriter is in a bad state.
49 static const int32_t kInvalidState = -1;
50 
51 // There was an IO error while writing to disk.
52 static const int32_t kIoError = -2;
53 
54 // The zip entry name was invalid.
55 static const int32_t kInvalidEntryName = -3;
56 
57 // An error occurred in zlib.
58 static const int32_t kZlibError = -4;
59 
60 // The start aligned function was called with the aligned flag.
61 static const int32_t kInvalidAlign32Flag = -5;
62 
63 // The alignment parameter is not a power of 2.
64 static const int32_t kInvalidAlignment = -6;
65 
66 static const char* sErrorCodes[] = {
67     "Invalid state",
68     "IO error",
69     "Invalid entry name",
70     "Zlib error",
71 };
72 
ErrorCodeString(int32_t error_code)73 const char* ZipWriter::ErrorCodeString(int32_t error_code) {
74   if (error_code < 0 && (-error_code) < static_cast<int32_t>(arraysize(sErrorCodes))) {
75     return sErrorCodes[-error_code];
76   }
77   return nullptr;
78 }
79 
DeleteZStream(z_stream * stream)80 static void DeleteZStream(z_stream* stream) {
81   deflateEnd(stream);
82   delete stream;
83 }
84 
ZipWriter(FILE * f)85 ZipWriter::ZipWriter(FILE* f) : file_(f), current_offset_(0), state_(State::kWritingZip),
86                                 z_stream_(nullptr, DeleteZStream), buffer_(kBufSize) {
87 }
88 
ZipWriter(ZipWriter && writer)89 ZipWriter::ZipWriter(ZipWriter&& writer) : file_(writer.file_),
90                                            current_offset_(writer.current_offset_),
91                                            state_(writer.state_),
92                                            files_(std::move(writer.files_)),
93                                            z_stream_(std::move(writer.z_stream_)),
94                                            buffer_(std::move(writer.buffer_)){
95   writer.file_ = nullptr;
96   writer.state_ = State::kError;
97 }
98 
operator =(ZipWriter && writer)99 ZipWriter& ZipWriter::operator=(ZipWriter&& writer) {
100   file_ = writer.file_;
101   current_offset_ = writer.current_offset_;
102   state_ = writer.state_;
103   files_ = std::move(writer.files_);
104   z_stream_ = std::move(writer.z_stream_);
105   buffer_ = std::move(writer.buffer_);
106   writer.file_ = nullptr;
107   writer.state_ = State::kError;
108   return *this;
109 }
110 
HandleError(int32_t error_code)111 int32_t ZipWriter::HandleError(int32_t error_code) {
112   state_ = State::kError;
113   z_stream_.reset();
114   return error_code;
115 }
116 
StartEntry(const char * path,size_t flags)117 int32_t ZipWriter::StartEntry(const char* path, size_t flags) {
118   uint32_t alignment = 0;
119   if (flags & kAlign32) {
120     flags &= ~kAlign32;
121     alignment = 4;
122   }
123   return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
124 }
125 
StartAlignedEntry(const char * path,size_t flags,uint32_t alignment)126 int32_t ZipWriter::StartAlignedEntry(const char* path, size_t flags, uint32_t alignment) {
127   return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
128 }
129 
StartEntryWithTime(const char * path,size_t flags,time_t time)130 int32_t ZipWriter::StartEntryWithTime(const char* path, size_t flags, time_t time) {
131   uint32_t alignment = 0;
132   if (flags & kAlign32) {
133     flags &= ~kAlign32;
134     alignment = 4;
135   }
136   return StartAlignedEntryWithTime(path, flags, time, alignment);
137 }
138 
ExtractTimeAndDate(time_t when,uint16_t * out_time,uint16_t * out_date)139 static void ExtractTimeAndDate(time_t when, uint16_t* out_time, uint16_t* out_date) {
140   /* round up to an even number of seconds */
141   when = static_cast<time_t>((static_cast<unsigned long>(when) + 1) & (~1));
142 
143   struct tm* ptm;
144 #if !defined(_WIN32)
145     struct tm tm_result;
146     ptm = localtime_r(&when, &tm_result);
147 #else
148     ptm = localtime(&when);
149 #endif
150 
151   int year = ptm->tm_year;
152   if (year < 80) {
153     year = 80;
154   }
155 
156   *out_date = (year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday;
157   *out_time = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
158 }
159 
StartAlignedEntryWithTime(const char * path,size_t flags,time_t time,uint32_t alignment)160 int32_t ZipWriter::StartAlignedEntryWithTime(const char* path, size_t flags,
161                                              time_t time, uint32_t alignment) {
162   if (state_ != State::kWritingZip) {
163     return kInvalidState;
164   }
165 
166   if (flags & kAlign32) {
167     return kInvalidAlign32Flag;
168   }
169 
170   if (powerof2(alignment) == 0) {
171     return kInvalidAlignment;
172   }
173 
174   FileInfo fileInfo = {};
175   fileInfo.path = std::string(path);
176   fileInfo.local_file_header_offset = current_offset_;
177 
178   if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(fileInfo.path.data()),
179                        fileInfo.path.size())) {
180     return kInvalidEntryName;
181   }
182 
183   LocalFileHeader header = {};
184   header.lfh_signature = LocalFileHeader::kSignature;
185 
186   // Set this flag to denote that a DataDescriptor struct will appear after the data,
187   // containing the crc and size fields.
188   header.gpb_flags |= kGPBDDFlagMask;
189 
190   if (flags & ZipWriter::kCompress) {
191     fileInfo.compression_method = kCompressDeflated;
192 
193     int32_t result = PrepareDeflate();
194     if (result != kNoError) {
195       return result;
196     }
197   } else {
198     fileInfo.compression_method = kCompressStored;
199   }
200   header.compression_method = fileInfo.compression_method;
201 
202   ExtractTimeAndDate(time, &fileInfo.last_mod_time, &fileInfo.last_mod_date);
203   header.last_mod_time = fileInfo.last_mod_time;
204   header.last_mod_date = fileInfo.last_mod_date;
205 
206   header.file_name_length = fileInfo.path.size();
207 
208   off64_t offset = current_offset_ + sizeof(header) + fileInfo.path.size();
209   std::vector<char> zero_padding;
210   if (alignment != 0 && (offset & (alignment - 1))) {
211     // Pad the extra field so the data will be aligned.
212     uint16_t padding = alignment - (offset % alignment);
213     header.extra_field_length = padding;
214     offset += padding;
215     zero_padding.resize(padding);
216     memset(zero_padding.data(), 0, zero_padding.size());
217   }
218 
219   if (fwrite(&header, sizeof(header), 1, file_) != 1) {
220     return HandleError(kIoError);
221   }
222 
223   if (fwrite(path, sizeof(*path), fileInfo.path.size(), file_) != fileInfo.path.size()) {
224     return HandleError(kIoError);
225   }
226 
227   if (header.extra_field_length != 0 &&
228       fwrite(zero_padding.data(), 1, header.extra_field_length, file_)
229       != header.extra_field_length) {
230     return HandleError(kIoError);
231   }
232 
233   files_.emplace_back(std::move(fileInfo));
234 
235   current_offset_ = offset;
236   state_ = State::kWritingEntry;
237   return kNoError;
238 }
239 
PrepareDeflate()240 int32_t ZipWriter::PrepareDeflate() {
241   assert(state_ == State::kWritingZip);
242 
243   // Initialize the z_stream for compression.
244   z_stream_ = std::unique_ptr<z_stream, void(*)(z_stream*)>(new z_stream(), DeleteZStream);
245 
246   int zerr = deflateInit2(z_stream_.get(), Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
247                           DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
248   if (zerr != Z_OK) {
249     if (zerr == Z_VERSION_ERROR) {
250       ALOGE("Installed zlib is not compatible with linked version (%s)", ZLIB_VERSION);
251       return HandleError(kZlibError);
252     } else {
253       ALOGE("deflateInit2 failed (zerr=%d)", zerr);
254       return HandleError(kZlibError);
255     }
256   }
257 
258   z_stream_->next_out = buffer_.data();
259   z_stream_->avail_out = buffer_.size();
260   return kNoError;
261 }
262 
WriteBytes(const void * data,size_t len)263 int32_t ZipWriter::WriteBytes(const void* data, size_t len) {
264   if (state_ != State::kWritingEntry) {
265     return HandleError(kInvalidState);
266   }
267 
268   FileInfo& currentFile = files_.back();
269   int32_t result = kNoError;
270   if (currentFile.compression_method & kCompressDeflated) {
271     result = CompressBytes(&currentFile, data, len);
272   } else {
273     result = StoreBytes(&currentFile, data, len);
274   }
275 
276   if (result != kNoError) {
277     return result;
278   }
279 
280   currentFile.crc32 = crc32(currentFile.crc32, reinterpret_cast<const Bytef*>(data), len);
281   currentFile.uncompressed_size += len;
282   return kNoError;
283 }
284 
StoreBytes(FileInfo * file,const void * data,size_t len)285 int32_t ZipWriter::StoreBytes(FileInfo* file, const void* data, size_t len) {
286   assert(state_ == State::kWritingEntry);
287 
288   if (fwrite(data, 1, len, file_) != len) {
289     return HandleError(kIoError);
290   }
291   file->compressed_size += len;
292   current_offset_ += len;
293   return kNoError;
294 }
295 
CompressBytes(FileInfo * file,const void * data,size_t len)296 int32_t ZipWriter::CompressBytes(FileInfo* file, const void* data, size_t len) {
297   assert(state_ == State::kWritingEntry);
298   assert(z_stream_);
299   assert(z_stream_->next_out != nullptr);
300   assert(z_stream_->avail_out != 0);
301 
302   // Prepare the input.
303   z_stream_->next_in = reinterpret_cast<const uint8_t*>(data);
304   z_stream_->avail_in = len;
305 
306   while (z_stream_->avail_in > 0) {
307     // We have more data to compress.
308     int zerr = deflate(z_stream_.get(), Z_NO_FLUSH);
309     if (zerr != Z_OK) {
310       return HandleError(kZlibError);
311     }
312 
313     if (z_stream_->avail_out == 0) {
314       // The output is full, let's write it to disk.
315       size_t write_bytes = z_stream_->next_out - buffer_.data();
316       if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
317         return HandleError(kIoError);
318       }
319       file->compressed_size += write_bytes;
320       current_offset_ += write_bytes;
321 
322       // Reset the output buffer for the next input.
323       z_stream_->next_out = buffer_.data();
324       z_stream_->avail_out = buffer_.size();
325     }
326   }
327   return kNoError;
328 }
329 
FlushCompressedBytes(FileInfo * file)330 int32_t ZipWriter::FlushCompressedBytes(FileInfo* file) {
331   assert(state_ == State::kWritingEntry);
332   assert(z_stream_);
333   assert(z_stream_->next_out != nullptr);
334   assert(z_stream_->avail_out != 0);
335 
336   // Keep deflating while there isn't enough space in the buffer to
337   // to complete the compress.
338   int zerr;
339   while ((zerr = deflate(z_stream_.get(), Z_FINISH)) == Z_OK) {
340     assert(z_stream_->avail_out == 0);
341     size_t write_bytes = z_stream_->next_out - buffer_.data();
342     if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
343       return HandleError(kIoError);
344     }
345     file->compressed_size += write_bytes;
346     current_offset_ += write_bytes;
347 
348     z_stream_->next_out = buffer_.data();
349     z_stream_->avail_out = buffer_.size();
350   }
351   if (zerr != Z_STREAM_END) {
352     return HandleError(kZlibError);
353   }
354 
355   size_t write_bytes = z_stream_->next_out - buffer_.data();
356   if (write_bytes != 0) {
357     if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
358       return HandleError(kIoError);
359     }
360     file->compressed_size += write_bytes;
361     current_offset_ += write_bytes;
362   }
363   z_stream_.reset();
364   return kNoError;
365 }
366 
FinishEntry()367 int32_t ZipWriter::FinishEntry() {
368   if (state_ != State::kWritingEntry) {
369     return kInvalidState;
370   }
371 
372   FileInfo& currentFile = files_.back();
373   if (currentFile.compression_method & kCompressDeflated) {
374     int32_t result = FlushCompressedBytes(&currentFile);
375     if (result != kNoError) {
376       return result;
377     }
378   }
379 
380   const uint32_t sig = DataDescriptor::kOptSignature;
381   if (fwrite(&sig, sizeof(sig), 1, file_) != 1) {
382     state_ = State::kError;
383     return kIoError;
384   }
385 
386   DataDescriptor dd = {};
387   dd.crc32 = currentFile.crc32;
388   dd.compressed_size = currentFile.compressed_size;
389   dd.uncompressed_size = currentFile.uncompressed_size;
390   if (fwrite(&dd, sizeof(dd), 1, file_) != 1) {
391     return HandleError(kIoError);
392   }
393 
394   current_offset_ += sizeof(DataDescriptor::kOptSignature) + sizeof(dd);
395   state_ = State::kWritingZip;
396   return kNoError;
397 }
398 
Finish()399 int32_t ZipWriter::Finish() {
400   if (state_ != State::kWritingZip) {
401     return kInvalidState;
402   }
403 
404   off64_t startOfCdr = current_offset_;
405   for (FileInfo& file : files_) {
406     CentralDirectoryRecord cdr = {};
407     cdr.record_signature = CentralDirectoryRecord::kSignature;
408     cdr.gpb_flags |= kGPBDDFlagMask;
409     cdr.compression_method = file.compression_method;
410     cdr.last_mod_time = file.last_mod_time;
411     cdr.last_mod_date = file.last_mod_date;
412     cdr.crc32 = file.crc32;
413     cdr.compressed_size = file.compressed_size;
414     cdr.uncompressed_size = file.uncompressed_size;
415     cdr.file_name_length = file.path.size();
416     cdr.local_file_header_offset = file.local_file_header_offset;
417     if (fwrite(&cdr, sizeof(cdr), 1, file_) != 1) {
418       return HandleError(kIoError);
419     }
420 
421     if (fwrite(file.path.data(), 1, file.path.size(), file_) != file.path.size()) {
422       return HandleError(kIoError);
423     }
424 
425     current_offset_ += sizeof(cdr) + file.path.size();
426   }
427 
428   EocdRecord er = {};
429   er.eocd_signature = EocdRecord::kSignature;
430   er.disk_num = 0;
431   er.cd_start_disk = 0;
432   er.num_records_on_disk = files_.size();
433   er.num_records = files_.size();
434   er.cd_size = current_offset_ - startOfCdr;
435   er.cd_start_offset = startOfCdr;
436 
437   if (fwrite(&er, sizeof(er), 1, file_) != 1) {
438     return HandleError(kIoError);
439   }
440 
441   if (fflush(file_) != 0) {
442     return HandleError(kIoError);
443   }
444 
445   current_offset_ += sizeof(er);
446   state_ = State::kDone;
447   return kNoError;
448 }
449