Home | History | Annotate | Download | only in filesystem
      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