Bug 934368 - Implement |remove| and |removeDeep| for Directory. r=dhylands

This commit is contained in:
Yuan Xulei 2014-03-12 14:30:21 +08:00
parent be52e2973e
commit 11142664f7
16 changed files with 873 additions and 2 deletions

View File

@ -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]

View File

@ -88,6 +88,32 @@ function TestGet(iframe, data) {
}, 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 @@ let gData = [
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
}
];

View File

@ -0,0 +1,215 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE HTML>
<html> <!--
https://bugzilla.mozilla.org/show_bug.cgi?id=934368
-->
<head>
<title>Test Directory#remove and #removeDeep of the FileSystem API for device storage</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="devicestorage_common.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=934368">Mozilla Bug 934368</a>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script class="testbody" type="application/javascript;version=1.7">
devicestorage_setup();
let gStorage = null;
let gTestCount = 0;
let gFileMap = {};
let gRemoveDeep = true;
let gTestCases = [
// Remove a non-existent file should return false.
{
dir: "/",
path: "non-existent.png",
ret: false,
shouldPass: true
},
// Remove parent directory should fail.
{
dir: "sub1/sub2",
target: "sub1",
ret: true,
shouldPass: false
},
// Remove root directory should fail.
{
dir: "/",
target: "/",
ret: true,
shouldPass: false
},
// Remove non-descendant file should fail.
{
dir: "sub1",
target: "sub/b.png",
ret: true,
shouldPass: false
},
// Remove descendant file should return true.
{
dir: "sub1",
target: "sub1/sub2/a.png",
ret: true,
shouldPass: true
},
// Remove empty directory should return true.
{
dir: "sub1",
path: "sub2",
ret: true,
shouldPass: true
},
// Remove non-empty directory should return true for "removeDeep" and fail
// for "remove".
{
dir: "/",
path: "sub",
ret: true,
get shouldPass() { return gRemoveDeep; }
}
];
function createTestFiles(storage, callback) {
function createTestFile(path) {
return new Promise(function(resolve, reject) {
function addNamed() {
var req = storage.addNamed(createRandomBlob("image/png"), path);
req.onsuccess = function() {
ok(true, path + " was created.");
resolve();
};
req.onerror = function(e) {
ok(false, "Failed to create " + path + ': ' + e.target.error.name);
reject();
};
}
// Bug 980136. Check if the file exists before we create.
var req = storage.get(path);
req.onsuccess = function() {
ok(true, path + " exists. Do not need to create.");
resolve();
};
req.onerror = function(e) {
ok(true, path + " does not exists: " + e.target.error.name);
addNamed();
};
});
}
let arr = [];
["sub1/sub2/a.png", "sub/b.png"].forEach(function(path) {
arr.push(createTestFile(path));
});
Promise.all(arr).then(function() {
callback();
}, function() {
ok(false, "Failed to created test files.");
devicestorage_cleanup();
});
}
function runTest() {
gTestCount = 0;
createTestFiles(gStorage, function() {
function cbError(e) {
ok(false, "Should not arrive at cbError! Error: " + e.name);
devicestorage_cleanup();
}
function cbSuccess(r) {
ok(r, "Should get the file - " + this);
gFileMap[this] = r;
}
// Get directory and file objects.
gStorage.getRoot().then(function(root) {
ok(root, "Should get root directory.");
gFileMap["/"] = root;
let arr = [];
["sub1", "sub1/sub2", "sub1/sub2/a.png", "sub/b.png"].forEach(function(path) {
arr.push(root.get(path).then(cbSuccess.bind(path), cbError));
});
Promise.all(arr).then(function() {
testNextRemove();
}, function() {
ok(false, "Failed to get test files.");
devicestorage_cleanup();
});
}, cbError);
});
}
function testNextRemove() {
if (gTestCount < gTestCases.length) {
let data = gTestCases[gTestCount++];
let dir = gFileMap[data.dir];
let path = data.path || gFileMap[data.target];
let targetPath = data.path || data.target;
let promise = gRemoveDeep ? dir.removeDeep(path) : dir.remove(path);
promise.then(function(result) {
ok(data.shouldPass, "Success callback was called to remove " +
targetPath + " from " + data.dir);
is(result, data.ret, "Return value should match to remove " +
targetPath + " from " + data.dir);
SimpleTest.executeSoon(testNextRemove);
}, function(err) {
ok(!data.shouldPass, "Error callback was called to remove " +
targetPath + " from " + data.dir + '. Error: ' + err.name);
SimpleTest.executeSoon(testNextRemove);
});
return;
}
if (gRemoveDeep) {
// Test "remove" after "removeDeep".
gRemoveDeep = false;
runTest();
return;
}
devicestorage_cleanup();
}
ok(navigator.getDeviceStorage, "Should have getDeviceStorage.");
let gStorage = navigator.getDeviceStorage("pictures");
ok(gStorage, "Should have gotten a storage.");
// Test "removeDeep" first.
gRemoveDeep = true;
runTest();
</script>
</pre>
</body>
</html>

