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 "ziparchive/zip_writer.h"
     18 
     19 #include <sys/param.h>
     20 #include <sys/stat.h>
     21 #include <zlib.h>
     22 #include <cstdio>
     23 #define DEF_MEM_LEVEL 8  // normally in zutil.h?
     24 
     25 #include <memory>
     26 #include <vector>
     27 
     28 #include "android-base/logging.h"
     29 #include "utils/Compat.h"
     30 #include "utils/Log.h"
     31 
     32 #include "entry_name_utils-inl.h"
     33 #include "zip_archive_common.h"
     34 
     35 #if !defined(powerof2)
     36 #define powerof2(x) ((((x)-1) & (x)) == 0)
     37 #endif
     38 
     39 /* Zip compression methods we support */
     40 enum {
     41   kCompressStored = 0,    // no compression
     42   kCompressDeflated = 8,  // standard deflate
     43 };
     44 
     45 // Size of the output buffer used for compression.
     46 static const size_t kBufSize = 32768u;
     47 
     48 // No error, operation completed successfully.
     49 static const int32_t kNoError = 0;
     50 
     51 // The ZipWriter is in a bad state.
     52 static const int32_t kInvalidState = -1;
     53 
     54 // There was an IO error while writing to disk.
     55 static const int32_t kIoError = -2;
     56 
     57 // The zip entry name was invalid.
     58 static const int32_t kInvalidEntryName = -3;
     59 
     60 // An error occurred in zlib.
     61 static const int32_t kZlibError = -4;
     62 
     63 // The start aligned function was called with the aligned flag.
     64 static const int32_t kInvalidAlign32Flag = -5;
     65 
     66 // The alignment parameter is not a power of 2.
     67 static const int32_t kInvalidAlignment = -6;
     68 
     69 static const char* sErrorCodes[] = {
     70     "Invalid state", "IO error", "Invalid entry name", "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)
     86     : file_(f),
     87       seekable_(false),
     88       current_offset_(0),
     89       state_(State::kWritingZip),
     90       z_stream_(nullptr, DeleteZStream),
     91       buffer_(kBufSize) {
     92   // Check if the file is seekable (regular file). If fstat fails, that's fine, subsequent calls
     93   // will fail as well.
     94   struct stat file_stats;
     95   if (fstat(fileno(f), &file_stats) == 0) {
     96     seekable_ = S_ISREG(file_stats.st_mode);
     97   }
     98 }
     99 
    100 ZipWriter::ZipWriter(ZipWriter&& writer)
    101     : file_(writer.file_),
    102       seekable_(writer.seekable_),
    103       current_offset_(writer.current_offset_),
    104       state_(writer.state_),
    105       files_(std::move(writer.files_)),
    106       z_stream_(std::move(writer.z_stream_)),
    107       buffer_(std::move(writer.buffer_)) {
    108   writer.file_ = nullptr;
    109   writer.state_ = State::kError;
    110 }
    111 
    112 ZipWriter& ZipWriter::operator=(ZipWriter&& writer) {
    113   file_ = writer.file_;
    114   seekable_ = writer.seekable_;
    115   current_offset_ = writer.current_offset_;
    116   state_ = writer.state_;
    117   files_ = std::move(writer.files_);
    118   z_stream_ = std::move(writer.z_stream_);
    119   buffer_ = std::move(writer.buffer_);
    120   writer.file_ = nullptr;
    121   writer.state_ = State::kError;
    122   return *this;
    123 }
    124 
    125 int32_t ZipWriter::HandleError(int32_t error_code) {
    126   state_ = State::kError;
    127   z_stream_.reset();
    128   return error_code;
    129 }
    130 
    131 int32_t ZipWriter::StartEntry(const char* path, size_t flags) {
    132   uint32_t alignment = 0;
    133   if (flags & kAlign32) {
    134     flags &= ~kAlign32;
    135     alignment = 4;
    136   }
    137   return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
    138 }
    139 
    140 int32_t ZipWriter::StartAlignedEntry(const char* path, size_t flags, uint32_t alignment) {
    141   return StartAlignedEntryWithTime(path, flags, time_t(), alignment);
    142 }
    143 
    144 int32_t ZipWriter::StartEntryWithTime(const char* path, size_t flags, time_t time) {
    145   uint32_t alignment = 0;
    146   if (flags & kAlign32) {
    147     flags &= ~kAlign32;
    148     alignment = 4;
    149   }
    150   return StartAlignedEntryWithTime(path, flags, time, alignment);
    151 }
    152 
    153 static void ExtractTimeAndDate(time_t when, uint16_t* out_time, uint16_t* out_date) {
    154   /* round up to an even number of seconds */
    155   when = static_cast<time_t>((static_cast<unsigned long>(when) + 1) & (~1));
    156 
    157   struct tm* ptm;
    158 #if !defined(_WIN32)
    159   struct tm tm_result;
    160   ptm = localtime_r(&when, &tm_result);
    161 #else
    162   ptm = localtime(&when);
    163 #endif
    164 
    165   int year = ptm->tm_year;
    166   if (year < 80) {
    167     year = 80;
    168   }
    169 
    170   *out_date = (year - 80) << 9 | (ptm->tm_mon + 1) << 5 | ptm->tm_mday;
    171   *out_time = ptm->tm_hour << 11 | ptm->tm_min << 5 | ptm->tm_sec >> 1;
    172 }
    173 
    174 static void CopyFromFileEntry(const ZipWriter::FileEntry& src, bool use_data_descriptor,
    175                               LocalFileHeader* dst) {
    176   dst->lfh_signature = LocalFileHeader::kSignature;
    177   if (use_data_descriptor) {
    178     // Set this flag to denote that a DataDescriptor struct will appear after the data,
    179     // containing the crc and size fields.
    180     dst->gpb_flags |= kGPBDDFlagMask;
    181 
    182     // The size and crc fields must be 0.
    183     dst->compressed_size = 0u;
    184     dst->uncompressed_size = 0u;
    185     dst->crc32 = 0u;
    186   } else {
    187     dst->compressed_size = src.compressed_size;
    188     dst->uncompressed_size = src.uncompressed_size;
    189     dst->crc32 = src.crc32;
    190   }
    191   dst->compression_method = src.compression_method;
    192   dst->last_mod_time = src.last_mod_time;
    193   dst->last_mod_date = src.last_mod_date;
    194   dst->file_name_length = src.path.size();
    195   dst->extra_field_length = src.padding_length;
    196 }
    197 
    198 int32_t ZipWriter::StartAlignedEntryWithTime(const char* path, size_t flags, time_t time,
    199                                              uint32_t alignment) {
    200   if (state_ != State::kWritingZip) {
    201     return kInvalidState;
    202   }
    203 
    204   if (flags & kAlign32) {
    205     return kInvalidAlign32Flag;
    206   }
    207 
    208   if (powerof2(alignment) == 0) {
    209     return kInvalidAlignment;
    210   }
    211 
    212   FileEntry file_entry = {};
    213   file_entry.local_file_header_offset = current_offset_;
    214   file_entry.path = path;
    215 
    216   if (!IsValidEntryName(reinterpret_cast<const uint8_t*>(file_entry.path.data()),
    217                         file_entry.path.size())) {
    218     return kInvalidEntryName;
    219   }
    220 
    221   if (flags & ZipWriter::kCompress) {
    222     file_entry.compression_method = kCompressDeflated;
    223 
    224     int32_t result = PrepareDeflate();
    225     if (result != kNoError) {
    226       return result;
    227     }
    228   } else {
    229     file_entry.compression_method = kCompressStored;
    230   }
    231 
    232   ExtractTimeAndDate(time, &file_entry.last_mod_time, &file_entry.last_mod_date);
    233 
    234   off_t offset = current_offset_ + sizeof(LocalFileHeader) + file_entry.path.size();
    235   std::vector<char> zero_padding;
    236   if (alignment != 0 && (offset & (alignment - 1))) {
    237     // Pad the extra field so the data will be aligned.
    238     uint16_t padding = alignment - (offset % alignment);
    239     file_entry.padding_length = padding;
    240     offset += padding;
    241     zero_padding.resize(padding, 0);
    242   }
    243 
    244   LocalFileHeader header = {};
    245   // Always start expecting a data descriptor. When the data has finished being written,
    246   // if it is possible to seek back, the GPB flag will reset and the sizes written.
    247   CopyFromFileEntry(file_entry, true /*use_data_descriptor*/, &header);
    248 
    249   if (fwrite(&header, sizeof(header), 1, file_) != 1) {
    250     return HandleError(kIoError);
    251   }
    252 
    253   if (fwrite(path, sizeof(*path), file_entry.path.size(), file_) != file_entry.path.size()) {
    254     return HandleError(kIoError);
    255   }
    256 
    257   if (file_entry.padding_length != 0 && fwrite(zero_padding.data(), 1, file_entry.padding_length,
    258                                                file_) != file_entry.padding_length) {
    259     return HandleError(kIoError);
    260   }
    261 
    262   current_file_entry_ = std::move(file_entry);
    263   current_offset_ = offset;
    264   state_ = State::kWritingEntry;
    265   return kNoError;
    266 }
    267 
    268 int32_t ZipWriter::DiscardLastEntry() {
    269   if (state_ != State::kWritingZip || files_.empty()) {
    270     return kInvalidState;
    271   }
    272 
    273   FileEntry& last_entry = files_.back();
    274   current_offset_ = last_entry.local_file_header_offset;
    275   if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
    276     return HandleError(kIoError);
    277   }
    278   files_.pop_back();
    279   return kNoError;
    280 }
    281 
    282 int32_t ZipWriter::GetLastEntry(FileEntry* out_entry) {
    283   CHECK(out_entry != nullptr);
    284 
    285   if (files_.empty()) {
    286     return kInvalidState;
    287   }
    288   *out_entry = files_.back();
    289   return kNoError;
    290 }
    291 
    292 int32_t ZipWriter::PrepareDeflate() {
    293   CHECK(state_ == State::kWritingZip);
    294 
    295   // Initialize the z_stream for compression.
    296   z_stream_ = std::unique_ptr<z_stream, void (*)(z_stream*)>(new z_stream(), DeleteZStream);
    297 
    298 #pragma GCC diagnostic push
    299 #pragma GCC diagnostic ignored "-Wold-style-cast"
    300   int zerr = deflateInit2(z_stream_.get(), Z_BEST_COMPRESSION, Z_DEFLATED, -MAX_WBITS,
    301                           DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
    302 #pragma GCC diagnostic pop
    303 
    304   if (zerr != Z_OK) {
    305     if (zerr == Z_VERSION_ERROR) {
    306       ALOGE("Installed zlib is not compatible with linked version (%s)", ZLIB_VERSION);
    307       return HandleError(kZlibError);
    308     } else {
    309       ALOGE("deflateInit2 failed (zerr=%d)", zerr);
    310       return HandleError(kZlibError);
    311     }
    312   }
    313 
    314   z_stream_->next_out = buffer_.data();
    315   z_stream_->avail_out = buffer_.size();
    316   return kNoError;
    317 }
    318 
    319 int32_t ZipWriter::WriteBytes(const void* data, size_t len) {
    320   if (state_ != State::kWritingEntry) {
    321     return HandleError(kInvalidState);
    322   }
    323 
    324   int32_t result = kNoError;
    325   if (current_file_entry_.compression_method & kCompressDeflated) {
    326     result = CompressBytes(&current_file_entry_, data, len);
    327   } else {
    328     result = StoreBytes(&current_file_entry_, data, len);
    329   }
    330 
    331   if (result != kNoError) {
    332     return result;
    333   }
    334 
    335   current_file_entry_.crc32 =
    336       crc32(current_file_entry_.crc32, reinterpret_cast<const Bytef*>(data), len);
    337   current_file_entry_.uncompressed_size += len;
    338   return kNoError;
    339 }
    340 
    341 int32_t ZipWriter::StoreBytes(FileEntry* file, const void* data, size_t len) {
    342   CHECK(state_ == State::kWritingEntry);
    343 
    344   if (fwrite(data, 1, len, file_) != len) {
    345     return HandleError(kIoError);
    346   }
    347   file->compressed_size += len;
    348   current_offset_ += len;
    349   return kNoError;
    350 }
    351 
    352 int32_t ZipWriter::CompressBytes(FileEntry* file, const void* data, size_t len) {
    353   CHECK(state_ == State::kWritingEntry);
    354   CHECK(z_stream_);
    355   CHECK(z_stream_->next_out != nullptr);
    356   CHECK(z_stream_->avail_out != 0);
    357 
    358   // Prepare the input.
    359   z_stream_->next_in = reinterpret_cast<const uint8_t*>(data);
    360   z_stream_->avail_in = len;
    361 
    362   while (z_stream_->avail_in > 0) {
    363     // We have more data to compress.
    364     int zerr = deflate(z_stream_.get(), Z_NO_FLUSH);
    365     if (zerr != Z_OK) {
    366       return HandleError(kZlibError);
    367     }
    368 
    369     if (z_stream_->avail_out == 0) {
    370       // The output is full, let's write it to disk.
    371       size_t write_bytes = z_stream_->next_out - buffer_.data();
    372       if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
    373         return HandleError(kIoError);
    374       }
    375       file->compressed_size += write_bytes;
    376       current_offset_ += write_bytes;
    377 
    378       // Reset the output buffer for the next input.
    379       z_stream_->next_out = buffer_.data();
    380       z_stream_->avail_out = buffer_.size();
    381     }
    382   }
    383   return kNoError;
    384 }
    385 
    386 int32_t ZipWriter::FlushCompressedBytes(FileEntry* file) {
    387   CHECK(state_ == State::kWritingEntry);
    388   CHECK(z_stream_);
    389   CHECK(z_stream_->next_out != nullptr);
    390   CHECK(z_stream_->avail_out != 0);
    391 
    392   // Keep deflating while there isn't enough space in the buffer to
    393   // to complete the compress.
    394   int zerr;
    395   while ((zerr = deflate(z_stream_.get(), Z_FINISH)) == Z_OK) {
    396     CHECK(z_stream_->avail_out == 0);
    397     size_t write_bytes = z_stream_->next_out - buffer_.data();
    398     if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
    399       return HandleError(kIoError);
    400     }
    401     file->compressed_size += write_bytes;
    402     current_offset_ += write_bytes;
    403 
    404     z_stream_->next_out = buffer_.data();
    405     z_stream_->avail_out = buffer_.size();
    406   }
    407   if (zerr != Z_STREAM_END) {
    408     return HandleError(kZlibError);
    409   }
    410 
    411   size_t write_bytes = z_stream_->next_out - buffer_.data();
    412   if (write_bytes != 0) {
    413     if (fwrite(buffer_.data(), 1, write_bytes, file_) != write_bytes) {
    414       return HandleError(kIoError);
    415     }
    416     file->compressed_size += write_bytes;
    417     current_offset_ += write_bytes;
    418   }
    419   z_stream_.reset();
    420   return kNoError;
    421 }
    422 
    423 int32_t ZipWriter::FinishEntry() {
    424   if (state_ != State::kWritingEntry) {
    425     return kInvalidState;
    426   }
    427 
    428   if (current_file_entry_.compression_method & kCompressDeflated) {
    429     int32_t result = FlushCompressedBytes(&current_file_entry_);
    430     if (result != kNoError) {
    431       return result;
    432     }
    433   }
    434 
    435   if ((current_file_entry_.compression_method & kCompressDeflated) || !seekable_) {
    436     // Some versions of ZIP don't allow STORED data to have a trailing DataDescriptor.
    437     // If this file is not seekable, or if the data is compressed, write a DataDescriptor.
    438     const uint32_t sig = DataDescriptor::kOptSignature;
    439     if (fwrite(&sig, sizeof(sig), 1, file_) != 1) {
    440       return HandleError(kIoError);
    441     }
    442 
    443     DataDescriptor dd = {};
    444     dd.crc32 = current_file_entry_.crc32;
    445     dd.compressed_size = current_file_entry_.compressed_size;
    446     dd.uncompressed_size = current_file_entry_.uncompressed_size;
    447     if (fwrite(&dd, sizeof(dd), 1, file_) != 1) {
    448       return HandleError(kIoError);
    449     }
    450     current_offset_ += sizeof(DataDescriptor::kOptSignature) + sizeof(dd);
    451   } else {
    452     // Seek back to the header and rewrite to include the size.
    453     if (fseeko(file_, current_file_entry_.local_file_header_offset, SEEK_SET) != 0) {
    454       return HandleError(kIoError);
    455     }
    456 
    457     LocalFileHeader header = {};
    458     CopyFromFileEntry(current_file_entry_, false /*use_data_descriptor*/, &header);
    459 
    460     if (fwrite(&header, sizeof(header), 1, file_) != 1) {
    461       return HandleError(kIoError);
    462     }
    463 
    464     if (fseeko(file_, current_offset_, SEEK_SET) != 0) {
    465       return HandleError(kIoError);
    466     }
    467   }
    468 
    469   files_.emplace_back(std::move(current_file_entry_));
    470   state_ = State::kWritingZip;
    471   return kNoError;
    472 }
    473 
    474 int32_t ZipWriter::Finish() {
    475   if (state_ != State::kWritingZip) {
    476     return kInvalidState;
    477   }
    478 
    479   off_t startOfCdr = current_offset_;
    480   for (FileEntry& file : files_) {
    481     CentralDirectoryRecord cdr = {};
    482     cdr.record_signature = CentralDirectoryRecord::kSignature;
    483     if ((file.compression_method & kCompressDeflated) || !seekable_) {
    484       cdr.gpb_flags |= kGPBDDFlagMask;
    485     }
    486     cdr.compression_method = file.compression_method;
    487     cdr.last_mod_time = file.last_mod_time;
    488     cdr.last_mod_date = file.last_mod_date;
    489     cdr.crc32 = file.crc32;
    490     cdr.compressed_size = file.compressed_size;
    491     cdr.uncompressed_size = file.uncompressed_size;
    492     cdr.file_name_length = file.path.size();
    493     cdr.local_file_header_offset = static_cast<uint32_t>(file.local_file_header_offset);
    494     if (fwrite(&cdr, sizeof(cdr), 1, file_) != 1) {
    495       return HandleError(kIoError);
    496     }
    497 
    498     if (fwrite(file.path.data(), 1, file.path.size(), file_) != file.path.size()) {
    499       return HandleError(kIoError);
    500     }
    501 
    502     current_offset_ += sizeof(cdr) + file.path.size();
    503   }
    504 
    505   EocdRecord er = {};
    506   er.eocd_signature = EocdRecord::kSignature;
    507   er.disk_num = 0;
    508   er.cd_start_disk = 0;
    509   er.num_records_on_disk = files_.size();
    510   er.num_records = files_.size();
    511   er.cd_size = current_offset_ - startOfCdr;
    512   er.cd_start_offset = startOfCdr;
    513 
    514   if (fwrite(&er, sizeof(er), 1, file_) != 1) {
    515     return HandleError(kIoError);
    516   }
    517 
    518   current_offset_ += sizeof(er);
    519 
    520   // Since we can BackUp() and potentially finish writing at an offset less than one we had
    521   // already written at, we must truncate the file.
    522 
    523   if (ftruncate(fileno(file_), current_offset_) != 0) {
    524     return HandleError(kIoError);
    525   }
    526 
    527   if (fflush(file_) != 0) {
    528     return HandleError(kIoError);
    529   }
    530 
    531   state_ = State::kDone;
    532   return kNoError;
    533 }
    534