From 60dcf06449d51a824ca29479ed245c28f9875cd9 Mon Sep 17 00:00:00 2001 From: Yuan Xulei Date: Wed, 12 Mar 2014 14:30:21 +0800 Subject: [PATCH] Bug 934368 - Implement |remove| and |removeDeep| for Directory. r=dhylands --- dom/devicestorage/test/mochitest.ini | 1 + .../test/test_fs_app_permissions.html | 184 +++++++++++++++ dom/devicestorage/test/test_fs_remove.html | 215 ++++++++++++++++++ dom/filesystem/DeviceStorageFileSystem.cpp | 46 +++- dom/filesystem/DeviceStorageFileSystem.h | 8 + dom/filesystem/Directory.cpp | 61 +++++ dom/filesystem/Directory.h | 14 ++ dom/filesystem/FileSystemBase.cpp | 6 + dom/filesystem/FileSystemBase.h | 14 ++ dom/filesystem/FileSystemRequestParent.cpp | 2 + dom/filesystem/PFileSystemRequest.ipdl | 6 + dom/filesystem/RemoveTask.cpp | 204 +++++++++++++++++ dom/filesystem/RemoveTask.h | 68 ++++++ dom/filesystem/moz.build | 1 + dom/ipc/PContent.ipdl | 15 ++ dom/webidl/Directory.webidl | 30 +++ 16 files changed, 873 insertions(+), 2 deletions(-) create mode 100644 dom/devicestorage/test/test_fs_remove.html create mode 100644 dom/filesystem/RemoveTask.cpp create mode 100644 dom/filesystem/RemoveTask.h diff --git a/dom/devicestorage/test/mochitest.ini b/dom/devicestorage/test/mochitest.ini index e18702f97c91d..ca2c386daadf4 100644 --- a/dom/devicestorage/test/mochitest.ini +++ b/dom/devicestorage/test/mochitest.ini @@ -28,3 +28,4 @@ support-files = devicestorage_common.js [test_fs_basic.html] [test_fs_createDirectory.html] [test_fs_get.html] +[test_fs_remove.html] diff --git a/dom/devicestorage/test/test_fs_app_permissions.html b/dom/devicestorage/test/test_fs_app_permissions.html index 94486c53d4aff..2dd0171b215f5 100644 --- a/dom/devicestorage/test/test_fs_app_permissions.html +++ b/dom/devicestorage/test/test_fs_app_permissions.html @@ -88,6 +88,32 @@ }, cbError); } +function TestRemove(iframe, data) { + function cbError(e) { + is(e.name, "SecurityError", "[TestRemove] Should fire a SecurityError for type " + data.type); + is(data.shouldPass, false, "[TestRemove] Error callback was called for type " + data.type + '. Error: ' + e.name); + testComplete(iframe, data); + } + + createTestFile(data.fileExtension); + + let storage = iframe.contentDocument.defaultView.navigator.getDeviceStorage(data.type); + isnot(storage, null, "[TestRemove] Should be able to get storage object for " + data.type); + + if (!storage) { + testComplete(iframe, data); + return; + } + + storage.getRoot().then(function(root) { + ok(true, "[TestRemove] Success callback of getRoot was called for type " + data.type); + root.remove("testfile" + data.fileExtension).then(function() { + is(data.shouldPass, true, "[TestRemove] Success callback was called for type " + data.type); + testComplete(iframe, data); + }, cbError); + }, cbError); +} + let gTestUri = "https://example.com/tests/dom/devicestorage/test/test_fs_app_permissions.html" let gData = [ @@ -344,6 +370,164 @@ permissions: ["device-storage:sdcard"], test: TestCreateDirectory + }, + + // Directory#remove + + // Web applications with no permissions + { + type: 'pictures', + shouldPass: false, + fileExtension: '.png', + test: TestRemove + }, + { + type: 'videos', + shouldPass: false, + fileExtension: '.ogv', + test: TestRemove + }, + { + type: 'videos', + shouldPass: false, + fileExtension: '.ogg', + test: TestRemove + }, + { + type: 'music', + shouldPass: false, + fileExtension: '.ogg', + test: TestRemove + }, + { + type: 'music', + shouldPass: false, + fileExtension: '.txt', + test: TestRemove + }, + { + type: 'sdcard', + shouldPass: false, + fileExtension: '.txt', + test: TestRemove + }, + + // Web applications with permission granted + { + type: 'pictures', + shouldPass: true, + fileExtension: '.png', + + permissions: ["device-storage:pictures"], + + test: TestRemove + }, + { + type: 'videos', + shouldPass: true, + fileExtension: '.ogv', + + permissions: ["device-storage:videos"], + + test: TestRemove + }, + { + type: 'videos', + shouldPass: true, + fileExtension: '.ogg', + + permissions: ["device-storage:videos"], + + test: TestRemove + }, + { + type: 'music', + shouldPass: true, + fileExtension: '.ogg', + + permissions: ["device-storage:music"], + + test: TestRemove + }, + { + type: 'music', + shouldPass: false, + fileExtension: '.txt', + + permissions: ["device-storage:music"], + + test: TestRemove + }, + { + type: 'sdcard', + shouldPass: true, + fileExtension: '.txt', + + permissions: ["device-storage:sdcard"], + + test: TestRemove + }, + + // Certified application with permision granted + { + type: 'pictures', + shouldPass: true, + fileExtension: '.png', + + app: "https://example.com/manifest_cert.webapp", + permissions: ["device-storage:pictures"], + + test: TestRemove + }, + { + type: 'videos', + shouldPass: true, + fileExtension: '.ogv', + + app: "https://example.com/manifest_cert.webapp", + permissions: ["device-storage:videos"], + + test: TestRemove + }, + { + type: 'videos', + shouldPass: true, + fileExtension: '.ogg', + + app: "https://example.com/manifest_cert.webapp", + permissions: ["device-storage:videos"], + + test: TestRemove + }, + { + type: 'music', + shouldPass: true, + fileExtension: '.ogg', + + app: "https://example.com/manifest_cert.webapp", + permissions: ["device-storage:music"], + + test: TestRemove + }, + { + type: 'music', + shouldPass: false, + fileExtension: '.txt', + + app: "https://example.com/manifest_cert.webapp", + permissions: ["device-storage:music"], + + test: TestRemove + }, + { + type: 'sdcard', + shouldPass: true, + fileExtension: '.txt', + + app: "https://example.com/manifest_cert.webapp", + permissions: ["device-storage:sdcard"], + + test: TestRemove } ]; diff --git a/dom/devicestorage/test/test_fs_remove.html b/dom/devicestorage/test/test_fs_remove.html new file mode 100644 index 0000000000000..0ab79f0ce1867 --- /dev/null +++ b/dom/devicestorage/test/test_fs_remove.html @@ -0,0 +1,215 @@ + + + + + Test Directory#remove and #removeDeep of the FileSystem API for device storage + + + + + + +Mozilla Bug 934368 +

