Home | History | Annotate | Download | only in fileapi
      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 "DOMFileSystemBase.h"
     33 
     34 #if ENABLE(FILE_SYSTEM)
     35 
     36 #include "DOMFilePath.h"
     37 #include "DirectoryEntry.h"
     38 #include "DirectoryReaderBase.h"
     39 #include "EntriesCallback.h"
     40 #include "EntryArray.h"
     41 #include "EntryBase.h"
     42 #include "EntryCallback.h"
     43 #include "ErrorCallback.h"
     44 #include "FileError.h"
     45 #include "FileSystemCallbacks.h"
     46 #include "MetadataCallback.h"
     47 #include "ScriptExecutionContext.h"
     48 #include "VoidCallback.h"
     49 #include <wtf/OwnPtr.h>
     50 
     51 namespace WebCore {
     52 
     53 const char DOMFileSystemBase::kPersistentPathPrefix[] = "persistent";
     54 const size_t DOMFileSystemBase::kPersistentPathPrefixLength = sizeof(DOMFileSystemBase::kPersistentPathPrefix) - 1;
     55 const char DOMFileSystemBase::kTemporaryPathPrefix[] = "temporary";
     56 const size_t DOMFileSystemBase::kTemporaryPathPrefixLength = sizeof(DOMFileSystemBase::kTemporaryPathPrefix) - 1;
     57 const char DOMFileSystemBase::kExternalPathPrefix[] = "external";
     58 const size_t DOMFileSystemBase::kExternalPathPrefixLength = sizeof(DOMFileSystemBase::kExternalPathPrefix) - 1;
     59 
     60 bool DOMFileSystemBase::crackFileSystemURL(const KURL& url, AsyncFileSystem::Type& type, String& filePath)
     61 {
     62     if (!url.protocolIs("filesystem"))
     63         return false;
     64 
     65     KURL originURL(ParsedURLString, url.path());
     66     String path = decodeURLEscapeSequences(originURL.path());
     67     if (path.isEmpty() || path[0] != '/')
     68         return false;
     69     path = path.substring(1);
     70 
     71     if (path.startsWith(kTemporaryPathPrefix)) {
     72         type = AsyncFileSystem::Temporary;
     73         path = path.substring(kTemporaryPathPrefixLength);
     74     } else if (path.startsWith(kPersistentPathPrefix)) {
     75         type = AsyncFileSystem::Persistent;
     76         path = path.substring(kPersistentPathPrefixLength);
     77     } else if (path.startsWith(kExternalPathPrefix)) {
     78         type = AsyncFileSystem::External;
     79         path = path.substring(kExternalPathPrefixLength);
     80     } else
     81         return false;
     82 
     83     if (path.isEmpty() || path[0] != '/')
     84         return false;
     85 
     86     filePath.swap(path);
     87     return true;
     88 }
     89 
     90 DOMFileSystemBase::DOMFileSystemBase(ScriptExecutionContext* context, const String& name, PassOwnPtr<AsyncFileSystem> asyncFileSystem)
     91     : m_context(context)
     92     , m_name(name)
     93     , m_asyncFileSystem(asyncFileSystem)
     94 {
     95 }
     96 
     97 DOMFileSystemBase::~DOMFileSystemBase()
     98 {
     99 }
    100 
    101 SecurityOrigin* DOMFileSystemBase::securityOrigin() const
    102 {
    103     return m_context->securityOrigin();
    104 }
    105 
    106 bool DOMFileSystemBase::getMetadata(const EntryBase* entry, PassRefPtr<MetadataCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    107 {
    108     String platformPath = m_asyncFileSystem->virtualToPlatformPath(entry->fullPath());
    109     m_asyncFileSystem->readMetadata(platformPath, MetadataCallbacks::create(successCallback, errorCallback));
    110     return true;
    111 }
    112 
    113 static bool verifyAndGetDestinationPathForCopyOrMove(const EntryBase* source, EntryBase* parent, const String& newName, String& destinationPath)
    114 {
    115     ASSERT(source);
    116 
    117     if (!parent || !parent->isDirectory())
    118         return false;
    119 
    120     if (!newName.isEmpty() && !DOMFilePath::isValidName(newName))
    121         return false;
    122 
    123     // It is an error to try to copy or move an entry inside itself at any depth if it is a directory.
    124     if (source->isDirectory() && DOMFilePath::isParentOf(source->fullPath(), parent->fullPath()))
    125         return false;
    126 
    127     // It is an error to copy or move an entry into its parent if a name different from its current one isn't provided.
    128     if ((newName.isEmpty() || source->name() == newName) && DOMFilePath::getDirectory(source->fullPath()) == parent->fullPath())
    129         return false;
    130 
    131     destinationPath = parent->fullPath();
    132     if (!newName.isEmpty())
    133         destinationPath = DOMFilePath::append(destinationPath, newName);
    134     else
    135         destinationPath = DOMFilePath::append(destinationPath, source->name());
    136 
    137     return true;
    138 }
    139 
    140 static bool pathToAbsolutePath(const EntryBase* base, String path, String& absolutePath)
    141 {
    142     ASSERT(base);
    143 
    144     if (!DOMFilePath::isAbsolute(path))
    145         path = DOMFilePath::append(base->fullPath(), path);
    146     absolutePath = DOMFilePath::removeExtraParentReferences(path);
    147 
    148     if (!DOMFilePath::isValidPath(absolutePath))
    149         return false;
    150     return true;
    151 }
    152 
    153 bool DOMFileSystemBase::move(const EntryBase* source, EntryBase* parent, const String& newName, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    154 {
    155     String destinationPath;
    156     if (!verifyAndGetDestinationPathForCopyOrMove(source, parent, newName, destinationPath))
    157         return false;
    158 
    159     String sourcePlatformPath = m_asyncFileSystem->virtualToPlatformPath(source->fullPath());
    160     String destinationPlatformPath = parent->filesystem()->asyncFileSystem()->virtualToPlatformPath(destinationPath);
    161     m_asyncFileSystem->move(sourcePlatformPath, destinationPlatformPath, EntryCallbacks::create(successCallback, errorCallback, this, destinationPath, source->isDirectory()));
    162     return true;
    163 }
    164 
    165 bool DOMFileSystemBase::copy(const EntryBase* source, EntryBase* parent, const String& newName, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    166 {
    167     String destinationPath;
    168     if (!verifyAndGetDestinationPathForCopyOrMove(source, parent, newName, destinationPath))
    169         return false;
    170 
    171     String sourcePlatformPath = m_asyncFileSystem->virtualToPlatformPath(source->fullPath());
    172     String destinationPlatformPath = parent->filesystem()->asyncFileSystem()->virtualToPlatformPath(destinationPath);
    173     m_asyncFileSystem->copy(sourcePlatformPath, destinationPlatformPath, EntryCallbacks::create(successCallback, errorCallback, this, destinationPath, source->isDirectory()));
    174     return true;
    175 }
    176 
    177 bool DOMFileSystemBase::remove(const EntryBase* entry, PassRefPtr<VoidCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    178 {
    179     ASSERT(entry);
    180     // We don't allow calling remove() on the root directory.
    181     if (entry->fullPath() == String(DOMFilePath::root))
    182         return false;
    183     String platformPath = m_asyncFileSystem->virtualToPlatformPath(entry->fullPath());
    184     m_asyncFileSystem->remove(platformPath, VoidCallbacks::create(successCallback, errorCallback));
    185     return true;
    186 }
    187 
    188 bool DOMFileSystemBase::removeRecursively(const EntryBase* entry, PassRefPtr<VoidCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    189 {
    190     ASSERT(entry && entry->isDirectory());
    191     // We don't allow calling remove() on the root directory.
    192     if (entry->fullPath() == String(DOMFilePath::root))
    193         return false;
    194     String platformPath = m_asyncFileSystem->virtualToPlatformPath(entry->fullPath());
    195     m_asyncFileSystem->removeRecursively(platformPath, VoidCallbacks::create(successCallback, errorCallback));
    196     return true;
    197 }
    198 
    199 bool DOMFileSystemBase::getParent(const EntryBase* entry, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    200 {
    201     ASSERT(entry);
    202     String path = DOMFilePath::getDirectory(entry->fullPath());
    203     String platformPath = m_asyncFileSystem->virtualToPlatformPath(path);
    204     m_asyncFileSystem->directoryExists(platformPath, EntryCallbacks::create(successCallback, errorCallback, this, path, true));
    205     return true;
    206 }
    207 
    208 bool DOMFileSystemBase::getFile(const EntryBase* base, const String& path, PassRefPtr<WebKitFlags> flags, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    209 {
    210     String absolutePath;
    211     if (!pathToAbsolutePath(base, path, absolutePath))
    212         return false;
    213 
    214     String platformPath = m_asyncFileSystem->virtualToPlatformPath(absolutePath);
    215     OwnPtr<EntryCallbacks> callbacks = EntryCallbacks::create(successCallback, errorCallback, this, absolutePath, false);
    216     if (flags && flags->isCreate())
    217         m_asyncFileSystem->createFile(platformPath, flags->isExclusive(), callbacks.release());
    218     else
    219         m_asyncFileSystem->fileExists(platformPath, callbacks.release());
    220     return true;
    221 }
    222 
    223 bool DOMFileSystemBase::getDirectory(const EntryBase* base, const String& path, PassRefPtr<WebKitFlags> flags, PassRefPtr<EntryCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    224 {
    225     String absolutePath;
    226     if (!pathToAbsolutePath(base, path, absolutePath))
    227         return false;
    228 
    229     String platformPath = m_asyncFileSystem->virtualToPlatformPath(absolutePath);
    230     OwnPtr<EntryCallbacks> callbacks = EntryCallbacks::create(successCallback, errorCallback, this, absolutePath, true);
    231     if (flags && flags->isCreate())
    232         m_asyncFileSystem->createDirectory(platformPath, flags->isExclusive(), callbacks.release());
    233     else
    234         m_asyncFileSystem->directoryExists(platformPath, callbacks.release());
    235     return true;
    236 }
    237 
    238 bool DOMFileSystemBase::readDirectory(PassRefPtr<DirectoryReaderBase> reader, const String& path, PassRefPtr<EntriesCallback> successCallback, PassRefPtr<ErrorCallback> errorCallback)
    239 {
    240     ASSERT(DOMFilePath::isAbsolute(path));
    241     String platformPath = m_asyncFileSystem->virtualToPlatformPath(path);
    242     m_asyncFileSystem->readDirectory(platformPath, EntriesCallbacks::create(successCallback, errorCallback, reader, path));
    243     return true;
    244 }
    245 
    246 } // namespace WebCore
    247 
    248 #endif // ENABLE(FILE_SYSTEM)
    249