| /* |
| * Copyright (C) 2010 Google Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions are |
| * met: |
| * |
| * * Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * * Redistributions in binary form must reproduce the above |
| * copyright notice, this list of conditions and the following disclaimer |
| * in the documentation and/or other materials provided with the |
| * distribution. |
| * * Neither the name of Google Inc. nor the names of its |
| * contributors may be used to endorse or promote products derived from |
| * this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "modules/filesystem/FileSystemCallbacks.h" |
| |
| #include <memory> |
| |
| #include "base/memory/ptr_util.h" |
| #include "bindings/core/v8/V8VoidCallback.h" |
| #include "bindings/modules/v8/V8EntryCallback.h" |
| #include "bindings/modules/v8/V8ErrorCallback.h" |
| #include "bindings/modules/v8/V8FileCallback.h" |
| #include "bindings/modules/v8/V8FileSystemCallback.h" |
| #include "bindings/modules/v8/V8FileWriterCallback.h" |
| #include "bindings/modules/v8/V8MetadataCallback.h" |
| #include "core/dom/ExecutionContext.h" |
| #include "core/fileapi/File.h" |
| #include "core/fileapi/FileError.h" |
| #include "modules/filesystem/DOMFilePath.h" |
| #include "modules/filesystem/DOMFileSystem.h" |
| #include "modules/filesystem/DOMFileSystemBase.h" |
| #include "modules/filesystem/DirectoryEntry.h" |
| #include "modules/filesystem/DirectoryReader.h" |
| #include "modules/filesystem/Entry.h" |
| #include "modules/filesystem/FileEntry.h" |
| #include "modules/filesystem/FileWriter.h" |
| #include "modules/filesystem/Metadata.h" |
| #include "platform/FileMetadata.h" |
| #include "public/platform/WebFileWriter.h" |
| |
| namespace blink { |
| |
| FileSystemCallbacksBase::FileSystemCallbacksBase( |
| ErrorCallbackBase* error_callback, |
| DOMFileSystemBase* file_system, |
| ExecutionContext* context) |
| : error_callback_(error_callback), |
| file_system_(file_system), |
| execution_context_(context) { |
| DCHECK(execution_context_); |
| |
| if (file_system_) |
| file_system_->AddPendingCallbacks(); |
| } |
| |
| FileSystemCallbacksBase::~FileSystemCallbacksBase() { |
| if (file_system_) |
| file_system_->RemovePendingCallbacks(); |
| } |
| |
| void FileSystemCallbacksBase::DidFail(int code) { |
| if (error_callback_) { |
| InvokeOrScheduleCallback(&ErrorCallbackBase::Invoke, |
| error_callback_.Release(), |
| static_cast<FileError::ErrorCode>(code)); |
| } |
| } |
| |
| bool FileSystemCallbacksBase::ShouldScheduleCallback() const { |
| return !ShouldBlockUntilCompletion() && execution_context_ && |
| execution_context_->IsContextPaused(); |
| } |
| |
| template <typename CallbackMemberFunction, |
| typename CallbackClass, |
| typename... Args> |
| void FileSystemCallbacksBase::InvokeOrScheduleCallback( |
| CallbackMemberFunction&& callback_member_function, |
| CallbackClass&& callback_object, |
| Args&&... args) { |
| DCHECK(callback_object); |
| |
| if (ShouldScheduleCallback()) { |
| DOMFileSystem::ScheduleCallback( |
| execution_context_.Get(), |
| WTF::Bind(callback_member_function, WrapPersistent(callback_object), |
| WrapPersistentIfNeeded(args)...)); |
| } else { |
| ((*callback_object).*callback_member_function)(args...); |
| } |
| execution_context_.Clear(); |
| } |
| |
| // ScriptErrorCallback -------------------------------------------------------- |
| |
| // static |
| ScriptErrorCallback* ScriptErrorCallback::Wrap(V8ErrorCallback* callback) { |
| // DOMFileSystem operations take an optional (nullable) callback. If a |
| // script callback was not passed, don't bother creating a dummy wrapper |
| // and checking during invoke(). |
| if (!callback) |
| return nullptr; |
| return new ScriptErrorCallback(callback); |
| } |
| |
| void ScriptErrorCallback::Trace(blink::Visitor* visitor) { |
| ErrorCallbackBase::Trace(visitor); |
| visitor->Trace(callback_); |
| } |
| |
| void ScriptErrorCallback::Invoke(FileError::ErrorCode error) { |
| callback_->handleEvent(FileError::CreateDOMException(error)); |
| }; |
| |
| ScriptErrorCallback::ScriptErrorCallback(V8ErrorCallback* callback) |
| : callback_(callback) {} |
| |
| // EntryCallbacks ------------------------------------------------------------- |
| |
| void EntryCallbacks::OnDidGetEntryV8Impl::Trace(blink::Visitor* visitor) { |
| visitor->Trace(callback_); |
| OnDidGetEntryCallback::Trace(visitor); |
| } |
| |
| void EntryCallbacks::OnDidGetEntryV8Impl::OnSuccess(Entry* entry) { |
| callback_->handleEvent(entry); |
| } |
| |
| std::unique_ptr<AsyncFileSystemCallbacks> EntryCallbacks::Create( |
| OnDidGetEntryCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| DOMFileSystemBase* file_system, |
| const String& expected_path, |
| bool is_directory) { |
| return base::WrapUnique(new EntryCallbacks(success_callback, error_callback, |
| context, file_system, |
| expected_path, is_directory)); |
| } |
| |
| EntryCallbacks::EntryCallbacks(OnDidGetEntryCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| DOMFileSystemBase* file_system, |
| const String& expected_path, |
| bool is_directory) |
| : FileSystemCallbacksBase(error_callback, file_system, context), |
| success_callback_(success_callback), |
| expected_path_(expected_path), |
| is_directory_(is_directory) {} |
| |
| void EntryCallbacks::DidSucceed() { |
| if (!success_callback_) |
| return; |
| |
| Entry* entry = is_directory_ ? static_cast<Entry*>(DirectoryEntry::Create( |
| file_system_, expected_path_)) |
| : static_cast<Entry*>(FileEntry::Create( |
| file_system_, expected_path_)); |
| InvokeOrScheduleCallback(&OnDidGetEntryCallback::OnSuccess, |
| success_callback_.Release(), entry); |
| } |
| |
| // EntriesCallbacks ----------------------------------------------------------- |
| |
| std::unique_ptr<AsyncFileSystemCallbacks> EntriesCallbacks::Create( |
| OnDidGetEntriesCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| DirectoryReaderBase* directory_reader, |
| const String& base_path) { |
| return base::WrapUnique(new EntriesCallbacks( |
| success_callback, error_callback, context, directory_reader, base_path)); |
| } |
| |
| EntriesCallbacks::EntriesCallbacks(OnDidGetEntriesCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| DirectoryReaderBase* directory_reader, |
| const String& base_path) |
| : FileSystemCallbacksBase(error_callback, |
| directory_reader->Filesystem(), |
| context), |
| success_callback_(success_callback), |
| directory_reader_(directory_reader), |
| base_path_(base_path) { |
| DCHECK(directory_reader_); |
| } |
| |
| void EntriesCallbacks::DidReadDirectoryEntry(const String& name, |
| bool is_directory) { |
| DOMFileSystemBase* filesystem = directory_reader_->Filesystem(); |
| const String& path = DOMFilePath::Append(base_path_, name); |
| Entry* entry = |
| is_directory |
| ? static_cast<Entry*>(DirectoryEntry::Create(filesystem, path)) |
| : static_cast<Entry*>(FileEntry::Create(filesystem, path)); |
| entries_.push_back(entry); |
| } |
| |
| void EntriesCallbacks::DidReadDirectoryEntries(bool has_more) { |
| directory_reader_->SetHasMoreEntries(has_more); |
| EntryHeapVector* entries = new EntryHeapVector(std::move(entries_)); |
| |
| if (!success_callback_) |
| return; |
| |
| InvokeOrScheduleCallback(&OnDidGetEntriesCallback::OnSuccess, |
| success_callback_.Get(), entries); |
| } |
| |
| // FileSystemCallbacks -------------------------------------------------------- |
| |
| void FileSystemCallbacks::OnDidOpenFileSystemV8Impl::Trace( |
| blink::Visitor* visitor) { |
| visitor->Trace(callback_); |
| OnDidOpenFileSystemCallback::Trace(visitor); |
| } |
| |
| void FileSystemCallbacks::OnDidOpenFileSystemV8Impl::OnSuccess( |
| DOMFileSystem* file_system) { |
| callback_->handleEvent(file_system); |
| } |
| |
| std::unique_ptr<AsyncFileSystemCallbacks> FileSystemCallbacks::Create( |
| OnDidOpenFileSystemCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| FileSystemType type) { |
| return base::WrapUnique( |
| new FileSystemCallbacks(success_callback, error_callback, context, type)); |
| } |
| |
| FileSystemCallbacks::FileSystemCallbacks( |
| OnDidOpenFileSystemCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| FileSystemType type) |
| : FileSystemCallbacksBase(error_callback, nullptr, context), |
| success_callback_(success_callback), |
| type_(type) {} |
| |
| void FileSystemCallbacks::DidOpenFileSystem(const String& name, |
| const KURL& root_url) { |
| if (!success_callback_) |
| return; |
| |
| InvokeOrScheduleCallback( |
| &OnDidOpenFileSystemCallback::OnSuccess, success_callback_.Release(), |
| DOMFileSystem::Create(execution_context_.Get(), name, type_, root_url)); |
| } |
| |
| // ResolveURICallbacks -------------------------------------------------------- |
| |
| std::unique_ptr<AsyncFileSystemCallbacks> ResolveURICallbacks::Create( |
| OnDidGetEntryCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context) { |
| return base::WrapUnique( |
| new ResolveURICallbacks(success_callback, error_callback, context)); |
| } |
| |
| ResolveURICallbacks::ResolveURICallbacks( |
| OnDidGetEntryCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context) |
| : FileSystemCallbacksBase(error_callback, nullptr, context), |
| success_callback_(success_callback) { |
| DCHECK(success_callback_); |
| } |
| |
| void ResolveURICallbacks::DidResolveURL(const String& name, |
| const KURL& root_url, |
| FileSystemType type, |
| const String& file_path, |
| bool is_directory) { |
| DOMFileSystem* filesystem = |
| DOMFileSystem::Create(execution_context_.Get(), name, type, root_url); |
| DirectoryEntry* root = filesystem->root(); |
| |
| String absolute_path; |
| if (!DOMFileSystemBase::PathToAbsolutePath(type, root, file_path, |
| absolute_path)) { |
| DidFail(FileError::kInvalidModificationErr); |
| return; |
| } |
| |
| Entry* entry = |
| is_directory |
| ? static_cast<Entry*>( |
| DirectoryEntry::Create(filesystem, absolute_path)) |
| : static_cast<Entry*>(FileEntry::Create(filesystem, absolute_path)); |
| InvokeOrScheduleCallback(&OnDidGetEntryCallback::OnSuccess, |
| success_callback_.Release(), entry); |
| } |
| |
| // MetadataCallbacks ---------------------------------------------------------- |
| |
| void MetadataCallbacks::OnDidReadMetadataV8Impl::Trace( |
| blink::Visitor* visitor) { |
| visitor->Trace(callback_); |
| OnDidReadMetadataCallback::Trace(visitor); |
| } |
| |
| void MetadataCallbacks::OnDidReadMetadataV8Impl::OnSuccess(Metadata* metadata) { |
| callback_->handleEvent(metadata); |
| } |
| |
| std::unique_ptr<AsyncFileSystemCallbacks> MetadataCallbacks::Create( |
| OnDidReadMetadataCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| DOMFileSystemBase* file_system) { |
| return base::WrapUnique(new MetadataCallbacks( |
| success_callback, error_callback, context, file_system)); |
| } |
| |
| MetadataCallbacks::MetadataCallbacks( |
| OnDidReadMetadataCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| DOMFileSystemBase* file_system) |
| : FileSystemCallbacksBase(error_callback, file_system, context), |
| success_callback_(success_callback) {} |
| |
| void MetadataCallbacks::DidReadMetadata(const FileMetadata& metadata) { |
| if (!success_callback_) |
| return; |
| |
| InvokeOrScheduleCallback(&OnDidReadMetadataCallback::OnSuccess, |
| success_callback_.Release(), |
| Metadata::Create(metadata)); |
| } |
| |
| // FileWriterCallbacks ---------------------------------------------------- |
| |
| void FileWriterCallbacks::OnDidCreateFileWriterV8Impl::Trace( |
| blink::Visitor* visitor) { |
| visitor->Trace(callback_); |
| OnDidCreateFileWriterCallback::Trace(visitor); |
| } |
| |
| void FileWriterCallbacks::OnDidCreateFileWriterV8Impl::OnSuccess( |
| FileWriterBase* file_writer) { |
| // The call sites must pass a FileWriter in |file_writer|. |
| callback_->handleEvent(static_cast<FileWriter*>(file_writer)); |
| } |
| |
| std::unique_ptr<AsyncFileSystemCallbacks> FileWriterCallbacks::Create( |
| FileWriterBase* file_writer, |
| OnDidCreateFileWriterCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context) { |
| return base::WrapUnique(new FileWriterCallbacks(file_writer, success_callback, |
| error_callback, context)); |
| } |
| |
| FileWriterCallbacks::FileWriterCallbacks( |
| FileWriterBase* file_writer, |
| OnDidCreateFileWriterCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context) |
| : FileSystemCallbacksBase(error_callback, nullptr, context), |
| file_writer_(file_writer), |
| success_callback_(success_callback) {} |
| |
| void FileWriterCallbacks::DidCreateFileWriter( |
| std::unique_ptr<WebFileWriter> file_writer, |
| long long length) { |
| file_writer_->Initialize(std::move(file_writer), length); |
| |
| if (!success_callback_) |
| return; |
| |
| InvokeOrScheduleCallback(&OnDidCreateFileWriterCallback::OnSuccess, |
| success_callback_.Release(), file_writer_.Release()); |
| } |
| |
| // SnapshotFileCallback ------------------------------------------------------- |
| |
| void SnapshotFileCallback::OnDidCreateSnapshotFileV8Impl::Trace( |
| blink::Visitor* visitor) { |
| visitor->Trace(callback_); |
| OnDidCreateSnapshotFileCallback::Trace(visitor); |
| } |
| |
| void SnapshotFileCallback::OnDidCreateSnapshotFileV8Impl::OnSuccess( |
| File* file) { |
| callback_->handleEvent(file); |
| } |
| |
| std::unique_ptr<AsyncFileSystemCallbacks> SnapshotFileCallback::Create( |
| DOMFileSystemBase* filesystem, |
| const String& name, |
| const KURL& url, |
| OnDidCreateSnapshotFileCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context) { |
| return base::WrapUnique(new SnapshotFileCallback( |
| filesystem, name, url, success_callback, error_callback, context)); |
| } |
| |
| SnapshotFileCallback::SnapshotFileCallback( |
| DOMFileSystemBase* filesystem, |
| const String& name, |
| const KURL& url, |
| OnDidCreateSnapshotFileCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context) |
| : FileSystemCallbacksBase(error_callback, filesystem, context), |
| name_(name), |
| url_(url), |
| success_callback_(success_callback) {} |
| |
| void SnapshotFileCallback::DidCreateSnapshotFile( |
| const FileMetadata& metadata, |
| scoped_refptr<BlobDataHandle> snapshot) { |
| if (!success_callback_) |
| return; |
| |
| // We can't directly use the snapshot blob data handle because the content |
| // type on it hasn't been set. The |snapshot| param is here to provide a |
| // chain of custody thru thread bridging that is held onto until *after* we've |
| // coined a File with a new handle that has the correct type set on it. This |
| // allows the blob storage system to track when a temp file can and can't be |
| // safely deleted. |
| |
| InvokeOrScheduleCallback(&OnDidCreateSnapshotFileCallback::OnSuccess, |
| success_callback_.Release(), |
| DOMFileSystemBase::CreateFile( |
| metadata, url_, file_system_->GetType(), name_)); |
| } |
| |
| // VoidCallbacks -------------------------------------------------------------- |
| |
| void VoidCallbacks::OnDidSucceedV8Impl::Trace(blink::Visitor* visitor) { |
| visitor->Trace(callback_); |
| OnDidSucceedCallback::Trace(visitor); |
| } |
| |
| void VoidCallbacks::OnDidSucceedV8Impl::OnSuccess( |
| ExecutionContext* dummy_arg_for_sync_helper) { |
| callback_->handleEvent(); |
| } |
| |
| std::unique_ptr<AsyncFileSystemCallbacks> VoidCallbacks::Create( |
| OnDidSucceedCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| DOMFileSystemBase* file_system) { |
| return base::WrapUnique(new VoidCallbacks(success_callback, error_callback, |
| context, file_system)); |
| } |
| |
| VoidCallbacks::VoidCallbacks(OnDidSucceedCallback* success_callback, |
| ErrorCallbackBase* error_callback, |
| ExecutionContext* context, |
| DOMFileSystemBase* file_system) |
| : FileSystemCallbacksBase(error_callback, file_system, context), |
| success_callback_(success_callback) {} |
| |
| void VoidCallbacks::DidSucceed() { |
| if (!success_callback_) |
| return; |
| |
| InvokeOrScheduleCallback(&OnDidSucceedCallback::OnSuccess, |
| success_callback_.Release(), |
| execution_context_.Get()); |
| } |
| |
| } // namespace blink |