View File

@ -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<FileSystemBase> 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

View File

@ -36,16 +36,24 @@ public:
virtual already_AddRefed<nsIFile>
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;

View File

@ -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<Promise>
Directory::Remove(const StringOrFileOrDirectory& aPath)
{
return RemoveInternal(aPath, false);
}
already_AddRefed<Promise>
Directory::RemoveDeep(const StringOrFileOrDirectory& aPath)
{
return RemoveInternal(aPath, true);
}
already_AddRefed<Promise>
Directory::RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive)
{
nsresult error = NS_OK;
nsString realPath;
nsCOMPtr<nsIDOMFile> 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<RemoveTask> 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
{

View File

@ -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 @@ public:
already_AddRefed<Promise>
Get(const nsAString& aPath);
already_AddRefed<Promise>
Remove(const StringOrFileOrDirectory& aPath);
already_AddRefed<Promise>
RemoveDeep(const StringOrFileOrDirectory& aPath);
// =========== End WebIDL bindings.============
FileSystemBase*
GetFileSystem() const;
private:
static bool
IsValidRelativePath(const nsString& aPath);
@ -71,6 +82,9 @@ private:
bool
DOMPathToRealPath(const nsAString& aPath, nsAString& aRealPath) const;
already_AddRefed<Promise>
RemoveInternal(const StringOrFileOrDirectory& aPath, bool aRecursive);
nsRefPtr<FileSystemBase> mFileSystem;
nsString mPath;
};

View File

@ -68,5 +68,11 @@ FileSystemBase::IsSafeFile(nsIFile* aFile) const
return false;
}
bool
FileSystemBase::IsSafeDirectory(Directory* aDir) const
{
return false;
}
} // namespace dom
} // namespace mozilla

View File

@ -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 @@ public:
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.
*/

View File

@ -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");

View File

@ -25,8 +25,14 @@ struct FileSystemErrorResponse
nsresult error;
};
struct FileSystemBooleanResponse
{
bool success;
};
union FileSystemResponseValue
{
FileSystemBooleanResponse;
FileSystemDirectoryResponse;
FileSystemFileResponse;
FileSystemErrorResponse;

View File

@ -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<nsIGlobalObject> 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<BlobParent*>(static_cast<PBlobParent*>(target));
nsCOMPtr<nsIDOMBlob> 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<Promise>
RemoveTask::GetPromise()
{
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread!");
return nsRefPtr<Promise>(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<nsIFile> 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> 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

View File

@ -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<Promise>
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<Promise> mPromise;
nsString mDirRealPath;
nsCOMPtr<nsIDOMFile> mTargetFile;
nsString mTargetRealPath;
bool mRecursive;
bool mReturnValue;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_RemoveTask_h

View File

@ -23,6 +23,7 @@ SOURCES += [
'FileSystemTaskBase.cpp',
'FileSystemUtils.cpp',
'GetFileOrDirectoryTask.cpp',
'RemoveTask.cpp',
]
FINAL_LIBRARY = 'gklayout'

View File

@ -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 {

View File

@ -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<boolean>
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<boolean>
Promise removeDeep((DOMString or File or Directory) path);
};