Bug 1673019 - Get and set file permissions in IOUtils r=emalysz

Differential Revision: https://phabricator.services.mozilla.com/D97689
This commit is contained in:
Barret Rennie 2020-12-03 05:37:45 +00:00
Родитель 69d3035e96
Коммит 47793f361c
5 изменённых файлов: 132 добавлений и 0 удалений

Просмотреть файл

@ -155,6 +155,22 @@ namespace IOUtils {
* DOMException.
*/
Promise<sequence<DOMString>> getChildren(DOMString path);
/**
* Set the permissions of the file at |path|.
*
* Windows does not make a distinction between user, group, and other
* permissions like UNICES do. If a permission flag is set for any of user,
* group, or other has a permission, then all users will have that
* permission. Additionally, Windows does not support setting the
* "executable" permission.
*
* @param path An absolute file path
* @param permissions The UNIX file mode representing the permissions.
*
* @return Resolves if the permissions were set successfully, otherwise
* rejects with a DOMException.
*/
Promise<void> setPermissions(DOMString path, unsigned long permissions);
};
/**
@ -305,4 +321,12 @@ dictionary FileInfo {
* This is only available on MacOS and Windows.
*/
long long creationTime;
/**
* The permissions of the file, expressed as a UNIX file mode.
*
* NB: Windows does not make a distinction between user, group, and other
* permissions like UNICES do. The user, group, and other parts will always
* be identical on Windows.
*/
unsigned long permissions;
};

Просмотреть файл

@ -131,6 +131,9 @@ MOZ_MUST_USE inline bool ToJSValue(
if (aInternalFileInfo.mCreationTime.isSome()) {
info.mCreationTime.Construct(aInternalFileInfo.mCreationTime.ref());
}
info.mPermissions.Construct(aInternalFileInfo.mPermissions);
return ToJSValue(aCx, info, aValue);
}
@ -456,6 +459,25 @@ already_AddRefed<Promise> IOUtils::GetChildren(GlobalObject& aGlobal,
return promise.forget();
}
/* static */
already_AddRefed<Promise> IOUtils::SetPermissions(GlobalObject& aGlobal,
const nsAString& aPath,
const uint32_t aPermissions) {
MOZ_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
NS_ENSURE_TRUE(!!promise, nullptr);
nsCOMPtr<nsIFile> file = new nsLocalFile();
REJECT_IF_INIT_PATH_FAILED(file, aPath, promise);
RunOnBackgroundThread<Ok>(
promise, [file = std::move(file), permissions = aPermissions]() {
return SetPermissionsSync(file, permissions);
});
return promise.forget();
}
/* static */
already_AddRefed<nsISerialEventTarget> IOUtils::GetBackgroundEventTarget() {
if (sShutdownStarted) {
@ -1117,6 +1139,8 @@ Result<IOUtils::InternalFileInfo, IOUtils::IOError> IOUtils::StatSync(
return Err(IOError(rv));
}
MOZ_TRY(aFile->GetPermissions(&info.mPermissions));
return info;
}
@ -1205,6 +1229,15 @@ Result<nsTArray<nsString>, IOUtils::IOError> IOUtils::GetChildrenSync(
return children;
}
/* static */
Result<Ok, IOUtils::IOError> IOUtils::SetPermissionsSync(
nsIFile* aFile, const uint32_t aPermissions) {
MOZ_ASSERT(!NS_IsMainThread());
MOZ_TRY(aFile->SetPermissions(aPermissions));
return Ok{};
}
/* static */
Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::MozLZ4::Compress(
Span<const uint8_t> aUncompressed) {

Просмотреть файл

@ -99,6 +99,10 @@ class IOUtils final {
static already_AddRefed<Promise> GetChildren(GlobalObject& aGlobal,
const nsAString& aPath);
static already_AddRefed<Promise> SetPermissions(GlobalObject& aGlobal,
const nsAString& aPath,
const uint32_t aPermissions);
static bool IsAbsolutePath(const nsAString& aPath);
private:
@ -326,6 +330,22 @@ class IOUtils final {
* If there are no children, an empty array. Otherwise, an error.
*/
static Result<nsTArray<nsString>, IOError> GetChildrenSync(nsIFile* aFile);
/**
* Set the permissions of the given file.
*
* Windows does not make a distinction between user, group, and other
* permissions like UNICES do. If a permission flag is set for any of user,
* group, or other has a permission, then all users will have that
* permission.
*
* @param aFile The location of the file.
* @param aPermissions The permissions to set, as a UNIX file mode.
*
* @return |Ok| if the permissions were successfully set, or an error.
*/
static Result<Ok, IOError> SetPermissionsSync(nsIFile* aFile,
const uint32_t aPermissions);
};
/**
@ -382,6 +402,7 @@ struct IOUtils::InternalFileInfo {
uint64_t mSize;
uint64_t mLastModified;
Maybe<uint64_t> mCreationTime;
uint32_t mPermissions;
};
/**

Просмотреть файл

@ -12,3 +12,4 @@ support-files =
[test_ioutils_remove.html]
[test_ioutils_stat_touch.html]
[test_ioutils_worker.xhtml]
[test_ioutils_set_permissions.html]

Просмотреть файл

@ -0,0 +1,53 @@
<!-- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/ -->
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test the IOUtils file I/O API</title>
<script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script src="file_ioutils_test_fixtures.js"></script>
<script>
"use strict";
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
add_task(async function test_setPermissions() {
const tempDir = await PathUtils.getTempDir();
const tempFile = PathUtils.join(tempDir, "setPermissions.tmp");
await IOUtils.writeAtomicUTF8(tempFile, "");
await IOUtils.setPermissions(tempFile, 0o421);
let stat = await IOUtils.stat(tempFile);
if (Services.appinfo.OS === "WINNT") {
// setPermissions ignores the x bit on Windows.
is(stat.permissions, 0o666, "Permissions munged on Windows");
} else {
is(stat.permissions, 0o421, "Permissions match");
}
await IOUtils.setPermissions(tempFile, 0o400);
stat = await IOUtils.stat(tempFile);
if (Services.appinfo.OS === "WINNT") {
is(stat.permissions, 0o444, "Permissions munged on Windows");
} else {
is(stat.permissions, 0o400, "Permissions match");
await cleanup(tempFile);
}
});
</script>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test"></pre>
</body>
</html>