Bug 967507 - [OS.File] Add |path| for error-reporting. r=Yoric

This commit is contained in:
Peiyong Lin 2014-02-24 10:16:01 -05:00
Родитель 8453de76b1
Коммит 78963dfcf5
9 изменённых файлов: 302 добавлений и 122 удалений

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

@ -701,6 +701,7 @@ static const dom::ConstantSpec gWinProperties[] =
INT_CONSTANT(DACL_SECURITY_INFORMATION),
// Errors
INT_CONSTANT(ERROR_INVALID_HANDLE),
INT_CONSTANT(ERROR_ACCESS_DENIED),
INT_CONSTANT(ERROR_DIR_NOT_EMPTY),
INT_CONSTANT(ERROR_FILE_EXISTS),

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

@ -1238,12 +1238,15 @@ exports.normalizeToPointer = normalizeToPointer;
* codes provided by subclasses of |OS.Shared.Error|.
*
* @param {string} operation The operation that failed.
* @param {string=} path The path of the file on which the operation failed,
* or nothing if there was no file involved in the failure.
*
* @constructor
*/
function OSError(operation) {
function OSError(operation, path = "") {
Error.call(this);
this.operation = operation;
this.path = path;
}
exports.OSError = OSError;

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

@ -25,10 +25,15 @@ let clone = SharedAll.clone;
* Code shared by implementations of File.
*
* @param {*} fd An OS-specific file handle.
* @param {string} path File path of the file handle, used for error-reporting.
* @constructor
*/
let AbstractFile = function AbstractFile(fd) {
let AbstractFile = function AbstractFile(fd, path) {
this._fd = fd;
if (!path) {
throw new TypeError("path is expected");
}
this._path = path;
};
AbstractFile.prototype = {
@ -41,7 +46,7 @@ AbstractFile.prototype = {
if (this._fd) {
return this._fd;
}
throw OS.File.Error.closed();
throw OS.File.Error.closed("accessing file", this._path);
},
/**
* Read bytes from this file to a new buffer.
@ -183,7 +188,7 @@ AbstractFile.openUnique = function openUnique(path, options = {}) {
// keep trying ...
}
}
throw OS.File.Error.exists("could not find an unused file name.");
throw OS.File.Error.exists("could not find an unused file name.", path);
}
};
@ -395,7 +400,7 @@ AbstractFile.writeAtomic =
}
let noOverwrite = options.noOverwrite;
if (noOverwrite && OS.File.exists(path)) {
throw OS.File.Error.exists("writeAtomic");
throw OS.File.Error.exists("writeAtomic", path);
}
if (typeof buffer == "string") {

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

@ -73,19 +73,23 @@ libc.declareLazy(LazyBindings, "strerror",
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
* @param {string=} path The file path that manipulated. If unspecified,
* assign the empty string.
*
* @constructor
* @extends {OS.Shared.Error}
*/
let OSError = function OSError(operation, errno) {
operation = operation || "unknown operation";
SharedAll.OSError.call(this, operation);
this.unixErrno = errno || ctypes.errno;
let OSError = function OSError(operation = "unknown operation",
errno = ctypes.errno, path = "") {
operation = operation;
SharedAll.OSError.call(this, operation, path);
this.unixErrno = errno;
};
OSError.prototype = Object.create(SharedAll.OSError.prototype);
OSError.prototype.toString = function toString() {
return "Unix error " + this.unixErrno +
" during operation " + this.operation +
(this.path? " on file " + this.path : "") +
" (" + LazyBindings.strerror(this.unixErrno).readString() + ")";
};
@ -143,7 +147,8 @@ Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
unixErrno: error.unixErrno
unixErrno: error.unixErrno,
path: error.path
};
};
@ -151,7 +156,7 @@ OSError.toMsg = function toMsg(error) {
* Deserialize a message back to an instance of OSError
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.unixErrno);
return new OSError(msg.operation, msg.unixErrno, msg.path);
};
exports.Error = OSError;
@ -160,9 +165,10 @@ exports.Error = OSError;
*
* @constructor
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, lastAccessDate,
let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode) {
this._path = path;
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._size = size;
@ -175,6 +181,14 @@ let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, lastAccessDate,
};
AbstractInfo.prototype = {
/**
* The path of the file, used for error-reporting.
*
* @type {string}
*/
get path() {
return this._path;
},
/**
* |true| if this file is a directory, |false| otherwise
*/
@ -305,16 +319,16 @@ Type.path = Type.cstring.withName("[in] path");
Type.out_path = Type.out_cstring.withName("[out] path");
// Special constructors that need to be defined on all threads
OSError.closed = function closed(operation) {
return new OSError(operation, Const.EBADF);
OSError.closed = function closed(operation, path) {
return new OSError(operation, Const.EBADF, path);
};
OSError.exists = function exists(operation) {
return new OSError(operation, Const.EEXIST);
OSError.exists = function exists(operation, path) {
return new OSError(operation, Const.EEXIST, path);
};
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, Const.ENOENT);
OSError.noSuchFile = function noSuchFile(operation, path) {
return new OSError(operation, Const.ENOENT, path);
};
let EXPORTED_SYMBOLS = [

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

@ -40,10 +40,11 @@
* to open a file, use function |OS.File.open|.
*
* @param fd A OS-specific file descriptor.
* @param {string} path File path of the file handle, used for error-reporting.
* @constructor
*/
let File = function File(fd) {
exports.OS.Shared.AbstractFile.call(this, fd);
let File = function File(fd, path) {
exports.OS.Shared.AbstractFile.call(this, fd, path);
this._closeResult = null;
};
File.prototype = Object.create(exports.OS.Shared.AbstractFile.prototype);
@ -70,7 +71,7 @@
fd.forget();
}
if (result == -1) {
this._closeResult = new File.Error("close");
this._closeResult = new File.Error("close", ctypes.errno, this._path);
}
}
if (this._closeResult) {
@ -103,7 +104,8 @@
OS.Constants.libc.POSIX_FADV_SEQUENTIAL);
}
return throw_on_negative("read",
UnixFile.read(this.fd, buffer, nbytes)
UnixFile.read(this.fd, buffer, nbytes),
this._path
);
};
@ -122,7 +124,8 @@
*/
File.prototype._write = function _write(buffer, nbytes, options = {}) {
return throw_on_negative("write",
UnixFile.write(this.fd, buffer, nbytes)
UnixFile.write(this.fd, buffer, nbytes),
this._path
);
};
@ -154,7 +157,8 @@
whence = Const.SEEK_SET;
}
return throw_on_negative("setPosition",
UnixFile.lseek(this.fd, pos, whence)
UnixFile.lseek(this.fd, pos, whence),
this._path
);
};
@ -164,8 +168,9 @@
* @return File.Info The information on |this| file.
*/
File.prototype.stat = function stat() {
throw_on_negative("stat", UnixFile.fstat(this.fd, gStatDataPtr));
return new File.Info(gStatData);
throw_on_negative("stat", UnixFile.fstat(this.fd, gStatDataPtr),
this._path);
return new File.Info(gStatData, this._path);
};
/**
@ -192,7 +197,8 @@
gTimevals[1].tv_sec = (modificationDate / 1000) | 0;
gTimevals[1].tv_usec = 0;
throw_on_negative("setDates",
UnixFile.futimes(this.fd, gTimevalsPtr));
UnixFile.futimes(this.fd, gTimevalsPtr),
this._path);
};
/**
@ -207,7 +213,7 @@
* @throws {OS.File.Error} In case of I/O error.
*/
File.prototype.flush = function flush() {
throw_on_negative("flush", UnixFile.fsync(this.fd));
throw_on_negative("flush", UnixFile.fsync(this.fd), this._path);
};
// The default unix mode for opening (0600)
@ -293,7 +299,7 @@
flags |= Const.O_APPEND;
}
}
return error_or_file(UnixFile.open(path, flags, omode));
return error_or_file(UnixFile.open(path, flags, omode), path);
};
/**
@ -328,7 +334,7 @@
ctypes.errno == Const.ENOENT) {
return;
}
throw new File.Error("remove");
throw new File.Error("remove", ctypes.errno, path);
}
};
@ -347,7 +353,7 @@
ctypes.errno == Const.ENOENT) {
return;
}
throw new File.Error("removeEmptyDir");
throw new File.Error("removeEmptyDir", ctypes.errno, path);
}
};
@ -399,7 +405,7 @@
(ctypes.errno == Const.EEXIST || ctypes.errno == Const.EISDIR)) {
return;
}
throw new File.Error("makeDir");
throw new File.Error("makeDir", ctypes.errno, path);
}
};
@ -466,7 +472,8 @@
flags |= Const.COPYFILE_EXCL;
}
throw_on_negative("copy",
UnixFile.copyfile(sourcePath, destPath, null, flags)
UnixFile.copyfile(sourcePath, destPath, null, flags),
sourcePath
);
};
} else {
@ -644,10 +651,10 @@
if (fd != -1) {
fd.dispose();
// The file exists and we have access
throw new File.Error("move", Const.EEXIST);
throw new File.Error("move", Const.EEXIST, sourcePath);
} else if (ctypes.errno == Const.EACCESS) {
// The file exists and we don't have access
throw new File.Error("move", Const.EEXIST);
throw new File.Error("move", Const.EEXIST, sourcePath);
}
}
@ -661,7 +668,7 @@
// that prevents us from crossing devices, throw the
// error.
if (ctypes.errno != Const.EXDEV || options.noCopy) {
throw new File.Error("move");
throw new File.Error("move", ctypes.errno, sourcePath);
}
// Otherwise, copy and remove.
@ -689,7 +696,7 @@
if (this._dir == null) {
let error = ctypes.errno;
if (error != Const.ENOENT) {
throw new File.Error("DirectoryIterator", error);
throw new File.Error("DirectoryIterator", error, path);
}
this._exists = false;
this._closed = true;
@ -712,7 +719,7 @@
*/
File.DirectoryIterator.prototype.next = function next() {
if (!this._exists) {
throw File.Error.noSuchFile("DirectoryIterator.prototype.next");
throw File.Error.noSuchFile("DirectoryIterator.prototype.next", this._path);
}
if (this._closed) {
throw StopIteration;
@ -730,7 +737,7 @@
if (!("d_type" in contents)) {
// |dirent| doesn't have d_type on some platforms (e.g. Solaris).
let path = Path.join(this._path, name);
throw_on_negative("lstat", UnixFile.lstat(path, gStatDataPtr));
throw_on_negative("lstat", UnixFile.lstat(path, gStatDataPtr), this._path);
isDir = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFDIR;
isSymLink = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFLNK;
} else {
@ -768,8 +775,8 @@
* Return directory as |File|
*/
File.DirectoryIterator.prototype.unixAsFile = function unixAsFile() {
if (!this._dir) throw File.Error.closed();
return error_or_file(UnixFile.dirfd(this._dir));
if (!this._dir) throw File.Error.closed("unixAsFile", this._path);
return error_or_file(UnixFile.dirfd(this._dir), this._path);
};
/**
@ -810,7 +817,7 @@
let gTimevals = new Type.timevals.implementation();
let gTimevalsPtr = gTimevals.address();
let MODE_MASK = 4095 /*= 07777*/;
File.Info = function Info(stat) {
File.Info = function Info(stat, path) {
let isDir = (stat.st_mode & Const.S_IFMT) == Const.S_IFDIR;
let isSymLink = (stat.st_mode & Const.S_IFMT) == Const.S_IFLNK;
let size = Type.off_t.importFromC(stat.st_size);
@ -823,8 +830,8 @@
let unixGroup = Type.gid_t.importFromC(stat.st_gid);
let unixMode = Type.mode_t.importFromC(stat.st_mode & MODE_MASK);
SysAll.AbstractInfo.call(this, isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
SysAll.AbstractInfo.call(this, path, isDir, isSymLink, size,
lastAccessDate, lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode);
// Some platforms (e.g. MacOS X, some BSDs) store a file creation date
@ -885,11 +892,11 @@
*/
File.stat = function stat(path, options = {}) {
if (options.unixNoFollowingLinks) {
throw_on_negative("stat", UnixFile.lstat(path, gStatDataPtr));
throw_on_negative("stat", UnixFile.lstat(path, gStatDataPtr), path);
} else {
throw_on_negative("stat", UnixFile.stat(path, gStatDataPtr));
throw_on_negative("stat", UnixFile.stat(path, gStatDataPtr), path);
}
return new File.Info(gStatData);
return new File.Info(gStatData, path);
};
/**
@ -916,7 +923,8 @@
gTimevals[1].tv_sec = (modificationDate / 1000) | 0;
gTimevals[1].tv_usec = 0;
throw_on_negative("setDates",
UnixFile.utimes(path, gTimevalsPtr));
UnixFile.utimes(path, gTimevalsPtr),
path);
};
File.read = exports.OS.Shared.AbstractFile.read;
@ -930,7 +938,7 @@
File.getCurrentDirectory = function getCurrentDirectory() {
let path = UnixFile.get_current_dir_name?UnixFile.get_current_dir_name():
UnixFile.getwd_auto(null);
throw_on_null("getCurrentDirectory",path);
throw_on_null("getCurrentDirectory", path);
return path.readString();
};
@ -939,7 +947,8 @@
*/
File.setCurrentDirectory = function setCurrentDirectory(path) {
throw_on_negative("setCurrentDirectory",
UnixFile.chdir(path)
UnixFile.chdir(path),
path
);
};
@ -960,33 +969,48 @@
/**
* Turn the result of |open| into an Error or a File
* @param {number} maybe The result of the |open| operation that may
* represent either an error or a success. If -1, this function raises
* an error holding ctypes.errno, otherwise it returns the opened file.
* @param {string=} path The path of the file.
*/
function error_or_file(maybe) {
function error_or_file(maybe, path) {
if (maybe == -1) {
throw new File.Error("open");
throw new File.Error("open", ctypes.errno, path);
}
return new File(maybe);
return new File(maybe, path);
}
/**
* Utility function to sort errors represented as "-1" from successes.
*
* @param {string=} operation The name of the operation. If unspecified,
* the name of the caller function.
* @param {number} result The result of the operation that may
* represent either an error or a success. If -1, this function raises
* an error holding ctypes.errno, otherwise it returns |result|.
* @param {string=} operation The name of the operation. If unspecified,
* the name of the caller function.
* @param {string=} path The path of the file.
*/
function throw_on_negative(operation, result) {
function throw_on_negative(operation, result, path) {
if (result < 0) {
throw new File.Error(operation);
throw new File.Error(operation, ctypes.errno, path);
}
return result;
}
function throw_on_null(operation, result) {
/**
* Utility function to sort errors represented as |null| from successes.
*
* @param {string=} operation The name of the operation. If unspecified,
* the name of the caller function.
* @param {pointer} result The result of the operation that may
* represent either an error or a success. If |null|, this function raises
* an error holding ctypes.errno, otherwise it returns |result|.
* @param {string=} path The path of the file.
*/
function throw_on_null(operation, result, path) {
if (result == null || (result.isNull && result.isNull())) {
throw new File.Error(operation);
throw new File.Error(operation, ctypes.errno, path);
}
return result;
}

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

@ -79,14 +79,17 @@ libc.declareLazy(Scope, "FormatMessage",
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
* @param {string=} path The file path that manipulated. If unspecified,
* assign the empty string.
*
* @constructor
* @extends {OS.Shared.Error}
*/
let OSError = function OSError(operation, lastError) {
operation = operation || "unknown operation";
SharedAll.OSError.call(this, operation);
this.winLastError = lastError || ctypes.winLastError;
let OSError = function OSError(operation = "unknown operation",
lastError = ctypes.winLastError, path = "") {
operation = operation;
SharedAll.OSError.call(this, operation, path);
this.winLastError = lastError;
};
OSError.prototype = Object.create(SharedAll.OSError.prototype);
OSError.prototype.toString = function toString() {
@ -107,7 +110,8 @@ OSError.prototype.toString = function toString() {
" while fetching system error message";
}
return "Win error " + this.winLastError + " during operation "
+ this.operation + " (" + buf.readString() + ")";
+ this.operation + (this.path? " on file " + this.path : "") +
" (" + buf.readString() + ")";
};
/**
@ -165,7 +169,8 @@ Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
winLastError: error.winLastError
winLastError: error.winLastError,
path: error.path
};
};
@ -173,7 +178,7 @@ OSError.toMsg = function toMsg(error) {
* Deserialize a message back to an instance of OSError
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.winLastError);
return new OSError(msg.operation, msg.winLastError, msg.path);
};
exports.Error = OSError;
@ -182,8 +187,10 @@ exports.Error = OSError;
*
* @constructor
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, winBirthDate,
let AbstractInfo = function AbstractInfo(path, isDir, isSymLink, size,
winBirthDate,
lastAccessDate, lastWriteDate) {
this._path = path;
this._isDir = isDir;
this._isSymLink = isSymLink;
this._size = size;
@ -193,6 +200,14 @@ let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, winBirthDate,
};
AbstractInfo.prototype = {
/**
* The path of the file, used for error-reporting.
*
* @type {string}
*/
get path() {
return this._path;
},
/**
* |true| if this file is a directory, |false| otherwise
*/
@ -341,16 +356,16 @@ Type.path = Type.wstring.withName("[in] path");
Type.out_path = Type.out_wstring.withName("[out] path");
// Special constructors that need to be defined on all threads
OSError.closed = function closed(operation) {
return new OSError(operation, Const.ERROR_INVALID_HANDLE);
OSError.closed = function closed(operation, path) {
return new OSError(operation, Const.ERROR_INVALID_HANDLE, path);
};
OSError.exists = function exists(operation) {
return new OSError(operation, Const.ERROR_FILE_EXISTS);
OSError.exists = function exists(operation, path) {
return new OSError(operation, Const.ERROR_FILE_EXISTS, path);
};
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, Const.ERROR_FILE_NOT_FOUND);
OSError.noSuchFile = function noSuchFile(operation, path) {
return new OSError(operation, Const.ERROR_FILE_NOT_FOUND, path);
};
let EXPORTED_SYMBOLS = [

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

@ -58,10 +58,11 @@
* to open a file, use function |OS.File.open|.
*
* @param fd A OS-specific file descriptor.
* @param {string} path File path of the file handle, used for error-reporting.
* @constructor
*/
let File = function File(fd) {
exports.OS.Shared.AbstractFile.call(this, fd);
let File = function File(fd, path) {
exports.OS.Shared.AbstractFile.call(this, fd, path);
this._closeResult = null;
};
File.prototype = Object.create(exports.OS.Shared.AbstractFile.prototype);
@ -88,7 +89,7 @@
fd.forget();
}
if (result == -1) {
this._closeResult = new File.Error("close");
this._closeResult = new File.Error("close", ctypes.winLastError, this._path);
}
}
if (this._closeResult) {
@ -115,7 +116,8 @@
File.prototype._read = function _read(buffer, nbytes, options) {
// |gBytesReadPtr| is a pointer to |gBytesRead|.
throw_on_zero("read",
WinFile.ReadFile(this.fd, buffer, nbytes, gBytesReadPtr, null)
WinFile.ReadFile(this.fd, buffer, nbytes, gBytesReadPtr, null),
this._path
);
return gBytesRead.value;
};
@ -141,7 +143,8 @@
}
// |gBytesWrittenPtr| is a pointer to |gBytesWritten|.
throw_on_zero("write",
WinFile.WriteFile(this.fd, buffer, nbytes, gBytesWrittenPtr, null)
WinFile.WriteFile(this.fd, buffer, nbytes, gBytesWrittenPtr, null),
this._path
);
return gBytesWritten.value;
};
@ -174,7 +177,8 @@
whence = Const.FILE_BEGIN;
}
return throw_on_negative("setPosition",
WinFile.SetFilePointer(this.fd, pos, null, whence));
WinFile.SetFilePointer(this.fd, pos, null, whence),
this._path);
};
/**
@ -184,8 +188,9 @@
*/
File.prototype.stat = function stat() {
throw_on_zero("stat",
WinFile.GetFileInformationByHandle(this.fd, gFileInfoPtr));
return new File.Info(gFileInfo);
WinFile.GetFileInformationByHandle(this.fd, gFileInfoPtr),
this._path);
return new File.Info(gFileInfo, this._path);
};
/**
@ -204,12 +209,14 @@
* @throws {OS.File.Error} In case of I/O error.
*/
File.prototype.setDates = function setDates(accessDate, modificationDate) {
accessDate = Date_to_FILETIME("File.prototype.setDates", accessDate);
accessDate = Date_to_FILETIME("File.prototype.setDates", accessDate, this._path);
modificationDate = Date_to_FILETIME("File.prototype.setDates",
modificationDate);
modificationDate,
this._path);
throw_on_zero("setDates",
WinFile.SetFileTime(this.fd, null, accessDate.address(),
modificationDate.address()));
modificationDate.address()),
this._path);
};
/**
@ -224,7 +231,7 @@
* @throws {OS.File.Error} In case of I/O error.
*/
File.prototype.flush = function flush() {
throw_on_zero("flush", WinFile.FlushFileBuffers(this.fd));
throw_on_zero("flush", WinFile.FlushFileBuffers(this.fd), this._path);
};
// The default sharing mode for opening files: files are not
@ -340,7 +347,7 @@
}
let file = error_or_file(WinFile.CreateFile(path,
access, share, security, disposition, flags, template));
access, share, security, disposition, flags, template), path);
file._appendMode = !!mode.append;
@ -350,7 +357,8 @@
// Now, perform manual truncation
file.setPosition(0, File.POS_START);
throw_on_zero("open",
WinFile.SetEndOfFile(file.fd));
WinFile.SetEndOfFile(file.fd),
path);
return file;
};
@ -402,7 +410,7 @@
}
}
throw new File.Error("remove");
throw new File.Error("remove", ctypes.winLastError, path);
};
/**
@ -420,7 +428,7 @@
ctypes.winLastError == Const.ERROR_FILE_NOT_FOUND) {
return;
}
throw new File.Error("removeEmptyDir");
throw new File.Error("removeEmptyDir", ctypes.winLastError, path);
}
};
@ -447,7 +455,7 @@
}
if (("ignoreExisting" in options) && !options.ignoreExisting) {
throw new File.Error("makeDir");
throw new File.Error("makeDir", ctypes.winLastError, path);
}
if (ctypes.winLastError == Const.ERROR_ALREADY_EXISTS) {
@ -469,7 +477,7 @@
return;
}
throw new File.Error("makeDir");
throw new File.Error("makeDir", ctypes.winLastError, path);
};
/**
@ -497,7 +505,8 @@
*/
File.copy = function copy(sourcePath, destPath, options = {}) {
throw_on_zero("copy",
WinFile.CopyFile(sourcePath, destPath, options.noOverwrite || false)
WinFile.CopyFile(sourcePath, destPath, options.noOverwrite || false),
sourcePath
);
};
@ -536,7 +545,8 @@
flags = flags | Const.MOVEFILE_REPLACE_EXISTING;
}
throw_on_zero("move",
WinFile.MoveFileEx(sourcePath, destPath, flags)
WinFile.MoveFileEx(sourcePath, destPath, flags),
sourcePath
);
// Inherit NTFS permissions from the destination directory
@ -600,13 +610,14 @@
/**
* Utility function: convert a FILETIME to a JavaScript Date.
*/
let FILETIME_to_Date = function FILETIME_to_Date(fileTime) {
let FILETIME_to_Date = function FILETIME_to_Date(fileTime, path) {
if (fileTime == null) {
throw new TypeError("Expecting a non-null filetime");
}
throw_on_zero("FILETIME_to_Date",
WinFile.FileTimeToSystemTime(fileTime.address(),
gSystemTimePtr));
gSystemTimePtr),
path);
// Windows counts hours, minutes, seconds from UTC,
// JS counts from local time, so we need to go through UTC.
let utc = Date.UTC(gSystemTime.wYear,
@ -626,7 +637,7 @@
* then the current date will be used. If numeric, assumed to be the date
* in milliseconds since epoch.
*/
let Date_to_FILETIME = function Date_to_FILETIME(fn, date) {
let Date_to_FILETIME = function Date_to_FILETIME(fn, date, path) {
if (typeof date === "number") {
date = new Date(date);
} else if (!date) {
@ -646,7 +657,8 @@
let result = new OS.Shared.Type.FILETIME.implementation();
throw_on_zero("Date_to_FILETIME",
WinFile.SystemTimeToFileTime(gSystemTimePtr,
result.address()));
result.address()),
path);
return result;
};
@ -693,7 +705,7 @@
this._closed = true;
this._exists = false;
} else {
throw new File.Error("DirectoryIterator", error);
throw new File.Error("DirectoryIterator", error, this._path);
}
} else {
this._closed = false;
@ -712,7 +724,7 @@
File.DirectoryIterator.prototype._next = function _next() {
// Bailout if the directory does not exist
if (!this._exists) {
throw File.Error.noSuchFile("DirectoryIterator.prototype.next");
throw File.Error.noSuchFile("DirectoryIterator.prototype.next", this._path);
}
// Bailout if the iterator is closed.
if (this._closed) {
@ -733,7 +745,7 @@
if (error == Const.ERROR_NO_MORE_FILES) {
return null;
} else {
throw new File.Error("iter (FindNextFile)", error);
throw new File.Error("iter (FindNextFile)", error, this._path);
}
}
},
@ -771,7 +783,8 @@
// We might not have a handle if the iterator is closed
// before being used.
throw_on_zero("FindClose",
WinFile.FindClose(this._handle));
WinFile.FindClose(this._handle),
this._path);
this._handle = null;
}
};
@ -795,9 +808,9 @@
let isDir = !!(win_entry.dwFileAttributes & Const.FILE_ATTRIBUTE_DIRECTORY);
let isSymLink = !!(win_entry.dwFileAttributes & Const.FILE_ATTRIBUTE_REPARSE_POINT);
let winCreationDate = FILETIME_to_Date(win_entry.ftCreationTime);
let winLastWriteDate = FILETIME_to_Date(win_entry.ftLastWriteTime);
let winLastAccessDate = FILETIME_to_Date(win_entry.ftLastAccessTime);
let winCreationDate = FILETIME_to_Date(win_entry.ftCreationTime, this._path);
let winLastWriteDate = FILETIME_to_Date(win_entry.ftLastWriteTime, this._path);
let winLastAccessDate = FILETIME_to_Date(win_entry.ftLastAccessTime, this._path);
let name = win_entry.cFileName.readString();
if (!name) {
@ -847,20 +860,19 @@
*
* @constructor
*/
File.Info = function Info(stat) {
File.Info = function Info(stat, path) {
let isDir = !!(stat.dwFileAttributes & Const.FILE_ATTRIBUTE_DIRECTORY);
let isSymLink = !!(stat.dwFileAttributes & Const.FILE_ATTRIBUTE_REPARSE_POINT);
let winBirthDate = FILETIME_to_Date(stat.ftCreationTime);
let lastAccessDate = FILETIME_to_Date(stat.ftLastAccessTime);
let lastWriteDate = FILETIME_to_Date(stat.ftLastWriteTime);
let winBirthDate = FILETIME_to_Date(stat.ftCreationTime, this._path);
let lastAccessDate = FILETIME_to_Date(stat.ftLastAccessTime, this._path);
let lastWriteDate = FILETIME_to_Date(stat.ftLastWriteTime, this._path);
let value = ctypes.UInt64.join(stat.nFileSizeHigh, stat.nFileSizeLow);
let size = Type.uint64_t.importFromC(value);
SysAll.AbstractInfo.call(this, isDir, isSymLink, size,
winBirthDate, lastAccessDate,
lastWriteDate);
SysAll.AbstractInfo.call(this, path, isDir, isSymLink, size,
winBirthDate, lastAccessDate, lastWriteDate);
};
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
@ -1004,7 +1016,8 @@
*/
File.setCurrentDirectory = function setCurrentDirectory(path) {
throw_on_zero("setCurrentDirectory",
WinFile.SetCurrentDirectory(path));
WinFile.SetCurrentDirectory(path),
path);
};
/**
@ -1021,27 +1034,68 @@
);
// Utility functions, used for error-handling
function error_or_file(maybe) {
/**
* Turn the result of |open| into an Error or a File
* @param {number} maybe The result of the |open| operation that may
* represent either an error or a success. If -1, this function raises
* an error holding ctypes.winLastError, otherwise it returns the opened file.
* @param {string=} path The path of the file.
*/
function error_or_file(maybe, path) {
if (maybe == Const.INVALID_HANDLE_VALUE) {
throw new File.Error("open");
throw new File.Error("open", ctypes.winLastError, path);
}
return new File(maybe);
return new File(maybe, path);
}
function throw_on_zero(operation, result) {
/**
* Utility function to sort errors represented as "0" from successes.
*
* @param {string=} operation The name of the operation. If unspecified,
* the name of the caller function.
* @param {number} result The result of the operation that may
* represent either an error or a success. If 0, this function raises
* an error holding ctypes.winLastError, otherwise it returns |result|.
* @param {string=} path The path of the file.
*/
function throw_on_zero(operation, result, path) {
if (result == 0) {
throw new File.Error(operation);
throw new File.Error(operation, ctypes.winLastError, path);
}
return result;
}
function throw_on_negative(operation, result) {
/**
* Utility function to sort errors represented as "-1" from successes.
*
* @param {string=} operation The name of the operation. If unspecified,
* the name of the caller function.
* @param {number} result The result of the operation that may
* represent either an error or a success. If -1, this function raises
* an error holding ctypes.winLastError, otherwise it returns |result|.
* @param {string=} path The path of the file.
*/
function throw_on_negative(operation, result, path) {
if (result < 0) {
throw new File.Error(operation);
throw new File.Error(operation, ctypes.winLastError, path);
}
return result;
}
function throw_on_null(operation, result) {
/**
* Utility function to sort errors represented as |null| from successes.
*
* @param {string=} operation The name of the operation. If unspecified,
* the name of the caller function.
* @param {pointer} result The result of the operation that may
* represent either an error or a success. If |null|, this function raises
* an error holding ctypes.winLastError, otherwise it returns |result|.
* @param {string=} path The path of the file.
*/
function throw_on_null(operation, result, path) {
if (result == null || (result.isNull && result.isNull())) {
throw new File.Error(operation);
throw new File.Error(operation, ctypes.winLastError, path);
}
return result;
}

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

@ -0,0 +1,63 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {});
Components.utils.import("resource://gre/modules/Task.jsm");
function run_test() {
run_next_test();
}
add_task(function* testFileError_with_writeAtomic() {
let DEFAULT_CONTENTS = "default contents" + Math.random();
let path = Path.join(Constants.Path.tmpDir,
"testFileError.tmp");
yield File.remove(path);
yield File.writeAtomic(path, DEFAULT_CONTENTS);
let exception;
try {
yield File.writeAtomic(path, DEFAULT_CONTENTS, { noOverwrite: true });
} catch (ex) {
exception = ex;
}
do_check_true(exception instanceof File.Error);
do_check_true(exception.path == path);
});
add_task(function* testFileError_with_makeDir() {
let path = Path.join(Constants.Path.tmpDir,
"directory");
yield File.removeDir(path);
yield File.makeDir(path);
let exception;
try {
yield File.makeDir(path, { ignoreExisting: false });
} catch (ex) {
exception = ex;
}
do_check_true(exception instanceof File.Error);
do_check_true(exception.path == path);
});
add_task(function* testFileError_with_move() {
let DEFAULT_CONTENTS = "default contents" + Math.random();
let sourcePath = Path.join(Constants.Path.tmpDir,
"src.tmp");
let destPath = Path.join(Constants.Path.tmpDir,
"dest.tmp");
yield File.remove(sourcePath);
yield File.remove(destPath);
yield File.writeAtomic(sourcePath, DEFAULT_CONTENTS);
yield File.writeAtomic(destPath, DEFAULT_CONTENTS);
let exception;
try {
yield File.move(sourcePath, destPath, { noOverwrite: true });
} catch (ex) {
exception = ex;
}
do_print(exception);
do_check_true(exception instanceof File.Error);
do_check_true(exception.path == sourcePath);
});

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

@ -27,3 +27,4 @@ tail =
[test_duration.js]
[test_compression.js]
[test_osfile_writeAtomic_backupTo_option.js]
[test_osfile_error.js]