Index: ui/file_manager/zip_archiver/unpacker/cpp/volume.cc |
diff --git a/ui/file_manager/zip_archiver/unpacker/cpp/volume.cc b/ui/file_manager/zip_archiver/unpacker/cpp/volume.cc |
deleted file mode 100644 |
index 588698f57c291199ede886f2c899912420dfeacc..0000000000000000000000000000000000000000 |
--- a/ui/file_manager/zip_archiver/unpacker/cpp/volume.cc |
+++ /dev/null |
@@ -1,489 +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.h" |
- |
-#include <cstring> |
-#include <sstream> |
- |
-#include "request.h" |
-#include "volume_archive_libarchive.h" |
-#include "volume_reader_javascript_stream.h" |
- |
-namespace { |
- |
-#define LOG(x) \ |
- do { \ |
- std::stringstream fmt; \ |
- fmt << x; \ |
- message_sender_->CONSOLE_LOG(file_system_id_, request_id, fmt.str()); \ |
- } while (0) |
- |
-typedef std::map<std::string, VolumeArchive*>::const_iterator |
- volume_archive_iterator; |
- |
-const char kPathDelimiter[] = "/"; |
- |
-// size is int64_t and modification_time is time_t because this is how |
-// libarchive is going to pass them to us. |
-pp::VarDictionary CreateEntry(int64_t index, |
- const std::string& name, |
- bool is_directory, |
- int64_t size, |
- time_t modification_time) { |
- pp::VarDictionary entry_metadata; |
- // index is int64_t, unsupported by pp::Var |
- std::stringstream ss_index; |
- ss_index << index; |
- entry_metadata.Set("index", ss_index.str()); |
- entry_metadata.Set("isDirectory", is_directory); |
- entry_metadata.Set("name", name); |
- // size is int64_t, unsupported by pp::Var |
- std::stringstream ss_size; |
- ss_size << size; |
- entry_metadata.Set("size", ss_size.str()); |
- // mtime is time_t, unsupported by pp::Var |
- std::stringstream ss_modification_time; |
- ss_modification_time << modification_time; |
- entry_metadata.Set("modificationTime", ss_modification_time.str()); |
- |
- if (is_directory) |
- entry_metadata.Set("entries", pp::VarDictionary()); |
- |
- return entry_metadata; |
-} |
- |
-void ConstructMetadata(int64_t index, |
- const std::string& entry_path, |
- int64_t size, |
- bool is_directory, |
- time_t modification_time, |
- pp::VarDictionary* parent_metadata) { |
- if (entry_path == "") |
- return; |
- |
- pp::VarDictionary parent_entries = |
- pp::VarDictionary(parent_metadata->Get("entries")); |
- |
- unsigned int position = entry_path.find(kPathDelimiter); |
- pp::VarDictionary entry_metadata; |
- std::string entry_name; |
- |
- if (position == std::string::npos) { // The entry itself. |
- entry_name = entry_path; |
- entry_metadata = |
- CreateEntry(index, entry_name, is_directory, size, modification_time); |
- |
- // Update directory information. Required as sometimes the directory itself |
- // is returned after the files inside it. |
- pp::Var old_entry_metadata_var = parent_entries.Get(entry_name); |
- if (!old_entry_metadata_var.is_undefined()) { |
- pp::VarDictionary old_entry_metadata = |
- pp::VarDictionary(old_entry_metadata_var); |
- PP_DCHECK(old_entry_metadata.Get("isDirectory").AsBool()); |
- entry_metadata.Set("entries", old_entry_metadata.Get("entries")); |
- } |
- } else { // Get next parent on the way to the entry. |
- entry_name = entry_path.substr(0, position); |
- |
- // Get next parent metadata. If none, create a new directory entry for it. |
- // Some archives don't have directory information inside and for some the |
- // information is returned later than the files inside it. |
- pp::Var entry_metadata_var = parent_entries.Get(entry_name); |
- if (entry_metadata_var.is_undefined()) |
- entry_metadata = CreateEntry(-1, entry_name, true, 0, modification_time); |
- else |
- entry_metadata = pp::VarDictionary(parent_entries.Get(entry_name)); |
- |
- // Continue to construct metadata for all directories on the path to the |
- // to the entry and for the entry itself. |
- std::string entry_path_without_next_parent = entry_path.substr( |
- position + sizeof(kPathDelimiter) - 1 /* Last char is '\0'. */); |
- |
- ConstructMetadata(index, |
- entry_path_without_next_parent, |
- size, |
- is_directory, |
- modification_time, |
- &entry_metadata); |
- } |
- |
- // Recreate parent_metadata. This is necessary because pp::VarDictionary::Get |
- // returns a Var, not a Var& or Var* to directly modify the result. |
- parent_entries.Set(entry_name, entry_metadata); |
- parent_metadata->Set("entries", parent_entries); |
-} |
- |
-// An internal implementation of JavaScriptRequestorInterface. |
-class JavaScriptRequestor : public JavaScriptRequestorInterface { |
- public: |
- // JavaScriptRequestor does not own the volume pointer. |
- explicit JavaScriptRequestor(Volume* volume) : volume_(volume) {} |
- |
- virtual void RequestFileChunk(const std::string& request_id, |
- int64_t offset, |
- int64_t bytes_to_read) { |
- PP_DCHECK(offset >= 0); |
- PP_DCHECK(bytes_to_read > 0); |
- volume_->message_sender()->SendFileChunkRequest( |
- volume_->file_system_id(), request_id, offset, bytes_to_read); |
- } |
- |
- virtual void RequestPassphrase(const std::string& request_id) { |
- volume_->message_sender()->SendPassphraseRequest( |
- volume_->file_system_id(), request_id); |
- } |
- |
- private: |
- Volume* volume_; |
-}; |
- |
-// An internal implementation of VolumeArchiveFactoryInterface for default |
-// Volume constructor. |
-class VolumeArchiveFactory : public VolumeArchiveFactoryInterface { |
- public: |
- virtual VolumeArchive* Create(VolumeReader* reader) { |
- return new VolumeArchiveLibarchive(reader); |
- } |
-}; |
- |
-// An internal implementation of VolumeReaderFactoryInterface for default Volume |
-// constructor. |
-class VolumeReaderFactory : public VolumeReaderFactoryInterface { |
- public: |
- // VolumeReaderFactory does not own the volume pointer. |
- explicit VolumeReaderFactory(Volume* volume) : volume_(volume) {} |
- |
- virtual VolumeReader* Create(int64_t archive_size) { |
- return new VolumeReaderJavaScriptStream(archive_size, volume_->requestor()); |
- } |
- |
- private: |
- Volume* volume_; |
-}; |
- |
-} // namespace |
- |
-struct Volume::OpenFileArgs { |
- OpenFileArgs(const std::string& request_id, |
- int64_t index, |
- const std::string& encoding, |
- int64_t archive_size) : request_id(request_id), |
- index(index), |
- encoding(encoding), |
- archive_size(archive_size) {} |
- const std::string request_id; |
- const int64_t index; |
- const std::string encoding; |
- const int64_t archive_size; |
-}; |
- |
-Volume::Volume(const pp::InstanceHandle& instance_handle, |
- const std::string& file_system_id, |
- JavaScriptMessageSenderInterface* message_sender) |
- : volume_archive_(NULL), |
- file_system_id_(file_system_id), |
- message_sender_(message_sender), |
- worker_(instance_handle), |
- callback_factory_(this) { |
- requestor_ = new JavaScriptRequestor(this); |
- volume_archive_factory_ = new VolumeArchiveFactory(); |
- volume_reader_factory_ = new VolumeReaderFactory(this); |
- // Delegating constructors only from c++11. |
-} |
- |
-Volume::Volume(const pp::InstanceHandle& instance_handle, |
- const std::string& file_system_id, |
- JavaScriptMessageSenderInterface* message_sender, |
- VolumeArchiveFactoryInterface* volume_archive_factory, |
- VolumeReaderFactoryInterface* volume_reader_factory) |
- : volume_archive_(NULL), |
- file_system_id_(file_system_id), |
- message_sender_(message_sender), |
- worker_(instance_handle), |
- callback_factory_(this), |
- volume_archive_factory_(volume_archive_factory), |
- volume_reader_factory_(volume_reader_factory) { |
- requestor_ = new JavaScriptRequestor(this); |
-} |
- |
-Volume::~Volume() { |
- worker_.Join(); |
- |
- if (volume_archive_) { |
- volume_archive_->Cleanup(); |
- delete volume_archive_; |
- } |
- |
- delete requestor_; |
- delete volume_archive_factory_; |
- delete volume_reader_factory_; |
-} |
- |
-bool Volume::Init() { |
- return worker_.Start(); |
-} |
- |
-void Volume::ReadMetadata(const std::string& request_id, |
- const std::string& encoding, |
- int64_t archive_size) { |
- worker_.message_loop().PostWork(callback_factory_.NewCallback( |
- &Volume::ReadMetadataCallback, request_id, encoding, archive_size)); |
-} |
- |
-void Volume::OpenFile(const std::string& request_id, |
- int64_t index, |
- const std::string& encoding, |
- int64_t archive_size) { |
- worker_.message_loop().PostWork(callback_factory_.NewCallback( |
- &Volume::OpenFileCallback, OpenFileArgs(request_id, index, encoding, |
- archive_size))); |
-} |
- |
-void Volume::CloseFile(const std::string& request_id, |
- const std::string& open_request_id) { |
- // Though close file could be executed on main thread, we send it to worker_ |
- // in order to ensure thread safety. |
- worker_.message_loop().PostWork(callback_factory_.NewCallback( |
- &Volume::CloseFileCallback, request_id, open_request_id)); |
-} |
- |
-void Volume::ReadFile(const std::string& request_id, |
- const pp::VarDictionary& dictionary) { |
- worker_.message_loop().PostWork(callback_factory_.NewCallback( |
- &Volume::ReadFileCallback, request_id, dictionary)); |
-} |
- |
-void Volume::ReadChunkDone(const std::string& request_id, |
- const pp::VarArrayBuffer& array_buffer, |
- int64_t read_offset) { |
- PP_DCHECK(volume_archive_); |
- |
- job_lock_.Acquire(); |
- if (request_id == reader_request_id_) { |
- static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())-> |
- SetBufferAndSignal(array_buffer, read_offset); |
- } |
- job_lock_.Release(); |
-} |
- |
-void Volume::ReadChunkError(const std::string& request_id) { |
- PP_DCHECK(volume_archive_); |
- job_lock_.Acquire(); |
- if (request_id == reader_request_id_) { |
- static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())-> |
- ReadErrorSignal(); |
- } |
- job_lock_.Release(); |
-} |
- |
-void Volume::ReadPassphraseDone(const std::string& request_id, |
- const std::string& passphrase) { |
- PP_DCHECK(volume_archive_); |
- |
- job_lock_.Acquire(); |
- if (request_id == reader_request_id_) { |
- static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())-> |
- SetPassphraseAndSignal(passphrase); |
- } |
- job_lock_.Release(); |
-} |
- |
-void Volume::ReadPassphraseError(const std::string& request_id) { |
- PP_DCHECK(volume_archive_); |
- |
- job_lock_.Acquire(); |
- if (request_id == reader_request_id_) { |
- static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())-> |
- PassphraseErrorSignal(); |
- } |
- job_lock_.Release(); |
-} |
- |
-void Volume::ReadMetadataCallback(int32_t /*result*/, |
- const std::string& request_id, |
- const std::string& encoding, |
- int64_t archive_size) { |
- if (volume_archive_) { |
- message_sender_->SendFileSystemError( |
- file_system_id_, request_id, "ALREADY_OPENED"); |
- } |
- |
- job_lock_.Acquire(); |
- volume_archive_ = volume_archive_factory_->Create( |
- volume_reader_factory_->Create(archive_size)); |
- static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())-> |
- SetRequestId(request_id); |
- reader_request_id_ = request_id; |
- job_lock_.Release(); |
- |
- if (!volume_archive_->Init(encoding)) { |
- message_sender_->SendFileSystemError( |
- file_system_id_, request_id, volume_archive_->error_message()); |
- ClearJob(); |
- delete volume_archive_; |
- volume_archive_ = NULL; |
- return; |
- } |
- |
- // Read and construct metadata. |
- pp::VarDictionary root_metadata = CreateEntry(-1, "" /* name */, true, 0, 0); |
- |
- const char* path_name = NULL; |
- int64_t size = 0; |
- bool is_directory = false; |
- time_t modification_time = 0; |
- int64_t index = 0; |
- |
- for (;;) { |
- VolumeArchive::Result ret = volume_archive_->GetNextHeader( |
- &path_name, &size, &is_directory, &modification_time); |
- if (ret == VolumeArchive::RESULT_FAIL) { |
- message_sender_->SendFileSystemError( |
- file_system_id_, request_id, volume_archive_->error_message()); |
- ClearJob(); |
- delete volume_archive_; |
- volume_archive_ = NULL; |
- return; |
- } else if (ret == VolumeArchive::RESULT_EOF) |
- break; |
- |
- ConstructMetadata(index, path_name, size, is_directory, modification_time, |
- &root_metadata); |
- |
- ++index; |
- } |
- |
- ClearJob(); |
- |
- // Send metadata back to JavaScript. |
- message_sender_->SendReadMetadataDone( |
- file_system_id_, request_id, root_metadata); |
-} |
- |
-void Volume::OpenFileCallback(int32_t /*result*/, |
- const OpenFileArgs& args) { |
- if (!volume_archive_) { |
- message_sender_->SendFileSystemError( |
- file_system_id_, args.request_id, "NOT_OPENED"); |
- return; |
- } |
- |
- job_lock_.Acquire(); |
- if (!reader_request_id_.empty()) { |
- // It is illegal to open a file while another operation is in progress or |
- // another file is opened. |
- message_sender_->SendFileSystemError( |
- file_system_id_, args.request_id, "ILLEGAL"); |
- job_lock_.Release(); |
- return; |
- } |
- static_cast<VolumeReaderJavaScriptStream*>(volume_archive_->reader())-> |
- SetRequestId(args.request_id); |
- reader_request_id_ = args.request_id; |
- job_lock_.Release(); |
- |
- if (!volume_archive_->SeekHeader(args.index)) { |
- message_sender_->SendFileSystemError( |
- file_system_id_, args.request_id, volume_archive_->error_message()); |
- ClearJob(); |
- return; |
- } |
- |
- if (volume_archive_->GetNextHeader() == VolumeArchive::RESULT_FAIL) { |
- message_sender_->SendFileSystemError( |
- file_system_id_, args.request_id, volume_archive_->error_message()); |
- ClearJob(); |
- return; |
- } |
- |
- // Send successful opened file response to NaCl. |
- message_sender_->SendOpenFileDone(file_system_id_, args.request_id); |
-} |
- |
-void Volume::CloseFileCallback(int32_t /*result*/, |
- const std::string& request_id, |
- const std::string& open_request_id) { |
- job_lock_.Acquire(); |
- reader_request_id_ = ""; |
- job_lock_.Release(); |
- |
- message_sender_->SendCloseFileDone( |
- file_system_id_, request_id, open_request_id); |
-} |
- |
-void Volume::ReadFileCallback(int32_t /*result*/, |
- const std::string& request_id, |
- const pp::VarDictionary& dictionary) { |
- if (!volume_archive_) { |
- message_sender_->SendFileSystemError( |
- file_system_id_, request_id, "NOT_OPENED"); |
- return; |
- } |
- |
- std::string open_request_id( |
- dictionary.Get(request::key::kOpenRequestId).AsString()); |
- int64_t offset = |
- request::GetInt64FromString(dictionary, request::key::kOffset); |
- int64_t length = |
- request::GetInt64FromString(dictionary, request::key::kLength); |
- PP_DCHECK(length > 0); // JavaScript must not make requests with length <= 0. |
- |
- job_lock_.Acquire(); |
- if (open_request_id != reader_request_id_) { |
- // The file is not opened. |
- message_sender_->SendFileSystemError( |
- file_system_id_, request_id, "FILE_NOT_OPENED"); |
- job_lock_.Release(); |
- return; |
- } |
- job_lock_.Release(); |
- |
- // Decompress data and send it to JavaScript. Sending data is done in chunks |
- // depending on how many bytes VolumeArchive::ReadData returns. |
- int64_t left_length = length; |
- while (left_length > 0) { |
- const char* destination_buffer = NULL; |
- int64_t read_bytes = volume_archive_->ReadData( |
- offset, left_length, &destination_buffer); |
- |
- if (read_bytes < 0) { |
- // Error messages should be sent to the read request (request_id), not |
- // open request (open_request_id), as the last one has finished and this |
- // is a read file. |
- message_sender_->SendFileSystemError( |
- file_system_id_, request_id, volume_archive_->error_message()); |
- |
- // Should not cleanup VolumeArchive as Volume::CloseFile will be called in |
- // case of failure. |
- return; |
- } |
- |
- // Send response back to ReadFile request. |
- pp::VarArrayBuffer array_buffer(read_bytes); |
- if (read_bytes > 0) { |
- char* array_buffer_data = static_cast<char*>(array_buffer.Map()); |
- memcpy(array_buffer_data, destination_buffer, read_bytes); |
- array_buffer.Unmap(); |
- } |
- |
- bool has_more_data = left_length - read_bytes > 0 && read_bytes > 0; |
- message_sender_->SendReadFileDone( |
- file_system_id_, request_id, array_buffer, has_more_data); |
- |
- if (read_bytes == 0) |
- break; // No more available data. |
- |
- left_length -= read_bytes; |
- offset += read_bytes; |
- } |
- volume_archive_->MaybeDecompressAhead(); |
-} |
- |
- |
-void Volume::ClearJob() { |
- job_lock_.Acquire(); |
- reader_request_id_ = ""; |
- job_lock_.Release(); |
-} |