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 = 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