Home | History | Annotate | Download | only in libziparchive
      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 
     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 
     80 static void DeleteZStream(z_stream* stream) {
     81   deflateEnd(stream);
     82   delete stream;
     83 }
     84 
     85 ZipWriter::ZipWriter(FILE* f) : file_(f), current_offset_(0), state_(State::kWritingZip),
     86                                 z_stream_(nullptr, DeleteZStream), buffer_(kBufSize) {
     87 }
     88 
     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 
     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 
    111 int32_t ZipWriter::HandleError(int32_t error_code) {
    112   state_ = State::kError;
    113   z_stream_.reset();
    114   return error_code;
    115 }
    116 
    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 
    126 int32_t ZipWriter::StartAlignedEntry(const char* path, size_t flags, uint32_t alignment) {
    127   return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
    128 }
    129 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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