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
crackFileSystemURL(const KURL & url,AsyncFileSystem::Type & type,String & filePath)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
DOMFileSystemBase(ScriptExecutionContext * context,const String & name,PassOwnPtr<AsyncFileSystem> asyncFileSystem)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
~DOMFileSystemBase()97 DOMFileSystemBase::~DOMFileSystemBase()
98 {
99 }
100
securityOrigin() const101 SecurityOrigin* DOMFileSystemBase::securityOrigin() const
102 {
103 return m_context->securityOrigin();
104 }
105
getMetadata(const EntryBase * entry,PassRefPtr<MetadataCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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
verifyAndGetDestinationPathForCopyOrMove(const EntryBase * source,EntryBase * parent,const String & newName,String & destinationPath)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
pathToAbsolutePath(const EntryBase * base,String path,String & absolutePath)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
move(const EntryBase * source,EntryBase * parent,const String & newName,PassRefPtr<EntryCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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
copy(const EntryBase * source,EntryBase * parent,const String & newName,PassRefPtr<EntryCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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
remove(const EntryBase * entry,PassRefPtr<VoidCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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
removeRecursively(const EntryBase * entry,PassRefPtr<VoidCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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
getParent(const EntryBase * entry,PassRefPtr<EntryCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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
getFile(const EntryBase * base,const String & path,PassRefPtr<WebKitFlags> flags,PassRefPtr<EntryCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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
getDirectory(const EntryBase * base,const String & path,PassRefPtr<WebKitFlags> flags,PassRefPtr<EntryCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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
readDirectory(PassRefPtr<DirectoryReaderBase> reader,const String & path,PassRefPtr<EntriesCallback> successCallback,PassRefPtr<ErrorCallback> errorCallback)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