+ +
+
+
+ + + diff --git a/dom/filesystem/DeviceStorageFileSystem.cpp b/dom/filesystem/DeviceStorageFileSystem.cpp index 7ca8b98df07ee..267f80e7266eb 100644 --- a/dom/filesystem/DeviceStorageFileSystem.cpp +++ b/dom/filesystem/DeviceStorageFileSystem.cpp @@ -13,6 +13,7 @@ #include "nsCOMPtr.h" #include "nsDebug.h" #include "nsDeviceStorage.h" +#include "nsIDOMFile.h" #include "nsIFile.h" #include "nsPIDOMWindow.h" @@ -112,6 +113,23 @@ DeviceStorageFileSystem::GetLocalFile(const nsAString& aRealPath) const return file.forget(); } +bool +DeviceStorageFileSystem::GetRealPath(nsIDOMFile* aFile, nsAString& aRealPath) const +{ + MOZ_ASSERT(FileSystemUtils::IsParentProcess(), + "Should be on parent process!"); + MOZ_ASSERT(aFile, "aFile Should not be null."); + + aRealPath.Truncate(); + + nsAutoString filePath; + if (NS_FAILED(aFile->GetMozFullPathInternal(filePath))) { + return false; + } + + return LocalPathToRealPath(filePath, aRealPath); +} + const nsAString& DeviceStorageFileSystem::GetRootName() const { @@ -130,8 +148,7 @@ DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const if (NS_FAILED(aFile->GetPath(path))) { return false; } - FileSystemUtils::LocalPathToNormalizedPath(path, path); - if (!FileSystemUtils::IsDescendantPath(mNormalizedLocalRootPath, path)) { + if (!LocalPathToRealPath(path, path)) { return false; } @@ -142,5 +159,30 @@ DeviceStorageFileSystem::IsSafeFile(nsIFile* aFile) const return typeChecker->Check(mStorageType, aFile); } +bool +DeviceStorageFileSystem::IsSafeDirectory(Directory* aDir) const +{ + MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); + MOZ_ASSERT(aDir); + nsRefPtr fs = aDir->GetFileSystem(); + MOZ_ASSERT(fs); + // Check if the given directory is from this storage. + return fs->ToString() == mString; +} + +bool +DeviceStorageFileSystem::LocalPathToRealPath(const nsAString& aLocalPath, + nsAString& aRealPath) const +{ + nsAutoString path; + FileSystemUtils::LocalPathToNormalizedPath(aLocalPath, path); + if (!FileSystemUtils::IsDescendantPath(mNormalizedLocalRootPath, path)) { + aRealPath.Truncate(); + return false; + } + aRealPath = Substring(path, mNormalizedLocalRootPath.Length()); + return true; +} + } // namespace dom } // namespace mozilla diff --git a/dom/filesystem/DeviceStorageFileSystem.h b/dom/filesystem/DeviceStorageFileSystem.h index 199026052d7a3..cd4e19431f0fc 100644 --- a/dom/filesystem/DeviceStorageFileSystem.h +++ b/dom/filesystem/DeviceStorageFileSystem.h @@ -36,16 +36,24 @@ class DeviceStorageFileSystem virtual already_AddRefed GetLocalFile(const nsAString& aRealPath) const MOZ_OVERRIDE; + virtual bool + GetRealPath(nsIDOMFile* aFile, nsAString& aRealPath) const MOZ_OVERRIDE; + virtual const nsAString& GetRootName() const MOZ_OVERRIDE; virtual bool IsSafeFile(nsIFile* aFile) const MOZ_OVERRIDE; + virtual bool + IsSafeDirectory(Directory* aDir) const MOZ_OVERRIDE; private: virtual ~DeviceStorageFileSystem(); + bool + LocalPathToRealPath(const nsAString& aLocalPath, nsAString& aRealPath) const; + nsString mStorageType; nsString mStorageName; diff --git a/dom/filesystem/Directory.cpp b/dom/filesystem/Directory.cpp index ed40e3627f652..d2756a11e8420 100644 --- a/dom/filesystem/Directory.cpp +++ b/dom/filesystem/Directory.cpp @@ -9,12 +9,14 @@ #include "CreateDirectoryTask.h" #include "FileSystemPermissionRequest.h" #include "GetFileOrDirectoryTask.h" +#include "RemoveTask.h" #include "nsCharSeparatedTokenizer.h" #include "nsString.h" #include "mozilla/dom/DirectoryBinding.h" #include "mozilla/dom/FileSystemBase.h" #include "mozilla/dom/FileSystemUtils.h" +#include "mozilla/dom/UnionTypes.h" // Resolve the name collision of Microsoft's API name with macros defined in // Windows header files. Undefine the macro of CreateDirectory to avoid @@ -116,6 +118,65 @@ Directory::Get(const nsAString& aPath) return task->GetPromise(); } +already_AddRefed +Directory::Remove(const StringOrFileOrDirectory& aPath) +{ + return RemoveInternal(aPath, false); +} + +already_AddRefed +Directory::RemoveDeep(const StringOrFileOrDirectory& aPath) +{ + return RemoveInternal(aPath, true); +} + +already_AddRefed +Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive) +{ + nsresult error = NS_OK; + nsString realPath; + nsCOMPtr file; + + // Check and get the target path. + + if (aPath.IsFile()) { + file = aPath.GetAsFile(); + goto parameters_check_done; + } + + if (aPath.IsString()) { + if (!DOMPathToRealPath(aPath.GetAsString(), realPath)) { + error = NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR; + } + goto parameters_check_done; + } + + if (!mFileSystem->IsSafeDirectory(&aPath.GetAsDirectory())) { + error = NS_ERROR_DOM_SECURITY_ERR; + goto parameters_check_done; + } + + realPath = aPath.GetAsDirectory().mPath; + // The target must be a descendant of this directory. + if (!FileSystemUtils::IsDescendantPath(mPath, realPath)) { + error = NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR; + } + +parameters_check_done: + + nsRefPtr task = new RemoveTask(mFileSystem, mPath, file, realPath, + aRecursive); + task->SetError(error); + FileSystemPermissionRequest::RequestForTask(task); + return task->GetPromise(); +} + +FileSystemBase* +Directory::GetFileSystem() const +{ + return mFileSystem.get(); +} + bool Directory::DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const { diff --git a/dom/filesystem/Directory.h b/dom/filesystem/Directory.h index 061d26b028a60..3c9ec32209f1a 100644 --- a/dom/filesystem/Directory.h +++ b/dom/filesystem/Directory.h @@ -11,6 +11,7 @@ #include "mozilla/dom/BindingDeclarations.h" #include "nsAutoPtr.h" #include "nsCycleCollectionParticipant.h" +#include "nsDOMFile.h" #include "nsPIDOMWindow.h" #include "nsWrapperCache.h" @@ -26,6 +27,7 @@ namespace dom { class FileSystemBase; class Promise; +class StringOrFileOrDirectory; class Directory MOZ_FINAL : public nsISupports @@ -59,7 +61,16 @@ class Directory MOZ_FINAL already_AddRefed Get(const nsAString& aPath); + already_AddRefed + Remove(const StringOrFileOrDirectory& aPath); + + already_AddRefed + RemoveDeep(const StringOrFileOrDirectory& aPath); + // =========== End WebIDL bindings.============ + + FileSystemBase* + GetFileSystem() const; private: static bool IsValidRelativePath(const nsString& aPath); @@ -71,6 +82,9 @@ class Directory MOZ_FINAL bool DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const; + already_AddRefed + RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive); + nsRefPtr mFileSystem; nsString mPath; }; diff --git a/dom/filesystem/FileSystemBase.cpp b/dom/filesystem/FileSystemBase.cpp index 614c8bb270346..cf5b00185c914 100644 --- a/dom/filesystem/FileSystemBase.cpp +++ b/dom/filesystem/FileSystemBase.cpp @@ -68,5 +68,11 @@ FileSystemBase::IsSafeFile(nsIFile* aFile) const return false; } +bool +FileSystemBase::IsSafeDirectory(Directory* aDir) const +{ + return false; +} + } // namespace dom } // namespace mozilla diff --git a/dom/filesystem/FileSystemBase.h b/dom/filesystem/FileSystemBase.h index e8f3a0da35aa3..490e53b46182c 100644 --- a/dom/filesystem/FileSystemBase.h +++ b/dom/filesystem/FileSystemBase.h @@ -10,11 +10,14 @@ #include "nsAutoPtr.h" #include "nsString.h" +class nsIDOMFile; class nsPIDOMWindow; namespace mozilla { namespace dom { +class Directory; + class FileSystemBase { NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FileSystemBase) @@ -61,6 +64,17 @@ class FileSystemBase virtual bool IsSafeFile(nsIFile* aFile) const; + virtual bool + IsSafeDirectory(Directory* aDir) const; + + /* + * Get the real path (absolute DOM path) of the DOM file in the file system. + * If succeeded, returns true. Otherwise, returns false and set aRealPath to + * empty string. + */ + virtual bool + GetRealPath(nsIDOMFile* aFile, nsAString& aRealPath) const = 0; + /* * Get the permission name required to access this file system. */ diff --git a/dom/filesystem/FileSystemRequestParent.cpp b/dom/filesystem/FileSystemRequestParent.cpp index 793a5a74b574e..0e35ecb87ad33 100644 --- a/dom/filesystem/FileSystemRequestParent.cpp +++ b/dom/filesystem/FileSystemRequestParent.cpp @@ -7,6 +7,7 @@ #include "CreateDirectoryTask.h" #include "GetFileOrDirectoryTask.h" +#include "RemoveTask.h" #include "mozilla/AppProcessChecker.h" #include "mozilla/dom/FileSystemBase.h" @@ -40,6 +41,7 @@ FileSystemRequestParent::Dispatch(ContentParent* aParent, FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(CreateDirectory) FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(GetFileOrDirectory) + FILESYSTEM_REQUEST_PARENT_DISPATCH_ENTRY(Remove) default: { NS_RUNTIMEABORT("not reached"); diff --git a/dom/filesystem/PFileSystemRequest.ipdl b/dom/filesystem/PFileSystemRequest.ipdl index b94aa59b62680..acd709c0d4387 100644 --- a/dom/filesystem/PFileSystemRequest.ipdl +++ b/dom/filesystem/PFileSystemRequest.ipdl @@ -25,8 +25,14 @@ struct FileSystemErrorResponse nsresult error; }; +struct FileSystemBooleanResponse +{ + bool success; +}; + union FileSystemResponseValue { + FileSystemBooleanResponse; FileSystemDirectoryResponse; FileSystemFileResponse; FileSystemErrorResponse; diff --git a/dom/filesystem/RemoveTask.cpp b/dom/filesystem/RemoveTask.cpp new file mode 100644 index 0000000000000..fd283bb5c26d8 --- /dev/null +++ b/dom/filesystem/RemoveTask.cpp @@ -0,0 +1,204 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "RemoveTask.h" + +#include "DOMError.h" +#include "mozilla/dom/FileSystemBase.h" +#include "mozilla/dom/FileSystemUtils.h" +#include "mozilla/dom/Promise.h" +#include "nsIDOMFile.h" +#include "nsIFile.h" +#include "nsStringGlue.h" + +namespace mozilla { +namespace dom { + +RemoveTask::RemoveTask(FileSystemBase* aFileSystem, + const nsAString& aDirPath, + nsIDOMFile* aTargetFile, + const nsAString& aTargetPath, + bool aRecursive) + : FileSystemTaskBase(aFileSystem) + , mDirRealPath(aDirPath) + , mTargetFile(aTargetFile) + , mTargetRealPath(aTargetPath) + , mRecursive(aRecursive) + , mReturnValue(false) +{ + MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); + MOZ_ASSERT(aFileSystem); + nsCOMPtr globalObject = + do_QueryInterface(aFileSystem->GetWindow()); + if (!globalObject) { + return; + } + mPromise = new Promise(globalObject); +} + +RemoveTask::RemoveTask(FileSystemBase* aFileSystem, + const FileSystemRemoveParams& aParam, + FileSystemRequestParent* aParent) + : FileSystemTaskBase(aFileSystem, aParam, aParent) + , mRecursive(false) + , mReturnValue(false) +{ + MOZ_ASSERT(FileSystemUtils::IsParentProcess(), + "Only call from parent process!"); + MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); + MOZ_ASSERT(aFileSystem); + + mDirRealPath = aParam.directory(); + + mRecursive = aParam.recursive(); + + const FileSystemPathOrFileValue& target = aParam.target(); + + if (target.type() == FileSystemPathOrFileValue::TnsString) { + mTargetRealPath = target; + return; + } + + BlobParent* bp = static_cast(static_cast(target)); + nsCOMPtr blob = bp->GetBlob(); + mTargetFile = do_QueryInterface(blob); + MOZ_ASSERT(mTargetFile, "mTargetFile should not be null."); +} + +RemoveTask::~RemoveTask() +{ + MOZ_ASSERT(!mPromise || NS_IsMainThread(), + "mPromise should be released on main thread!"); +} + +already_AddRefed +RemoveTask::GetPromise() +{ + MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); + return nsRefPtr(mPromise).forget(); +} + +FileSystemParams +RemoveTask::GetRequestParams(const nsString& aFileSystem) const +{ + MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); + FileSystemRemoveParams param; + param.filesystem() = aFileSystem; + param.directory() = mDirRealPath; + param.recursive() = mRecursive; + if (mTargetFile) { + BlobChild* actor + = ContentChild::GetSingleton()->GetOrCreateActorForBlob(mTargetFile); + if (actor) { + param.target() = actor; + } + } else { + param.target() = mTargetRealPath; + } + return param; +} + +FileSystemResponseValue +RemoveTask::GetSuccessRequestResult() const +{ + MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); + return FileSystemBooleanResponse(mReturnValue); +} + +void +RemoveTask::SetSuccessRequestResult(const FileSystemResponseValue& aValue) +{ + MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); + FileSystemBooleanResponse r = aValue; + mReturnValue = r.success(); +} + +nsresult +RemoveTask::Work() +{ + MOZ_ASSERT(FileSystemUtils::IsParentProcess(), + "Only call from parent process!"); + MOZ_ASSERT(!NS_IsMainThread(), "Only call on worker thread!"); + + if (mFileSystem->IsShutdown()) { + return NS_ERROR_FAILURE; + } + + // Get the DOM path if a DOMFile is passed as the target. + if (mTargetFile) { + if (!mFileSystem->GetRealPath(mTargetFile, mTargetRealPath)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + if (!FileSystemUtils::IsDescendantPath(mDirRealPath, mTargetRealPath)) { + return NS_ERROR_DOM_FILESYSTEM_NO_MODIFICATION_ALLOWED_ERR; + } + } + + nsCOMPtr file = mFileSystem->GetLocalFile(mTargetRealPath); + if (!file) { + return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR; + } + + bool exists = false; + nsresult rv = file->Exists(&exists); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (!exists) { + mReturnValue = false; + return NS_OK; + } + + bool isFile = false; + rv = file->IsFile(&isFile); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + if (isFile && !mFileSystem->IsSafeFile(file)) { + return NS_ERROR_DOM_SECURITY_ERR; + } + + rv = file->Remove(mRecursive); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + mReturnValue = true; + + return NS_OK; +} + +void +RemoveTask::HandlerCallback() +{ + MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!"); + if (mFileSystem->IsShutdown()) { + mPromise = nullptr; + return; + } + + if (HasError()) { + nsRefPtr domError = new DOMError(mFileSystem->GetWindow(), + mErrorValue); + mPromise->MaybeReject(domError); + mPromise = nullptr; + return; + } + + mPromise->MaybeResolve(mReturnValue); + mPromise = nullptr; +} + +void +RemoveTask::GetPermissionAccessType(nsCString& aAccess) const +{ + aAccess.AssignLiteral("write"); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/filesystem/RemoveTask.h b/dom/filesystem/RemoveTask.h new file mode 100644 index 0000000000000..41e4e1c4b48f9 --- /dev/null +++ b/dom/filesystem/RemoveTask.h @@ -0,0 +1,68 @@ +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */ +/* vim: set ts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_RemoveTask_h +#define mozilla_dom_RemoveTask_h + +#include "mozilla/dom/FileSystemTaskBase.h" +#include "nsAutoPtr.h" + +namespace mozilla { +namespace dom { + +class Promise; + +class RemoveTask MOZ_FINAL + : public FileSystemTaskBase +{ +public: + RemoveTask(FileSystemBase* aFileSystem, + const nsAString& aDirPath, + nsIDOMFile* aTargetFile, + const nsAString& aTargetPath, + bool aRecursive); + RemoveTask(FileSystemBase* aFileSystem, + const FileSystemRemoveParams& aParam, + FileSystemRequestParent* aParent); + + virtual + ~RemoveTask(); + + already_AddRefed + GetPromise(); + + virtual void + GetPermissionAccessType(nsCString& aAccess) const MOZ_OVERRIDE; + +protected: + virtual FileSystemParams + GetRequestParams(const nsString& aFileSystem) const MOZ_OVERRIDE; + + virtual FileSystemResponseValue + GetSuccessRequestResult() const MOZ_OVERRIDE; + + virtual void + SetSuccessRequestResult(const FileSystemResponseValue& aValue) MOZ_OVERRIDE; + + virtual nsresult + Work() MOZ_OVERRIDE; + + virtual void + HandlerCallback() MOZ_OVERRIDE; + +private: + nsRefPtr mPromise; + nsString mDirRealPath; + nsCOMPtr mTargetFile; + nsString mTargetRealPath; + bool mRecursive; + bool mReturnValue; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_RemoveTask_h diff --git a/dom/filesystem/moz.build b/dom/filesystem/moz.build index 34cda14970fb0..6abdde0cab06a 100644 --- a/dom/filesystem/moz.build +++ b/dom/filesystem/moz.build @@ -23,6 +23,7 @@ SOURCES += [ 'FileSystemTaskBase.cpp', 'FileSystemUtils.cpp', 'GetFileOrDirectoryTask.cpp', + 'RemoveTask.cpp', ] FINAL_LIBRARY = 'gklayout' diff --git a/dom/ipc/PContent.ipdl b/dom/ipc/PContent.ipdl index 5541f09c85dc3..9e4eaffc5b5f7 100644 --- a/dom/ipc/PContent.ipdl +++ b/dom/ipc/PContent.ipdl @@ -206,10 +206,25 @@ struct FileSystemGetFileOrDirectoryParams nsString realPath; }; +union FileSystemPathOrFileValue +{ + nsString; + PBlob; +}; + +struct FileSystemRemoveParams +{ + nsString filesystem; + nsString directory; + FileSystemPathOrFileValue target; + bool recursive; +}; + union FileSystemParams { FileSystemCreateDirectoryParams; FileSystemGetFileOrDirectoryParams; + FileSystemRemoveParams; }; union PrefValue { diff --git a/dom/webidl/Directory.webidl b/dom/webidl/Directory.webidl index e7ceaa5fd5f93..ac466ef7aba72 100644 --- a/dom/webidl/Directory.webidl +++ b/dom/webidl/Directory.webidl @@ -45,5 +45,35 @@ interface Directory { [NewObject] // Promise<(File or Directory)> Promise get(DOMString path); + + /* + * Deletes a file or an empty directory. The target must be a descendent of + * current directory. + * @param path If a DOM string is passed, it is the relative path of the + * target. Otherwise, the File or Directory object of the target should be + * passed. + * @return If the target is a non-empty directory, or if deleting the target + * fails, the promise is rejected with a DOM error. If the target did not + * exist, the promise is resolved with boolean false. If the target did exist + * and was successfully deleted, the promise is resolved with boolean true. + */ + [NewObject] + // Promise + Promise remove((DOMString or File or Directory) path); + + /* + * Deletes a file or a directory recursively. The target should be a + * descendent of current directory. + * @param path If a DOM string is passed, it is the relative path of the + * target. Otherwise, the File or Directory object of the target should be + * passed. + * @return If the target exists, but deleting the target fails, the promise is + * rejected with a DOM error. If the target did not exist, the promise is + * resolved with boolean false. If the target did exist and was successfully + * deleted, the promise is resolved with boolean true. + */ + [NewObject] + // Promise + Promise removeDeep((DOMString or File or Directory) path); };