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 */ 37enum { 38 kCompressStored = 0, // no compression 39 kCompressDeflated = 8, // standard deflate 40}; 41 42// Size of the output buffer used for compression. 43static const size_t kBufSize = 32768u; 44 45// No error, operation completed successfully. 46static const int32_t kNoError = 0; 47 48// The ZipWriter is in a bad state. 49static const int32_t kInvalidState = -1; 50 51// There was an IO error while writing to disk. 52static const int32_t kIoError = -2; 53 54// The zip entry name was invalid. 55static const int32_t kInvalidEntryName = -3; 56 57// An error occurred in zlib. 58static const int32_t kZlibError = -4; 59 60// The start aligned function was called with the aligned flag. 61static const int32_t kInvalidAlign32Flag = -5; 62 63// The alignment parameter is not a power of 2. 64static const int32_t kInvalidAlignment = -6; 65 66static const char* sErrorCodes[] = { 67 "Invalid state", 68 "IO error", 69 "Invalid entry name", 70 "Zlib error", 71}; 72 73const 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 80static void DeleteZStream(z_stream* stream) { 81 deflateEnd(stream); 82 delete stream; 83} 84 85ZipWriter::ZipWriter(FILE* f) : file_(f), current_offset_(0), state_(State::kWritingZip), 86 z_stream_(nullptr, DeleteZStream), buffer_(kBufSize) { 87} 88 89ZipWriter::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 99ZipWriter& 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 111int32_t ZipWriter::HandleError(int32_t error_code) { 112 state_ = State::kError; 113 z_stream_.reset(); 114 return error_code; 115} 116 117int32_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 126int32_t ZipWriter::StartAlignedEntry(const char* path, size_t flags, uint32_t alignment) { 127 return StartAlignedEntryWithTime(path, flags, time_t(), alignment); 128} 129 130int32_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 139static 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 160int32_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 240int32_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 263int32_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(¤tFile, data, len); 272 } else { 273 result = StoreBytes(¤tFile, 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 285int32_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 296int32_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 330int32_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 367int32_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(¤tFile); 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 399int32_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