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/DOMFileSystemBase.h"
     33 
     34 #include "core/dom/ScriptExecutionContext.h"
     35 #include "core/fileapi/FileError.h"
     36 #include "core/html/VoidCallback.h"
     37 #include "modules/filesystem/DOMFilePath.h"
     38 #include "modules/filesystem/DirectoryEntry.h"
     39 #include "modules/filesystem/DirectoryReaderBase.h"
     40 #include "modules/filesystem/EntriesCallback.h"
     41 #include "modules/filesystem/Entry.h"
     42 #include "modules/filesystem/EntryBase.h"
     43 #include "modules/filesystem/EntryCallback.h"
     44 #include "modules/filesystem/ErrorCallback.h"
     45 #include "modules/filesystem/FileSystemCallbacks.h"
     46 #include "modules/filesystem/MetadataCallback.h"
     47 #include "weborigin/SecurityOrigin.h"
     48 #include "wtf/OwnPtr.h"
     49 #include "wtf/text/StringBuilder.h"
     50 #include "wtf/text/WTFString.h"
     51 
     52 namespace WebCore {
     53 
     54 const char DOMFileSystemBase::persistentPathPrefix[] = "persistent";
     55 const char DOMFileSystemBase::temporaryPathPrefix[] = "temporary";
     56 const char DOMFileSystemBase::isolatedPathPrefix[] = "isolated";
     57 const char DOMFileSystemBase::externalPathPrefix[] = "external";
     58 
     59 DOMFileSystemBase::DOMFileSystemBase(ScriptExecutionContext* context, const String& name, FileSystemType type, const KURL& rootURL, PassOwnPtr<AsyncFileSystem> asyncFileSystem)
     60     : m_context(context)
     61     , m_name(name)
     62     , m_type(type)
     63     , m_filesystemRootURL(rootURL)
     64     , m_clonable(false)
     65     , m_asyncFileSystem(asyncFileSystem)
     66 {
     67 }
     68 
     69 DOMFileSystemBase::~DOMFileSystemBase()
     70 {
     71 }
     72 
     73 SecurityOrigin* DOMFileSystemBase::securityOrigin() const
     74 {
     75     return m_context->securityOrigin();
     76 }
     77 
     78 bool DOMFileSystemBase::isValidType(FileSystemType type)
     79 {
     80     return type == FileSystemTypeTemporary || type == FileSystemTypePersistent || type == FileSystemTypeIsolated || type == FileSystemTypeExternal;
     81 }
     82 
     83 bool DOMFileSystemBase::crackFileSystemURL(const KURL& url, FileSystemType& type, String& filePath)
     84 {
     85     if (!url.protocolIs("filesystem"))
     86         return false;
     87 
     88     if (!url.innerURL())
     89         return false;
     90 
     91     String typeString = url.innerURL()->path().substring(1);
     92     if (typeString == temporaryPathPrefix)
     93         type = FileSystemTypeTemporary;
     94     else if (typeString == persistentPathPrefix)
     95         type = FileSystemTypePersistent;
     96     else if (typeString == externalPathPrefix)
     97         type = FileSystemTypeExternal;
     98     else
     99         return false;
    100 
    101     filePath = decodeURLEscapeSequences(url.path());
    102     return true;
    103 }
    104 
    105 bool DOMFileSystemBase::supportsToURL() const
    106 {
    107     ASSERT(isValidType(m_type));
    108     return m_type != FileSystemTypeIsolated;
    109 }
    110 
    111 KURL DOMFileSystemBase::createFileSystemURL(const EntryBase* entry) const
    112 {
    113     return createFileSystemURL(entry->fullPath());
    114 }
    115 
    116 KURL DOMFileSystemBase::createFileSystemURL(const String& fullPath) const
    117 {
    118     ASSERT(DOMFilePath::isAbsolute(fullPath));
    119 
    120     if (type() == FileSystemTypeExternal) {
    121         // For external filesystem originString could be different from what we have in m_filesystemRootURL.
    122         StringBuilder result;
    123         result.append("filesystem:");
    124         result.append(securityOrigin()->toString());
    125         result.append("/");
    126         result.append(externalPathPrefix);
    127         result.append(m_filesystemRootURL.path());
    128         // Remove the extra leading slash.
    129         result.append(encodeWithURLEscapeSequences(fullPath.substring(1)));
    130         return KURL(ParsedURLString, result.toString());
    131     }
    132 
    133     // For regular types we can just append the entry's fullPath to the m_filesystemRootURL that should look like 'filesystem:<origin>/<typePrefix>'.
    134     ASSERT(!m_filesystemRootURL.isEmpty());
    135     KURL url = m_filesystemRootURL;
    136     // Remove the extra leading slash.
    137     url.setPath(url.path() + encodeWithURLEscapeSequences(fullPath.substring(1)));
    138     return url;
    139 }
    140 
    141 bool DOMFileSystemBase::getMetadata(const EntryBase* entry, PassRefPtr<MetadataCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
    142 {
    143     OwnPtr<MetadataCallbacks> callbacks(MetadataCallbacks::create(successCallback, errorCallback));
    144     callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous);
    145     m_asyncFileSystem->readMetadata(createFileSystemURL(entry), callbacks.release());
    146     return true;
    147 }
    148 
    149 static bool verifyAndGetDestinationPathForCopyOrMove(const EntryBase* source, EntryBase* parent, const String& newName, String& destinationPath)
    150 {
    151     ASSERT(source);
    152 
    153     if (!parent || !parent->isDirectory())
    154         return false;
    155 
    156     if (!newName.isEmpty() && !DOMFilePath::isValidName(newName))
    157         return false;
    158 
    159     const bool isSameFileSystem = (*source->filesystem() == *parent->filesystem());
    160 
    161     // It is an error to try to copy or move an entry inside itself at any depth if it is a directory.
    162     if (source->isDirectory() && isSameFileSystem && DOMFilePath::isParentOf(source->fullPath(), parent->fullPath()))
    163         return false;
    164 
    165     // It is an error to copy or move an entry into its parent if a name different from its current one isn't provided.
    166     if (isSameFileSystem && (newName.isEmpty() || source->name() == newName) && DOMFilePath::getDirectory(source->fullPath()) == parent->fullPath())
    167         return false;
    168 
    169     destinationPath = parent->fullPath();
    170     if (!newName.isEmpty())
    171         destinationPath = DOMFilePath::append(destinationPath, newName);
    172     else
    173         destinationPath = DOMFilePath::append(destinationPath, source->name());
    174 
    175     return true;
    176 }
    177 
    178 static bool pathToAbsolutePath(FileSystemType type, const EntryBase* base, String path, String& absolutePath)
    179 {
    180     ASSERT(base);
    181 
    182     if (!DOMFilePath::isAbsolute(path))
    183         path = DOMFilePath::append(base->fullPath(), path);
    184     absolutePath = DOMFilePath::removeExtraParentReferences(path);
    185 
    186     if ((type == FileSystemTypeTemporary || type == FileSystemTypePersistent) && !DOMFilePath::isValidPath(absolutePath))
    187         return false;
    188     return true;
    189 }
    190 
    191 bool DOMFileSystemBase::move(const EntryBase* source, EntryBase* parent, const String& newName, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
    192 {
    193     String destinationPath;
    194     if (!verifyAndGetDestinationPathForCopyOrMove(source, parent, newName, destinationPath))
    195         return false;
    196 
    197     OwnPtr<EntryCallbacks> callbacks(EntryCallbacks::create(successCallback, errorCallback, parent->filesystem(), destinationPath, source->isDirectory()));
    198     callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous);
    199 
    200     m_asyncFileSystem->move(createFileSystemURL(source), parent->filesystem()->createFileSystemURL(destinationPath), callbacks.release());
    201     return true;
    202 }
    203 
    204 bool DOMFileSystemBase::copy(const EntryBase* source, EntryBase* parent, const String& newName, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
    205 {
    206     String destinationPath;
    207     if (!verifyAndGetDestinationPathForCopyOrMove(source, parent, newName, destinationPath))
    208         return false;
    209 
    210     OwnPtr<EntryCallbacks> callbacks(EntryCallbacks::create(successCallback, errorCallback, parent->filesystem(), destinationPath, source->isDirectory()));
    211     callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous);
    212 
    213     m_asyncFileSystem->copy(createFileSystemURL(source), parent->filesystem()->createFileSystemURL(destinationPath), callbacks.release());
    214     return true;
    215 }
    216 
    217 bool DOMFileSystemBase::remove(const EntryBase* entry, PassRefPtr<VoidCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
    218 {
    219     ASSERT(entry);
    220     // We don't allow calling remove() on the root directory.
    221     if (entry->fullPath() == String(DOMFilePath::root))
    222         return false;
    223 
    224     OwnPtr<VoidCallbacks> callbacks(VoidCallbacks::create(successCallback, errorCallback));
    225     callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous);
    226 
    227     m_asyncFileSystem->remove(createFileSystemURL(entry), callbacks.release());
    228     return true;
    229 }
    230 
    231 bool DOMFileSystemBase::removeRecursively(const EntryBase* entry, PassRefPtr<VoidCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
    232 {
    233     ASSERT(entry && entry->isDirectory());
    234     // We don't allow calling remove() on the root directory.
    235     if (entry->fullPath() == String(DOMFilePath::root))
    236         return false;
    237 
    238     OwnPtr<VoidCallbacks> callbacks(VoidCallbacks::create(successCallback, errorCallback));
    239     callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous);
    240 
    241     m_asyncFileSystem->removeRecursively(createFileSystemURL(entry), callbacks.release());
    242     return true;
    243 }
    244 
    245 bool DOMFileSystemBase::getParent(const EntryBase* entry, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    246 {
    247     ASSERT(entry);
    248     String path = DOMFilePath::getDirectory(entry->fullPath());
    249 
    250     m_asyncFileSystem->directoryExists(createFileSystemURL(path), EntryCallbacks::create(successCallback, errorCallback, this, path, true));
    251     return true;
    252 }
    253 
    254 bool DOMFileSystemBase::getFile(const EntryBase* entry, const String& path, const FileSystemFlags& flags, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
    255 {
    256     String absolutePath;
    257     if (!pathToAbsolutePath(m_type, entry, path, absolutePath))
    258         return false;
    259 
    260     OwnPtr<EntryCallbacks> callbacks(EntryCallbacks::create(successCallback, errorCallback, this, absolutePath, false));
    261     callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous);
    262 
    263     if (flags.create)
    264         m_asyncFileSystem->createFile(createFileSystemURL(absolutePath), flags.exclusive, callbacks.release());
    265     else
    266         m_asyncFileSystem->fileExists(createFileSystemURL(absolutePath), callbacks.release());
    267     return true;
    268 }
    269 
    270 bool DOMFileSystemBase::getDirectory(const EntryBase* entry, const String& path, const FileSystemFlags& flags, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
    271 {
    272     String absolutePath;
    273     if (!pathToAbsolutePath(m_type, entry, path, absolutePath))
    274         return false;
    275 
    276     OwnPtr<EntryCallbacks> callbacks(EntryCallbacks::create(successCallback, errorCallback, this, absolutePath, true));
    277     callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous);
    278 
    279     if (flags.create)
    280         m_asyncFileSystem->createDirectory(createFileSystemURL(absolutePath), flags.exclusive, callbacks.release());
    281     else
    282         m_asyncFileSystem->directoryExists(createFileSystemURL(absolutePath), callbacks.release());
    283     return true;
    284 }
    285 
    286 bool DOMFileSystemBase::readDirectory(PassRefPtr<DirectoryReaderBase> reader, const String& path, PassRefPtr<EntriesCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback, SynchronousType synchronousType)
    287 {
    288     ASSERT(DOMFilePath::isAbsolute(path));
    289 
    290     OwnPtr<EntriesCallbacks> callbacks(EntriesCallbacks::create(successCallback, errorCallback, reader, path));
    291     callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous);
    292 
    293     m_asyncFileSystem->readDirectory(createFileSystemURL(path), callbacks.release());
    294     return true;
    295 }
    296 
    297 } // namespace WebCore
    298