Index: ui/file_manager/zip_archiver/unpacker/cpp/volume_archive_libarchive.cc |
diff --git a/ui/file_manager/zip_archiver/unpacker/cpp/volume_archive_libarchive.cc b/ui/file_manager/zip_archiver/unpacker/cpp/volume_archive_libarchive.cc |
deleted file mode 100644 |
index 72f71d63573796f9aa289dfea9932676a37ff528..0000000000000000000000000000000000000000 |
--- a/ui/file_manager/zip_archiver/unpacker/cpp/volume_archive_libarchive.cc |
+++ /dev/null |
@@ -1,354 +0,0 @@ |
-// Copyright 2014 The Chromium OS Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "volume_archive_libarchive.h" |
- |
-#include <algorithm> |
-#include <cerrno> |
-#include <limits> |
- |
-#include "archive_entry.h" |
-#include "ppapi/cpp/logging.h" |
- |
-namespace { |
- |
-const int64_t kArchiveReadDataError = -1; // Negative value means error. |
- |
-std::string ArchiveError(const std::string& message, archive* archive_object) { |
- return message + archive_error_string(archive_object); |
-} |
- |
-// Sets the libarchive internal error to a VolumeReader related error. |
-// archive_error_string function must work on valid strings, but in case of |
-// errors in the custom functions, libarchive API assumes the error is set by |
-// us. If we don't set it, we will get a Segmentation Fault because |
-// archive_error_string will work on invalid memory. |
-void SetLibarchiveErrorToVolumeReaderError(archive* archive_object) { |
- archive_set_error(archive_object, |
- EIO /* I/O error. */, |
- "%s" /* Format string similar to printf. */, |
- volume_archive_constants::kVolumeReaderError); |
-} |
- |
-ssize_t CustomArchiveRead(archive* archive_object, |
- void* client_data, |
- const void** buffer) { |
- VolumeArchiveLibarchive* volume_archive = |
- static_cast<VolumeArchiveLibarchive*>(client_data); |
- |
- int64_t read_bytes = volume_archive->reader()->Read( |
- volume_archive->reader_data_size(), buffer); |
- if (read_bytes == ARCHIVE_FATAL) |
- SetLibarchiveErrorToVolumeReaderError(archive_object); |
- return read_bytes; |
-} |
- |
-int64_t CustomArchiveSkip(archive* archive_object, |
- void* client_data, |
- int64_t request) { |
- VolumeArchiveLibarchive* volume_archive = |
- static_cast<VolumeArchiveLibarchive*>(client_data); |
- // VolumeReader::Skip returns 0 in case of failure and CustomArchiveRead is |
- // used instead, so there is no need to check for VolumeReader error. |
- return volume_archive->reader()->Skip(request); |
-} |
- |
-int64_t CustomArchiveSeek(archive* archive_object, |
- void* client_data, |
- int64_t offset, |
- int whence) { |
- VolumeArchiveLibarchive* volume_archive = |
- static_cast<VolumeArchiveLibarchive*>(client_data); |
- |
- int64_t new_offset = volume_archive->reader()->Seek(offset, whence); |
- if (new_offset == ARCHIVE_FATAL) |
- SetLibarchiveErrorToVolumeReaderError(archive_object); |
- |
- return new_offset; |
-} |
- |
-int CustomArchiveClose(archive* archive_object, void* client_data) { |
- return ARCHIVE_OK; |
-} |
- |
-const char* CustomArchivePassphrase( |
- archive* archive_object, void* client_data) { |
- VolumeArchiveLibarchive* volume_archive = |
- static_cast<VolumeArchiveLibarchive*>(client_data); |
- |
- return volume_archive->reader()->Passphrase(); |
-} |
- |
-} // namespace |
- |
-VolumeArchiveLibarchive::VolumeArchiveLibarchive(VolumeReader* reader) |
- : VolumeArchive(reader), |
- reader_data_size_(volume_archive_constants::kMinimumDataChunkSize), |
- archive_(NULL), |
- current_archive_entry_(NULL), |
- last_read_data_offset_(0), |
- last_read_data_length_(0), |
- decompressed_data_(NULL), |
- decompressed_data_size_(0), |
- decompressed_error_(false) { |
-} |
- |
-VolumeArchiveLibarchive::~VolumeArchiveLibarchive() { |
- Cleanup(); |
-} |
- |
-bool VolumeArchiveLibarchive::Init(const std::string& encoding) { |
- archive_ = archive_read_new(); |
- if (!archive_) { |
- set_error_message(volume_archive_constants::kArchiveReadNewError); |
- return false; |
- } |
- |
- // TODO(cmihail): Once the bug mentioned at |
- // https://github.com/libarchive/libarchive/issues/373 is resolved |
- // add RAR file handler to manifest.json. |
- if (archive_read_support_format_rar(archive_) != ARCHIVE_OK || |
- archive_read_support_format_zip_seekable(archive_) != ARCHIVE_OK) { |
- set_error_message(ArchiveError( |
- volume_archive_constants::kArchiveSupportErrorPrefix, archive_)); |
- return false; |
- } |
- |
- // Default encoding for file names in headers. Note, that another one may be |
- // used if specified in the archive. |
- std::string options = std::string("hdrcharset=") + encoding; |
- if (!encoding.empty() && |
- archive_read_set_options(archive_, options.c_str()) != ARCHIVE_OK) { |
- set_error_message(ArchiveError( |
- volume_archive_constants::kArchiveSupportErrorPrefix, archive_)); |
- return false; |
- } |
- |
- // Set callbacks for processing the archive's data and open the archive. |
- // The callback data is the VolumeArchive itself. |
- int ok = ARCHIVE_OK; |
- if (archive_read_set_read_callback(archive_, CustomArchiveRead) != ok || |
- archive_read_set_skip_callback(archive_, CustomArchiveSkip) != ok || |
- archive_read_set_seek_callback(archive_, CustomArchiveSeek) != ok || |
- archive_read_set_close_callback(archive_, CustomArchiveClose) != ok || |
- archive_read_set_passphrase_callback( |
- archive_, this, CustomArchivePassphrase) != ok || |
- archive_read_set_callback_data(archive_, this) != ok || |
- archive_read_open1(archive_) != ok) { |
- set_error_message(ArchiveError( |
- volume_archive_constants::kArchiveOpenErrorPrefix, archive_)); |
- return false; |
- } |
- |
- return true; |
-} |
- |
-VolumeArchive::Result VolumeArchiveLibarchive::GetNextHeader() { |
- // Headers are being read from the central directory (in the ZIP format), so |
- // use a large block size to save on IPC calls. The headers in EOCD are |
- // grouped one by one. |
- reader_data_size_ = volume_archive_constants::kMaximumDataChunkSize; |
- |
- // Reset to 0 for new VolumeArchive::ReadData operation. |
- last_read_data_offset_ = 0; |
- decompressed_data_size_ = 0; |
- |
- // Archive data is skipped automatically by next call to |
- // archive_read_next_header. |
- switch (archive_read_next_header(archive_, ¤t_archive_entry_)) { |
- case ARCHIVE_EOF: |
- return RESULT_EOF; |
- case ARCHIVE_OK: |
- return RESULT_SUCCESS; |
- default: |
- set_error_message(ArchiveError( |
- volume_archive_constants::kArchiveNextHeaderErrorPrefix, archive_)); |
- return RESULT_FAIL; |
- } |
-} |
- |
-VolumeArchive::Result VolumeArchiveLibarchive::GetNextHeader( |
- const char** pathname, |
- int64_t* size, |
- bool* is_directory, |
- time_t* modification_time) { |
- Result ret = GetNextHeader(); |
- |
- if (ret == RESULT_SUCCESS) { |
- *pathname = archive_entry_pathname(current_archive_entry_); |
- *size = archive_entry_size(current_archive_entry_); |
- *modification_time = archive_entry_mtime(current_archive_entry_); |
- *is_directory = archive_entry_filetype(current_archive_entry_) == AE_IFDIR; |
- } |
- |
- return ret; |
-} |
- |
-bool VolumeArchiveLibarchive::SeekHeader(int64_t index) { |
- // Reset to 0 for new VolumeArchive::ReadData operation. |
- last_read_data_offset_ = 0; |
- decompressed_data_size_ = 0; |
- |
- if (archive_read_seek_header(archive_, index) != ARCHIVE_OK) { |
- set_error_message(ArchiveError( |
- volume_archive_constants::kArchiveNextHeaderErrorPrefix, archive_)); |
- return false; |
- } |
- |
- return true; |
-} |
- |
-void VolumeArchiveLibarchive::DecompressData(int64_t offset, int64_t length) { |
- // TODO(cmihail): As an optimization consider using archive_read_data_block |
- // which avoids extra copying in case offset != last_read_data_offset_. |
- // The logic will be more complicated because archive_read_data_block offset |
- // will not be aligned with the offset of the read request from JavaScript. |
- |
- // Requests with offset smaller than last read offset are not supported. |
- if (offset < last_read_data_offset_) { |
- set_error_message( |
- std::string(volume_archive_constants::kArchiveReadDataErrorPrefix) + |
- "Reading backwards is not supported."); |
- decompressed_error_ = true; |
- return; |
- } |
- |
- // Request with offset greater than last read offset. Skip not needed bytes. |
- // Because files are compressed, seeking is not possible, so all of the bytes |
- // until the requested position must be unpacked. |
- ssize_t size = -1; |
- while (offset > last_read_data_offset_) { |
- // ReadData will call CustomArchiveRead when calling archive_read_data. Read |
- // should not request more bytes than possibly needed, so we request either |
- // offset - last_read_data_offset_, kMaximumDataChunkSize in case the former |
- // is too big or kMinimumDataChunkSize in case its too small and we might |
- // end up with too many IPCs. |
- reader_data_size_ = |
- std::max(std::min(offset - last_read_data_offset_, |
- volume_archive_constants::kMaximumDataChunkSize), |
- volume_archive_constants::kMinimumDataChunkSize); |
- |
- // No need for an offset in dummy_buffer as it will be ignored anyway. |
- // archive_read_data receives size_t as length parameter, but we limit it to |
- // volume_archive_constants::kDummyBufferSize which is positive and less |
- // than size_t maximum. So conversion from int64_t to size_t is safe here. |
- size = |
- archive_read_data(archive_, |
- dummy_buffer_, |
- std::min(offset - last_read_data_offset_, |
- volume_archive_constants::kDummyBufferSize)); |
- PP_DCHECK(size != 0); // The actual read is done below. We shouldn't get to |
- // end of file here. |
- if (size < 0) { // Error. |
- set_error_message(ArchiveError( |
- volume_archive_constants::kArchiveReadDataErrorPrefix, archive_)); |
- decompressed_error_ = true; |
- return; |
- } |
- last_read_data_offset_ += size; |
- } |
- |
- // Do not decompress more bytes than we can store internally. The |
- // kDecompressBufferSize limit is used to avoid huge memory usage. |
- int64_t left_length = |
- std::min(length, volume_archive_constants::kDecompressBufferSize); |
- |
- // ReadData will call CustomArchiveRead when calling archive_read_data. The |
- // read should be done with a value similar to length, which is the requested |
- // number of bytes, or kMaximumDataChunkSize / kMinimumDataChunkSize |
- // in case length is too big or too small. |
- reader_data_size_ = |
- std::max(std::min(static_cast<int64_t>(left_length), |
- volume_archive_constants::kMaximumDataChunkSize), |
- volume_archive_constants::kMinimumDataChunkSize); |
- |
- // Perform the actual copy. |
- int64_t bytes_read = 0; |
- do { |
- // archive_read_data receives size_t as length parameter, but we limit it to |
- // volume_archive_constants::kMinimumDataChunkSize (see left_length |
- // initialization), which is positive and less than size_t maximum. |
- // So conversion from int64_t to size_t is safe here. |
- size = archive_read_data( |
- archive_, decompressed_data_buffer_ + bytes_read, left_length); |
- if (size < 0) { // Error. |
- set_error_message(ArchiveError( |
- volume_archive_constants::kArchiveReadDataErrorPrefix, archive_)); |
- decompressed_error_ = true; |
- return; |
- } |
- bytes_read += size; |
- left_length -= size; |
- } while (left_length > 0 && size != 0); // There is still data to read. |
- |
- // VolumeArchiveLibarchive::DecompressData always stores the data from |
- // beginning of the buffer. VolumeArchiveLibarchive::ConsumeData is used |
- // to preserve the bytes that are decompressed but not required by |
- // VolumeArchiveLibarchive::ReadData. |
- decompressed_data_ = decompressed_data_buffer_; |
- decompressed_data_size_ = bytes_read; |
-} |
- |
-bool VolumeArchiveLibarchive::Cleanup() { |
- bool returnValue = true; |
- if (archive_ && archive_read_free(archive_) != ARCHIVE_OK) { |
- set_error_message(ArchiveError( |
- volume_archive_constants::kArchiveReadFreeErrorPrefix, archive_)); |
- returnValue = false; // Cleanup should release all resources even |
- // in case of failures. |
- } |
- archive_ = NULL; |
- |
- CleanupReader(); |
- |
- return returnValue; |
-} |
- |
-int64_t VolumeArchiveLibarchive::ReadData(int64_t offset, |
- int64_t length, |
- const char** buffer) { |
- PP_DCHECK(length > 0); // Length must be at least 1. |
- PP_DCHECK(current_archive_entry_); // Check that GetNextHeader was called at |
- // least once. In case it wasn't, this is |
- // a programmer error. |
- |
- // End of archive. |
- if (archive_entry_size_is_set(current_archive_entry_) && |
- archive_entry_size(current_archive_entry_) <= offset) |
- return 0; |
- |
- // In case of first read or no more available data in the internal buffer or |
- // offset is different from the last_read_data_offset_, then force |
- // VolumeArchiveLibarchive::DecompressData as the decompressed data is |
- // invalid. |
- if (!decompressed_data_ || last_read_data_offset_ != offset || |
- decompressed_data_size_ == 0) |
- DecompressData(offset, length); |
- |
- // Decompressed failed. |
- if (decompressed_error_) |
- return kArchiveReadDataError; |
- |
- last_read_data_length_ = length; // Used for decompress ahead. |
- |
- // Assign the output *buffer parameter to the internal buffer. |
- *buffer = decompressed_data_; |
- |
- // Advance internal buffer for next ReadData call. |
- int64_t read_bytes = std::min(decompressed_data_size_, length); |
- decompressed_data_ = decompressed_data_ + read_bytes; |
- decompressed_data_size_ -= read_bytes; |
- last_read_data_offset_ += read_bytes; |
- |
- PP_DCHECK(decompressed_data_ + decompressed_data_size_ <= |
- decompressed_data_buffer_ + |
- volume_archive_constants::kDecompressBufferSize); |
- |
- return read_bytes; |
-} |
- |
-void VolumeArchiveLibarchive::MaybeDecompressAhead() { |
- if (decompressed_data_size_ == 0) |
- DecompressData(last_read_data_offset_, last_read_data_length_); |
-} |