| OLD | NEW |
| (Empty) |
| 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 "modules/filesystem/DOMFileSystemBase.h" | |
| 32 | |
| 33 #include "core/dom/ExecutionContext.h" | |
| 34 #include "core/fileapi/File.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/FileSystemCallbacks.h" | |
| 45 #include "modules/filesystem/MetadataCallback.h" | |
| 46 #include "platform/weborigin/SecurityOrigin.h" | |
| 47 #include "public/platform/Platform.h" | |
| 48 #include "public/platform/WebFileSystem.h" | |
| 49 #include "public/platform/WebFileSystemCallbacks.h" | |
| 50 #include "wtf/text/StringBuilder.h" | |
| 51 #include "wtf/text/TextEncoding.h" | |
| 52 #include <memory> | |
| 53 | |
| 54 namespace blink { | |
| 55 | |
| 56 const char DOMFileSystemBase::persistentPathPrefix[] = "persistent"; | |
| 57 const char DOMFileSystemBase::temporaryPathPrefix[] = "temporary"; | |
| 58 const char DOMFileSystemBase::isolatedPathPrefix[] = "isolated"; | |
| 59 const char DOMFileSystemBase::externalPathPrefix[] = "external"; | |
| 60 | |
| 61 DOMFileSystemBase::DOMFileSystemBase(ExecutionContext* context, | |
| 62 const String& name, | |
| 63 FileSystemType type, | |
| 64 const KURL& rootURL) | |
| 65 : m_context(context), | |
| 66 m_name(name), | |
| 67 m_type(type), | |
| 68 m_filesystemRootURL(rootURL), | |
| 69 m_clonable(false) {} | |
| 70 | |
| 71 DOMFileSystemBase::~DOMFileSystemBase() {} | |
| 72 | |
| 73 DEFINE_TRACE(DOMFileSystemBase) { | |
| 74 visitor->trace(m_context); | |
| 75 } | |
| 76 | |
| 77 WebFileSystem* DOMFileSystemBase::fileSystem() const { | |
| 78 Platform* platform = Platform::current(); | |
| 79 if (!platform) | |
| 80 return nullptr; | |
| 81 return platform->fileSystem(); | |
| 82 } | |
| 83 | |
| 84 SecurityOrigin* DOMFileSystemBase::getSecurityOrigin() const { | |
| 85 return m_context->getSecurityOrigin(); | |
| 86 } | |
| 87 | |
| 88 bool DOMFileSystemBase::isValidType(FileSystemType type) { | |
| 89 return type == FileSystemTypeTemporary || type == FileSystemTypePersistent || | |
| 90 type == FileSystemTypeIsolated || type == FileSystemTypeExternal; | |
| 91 } | |
| 92 | |
| 93 KURL DOMFileSystemBase::createFileSystemRootURL(const String& origin, | |
| 94 FileSystemType type) { | |
| 95 String typeString; | |
| 96 if (type == FileSystemTypeTemporary) | |
| 97 typeString = temporaryPathPrefix; | |
| 98 else if (type == FileSystemTypePersistent) | |
| 99 typeString = persistentPathPrefix; | |
| 100 else if (type == FileSystemTypeExternal) | |
| 101 typeString = externalPathPrefix; | |
| 102 else | |
| 103 return KURL(); | |
| 104 | |
| 105 String result = "filesystem:" + origin + "/" + typeString + "/"; | |
| 106 return KURL(ParsedURLString, result); | |
| 107 } | |
| 108 | |
| 109 bool DOMFileSystemBase::supportsToURL() const { | |
| 110 ASSERT(isValidType(m_type)); | |
| 111 return m_type != FileSystemTypeIsolated; | |
| 112 } | |
| 113 | |
| 114 KURL DOMFileSystemBase::createFileSystemURL(const EntryBase* entry) const { | |
| 115 return createFileSystemURL(entry->fullPath()); | |
| 116 } | |
| 117 | |
| 118 KURL DOMFileSystemBase::createFileSystemURL(const String& fullPath) const { | |
| 119 ASSERT(DOMFilePath::isAbsolute(fullPath)); | |
| 120 | |
| 121 if (type() == FileSystemTypeExternal) { | |
| 122 // For external filesystem originString could be different from what we have | |
| 123 // in m_filesystemRootURL. | |
| 124 StringBuilder result; | |
| 125 result.append("filesystem:"); | |
| 126 result.append(getSecurityOrigin()->toString()); | |
| 127 result.append('/'); | |
| 128 result.append(externalPathPrefix); | |
| 129 result.append(m_filesystemRootURL.path()); | |
| 130 // Remove the extra leading slash. | |
| 131 result.append(encodeWithURLEscapeSequences(fullPath.substring(1))); | |
| 132 return KURL(ParsedURLString, result.toString()); | |
| 133 } | |
| 134 | |
| 135 // For regular types we can just append the entry's fullPath to the | |
| 136 // m_filesystemRootURL that should look like | |
| 137 // 'filesystem:<origin>/<typePrefix>'. | |
| 138 ASSERT(!m_filesystemRootURL.isEmpty()); | |
| 139 KURL url = m_filesystemRootURL; | |
| 140 // Remove the extra leading slash. | |
| 141 url.setPath(url.path() + encodeWithURLEscapeSequences(fullPath.substring(1))); | |
| 142 return url; | |
| 143 } | |
| 144 | |
| 145 bool DOMFileSystemBase::pathToAbsolutePath(FileSystemType type, | |
| 146 const EntryBase* base, | |
| 147 String path, | |
| 148 String& absolutePath) { | |
| 149 ASSERT(base); | |
| 150 | |
| 151 if (!DOMFilePath::isAbsolute(path)) | |
| 152 path = DOMFilePath::append(base->fullPath(), path); | |
| 153 absolutePath = DOMFilePath::removeExtraParentReferences(path); | |
| 154 | |
| 155 return (type != FileSystemTypeTemporary && | |
| 156 type != FileSystemTypePersistent) || | |
| 157 DOMFilePath::isValidPath(absolutePath); | |
| 158 } | |
| 159 | |
| 160 bool DOMFileSystemBase::pathPrefixToFileSystemType(const String& pathPrefix, | |
| 161 FileSystemType& type) { | |
| 162 if (pathPrefix == temporaryPathPrefix) { | |
| 163 type = FileSystemTypeTemporary; | |
| 164 return true; | |
| 165 } | |
| 166 | |
| 167 if (pathPrefix == persistentPathPrefix) { | |
| 168 type = FileSystemTypePersistent; | |
| 169 return true; | |
| 170 } | |
| 171 | |
| 172 if (pathPrefix == externalPathPrefix) { | |
| 173 type = FileSystemTypeExternal; | |
| 174 return true; | |
| 175 } | |
| 176 | |
| 177 return false; | |
| 178 } | |
| 179 | |
| 180 File* DOMFileSystemBase::createFile(const FileMetadata& metadata, | |
| 181 const KURL& fileSystemURL, | |
| 182 FileSystemType type, | |
| 183 const String name) { | |
| 184 // For regular filesystem types (temporary or persistent), we should not cache | |
| 185 // file metadata as it could change File semantics. For other filesystem | |
| 186 // types (which could be platform-specific ones), there's a chance that the | |
| 187 // files are on remote filesystem. If the port has returned metadata just | |
| 188 // pass it to File constructor (so we may cache the metadata). | |
| 189 // FIXME: We should use the snapshot metadata for all files. | |
| 190 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=17746 | |
| 191 if (type == FileSystemTypeTemporary || type == FileSystemTypePersistent) | |
| 192 return File::createForFileSystemFile(metadata.platformPath, name); | |
| 193 | |
| 194 const File::UserVisibility userVisibility = (type == FileSystemTypeExternal) | |
| 195 ? File::IsUserVisible | |
| 196 : File::IsNotUserVisible; | |
| 197 | |
| 198 if (!metadata.platformPath.isEmpty()) { | |
| 199 // If the platformPath in the returned metadata is given, we create a File | |
| 200 // object for the snapshot path. | |
| 201 return File::createForFileSystemFile(name, metadata, userVisibility); | |
| 202 } else { | |
| 203 // Otherwise we create a File object for the fileSystemURL. | |
| 204 return File::createForFileSystemFile(fileSystemURL, metadata, | |
| 205 userVisibility); | |
| 206 } | |
| 207 } | |
| 208 | |
| 209 void DOMFileSystemBase::getMetadata(const EntryBase* entry, | |
| 210 MetadataCallback* successCallback, | |
| 211 ErrorCallbackBase* errorCallback, | |
| 212 SynchronousType synchronousType) { | |
| 213 if (!fileSystem()) { | |
| 214 reportError(errorCallback, FileError::kAbortErr); | |
| 215 return; | |
| 216 } | |
| 217 | |
| 218 std::unique_ptr<AsyncFileSystemCallbacks> callbacks(MetadataCallbacks::create( | |
| 219 successCallback, errorCallback, m_context, this)); | |
| 220 callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous); | |
| 221 fileSystem()->readMetadata(createFileSystemURL(entry), std::move(callbacks)); | |
| 222 } | |
| 223 | |
| 224 static bool verifyAndGetDestinationPathForCopyOrMove(const EntryBase* source, | |
| 225 EntryBase* parent, | |
| 226 const String& newName, | |
| 227 String& destinationPath) { | |
| 228 ASSERT(source); | |
| 229 | |
| 230 if (!parent || !parent->isDirectory()) | |
| 231 return false; | |
| 232 | |
| 233 if (!newName.isEmpty() && !DOMFilePath::isValidName(newName)) | |
| 234 return false; | |
| 235 | |
| 236 const bool isSameFileSystem = | |
| 237 (*source->filesystem() == *parent->filesystem()); | |
| 238 | |
| 239 // It is an error to try to copy or move an entry inside itself at any depth | |
| 240 // if it is a directory. | |
| 241 if (source->isDirectory() && isSameFileSystem && | |
| 242 DOMFilePath::isParentOf(source->fullPath(), parent->fullPath())) | |
| 243 return false; | |
| 244 | |
| 245 // It is an error to copy or move an entry into its parent if a name different | |
| 246 // from its current one isn't provided. | |
| 247 if (isSameFileSystem && (newName.isEmpty() || source->name() == newName) && | |
| 248 DOMFilePath::getDirectory(source->fullPath()) == parent->fullPath()) | |
| 249 return false; | |
| 250 | |
| 251 destinationPath = parent->fullPath(); | |
| 252 if (!newName.isEmpty()) | |
| 253 destinationPath = DOMFilePath::append(destinationPath, newName); | |
| 254 else | |
| 255 destinationPath = DOMFilePath::append(destinationPath, source->name()); | |
| 256 | |
| 257 return true; | |
| 258 } | |
| 259 | |
| 260 void DOMFileSystemBase::move(const EntryBase* source, | |
| 261 EntryBase* parent, | |
| 262 const String& newName, | |
| 263 EntryCallback* successCallback, | |
| 264 ErrorCallbackBase* errorCallback, | |
| 265 SynchronousType synchronousType) { | |
| 266 if (!fileSystem()) { | |
| 267 reportError(errorCallback, FileError::kAbortErr); | |
| 268 return; | |
| 269 } | |
| 270 | |
| 271 String destinationPath; | |
| 272 if (!verifyAndGetDestinationPathForCopyOrMove(source, parent, newName, | |
| 273 destinationPath)) { | |
| 274 reportError(errorCallback, FileError::kInvalidModificationErr); | |
| 275 return; | |
| 276 } | |
| 277 | |
| 278 std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::create( | |
| 279 successCallback, errorCallback, m_context, parent->filesystem(), | |
| 280 destinationPath, source->isDirectory())); | |
| 281 callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous); | |
| 282 | |
| 283 fileSystem()->move(createFileSystemURL(source), | |
| 284 parent->filesystem()->createFileSystemURL(destinationPath), | |
| 285 std::move(callbacks)); | |
| 286 } | |
| 287 | |
| 288 void DOMFileSystemBase::copy(const EntryBase* source, | |
| 289 EntryBase* parent, | |
| 290 const String& newName, | |
| 291 EntryCallback* successCallback, | |
| 292 ErrorCallbackBase* errorCallback, | |
| 293 SynchronousType synchronousType) { | |
| 294 if (!fileSystem()) { | |
| 295 reportError(errorCallback, FileError::kAbortErr); | |
| 296 return; | |
| 297 } | |
| 298 | |
| 299 String destinationPath; | |
| 300 if (!verifyAndGetDestinationPathForCopyOrMove(source, parent, newName, | |
| 301 destinationPath)) { | |
| 302 reportError(errorCallback, FileError::kInvalidModificationErr); | |
| 303 return; | |
| 304 } | |
| 305 | |
| 306 std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::create( | |
| 307 successCallback, errorCallback, m_context, parent->filesystem(), | |
| 308 destinationPath, source->isDirectory())); | |
| 309 callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous); | |
| 310 | |
| 311 fileSystem()->copy(createFileSystemURL(source), | |
| 312 parent->filesystem()->createFileSystemURL(destinationPath), | |
| 313 std::move(callbacks)); | |
| 314 } | |
| 315 | |
| 316 void DOMFileSystemBase::remove(const EntryBase* entry, | |
| 317 VoidCallback* successCallback, | |
| 318 ErrorCallbackBase* errorCallback, | |
| 319 SynchronousType synchronousType) { | |
| 320 if (!fileSystem()) { | |
| 321 reportError(errorCallback, FileError::kAbortErr); | |
| 322 return; | |
| 323 } | |
| 324 | |
| 325 ASSERT(entry); | |
| 326 // We don't allow calling remove() on the root directory. | |
| 327 if (entry->fullPath() == String(DOMFilePath::root)) { | |
| 328 reportError(errorCallback, FileError::kInvalidModificationErr); | |
| 329 return; | |
| 330 } | |
| 331 | |
| 332 std::unique_ptr<AsyncFileSystemCallbacks> callbacks( | |
| 333 VoidCallbacks::create(successCallback, errorCallback, m_context, this)); | |
| 334 callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous); | |
| 335 | |
| 336 fileSystem()->remove(createFileSystemURL(entry), std::move(callbacks)); | |
| 337 } | |
| 338 | |
| 339 void DOMFileSystemBase::removeRecursively(const EntryBase* entry, | |
| 340 VoidCallback* successCallback, | |
| 341 ErrorCallbackBase* errorCallback, | |
| 342 SynchronousType synchronousType) { | |
| 343 if (!fileSystem()) { | |
| 344 reportError(errorCallback, FileError::kAbortErr); | |
| 345 return; | |
| 346 } | |
| 347 | |
| 348 ASSERT(entry && entry->isDirectory()); | |
| 349 // We don't allow calling remove() on the root directory. | |
| 350 if (entry->fullPath() == String(DOMFilePath::root)) { | |
| 351 reportError(errorCallback, FileError::kInvalidModificationErr); | |
| 352 return; | |
| 353 } | |
| 354 | |
| 355 std::unique_ptr<AsyncFileSystemCallbacks> callbacks( | |
| 356 VoidCallbacks::create(successCallback, errorCallback, m_context, this)); | |
| 357 callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous); | |
| 358 | |
| 359 fileSystem()->removeRecursively(createFileSystemURL(entry), | |
| 360 std::move(callbacks)); | |
| 361 } | |
| 362 | |
| 363 void DOMFileSystemBase::getParent(const EntryBase* entry, | |
| 364 EntryCallback* successCallback, | |
| 365 ErrorCallbackBase* errorCallback) { | |
| 366 if (!fileSystem()) { | |
| 367 reportError(errorCallback, FileError::kAbortErr); | |
| 368 return; | |
| 369 } | |
| 370 | |
| 371 ASSERT(entry); | |
| 372 String path = DOMFilePath::getDirectory(entry->fullPath()); | |
| 373 | |
| 374 fileSystem()->directoryExists( | |
| 375 createFileSystemURL(path), | |
| 376 EntryCallbacks::create(successCallback, errorCallback, m_context, this, | |
| 377 path, true)); | |
| 378 } | |
| 379 | |
| 380 void DOMFileSystemBase::getFile(const EntryBase* entry, | |
| 381 const String& path, | |
| 382 const FileSystemFlags& flags, | |
| 383 EntryCallback* successCallback, | |
| 384 ErrorCallbackBase* errorCallback, | |
| 385 SynchronousType synchronousType) { | |
| 386 if (!fileSystem()) { | |
| 387 reportError(errorCallback, FileError::kAbortErr); | |
| 388 return; | |
| 389 } | |
| 390 | |
| 391 String absolutePath; | |
| 392 if (!pathToAbsolutePath(m_type, entry, path, absolutePath)) { | |
| 393 reportError(errorCallback, FileError::kInvalidModificationErr); | |
| 394 return; | |
| 395 } | |
| 396 | |
| 397 std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::create( | |
| 398 successCallback, errorCallback, m_context, this, absolutePath, false)); | |
| 399 callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous); | |
| 400 | |
| 401 if (flags.createFlag()) | |
| 402 fileSystem()->createFile(createFileSystemURL(absolutePath), | |
| 403 flags.exclusive(), std::move(callbacks)); | |
| 404 else | |
| 405 fileSystem()->fileExists(createFileSystemURL(absolutePath), | |
| 406 std::move(callbacks)); | |
| 407 } | |
| 408 | |
| 409 void DOMFileSystemBase::getDirectory(const EntryBase* entry, | |
| 410 const String& path, | |
| 411 const FileSystemFlags& flags, | |
| 412 EntryCallback* successCallback, | |
| 413 ErrorCallbackBase* errorCallback, | |
| 414 SynchronousType synchronousType) { | |
| 415 if (!fileSystem()) { | |
| 416 reportError(errorCallback, FileError::kAbortErr); | |
| 417 return; | |
| 418 } | |
| 419 | |
| 420 String absolutePath; | |
| 421 if (!pathToAbsolutePath(m_type, entry, path, absolutePath)) { | |
| 422 reportError(errorCallback, FileError::kInvalidModificationErr); | |
| 423 return; | |
| 424 } | |
| 425 | |
| 426 std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntryCallbacks::create( | |
| 427 successCallback, errorCallback, m_context, this, absolutePath, true)); | |
| 428 callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous); | |
| 429 | |
| 430 if (flags.createFlag()) | |
| 431 fileSystem()->createDirectory(createFileSystemURL(absolutePath), | |
| 432 flags.exclusive(), std::move(callbacks)); | |
| 433 else | |
| 434 fileSystem()->directoryExists(createFileSystemURL(absolutePath), | |
| 435 std::move(callbacks)); | |
| 436 } | |
| 437 | |
| 438 int DOMFileSystemBase::readDirectory(DirectoryReaderBase* reader, | |
| 439 const String& path, | |
| 440 EntriesCallback* successCallback, | |
| 441 ErrorCallbackBase* errorCallback, | |
| 442 SynchronousType synchronousType) { | |
| 443 if (!fileSystem()) { | |
| 444 reportError(errorCallback, FileError::kAbortErr); | |
| 445 return 0; | |
| 446 } | |
| 447 | |
| 448 ASSERT(DOMFilePath::isAbsolute(path)); | |
| 449 | |
| 450 std::unique_ptr<AsyncFileSystemCallbacks> callbacks(EntriesCallbacks::create( | |
| 451 successCallback, errorCallback, m_context, reader, path)); | |
| 452 callbacks->setShouldBlockUntilCompletion(synchronousType == Synchronous); | |
| 453 | |
| 454 return fileSystem()->readDirectory(createFileSystemURL(path), | |
| 455 std::move(callbacks)); | |
| 456 } | |
| 457 | |
| 458 bool DOMFileSystemBase::waitForAdditionalResult(int callbacksId) { | |
| 459 if (!fileSystem()) | |
| 460 return false; | |
| 461 return fileSystem()->waitForAdditionalResult(callbacksId); | |
| 462 } | |
| 463 | |
| 464 } // namespace blink | |
| OLD | NEW |