1/* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31#include "config.h" 32#include "modules/filesystem/FileSystemCallbacks.h" 33 34#include "core/dom/ExecutionContext.h" 35#include "core/fileapi/File.h" 36#include "core/fileapi/FileError.h" 37#include "core/html/VoidCallback.h" 38#include "core/inspector/InspectorInstrumentation.h" 39#include "modules/filesystem/DOMFilePath.h" 40#include "modules/filesystem/DOMFileSystem.h" 41#include "modules/filesystem/DOMFileSystemBase.h" 42#include "modules/filesystem/DirectoryEntry.h" 43#include "modules/filesystem/DirectoryReader.h" 44#include "modules/filesystem/Entry.h" 45#include "modules/filesystem/EntryCallback.h" 46#include "modules/filesystem/ErrorCallback.h" 47#include "modules/filesystem/FileCallback.h" 48#include "modules/filesystem/FileEntry.h" 49#include "modules/filesystem/FileSystemCallback.h" 50#include "modules/filesystem/FileWriterBase.h" 51#include "modules/filesystem/FileWriterBaseCallback.h" 52#include "modules/filesystem/Metadata.h" 53#include "modules/filesystem/MetadataCallback.h" 54#include "platform/FileMetadata.h" 55#include "public/platform/WebFileWriter.h" 56 57namespace blink { 58 59FileSystemCallbacksBase::FileSystemCallbacksBase(ErrorCallback* errorCallback, DOMFileSystemBase* fileSystem, ExecutionContext* context) 60 : m_errorCallback(errorCallback) 61 , m_fileSystem(fileSystem) 62 , m_executionContext(context) 63 , m_asyncOperationId(0) 64{ 65 if (m_fileSystem) 66 m_fileSystem->addPendingCallbacks(); 67 if (m_executionContext) 68 m_asyncOperationId = InspectorInstrumentation::traceAsyncOperationStarting(m_executionContext.get(), "FileSystem"); 69} 70 71FileSystemCallbacksBase::~FileSystemCallbacksBase() 72{ 73 if (m_fileSystem) 74 m_fileSystem->removePendingCallbacks(); 75 if (m_asyncOperationId && m_executionContext) 76 InspectorInstrumentation::traceAsyncOperationCompleted(m_executionContext.get(), m_asyncOperationId); 77} 78 79void FileSystemCallbacksBase::didFail(int code) 80{ 81 if (m_errorCallback) 82 handleEventOrScheduleCallback(m_errorCallback.release(), FileError::create(static_cast<FileError::ErrorCode>(code))); 83} 84 85bool FileSystemCallbacksBase::shouldScheduleCallback() const 86{ 87 return !shouldBlockUntilCompletion() && m_executionContext && m_executionContext->activeDOMObjectsAreSuspended(); 88} 89 90#if !ENABLE(OILPAN) 91template <typename CB, typename CBArg> 92void FileSystemCallbacksBase::handleEventOrScheduleCallback(RawPtr<CB> callback, RawPtr<CBArg> arg) 93{ 94 handleEventOrScheduleCallback(callback, arg.get()); 95} 96#endif 97 98template <typename CB, typename CBArg> 99void FileSystemCallbacksBase::handleEventOrScheduleCallback(RawPtr<CB> callback, CBArg* arg) 100{ 101 ASSERT(callback); 102 InspectorInstrumentationCookie cookie = InspectorInstrumentation::traceAsyncOperationCompletedCallbackStarting(m_executionContext.get(), m_asyncOperationId); 103 if (shouldScheduleCallback()) 104 DOMFileSystem::scheduleCallback(m_executionContext.get(), callback.get(), arg); 105 else if (callback) 106 callback->handleEvent(arg); 107 m_executionContext.clear(); 108 InspectorInstrumentation::traceAsyncCallbackCompleted(cookie); 109} 110 111template <typename CB, typename CBArg> 112void FileSystemCallbacksBase::handleEventOrScheduleCallback(RawPtr<CB> callback, PassRefPtrWillBeRawPtr<CBArg> arg) 113{ 114 ASSERT(callback); 115 InspectorInstrumentationCookie cookie = InspectorInstrumentation::traceAsyncOperationCompletedCallbackStarting(m_executionContext.get(), m_asyncOperationId); 116 if (shouldScheduleCallback()) 117 DOMFileSystem::scheduleCallback(m_executionContext.get(), callback.get(), arg); 118 else if (callback) 119 callback->handleEvent(arg.get()); 120 m_executionContext.clear(); 121 InspectorInstrumentation::traceAsyncCallbackCompleted(cookie); 122} 123 124template <typename CB> 125void FileSystemCallbacksBase::handleEventOrScheduleCallback(RawPtr<CB> callback) 126{ 127 ASSERT(callback); 128 InspectorInstrumentationCookie cookie = InspectorInstrumentation::traceAsyncOperationCompletedCallbackStarting(m_executionContext.get(), m_asyncOperationId); 129 if (shouldScheduleCallback()) 130 DOMFileSystem::scheduleCallback(m_executionContext.get(), callback.get()); 131 else if (callback) 132 callback->handleEvent(); 133 m_executionContext.clear(); 134 InspectorInstrumentation::traceAsyncCallbackCompleted(cookie); 135} 136 137// EntryCallbacks ------------------------------------------------------------- 138 139PassOwnPtr<AsyncFileSystemCallbacks> EntryCallbacks::create(EntryCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem, const String& expectedPath, bool isDirectory) 140{ 141 return adoptPtr(new EntryCallbacks(successCallback, errorCallback, context, fileSystem, expectedPath, isDirectory)); 142} 143 144EntryCallbacks::EntryCallbacks(EntryCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem, const String& expectedPath, bool isDirectory) 145 : FileSystemCallbacksBase(errorCallback, fileSystem, context) 146 , m_successCallback(successCallback) 147 , m_expectedPath(expectedPath) 148 , m_isDirectory(isDirectory) 149{ 150} 151 152void EntryCallbacks::didSucceed() 153{ 154 if (m_successCallback) { 155 if (m_isDirectory) 156 handleEventOrScheduleCallback(m_successCallback.release(), DirectoryEntry::create(m_fileSystem, m_expectedPath)); 157 else 158 handleEventOrScheduleCallback(m_successCallback.release(), FileEntry::create(m_fileSystem, m_expectedPath)); 159 } 160} 161 162// EntriesCallbacks ----------------------------------------------------------- 163 164PassOwnPtr<AsyncFileSystemCallbacks> EntriesCallbacks::create(EntriesCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DirectoryReaderBase* directoryReader, const String& basePath) 165{ 166 return adoptPtr(new EntriesCallbacks(successCallback, errorCallback, context, directoryReader, basePath)); 167} 168 169EntriesCallbacks::EntriesCallbacks(EntriesCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DirectoryReaderBase* directoryReader, const String& basePath) 170 : FileSystemCallbacksBase(errorCallback, directoryReader->filesystem(), context) 171 , m_successCallback(successCallback) 172 , m_directoryReader(directoryReader) 173 , m_basePath(basePath) 174{ 175 ASSERT(m_directoryReader); 176} 177 178void EntriesCallbacks::didReadDirectoryEntry(const String& name, bool isDirectory) 179{ 180 if (isDirectory) 181 m_entries.append(DirectoryEntry::create(m_directoryReader->filesystem(), DOMFilePath::append(m_basePath, name))); 182 else 183 m_entries.append(FileEntry::create(m_directoryReader->filesystem(), DOMFilePath::append(m_basePath, name))); 184} 185 186void EntriesCallbacks::didReadDirectoryEntries(bool hasMore) 187{ 188 m_directoryReader->setHasMoreEntries(hasMore); 189 EntryHeapVector entries; 190 entries.swap(m_entries); 191 // FIXME: delay the callback iff shouldScheduleCallback() is true. 192 InspectorInstrumentationCookie cookie = InspectorInstrumentation::traceAsyncCallbackStarting(m_executionContext.get(), m_asyncOperationId); 193 if (m_successCallback) 194 m_successCallback->handleEvent(entries); 195 InspectorInstrumentation::traceAsyncCallbackCompleted(cookie); 196 if (!hasMore) 197 InspectorInstrumentation::traceAsyncOperationCompleted(m_executionContext.get(), m_asyncOperationId); 198} 199 200// FileSystemCallbacks -------------------------------------------------------- 201 202PassOwnPtr<AsyncFileSystemCallbacks> FileSystemCallbacks::create(FileSystemCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, FileSystemType type) 203{ 204 return adoptPtr(new FileSystemCallbacks(successCallback, errorCallback, context, type)); 205} 206 207FileSystemCallbacks::FileSystemCallbacks(FileSystemCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, FileSystemType type) 208 : FileSystemCallbacksBase(errorCallback, nullptr, context) 209 , m_successCallback(successCallback) 210 , m_type(type) 211{ 212} 213 214void FileSystemCallbacks::didOpenFileSystem(const String& name, const KURL& rootURL) 215{ 216 if (m_successCallback) 217 handleEventOrScheduleCallback(m_successCallback.release(), DOMFileSystem::create(m_executionContext.get(), name, m_type, rootURL)); 218} 219 220// ResolveURICallbacks -------------------------------------------------------- 221 222PassOwnPtr<AsyncFileSystemCallbacks> ResolveURICallbacks::create(EntryCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 223{ 224 return adoptPtr(new ResolveURICallbacks(successCallback, errorCallback, context)); 225} 226 227ResolveURICallbacks::ResolveURICallbacks(EntryCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 228 : FileSystemCallbacksBase(errorCallback, nullptr, context) 229 , m_successCallback(successCallback) 230{ 231} 232 233void ResolveURICallbacks::didResolveURL(const String& name, const KURL& rootURL, FileSystemType type, const String& filePath, bool isDirectory) 234{ 235 DOMFileSystem* filesystem = DOMFileSystem::create(m_executionContext.get(), name, type, rootURL); 236 DirectoryEntry* root = filesystem->root(); 237 238 String absolutePath; 239 if (!DOMFileSystemBase::pathToAbsolutePath(type, root, filePath, absolutePath)) { 240 handleEventOrScheduleCallback(m_errorCallback.release(), FileError::create(FileError::INVALID_MODIFICATION_ERR)); 241 return; 242 } 243 244 if (isDirectory) 245 handleEventOrScheduleCallback(m_successCallback.release(), DirectoryEntry::create(filesystem, absolutePath)); 246 else 247 handleEventOrScheduleCallback(m_successCallback.release(), FileEntry::create(filesystem, absolutePath)); 248} 249 250// MetadataCallbacks ---------------------------------------------------------- 251 252PassOwnPtr<AsyncFileSystemCallbacks> MetadataCallbacks::create(MetadataCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem) 253{ 254 return adoptPtr(new MetadataCallbacks(successCallback, errorCallback, context, fileSystem)); 255} 256 257MetadataCallbacks::MetadataCallbacks(MetadataCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem) 258 : FileSystemCallbacksBase(errorCallback, fileSystem, context) 259 , m_successCallback(successCallback) 260{ 261} 262 263void MetadataCallbacks::didReadMetadata(const FileMetadata& metadata) 264{ 265 if (m_successCallback) 266 handleEventOrScheduleCallback(m_successCallback.release(), Metadata::create(metadata)); 267} 268 269// FileWriterBaseCallbacks ---------------------------------------------------- 270 271PassOwnPtr<AsyncFileSystemCallbacks> FileWriterBaseCallbacks::create(PassRefPtrWillBeRawPtr<FileWriterBase> fileWriter, FileWriterBaseCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 272{ 273 return adoptPtr(new FileWriterBaseCallbacks(fileWriter, successCallback, errorCallback, context)); 274} 275 276FileWriterBaseCallbacks::FileWriterBaseCallbacks(PassRefPtrWillBeRawPtr<FileWriterBase> fileWriter, FileWriterBaseCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 277 : FileSystemCallbacksBase(errorCallback, nullptr, context) 278 , m_fileWriter(fileWriter.get()) 279 , m_successCallback(successCallback) 280{ 281} 282 283void FileWriterBaseCallbacks::didCreateFileWriter(PassOwnPtr<WebFileWriter> fileWriter, long long length) 284{ 285 m_fileWriter->initialize(fileWriter, length); 286 if (m_successCallback) 287 handleEventOrScheduleCallback(m_successCallback.release(), m_fileWriter.release()); 288} 289 290// SnapshotFileCallback ------------------------------------------------------- 291 292PassOwnPtr<AsyncFileSystemCallbacks> SnapshotFileCallback::create(DOMFileSystemBase* filesystem, const String& name, const KURL& url, FileCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 293{ 294 return adoptPtr(new SnapshotFileCallback(filesystem, name, url, successCallback, errorCallback, context)); 295} 296 297SnapshotFileCallback::SnapshotFileCallback(DOMFileSystemBase* filesystem, const String& name, const KURL& url, FileCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 298 : FileSystemCallbacksBase(errorCallback, filesystem, context) 299 , m_name(name) 300 , m_url(url) 301 , m_successCallback(successCallback) 302{ 303} 304 305void SnapshotFileCallback::didCreateSnapshotFile(const FileMetadata& metadata, PassRefPtr<BlobDataHandle> snapshot) 306{ 307 if (!m_successCallback) 308 return; 309 310 // We can't directly use the snapshot blob data handle because the content type on it hasn't been set. 311 // The |snapshot| param is here to provide a a chain of custody thru thread bridging that is held onto until 312 // *after* we've coined a File with a new handle that has the correct type set on it. This allows the 313 // blob storage system to track when a temp file can and can't be safely deleted. 314 315 handleEventOrScheduleCallback(m_successCallback.release(), DOMFileSystemBase::createFile(metadata, m_url, m_fileSystem->type(), m_name)); 316} 317 318// VoidCallbacks -------------------------------------------------------------- 319 320PassOwnPtr<AsyncFileSystemCallbacks> VoidCallbacks::create(VoidCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem) 321{ 322 return adoptPtr(new VoidCallbacks(successCallback, errorCallback, context, fileSystem)); 323} 324 325VoidCallbacks::VoidCallbacks(VoidCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem) 326 : FileSystemCallbacksBase(errorCallback, fileSystem, context) 327 , m_successCallback(successCallback) 328{ 329} 330 331void VoidCallbacks::didSucceed() 332{ 333 if (m_successCallback) 334 handleEventOrScheduleCallback(m_successCallback.release()); 335} 336 337} // namespace blink 338