Bug 1022816 - OS.File will now be able to change the readOnly, hidden, and system file attributes on Windows. r=paolo

This commit is contained in:
Ganesh Sahukari 2015-03-13 15:51:53 +00:00
parent a552b87f85
commit 4b15c2aa09
5 changed files with 188 additions and 6 deletions

View File

@ -727,9 +727,11 @@ static const dom::ConstantSpec gWinProperties[] =
// CreateFile attributes
INT_CONSTANT(FILE_ATTRIBUTE_ARCHIVE),
INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
INT_CONSTANT(FILE_ATTRIBUTE_HIDDEN),
INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
INT_CONSTANT(FILE_ATTRIBUTE_SYSTEM),
INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),

View File

@ -210,7 +210,8 @@ exports.Error = OSError;
*/
let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size,
winBirthDate,
lastAccessDate, lastWriteDate) {
lastAccessDate, lastWriteDate,
winAttributes) {
this._path = path;
this._isDir = isDir;
this._isSymLink = isSymLink;
@ -218,6 +219,7 @@ let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size,
this._winBirthDate = winBirthDate;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastWriteDate;
this._winAttributes = winAttributes;
};
AbstractInfo.prototype = {
@ -285,6 +287,15 @@ AbstractInfo.prototype = {
*/
get lastModificationDate() {
return this._lastModificationDate;
},
/**
* The Object with following boolean properties of this file.
* {readOnly, system, hidden}
*
* @type {object}
*/
get winAttributes() {
return this._winAttributes;
}
};
exports.AbstractInfo = AbstractInfo;

View File

@ -236,10 +236,19 @@
/**
* Set the file's access permission bits.
* Not implemented for Windows (bug 1022816).
*/
File.prototype.setPermissions = function setPermissions(options = {}) {
// do nothing
if (!("winAttributes" in options)) {
return;
}
let oldAttributes = WinFile.GetFileAttributes(this._path);
if (oldAttributes == Const.INVALID_FILE_ATTRIBUTES) {
throw new File.Error("setPermissions", ctypes.winLastError, this._path);
}
let newAttributes = toFileAttributes(options.winAttributes, oldAttributes);
throw_on_zero("setPermissions",
WinFile.SetFileAttributes(this._path, newAttributes),
this._path);
};
/**
@ -904,9 +913,14 @@
let value = ctypes.UInt64.join(stat.nFileSizeHigh, stat.nFileSizeLow);
let size = Type.uint64_t.importFromC(value);
let winAttributes = {
readOnly: !!(stat.dwFileAttributes & Const.FILE_ATTRIBUTE_READONLY),
system: !!(stat.dwFileAttributes & Const.FILE_ATTRIBUTE_SYSTEM),
hidden: !!(stat.dwFileAttributes & Const.FILE_ATTRIBUTE_HIDDEN),
};
SysAll.AbstractInfo.call(this, path, isDir, isSymLink, size,
winBirthDate, lastAccessDate, lastWriteDate);
winBirthDate, lastAccessDate, lastWriteDate, winAttributes);
};
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
@ -963,10 +977,19 @@
/**
* Set the file's access permission bits.
* Not implemented for Windows (bug 1022816).
*/
File.setPermissions = function setPermissions(path, options = {}) {
// do nothing
if (!("winAttributes" in options)) {
return;
}
let oldAttributes = WinFile.GetFileAttributes(path);
if (oldAttributes == Const.INVALID_FILE_ATTRIBUTES) {
throw new File.Error("setPermissions", ctypes.winLastError, path);
}
let newAttributes = toFileAttributes(options.winAttributes, oldAttributes);
throw_on_zero("setPermissions",
WinFile.SetFileAttributes(path, newAttributes),
path);
};
/**
@ -1175,6 +1198,34 @@
return result;
}
/**
* Helper used by both versions of setPermissions
*/
function toFileAttributes(winAttributes, oldDwAttrs) {
if ("readOnly" in winAttributes) {
if (winAttributes.readOnly) {
oldDwAttrs |= Const.FILE_ATTRIBUTE_READONLY;
} else {
oldDwAttrs &= ~Const.FILE_ATTRIBUTE_READONLY;
}
}
if ("system" in winAttributes) {
if (winAttributes.system) {
oldDwAttrs |= Const.FILE_ATTRIBUTE_SYSTEM;
} else {
oldDwAttrs &= ~Const.FILE_ATTRIBUTE_SYSTEM;
}
}
if ("hidden" in winAttributes) {
if (winAttributes.hidden) {
oldDwAttrs |= Const.FILE_ATTRIBUTE_HIDDEN;
} else {
oldDwAttrs &= ~Const.FILE_ATTRIBUTE_HIDDEN;
}
}
return oldDwAttrs;
}
File.Win = exports.OS.Win.File;
File.Error = SysAll.Error;
exports.OS.File = File;

View File

@ -0,0 +1,114 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
/**
* A test to ensure that OS.File.setPermissions and
* OS.File.prototype.setPermissions are all working correctly.
* (see bug 1022816)
* The manifest tests on Windows.
*/
// Sequence of setPermission parameters.
let testSequence = [
[ { winAttributes: { readOnly: true, system: true, hidden: true } },
{ readOnly: true, system: true, hidden: true } ],
[ { winAttributes: { readOnly: false } },
{ readOnly: false, system: true, hidden: true } ],
[ { winAttributes: { system: false } },
{ readOnly: false, system: false, hidden: true } ],
[ { winAttributes: { hidden: false } },
{ readOnly: false, system: false, hidden: false } ],
[ { winAttributes: {readOnly: true, system: false, hidden: false} },
{ readOnly: true, system: false, hidden: false } ],
[ { winAttributes: {readOnly: false, system: true, hidden: false} },
{ readOnly: false, system: true, hidden: false } ],
[ { winAttributes: {readOnly: false, system: false, hidden: true} },
{ readOnly: false, system: false, hidden: true } ],
];
// Test application to paths.
add_task(function* test_path_setPermissions() {
let path = OS.Path.join(OS.Constants.Path.tmpDir,
"test_osfile_win_async_setPermissions_path.tmp");
yield OS.File.writeAtomic(path, new Uint8Array(1));
try {
for (let [options, attributesExpected] of testSequence) {
if (options !== null) {
do_print("Setting permissions to " + JSON.stringify(options));
yield OS.File.setPermissions(path, options);
}
let stat = yield OS.File.stat(path);
do_print("Got stat winAttributes: " + JSON.stringify(stat.winAttributes));
do_check_eq(stat.winAttributes.readOnly, attributesExpected.readOnly);
do_check_eq(stat.winAttributes.system, attributesExpected.system);
do_check_eq(stat.winAttributes.hidden, attributesExpected.hidden);
}
} finally {
yield OS.File.remove(path);
}
});
// Test application to open files.
add_task(function* test_file_setPermissions() {
let path = OS.Path.join(OS.Constants.Path.tmpDir,
"test_osfile_win_async_setPermissions_file.tmp");
yield OS.File.writeAtomic(path, new Uint8Array(1));
try {
let fd = yield OS.File.open(path, { write: true });
try {
for (let [options, attributesExpected] of testSequence) {
if (options !== null) {
do_print("Setting permissions to " + JSON.stringify(options));
yield fd.setPermissions(options);
}
let stat = yield fd.stat();
do_print("Got stat winAttributes: " + JSON.stringify(stat.winAttributes));
do_check_eq(stat.winAttributes.readOnly, attributesExpected.readOnly);
do_check_eq(stat.winAttributes.system, attributesExpected.system);
do_check_eq(stat.winAttributes.hidden, attributesExpected.hidden);
}
} finally {
yield fd.close();
}
} finally {
yield OS.File.remove(path);
}
});
// Test application to Check setPermissions on a non-existant file path.
add_task(function* test_non_existant_file_path_setPermissions() {
let path = OS.Path.join(OS.Constants.Path.tmpDir,
"test_osfile_win_async_setPermissions_path.tmp");
Assert.rejects(OS.File.setPermissions(path, {winAttributes: {readOnly: true}}),
/The system cannot find the file specified/,
"setPermissions failed as expected on a non-existant file path");
});
// Test application to Check setPermissions on a invalid file handle.
add_task(function* test_closed_file_handle_setPermissions() {
let path = OS.Path.join(OS.Constants.Path.tmpDir,
"test_osfile_win_async_setPermissions_path.tmp");
yield OS.File.writeAtomic(path, new Uint8Array(1));
try {
let fd = yield OS.File.open(path, { write: true });
yield fd.close();
Assert.rejects(fd.setPermissions(path, {winAttributes: {readOnly: true}}),
/The handle is invalid/,
"setPermissions failed as expected on a invalid file handle");
} finally {
yield OS.File.remove(path);
}
});
function run_test() {
run_next_test();
}

View File

@ -46,3 +46,7 @@ support-files =
# filesystem backing /mnt/sdcard (not worth trying to fix).
[test_osfile_async_setPermissions.js]
skip-if = os == "win" || os == "android"
# Windows test
[test_osfile_win_async_setPermissions.js]
skip-if = os != "win"