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 57 namespace blink { 58 59 FileSystemCallbacksBase::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 71 FileSystemCallbacksBase::~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 79 void FileSystemCallbacksBase::didFail(int code) 80 { 81 if (m_errorCallback) 82 handleEventOrScheduleCallback(m_errorCallback.release(), FileError::create(static_cast<FileError::ErrorCode>(code))); 83 } 84 85 bool FileSystemCallbacksBase::shouldScheduleCallback() const 86 { 87 return !shouldBlockUntilCompletion() && m_executionContext && m_executionContext->activeDOMObjectsAreSuspended(); 88 } 89 90 #if !ENABLE(OILPAN) 91 template <typename CB, typename CBArg> 92 void FileSystemCallbacksBase::handleEventOrScheduleCallback(RawPtr<CB> callback, RawPtr<CBArg> arg) 93 { 94 handleEventOrScheduleCallback(callback, arg.get()); 95 } 96 #endif 97 98 template <typename CB, typename CBArg> 99 void 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 111 template <typename CB, typename CBArg> 112 void 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 124 template <typename CB> 125 void 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 139 PassOwnPtr<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 144 EntryCallbacks::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 152 void 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 164 PassOwnPtr<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 169 EntriesCallbacks::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 178 void 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 186 void 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 202 PassOwnPtr<AsyncFileSystemCallbacks> FileSystemCallbacks::create(FileSystemCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, FileSystemType type) 203 { 204 return adoptPtr(new FileSystemCallbacks(successCallback, errorCallback, context, type)); 205 } 206 207 FileSystemCallbacks::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 214 void 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 222 PassOwnPtr<AsyncFileSystemCallbacks> ResolveURICallbacks::create(EntryCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 223 { 224 return adoptPtr(new ResolveURICallbacks(successCallback, errorCallback, context)); 225 } 226 227 ResolveURICallbacks::ResolveURICallbacks(EntryCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 228 : FileSystemCallbacksBase(errorCallback, nullptr, context) 229 , m_successCallback(successCallback) 230 { 231 } 232 233 void 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 252 PassOwnPtr<AsyncFileSystemCallbacks> MetadataCallbacks::create(MetadataCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem) 253 { 254 return adoptPtr(new MetadataCallbacks(successCallback, errorCallback, context, fileSystem)); 255 } 256 257 MetadataCallbacks::MetadataCallbacks(MetadataCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem) 258 : FileSystemCallbacksBase(errorCallback, fileSystem, context) 259 , m_successCallback(successCallback) 260 { 261 } 262 263 void MetadataCallbacks::didReadMetadata(const FileMetadata& metadata) 264 { 265 if (m_successCallback) 266 handleEventOrScheduleCallback(m_successCallback.release(), Metadata::create(metadata)); 267 } 268 269 // FileWriterBaseCallbacks ---------------------------------------------------- 270 271 PassOwnPtr<AsyncFileSystemCallbacks> FileWriterBaseCallbacks::create(PassRefPtrWillBeRawPtr<FileWriterBase> fileWriter, FileWriterBaseCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context) 272 { 273 return adoptPtr(new FileWriterBaseCallbacks(fileWriter, successCallback, errorCallback, context)); 274 } 275 276 FileWriterBaseCallbacks::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 283 void 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 292 PassOwnPtr<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 297 SnapshotFileCallback::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 305 void 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 320 PassOwnPtr<AsyncFileSystemCallbacks> VoidCallbacks::create(VoidCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem) 321 { 322 return adoptPtr(new VoidCallbacks(successCallback, errorCallback, context, fileSystem)); 323 } 324 325 VoidCallbacks::VoidCallbacks(VoidCallback* successCallback, ErrorCallback* errorCallback, ExecutionContext* context, DOMFileSystemBase* fileSystem) 326 : FileSystemCallbacksBase(errorCallback, fileSystem, context) 327 , m_successCallback(successCallback) 328 { 329 } 330 331 void VoidCallbacks::didSucceed() 332 { 333 if (m_successCallback) 334 handleEventOrScheduleCallback(m_successCallback.release()); 335 } 336 337 } // namespace blink 338