Bug 904652 - Port osfile_{win, unix}_allthreads.jsm to a module loader. r=froydnj

This commit is contained in:
David Rajchenbach-Teller 2013-10-16 11:15:04 -04:00
parent b93454baad
commit 9622566cdc
16 changed files with 1232 additions and 1191 deletions

View File

@ -98,7 +98,7 @@ PromiseWorker.prototype = {
* @param {Error} error Some JS error.
*/
worker.onerror = function onerror(error) {
self._log("Received uncaught error from worker", error.message);
self._log("Received uncaught error from worker", error.message, error.filename, error.lineno);
error.preventDefault();
let {deferred} = self._queue.pop();
deferred.reject(error);

View File

@ -29,24 +29,21 @@ Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAl
Cu.import("resource://gre/modules/Deprecated.jsm", this);
// Boilerplate, to simplify the transition to require()
let OS = SharedAll.OS;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Controller");
let isTypedArray = OS.Shared.isTypedArray;
let LOG = SharedAll.LOG.bind(SharedAll, "Controller");
let isTypedArray = SharedAll.isTypedArray;
// The constructor for file errors.
let OSError;
if (OS.Constants.Win) {
Cu.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", this);
OSError = OS.Shared.Win.Error;
} else if (OS.Constants.libc) {
Cu.import("resource://gre/modules/osfile/osfile_unix_allthreads.jsm", this);
OSError = OS.Shared.Unix.Error;
let SysAll = {};
if (SharedAll.Constants.Win) {
Cu.import("resource://gre/modules/osfile/osfile_win_allthreads.jsm", SysAll);
} else if (SharedAll.Constants.libc) {
Cu.import("resource://gre/modules/osfile/osfile_unix_allthreads.jsm", SysAll);
} else {
throw new Error("I am neither under Windows nor under a Posix system");
}
let Type = OS.Shared.Type;
let OSError = SysAll.Error;
let Type = SysAll.Type;
let Path = {};
Cu.import("resource://gre/modules/osfile/ospath.jsm", Path);
@ -60,18 +57,16 @@ Cu.import("resource://gre/modules/Services.jsm", this);
Cu.import("resource://gre/modules/AsyncShutdown.jsm", this);
LOG("Checking profileDir", OS.Constants.Path);
// If profileDir is not available, osfile.jsm has been imported before the
// profile is setup. In this case, make this a lazy getter.
if (!("profileDir" in OS.Constants.Path)) {
Object.defineProperty(OS.Constants.Path, "profileDir", {
if (!("profileDir" in SharedAll.Constants.Path)) {
Object.defineProperty(SharedAll.Constants.Path, "profileDir", {
get: function() {
let path = undefined;
try {
path = Services.dirsvc.get("ProfD", Ci.nsIFile).path;
delete OS.Constants.Path.profileDir;
OS.Constants.Path.profileDir = path;
delete SharedAll.Constants.Path.profileDir;
SharedAll.Constants.Path.profileDir = path;
} catch (ex) {
// Ignore errors: profileDir is still not available
}
@ -82,14 +77,14 @@ if (!("profileDir" in OS.Constants.Path)) {
LOG("Checking localProfileDir");
if (!("localProfileDir" in OS.Constants.Path)) {
Object.defineProperty(OS.Constants.Path, "localProfileDir", {
if (!("localProfileDir" in SharedAll.Constants.Path)) {
Object.defineProperty(SharedAll.Constants.Path, "localProfileDir", {
get: function() {
let path = undefined;
try {
path = Services.dirsvc.get("ProfLD", Ci.nsIFile).path;
delete OS.Constants.Path.localProfileDir;
OS.Constants.Path.localProfileDir = path;
delete SharedAll.Constants.Path.localProfileDir;
SharedAll.Constants.Path.localProfileDir = path;
} catch (ex) {
// Ignore errors: localProfileDir is still not available
}
@ -123,7 +118,7 @@ let Scheduler = {
latestPromise: Promise.resolve("OS.File scheduler hasn't been launched yet"),
post: function post(...args) {
if (!this.launched && OS.Shared.DEBUG) {
if (!this.launched && SharedAll.Config.DEBUG) {
// If we have delayed sending SET_DEBUG, do it now.
worker.post("SET_DEBUG", [true]);
}
@ -212,23 +207,23 @@ let readDebugPref = function readDebugPref(prefName, oldPref = false) {
*/
Services.prefs.addObserver(PREF_OSFILE_LOG,
function prefObserver(aSubject, aTopic, aData) {
OS.Shared.DEBUG = readDebugPref(PREF_OSFILE_LOG, OS.Shared.DEBUG);
SharedAll.Config.DEBUG = readDebugPref(PREF_OSFILE_LOG, SharedAll.Config.DEBUG);
if (Scheduler.launched) {
// Don't start the worker just to set this preference.
Scheduler.post("SET_DEBUG", [OS.Shared.DEBUG]);
Scheduler.post("SET_DEBUG", [SharedAll.Config.DEBUG]);
}
}, false);
OS.Shared.DEBUG = readDebugPref(PREF_OSFILE_LOG, false);
SharedAll.Config.DEBUG = readDebugPref(PREF_OSFILE_LOG, false);
Services.prefs.addObserver(PREF_OSFILE_LOG_REDIRECT,
function prefObserver(aSubject, aTopic, aData) {
OS.Shared.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, OS.Shared.TEST);
SharedAll.Config.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, OS.Shared.TEST);
}, false);
OS.Shared.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, false);
SharedAll.Config.TEST = readDebugPref(PREF_OSFILE_LOG_REDIRECT, false);
// Update worker's DEBUG flag if it's true.
// Don't start the worker just for this, though.
if (OS.Shared.DEBUG && Scheduler.launched) {
if (SharedAll.Config.DEBUG && Scheduler.launched) {
Scheduler.post("SET_DEBUG", [true]);
}
@ -798,13 +793,7 @@ File.Info = function Info(value) {
}
Object.defineProperty(this, "_deprecatedCreationDate", {value: value["creationDate"]});
};
if (OS.Constants.Win) {
File.Info.prototype = Object.create(OS.Shared.Win.AbstractInfo.prototype);
} else if (OS.Constants.libc) {
File.Info.prototype = Object.create(OS.Shared.Unix.AbstractInfo.prototype);
} else {
throw new Error("I am neither under Windows nor under a Posix system");
}
File.Info.prototype = SysAll.AbstractInfo.prototype;
// Deprecated
Object.defineProperty(File.Info.prototype, "creationDate", {
@ -1000,26 +989,35 @@ DirectoryIterator.prototype = {
DirectoryIterator.Entry = function Entry(value) {
return value;
};
if (OS.Constants.Win) {
DirectoryIterator.Entry.prototype = Object.create(OS.Shared.Win.AbstractEntry.prototype);
} else if (OS.Constants.libc) {
DirectoryIterator.Entry.prototype = Object.create(OS.Shared.Unix.AbstractEntry.prototype);
} else {
throw new Error("I am neither under Windows nor under a Posix system");
}
DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
DirectoryIterator.Entry.fromMsg = function fromMsg(value) {
return new DirectoryIterator.Entry(value);
};
// Constants
Object.defineProperty(File, "POS_START", {value: OS.Shared.POS_START});
Object.defineProperty(File, "POS_CURRENT", {value: OS.Shared.POS_CURRENT});
Object.defineProperty(File, "POS_END", {value: OS.Shared.POS_END});
File.POS_START = SysAll.POS_START;
File.POS_CURRENT = SysAll.POS_CURRENT;
File.POS_END = SysAll.POS_END;
// Exports
File.Error = OSError;
File.DirectoryIterator = DirectoryIterator;
this.OS = {};
OS.File = File;
OS.File.Error = OSError;
OS.File.DirectoryIterator = DirectoryIterator;
OS.Constants = SharedAll.Constants;
OS.Shared = {
LOG: SharedAll.LOG,
Type: SysAll.Type,
get DEBUG() {
return SharedAll.Config.DEBUG;
},
set DEBUG(x) {
return SharedAll.Config.DEBUG = x;
}
};
Object.freeze(OS.Shared);
OS.Path = Path;

View File

@ -14,7 +14,8 @@ if (this.Components) {
importScripts("resource://gre/modules/osfile.jsm");
let LOG = exports.OS.Shared.LOG.bind(exports.OS.Shared.LOG, "Agent");
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let LOG = SharedAll.LOG.bind(SharedAll, "Agent");
/**
* Communications with the controller.
@ -216,12 +217,12 @@ if (this.Components) {
let Agent = {
// Update worker's OS.Shared.DEBUG flag message from controller.
SET_DEBUG: function SET_DEBUG (aDEBUG) {
exports.OS.Shared.DEBUG = aDEBUG;
SharedAll.Config.DEBUG = aDEBUG;
},
// Return worker's current OS.Shared.DEBUG value to controller.
// Note: This is used for testing purposes.
GET_DEBUG: function GET_DEBUG () {
return exports.OS.Shared.DEBUG;
return SharedAll.Config.DEBUG;
},
// Report file descriptors leaks.
System_shutdown: function System_shutdown () {

View File

@ -1026,11 +1026,6 @@ exports.OS = {
offsetBy: offsetBy
}
};
if (exports.Constants.Win) {
exports.OS.Win = {};
} else {
exports.OS.Unix = {};
}
Object.defineProperty(exports.OS.Shared, "DEBUG", {
get: function() {

View File

@ -14,10 +14,11 @@ if (typeof Components != "undefined") {
}
(function(exports) {
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
let SharedAll =
require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let LOG = exports.OS.Shared.LOG.bind(OS.Shared, "Shared front-end");
let clone = exports.OS.Shared.clone;
let LOG = SharedAll.LOG.bind(SharedAll, "Shared front-end");
let clone = SharedAll.clone;
/**
* Code shared by implementations of File.
@ -89,7 +90,7 @@ AbstractFile.prototype = {
break;
}
pos += chunkSize;
ptr = exports.OS.Shared.offsetBy(ptr, chunkSize);
ptr = SharedAll.offsetBy(ptr, chunkSize);
}
return pos;
@ -121,7 +122,7 @@ AbstractFile.prototype = {
while (pos < bytes) {
let chunkSize = this._write(ptr, bytes - pos, options);
pos += chunkSize;
ptr = exports.OS.Shared.offsetBy(ptr, chunkSize);
ptr = SharedAll.offsetBy(ptr, chunkSize);
}
return pos;
}
@ -208,13 +209,13 @@ AbstractFile.normalizeToPointer = function normalizeToPointer(candidate, bytes)
if (candidate.isNull()) {
throw new TypeError("Expecting a non-null pointer");
}
ptr = exports.OS.Shared.Type.uint8_t.out_ptr.cast(candidate);
ptr = SharedAll.Type.uint8_t.out_ptr.cast(candidate);
if (bytes == null) {
throw new TypeError("C pointer missing bytes indication.");
}
} else if (exports.OS.Shared.isTypedArray(candidate)) {
} else if (SharedAll.isTypedArray(candidate)) {
// Typed Array
ptr = exports.OS.Shared.Type.uint8_t.out_ptr.implementation(candidate.buffer);
ptr = SharedAll.Type.uint8_t.out_ptr.implementation(candidate.buffer);
if (bytes == null) {
bytes = candidate.byteLength;
} else if (candidate.byteLength < bytes) {
@ -488,5 +489,8 @@ AbstractFile.removeDir = function(path, options = {}) {
OS.File.removeEmptyDir(path);
};
exports.OS.Shared.AbstractFile = AbstractFile;
if (!exports.OS.Shared) {
exports.OS.Shared = {};
}
exports.OS.Shared.AbstractFile = AbstractFile;
})(this);

View File

@ -14,323 +14,339 @@
*
* This module can be:
* - opened from the main thread as a jsm module;
* - opened from a chrome worker through importScripts.
* - opened from a chrome worker through require().
*/
"use strict";
let SharedAll;
if (typeof Components != "undefined") {
let Cu = Components.utils;
// Module is opened as a jsm module
this.EXPORTED_SYMBOLS = ["OS"];
Components.utils.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/ctypes.jsm", this);
SharedAll = {};
Components.utils.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
} else {
Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
this.exports = {};
} else if (typeof "module" != "undefined" && typeof "require" != "undefined") {
// Module is loaded with require()
SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
} else {
throw new Error("Please open this module with Component.utils.import or with require()");
}
(function(exports) {
"use strict";
if ("OS" in exports && "Shared" in exports.OS && "Unix" in exports.OS.Shared) {
// Avoid double inclusion
return;
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "allthreads");
let Const = SharedAll.Constants.libc;
// Open libc
let libc;
let libc_candidates = [ "libSystem.B.dylib",
"libc.so.6",
"libc.so" ];
for (let i = 0; i < libc_candidates.length; ++i) {
try {
libc = ctypes.open(libc_candidates[i]);
break;
} catch (x) {
LOG("Could not open libc ", libc_candidates[i]);
}
}
exports.OS = SharedAll.OS;
if (!libc) {
// Note: If you change the string here, please adapt tests accordingly
throw new Error("Could not open system library: no libc");
}
exports.libc = libc;
exports.OS.Shared.Unix = {};
// Define declareFFI
let declareFFI = SharedAll.declareFFI.bind(null, libc);
exports.declareFFI = declareFFI;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Unix", "allthreads");
// Define Error
let strerror = libc.declare("strerror",
ctypes.default_abi,
/*return*/ ctypes.char.ptr,
/*errnum*/ ctypes.int);
// Open libc
let libc;
let libc_candidates = [ "libSystem.B.dylib",
"libc.so.6",
"libc.so" ];
for (let i = 0; i < libc_candidates.length; ++i) {
try {
libc = ctypes.open(libc_candidates[i]);
break;
} catch (x) {
LOG("Could not open libc ", libc_candidates[i]);
}
/**
* A File-related error.
*
* To obtain a human-readable error message, use method |toString|.
* To determine the cause of the error, use the various |becauseX|
* getters. To determine the operation that failed, use field
* |operation|.
*
* Additionally, this implementation offers a field
* |unixErrno|, which holds the OS-specific error
* constant. If you need this level of detail, you may match the value
* of this field against the error constants of |OS.Constants.libc|.
*
* @param {string=} operation The operation that failed. If unspecified,
* the name of the calling function is taken to be the operation that
* failed.
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
*
* @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;
};
OSError.prototype = Object.create(SharedAll.OSError.prototype);
OSError.prototype.toString = function toString() {
return "Unix error " + this.unixErrno +
" during operation " + this.operation +
" (" + strerror(this.unixErrno).readString() + ")";
};
/**
* |true| if the error was raised because a file or directory
* already exists, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseExists", {
get: function becauseExists() {
return this.unixErrno == Const.EEXIST;
}
if (!libc) {
// Note: If you change the string here, please adapt tests accordingly
throw new Error("Could not open system library: no libc");
});
/**
* |true| if the error was raised because a file or directory
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.unixErrno == Const.ENOENT;
}
exports.OS.Shared.Unix.libc = libc;
});
// Define declareFFI
let declareFFI = OS.Shared.declareFFI.bind(null, libc);
exports.OS.Shared.Unix.declareFFI = declareFFI;
/**
* |true| if the error was raised because a directory is not empty
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
get: function becauseNotEmpty() {
return this.unixErrno == Const.ENOTEMPTY;
}
});
/**
* |true| if the error was raised because a file or directory
* is closed, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseClosed", {
get: function becauseClosed() {
return this.unixErrno == Const.EBADF;
}
});
/**
* |true| if the error was raised because permission is denied to
* access a file or directory, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
get: function becauseAccessDenied() {
return this.unixErrno == Const.EACCES;
}
});
// Define Error
let strerror = libc.declare("strerror",
ctypes.default_abi,
/*return*/ ctypes.char.ptr,
/*errnum*/ ctypes.int);
/**
* Serialize an instance of OSError to something that can be
* transmitted across threads (not necessarily a string).
*/
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
unixErrno: error.unixErrno
};
};
/**
* Deserialize a message back to an instance of OSError
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.unixErrno);
};
exports.Error = OSError;
/**
* Code shared by implementations of File.Info on Unix
*
* @constructor
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode) {
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._size = size;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastModificationDate;
this._unixLastStatusChangeDate = unixLastStatusChangeDate;
this._unixOwner = unixOwner;
this._unixGroup = unixGroup;
this._unixMode = unixMode;
};
AbstractInfo.prototype = {
/**
* A File-related error.
* |true| if this file is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if this file is a symbolink link, |false| otherwise
*/
get isSymLink() {
return this._isSymlLink;
},
/**
* The size of the file, in bytes.
*
* To obtain a human-readable error message, use method |toString|.
* To determine the cause of the error, use the various |becauseX|
* getters. To determine the operation that failed, use field
* |operation|.
* Note that the result may be |NaN| if the size of the file cannot be
* represented in JavaScript.
*
* Additionally, this implementation offers a field
* |unixErrno|, which holds the OS-specific error
* constant. If you need this level of detail, you may match the value
* of this field against the error constants of |OS.Constants.libc|.
* @type {number}
*/
get size() {
return this._size;
},
/**
* The date of last access to this file.
*
* @param {string=} operation The operation that failed. If unspecified,
* the name of the calling function is taken to be the operation that
* failed.
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
* Note that the definition of last access may depend on the
* underlying operating system and file system.
*
* @constructor
* @extends {OS.Shared.Error}
* @type {Date}
*/
let OSError = function OSError(operation, errno) {
operation = operation || "unknown operation";
exports.OS.Shared.Error.call(this, operation);
this.unixErrno = errno || ctypes.errno;
};
OSError.prototype = new exports.OS.Shared.Error();
OSError.prototype.toString = function toString() {
return "Unix error " + this.unixErrno +
" during operation " + this.operation +
" (" + strerror(this.unixErrno).readString() + ")";
};
get lastAccessDate() {
return this._lastAccessDate;
},
/**
* |true| if the error was raised because a file or directory
* already exists, |false| otherwise.
* Return the date of last modification of this file.
*/
Object.defineProperty(OSError.prototype, "becauseExists", {
get: function becauseExists() {
return this.unixErrno == OS.Constants.libc.EEXIST;
}
});
get lastModificationDate() {
return this._lastModificationDate;
},
/**
* |true| if the error was raised because a file or directory
* does not exist, |false| otherwise.
* Return the date at which the status of this file was last modified
* (this is the date of the latest write/renaming/mode change/...
* of the file)
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.unixErrno == OS.Constants.libc.ENOENT;
}
});
/**
* |true| if the error was raised because a directory is not empty
* does not exist, |false| otherwise.
get unixLastStatusChangeDate() {
return this._unixLastStatusChangeDate;
},
/*
* Return the Unix owner of this file
*/
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
get: function becauseNotEmpty() {
return this.unixErrno == OS.Constants.libc.ENOTEMPTY;
}
});
/**
* |true| if the error was raised because a file or directory
* is closed, |false| otherwise.
get unixOwner() {
return this._unixOwner;
},
/*
* Return the Unix group of this file
*/
Object.defineProperty(OSError.prototype, "becauseClosed", {
get: function becauseClosed() {
return this.unixErrno == OS.Constants.libc.EBADF;
}
});
/**
* |true| if the error was raised because permission is denied to
* access a file or directory, |false| otherwise.
get unixGroup() {
return this._unixGroup;
},
/*
* Return the Unix group of this file
*/
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
get: function becauseAccessDenied() {
return this.unixErrno == OS.Constants.libc.EACCES;
}
});
get unixMode() {
return this._unixMode;
}
};
exports.AbstractInfo = AbstractInfo;
/**
* Code shared by implementations of File.DirectoryIterator.Entry on Unix
*
* @constructor
*/
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) {
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._name = name;
this._path = path;
};
AbstractEntry.prototype = {
/**
* Serialize an instance of OSError to something that can be
* transmitted across threads (not necessarily a string).
* |true| if the entry is a directory, |false| otherwise
*/
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
unixErrno: error.unixErrno
};
};
get isDir() {
return this._isDir;
},
/**
* Deserialize a message back to an instance of OSError
* |true| if the entry is a directory, |false| otherwise
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.unixErrno);
};
exports.OS.Shared.Unix.Error = OSError;
get isSymLink() {
return this._isSymlLink;
},
/**
* Code shared by implementations of File.Info on Unix
*
* @constructor
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode) {
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._size = size;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastModificationDate;
this._unixLastStatusChangeDate = unixLastStatusChangeDate;
this._unixOwner = unixOwner;
this._unixGroup = unixGroup;
this._unixMode = unixMode;
};
AbstractInfo.prototype = {
/**
* |true| if this file is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if this file is a symbolink link, |false| otherwise
*/
get isSymLink() {
return this._isSymlLink;
},
/**
* The size of the file, in bytes.
*
* Note that the result may be |NaN| if the size of the file cannot be
* represented in JavaScript.
*
* @type {number}
*/
get size() {
return this._size;
},
/**
* The date of last access to this file.
*
* Note that the definition of last access may depend on the
* underlying operating system and file system.
*
* @type {Date}
*/
get lastAccessDate() {
return this._lastAccessDate;
},
/**
* Return the date of last modification of this file.
*/
get lastModificationDate() {
return this._lastModificationDate;
},
/**
* Return the date at which the status of this file was last modified
* (this is the date of the latest write/renaming/mode change/...
* of the file)
*/
get unixLastStatusChangeDate() {
return this._unixLastStatusChangeDate;
},
/*
* Return the Unix owner of this file
*/
get unixOwner() {
return this._unixOwner;
},
/*
* Return the Unix group of this file
*/
get unixGroup() {
return this._unixGroup;
},
/*
* Return the Unix group of this file
*/
get unixMode() {
return this._unixMode;
}
};
exports.OS.Shared.Unix.AbstractInfo = AbstractInfo;
* The name of the entry
* @type {string}
*/
get name() {
return this._name;
},
/**
* Code shared by implementations of File.DirectoryIterator.Entry on Unix
*
* @constructor
*/
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name, path) {
this._isDir = isDir;
this._isSymlLink = isSymLink;
this._name = name;
this._path = path;
};
* The full path to the entry
*/
get path() {
return this._path;
}
};
exports.AbstractEntry = AbstractEntry;
AbstractEntry.prototype = {
/**
* |true| if the entry is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if the entry is a directory, |false| otherwise
*/
get isSymLink() {
return this._isSymlLink;
},
/**
* The name of the entry
* @type {string}
*/
get name() {
return this._name;
},
/**
* The full path to the entry
*/
get path() {
return this._path;
}
};
exports.OS.Shared.Unix.AbstractEntry = AbstractEntry;
// Special constants that need to be defined on all platforms
// Special constants that need to be defined on all platforms
exports.POS_START = Const.SEEK_SET;
exports.POS_CURRENT = Const.SEEK_CUR;
exports.POS_END = Const.SEEK_END;
Object.defineProperty(exports.OS.Shared, "POS_START", { value: exports.OS.Constants.libc.SEEK_SET });
Object.defineProperty(exports.OS.Shared, "POS_CURRENT", { value: exports.OS.Constants.libc.SEEK_CUR });
Object.defineProperty(exports.OS.Shared, "POS_END", { value: exports.OS.Constants.libc.SEEK_END });
// Special types that need to be defined for communication
// between threads
let Type = Object.create(SharedAll.Type);
exports.Type = Type;
// Special types that need to be defined for communication
// between threads
let Types = exports.OS.Shared.Type;
/**
* Native paths
*
* Under Unix, expressed as C strings
*/
Type.path = Type.cstring.withName("[in] path");
Type.out_path = Type.out_cstring.withName("[out] path");
/**
* Native paths
*
* Under Unix, expressed as C strings
*/
Types.path = Types.cstring.withName("[in] path");
Types.out_path = Types.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);
};
// Special constructors that need to be defined on all threads
OSError.closed = function closed(operation) {
return new OSError(operation, OS.Constants.libc.EBADF);
};
OSError.exists = function exists(operation) {
return new OSError(operation, Const.EEXIST);
};
OSError.exists = function exists(operation) {
return new OSError(operation, OS.Constants.libc.EEXIST);
};
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, Const.ENOENT);
};
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, OS.Constants.libc.ENOENT);
};
})(this);
let EXPORTED_SYMBOLS = [
"declareFFI",
"libc",
"Error",
"AbstractInfo",
"AbstractEntry",
"Type",
"POS_START",
"POS_CURRENT",
"POS_END"
];
//////////// Boilerplate
if (typeof Components != "undefined") {
this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS;
for (let symbol of EXPORTED_SYMBOLS) {
this[symbol] = exports[symbol];
}
}

View File

@ -17,12 +17,13 @@
return; // Avoid double initialization
}
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
exports.OS.Unix.File = {};
let LOG = exports.OS.Shared.LOG.bind(OS.Shared, "Unix", "back");
let libc = exports.OS.Shared.Unix.libc;
let SharedAll =
require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let SysAll =
require("resource://gre/modules/osfile/osfile_unix_allthreads.jsm");
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "back");
let libc = SysAll.libc;
let Const = SharedAll.Constants.libc;
/**
* Initialize the Unix module.
@ -35,27 +36,20 @@
if (aDeclareFFI) {
declareFFI = aDeclareFFI.bind(null, libc);
} else {
declareFFI = exports.OS.Shared.Unix.declareFFI;
declareFFI = SysAll.declareFFI;
}
// Shorthands
let OSUnix = exports.OS.Unix;
let UnixFile = exports.OS.Unix.File;
if (!exports.OS.Types) {
exports.OS.Types = {};
}
let Type = exports.OS.Shared.Type;
let Types = Type;
// Initialize types that require additional OS-specific
// support - either finalization or matching against
// OS-specific constants.
let Type = Object.create(SysAll.Type);
let SysFile = exports.OS.Unix.File = { Type: Type };
/**
* A file descriptor.
*/
Types.fd = Type.int.withName("fd");
Types.fd.importFromC = function importFromC(fd_int) {
Type.fd = Type.int.withName("fd");
Type.fd.importFromC = function importFromC(fd_int) {
return ctypes.CDataFinalizer(fd_int, _close);
};
@ -64,8 +58,8 @@
* A C integer holding -1 in case of error or a file descriptor
* in case of success.
*/
Types.negativeone_or_fd = Types.fd.withName("negativeone_or_fd");
Types.negativeone_or_fd.importFromC =
Type.negativeone_or_fd = Type.fd.withName("negativeone_or_fd");
Type.negativeone_or_fd.importFromC =
function importFromC(fd_int) {
if (fd_int == -1) {
return -1;
@ -77,31 +71,31 @@
* A C integer holding -1 in case of error or a meaningless value
* in case of success.
*/
Types.negativeone_or_nothing =
Types.int.withName("negativeone_or_nothing");
Type.negativeone_or_nothing =
Type.int.withName("negativeone_or_nothing");
/**
* A C integer holding -1 in case of error or a positive integer
* in case of success.
*/
Types.negativeone_or_ssize_t =
Types.ssize_t.withName("negativeone_or_ssize_t");
Type.negativeone_or_ssize_t =
Type.ssize_t.withName("negativeone_or_ssize_t");
/**
* Various libc integer types
*/
Types.mode_t =
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_MODE_T).withName("mode_t");
Types.uid_t =
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_UID_T).withName("uid_t");
Types.gid_t =
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_GID_T).withName("gid_t");
Type.mode_t =
Type.intn_t(Const.OSFILE_SIZEOF_MODE_T).withName("mode_t");
Type.uid_t =
Type.intn_t(Const.OSFILE_SIZEOF_UID_T).withName("uid_t");
Type.gid_t =
Type.intn_t(Const.OSFILE_SIZEOF_GID_T).withName("gid_t");
/**
* Type |time_t|
*/
Types.time_t =
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_TIME_T).withName("time_t");
Type.time_t =
Type.intn_t(Const.OSFILE_SIZEOF_TIME_T).withName("time_t");
// Structure |dirent|
// Building this type is rather complicated, as its layout varies between
@ -115,90 +109,90 @@
// };
{
let d_name_extra_size = 0;
if (OS.Constants.libc.OSFILE_SIZEOF_DIRENT_D_NAME < 8) {
if (Const.OSFILE_SIZEOF_DIRENT_D_NAME < 8) {
// d_name is defined like "char d_name[1];" on some platforms
// (e.g. Solaris), we need to give it more size for our structure.
d_name_extra_size = 256;
}
let dirent = new OS.Shared.HollowStructure("dirent",
OS.Constants.libc.OSFILE_SIZEOF_DIRENT + d_name_extra_size);
if (OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_TYPE != undefined) {
let dirent = new SharedAll.HollowStructure("dirent",
Const.OSFILE_SIZEOF_DIRENT + d_name_extra_size);
if (Const.OSFILE_OFFSETOF_DIRENT_D_TYPE != undefined) {
// |dirent| doesn't have d_type on some platforms (e.g. Solaris).
dirent.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_TYPE,
dirent.add_field_at(Const.OSFILE_OFFSETOF_DIRENT_D_TYPE,
"d_type", ctypes.uint8_t);
}
dirent.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_NAME,
dirent.add_field_at(Const.OSFILE_OFFSETOF_DIRENT_D_NAME,
"d_name", ctypes.ArrayType(ctypes.char,
OS.Constants.libc.OSFILE_SIZEOF_DIRENT_D_NAME + d_name_extra_size));
Const.OSFILE_SIZEOF_DIRENT_D_NAME + d_name_extra_size));
// We now have built |dirent|.
Types.dirent = dirent.getType();
Type.dirent = dirent.getType();
}
Types.null_or_dirent_ptr =
new Type("null_of_dirent",
Types.dirent.out_ptr.implementation);
Type.null_or_dirent_ptr =
new SharedAll.Type("null_of_dirent",
Type.dirent.out_ptr.implementation);
// Structure |stat|
// Same technique
{
let stat = new OS.Shared.HollowStructure("stat",
OS.Constants.libc.OSFILE_SIZEOF_STAT);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_MODE,
"st_mode", Types.mode_t.implementation);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_UID,
"st_uid", Types.uid_t.implementation);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_GID,
"st_gid", Types.gid_t.implementation);
let stat = new SharedAll.HollowStructure("stat",
Const.OSFILE_SIZEOF_STAT);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_MODE,
"st_mode", Type.mode_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_UID,
"st_uid", Type.uid_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_GID,
"st_gid", Type.gid_t.implementation);
// Here, things get complicated with different data structures.
// Some platforms have |time_t st_atime| and some platforms have
// |timespec st_atimespec|. However, since |timespec| starts with
// a |time_t|, followed by nanoseconds, we just cheat and pretend
// that everybody has |time_t st_atime|, possibly followed by padding
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_ATIME,
"st_atime", Types.time_t.implementation);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_MTIME,
"st_mtime", Types.time_t.implementation);
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_CTIME,
"st_ctime", Types.time_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_ATIME,
"st_atime", Type.time_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_MTIME,
"st_mtime", Type.time_t.implementation);
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_CTIME,
"st_ctime", Type.time_t.implementation);
// To complicate further, MacOS and some BSDs have a field |birthtime|
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in OS.Constants.libc) {
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_BIRTHTIME,
"st_birthtime", Types.time_t.implementation);
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in Const) {
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_BIRTHTIME,
"st_birthtime", Type.time_t.implementation);
}
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_SIZE,
"st_size", Types.size_t.implementation);
Types.stat = stat.getType();
stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_SIZE,
"st_size", Type.size_t.implementation);
Type.stat = stat.getType();
}
// Structure |DIR|
if ("OSFILE_SIZEOF_DIR" in OS.Constants.libc) {
if ("OSFILE_SIZEOF_DIR" in Const) {
// On platforms for which we need to access the fields of DIR
// directly (e.g. because certain functions are implemented
// as macros), we need to define DIR as a hollow structure.
let DIR = new OS.Shared.HollowStructure(
let DIR = new SharedAll.HollowStructure(
"DIR",
OS.Constants.libc.OSFILE_SIZEOF_DIR);
Const.OSFILE_SIZEOF_DIR);
DIR.add_field_at(
OS.Constants.libc.OSFILE_OFFSETOF_DIR_DD_FD,
Const.OSFILE_OFFSETOF_DIR_DD_FD,
"dd_fd",
Types.fd.implementation);
Type.fd.implementation);
Types.DIR = DIR.getType();
Type.DIR = DIR.getType();
} else {
// On other platforms, we keep DIR as a blackbox
Types.DIR =
new Type("DIR",
Type.DIR =
new SharedAll.Type("DIR",
ctypes.StructType("DIR"));
}
Types.null_or_DIR_ptr =
Types.DIR.out_ptr.withName("null_or_DIR*");
Types.null_or_DIR_ptr.importFromC = function importFromC(dir) {
Type.null_or_DIR_ptr =
Type.DIR.out_ptr.withName("null_or_DIR*");
Type.null_or_DIR_ptr.importFromC = function importFromC(dir) {
if (dir == null || dir.isNull()) {
return null;
}
@ -208,12 +202,12 @@
// Declare libc functions as functions of |OS.Unix.File|
// Finalizer-related functions
let _close = UnixFile._close =
let _close = SysFile._close =
libc.declare("close", ctypes.default_abi,
/*return */ctypes.int,
/*fd*/ ctypes.int);
UnixFile.close = function close(fd) {
SysFile.close = function close(fd) {
// Detach the finalizer and call |_close|.
return fd.dispose();
};
@ -221,9 +215,9 @@
let _close_dir =
libc.declare("closedir", ctypes.default_abi,
/*return */ctypes.int,
/*dirp*/ Types.DIR.in_ptr.implementation);
/*dirp*/ Type.DIR.in_ptr.implementation);
UnixFile.closedir = function closedir(fd) {
SysFile.closedir = function closedir(fd) {
// Detach the finalizer and call |_close_dir|.
return fd.dispose();
};
@ -238,7 +232,7 @@
// correct implementation free().
default_lib = ctypes.open("a.out");
UnixFile.free =
SysFile.free =
default_lib.declare("free", ctypes.default_abi,
/*return*/ ctypes.void_t,
/*ptr*/ ctypes.voidptr_t);
@ -247,7 +241,7 @@
// We don't have an a.out library or a.out doesn't contain free.
// Either way, use the ordinary libc free.
UnixFile.free =
SysFile.free =
libc.declare("free", ctypes.default_abi,
/*return*/ ctypes.void_t,
/*ptr*/ ctypes.voidptr_t);
@ -256,293 +250,293 @@
// Other functions
UnixFile.access =
SysFile.access =
declareFFI("access", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*mode*/ Types.int);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*mode*/ Type.int);
UnixFile.chdir =
SysFile.chdir =
declareFFI("chdir", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path);
UnixFile.chmod =
SysFile.chmod =
declareFFI("chmod", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*mode*/ Types.mode_t);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*mode*/ Type.mode_t);
UnixFile.chown =
SysFile.chown =
declareFFI("chown", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*uid*/ Types.uid_t,
/*gid*/ Types.gid_t);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*uid*/ Type.uid_t,
/*gid*/ Type.gid_t);
UnixFile.copyfile =
SysFile.copyfile =
declareFFI("copyfile", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*source*/ Types.path,
/*dest*/ Types.path,
/*state*/ Types.void_t.in_ptr, // Ignored atm
/*flags*/ Types.uint32_t);
/*return*/ Type.negativeone_or_nothing,
/*source*/ Type.path,
/*dest*/ Type.path,
/*state*/ Type.void_t.in_ptr, // Ignored atm
/*flags*/ Type.uint32_t);
UnixFile.dup =
SysFile.dup =
declareFFI("dup", ctypes.default_abi,
/*return*/ Types.negativeone_or_fd,
/*fd*/ Types.fd);
/*return*/ Type.negativeone_or_fd,
/*fd*/ Type.fd);
if ("OSFILE_SIZEOF_DIR" in OS.Constants.libc) {
if ("OSFILE_SIZEOF_DIR" in Const) {
// On platforms for which |dirfd| is a macro
UnixFile.dirfd =
SysFile.dirfd =
function dirfd(DIRp) {
return Types.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
return Type.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
};
} else {
// On platforms for which |dirfd| is a function
UnixFile.dirfd =
SysFile.dirfd =
declareFFI("dirfd", ctypes.default_abi,
/*return*/ Types.negativeone_or_fd,
/*dir*/ Types.DIR.in_ptr);
/*return*/ Type.negativeone_or_fd,
/*dir*/ Type.DIR.in_ptr);
}
UnixFile.chdir =
SysFile.chdir =
declareFFI("chdir", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path);
UnixFile.fchdir =
SysFile.fchdir =
declareFFI("fchdir", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd);
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd);
UnixFile.fchown =
SysFile.fchown =
declareFFI("fchown", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd,
/*uid_t*/ Types.uid_t,
/*gid_t*/ Types.gid_t);
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd,
/*uid_t*/ Type.uid_t,
/*gid_t*/ Type.gid_t);
UnixFile.fsync =
SysFile.fsync =
declareFFI("fsync", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd);
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd);
UnixFile.getcwd =
SysFile.getcwd =
declareFFI("getcwd", ctypes.default_abi,
/*return*/ Types.out_path,
/*buf*/ Types.out_path,
/*size*/ Types.size_t);
/*return*/ Type.out_path,
/*buf*/ Type.out_path,
/*size*/ Type.size_t);
UnixFile.getwd =
SysFile.getwd =
declareFFI("getwd", ctypes.default_abi,
/*return*/ Types.out_path,
/*buf*/ Types.out_path);
/*return*/ Type.out_path,
/*buf*/ Type.out_path);
// Two variants of |getwd| which allocate the memory
// dynamically.
// Linux/Android version
UnixFile.get_current_dir_name =
SysFile.get_current_dir_name =
declareFFI("get_current_dir_name", ctypes.default_abi,
/*return*/ Types.out_path.releaseWith(UnixFile.free));
/*return*/ Type.out_path.releaseWith(SysFile.free));
// MacOS/BSD version (will return NULL on Linux/Android)
UnixFile.getwd_auto =
SysFile.getwd_auto =
declareFFI("getwd", ctypes.default_abi,
/*return*/ Types.out_path.releaseWith(UnixFile.free),
/*buf*/ Types.void_t.out_ptr);
/*return*/ Type.out_path.releaseWith(SysFile.free),
/*buf*/ Type.void_t.out_ptr);
UnixFile.fdatasync =
SysFile.fdatasync =
declareFFI("fdatasync", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd); // Note: MacOS/BSD-specific
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd); // Note: MacOS/BSD-specific
UnixFile.ftruncate =
SysFile.ftruncate =
declareFFI("ftruncate", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd,
/*length*/ Types.off_t);
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd,
/*length*/ Type.off_t);
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
UnixFile.fstat =
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
SysFile.fstat =
declareFFI("fstat$INODE64", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.fd,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.fd,
/*buf*/ Type.stat.out_ptr
);
} else {
UnixFile.fstat =
SysFile.fstat =
declareFFI("fstat", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.fd,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.fd,
/*buf*/ Type.stat.out_ptr
);
}
UnixFile.lchown =
SysFile.lchown =
declareFFI("lchown", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*uid_t*/ Types.uid_t,
/*gid_t*/ Types.gid_t);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*uid_t*/ Type.uid_t,
/*gid_t*/ Type.gid_t);
UnixFile.link =
SysFile.link =
declareFFI("link", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*source*/ Types.path,
/*dest*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*source*/ Type.path,
/*dest*/ Type.path);
UnixFile.lseek =
SysFile.lseek =
declareFFI("lseek", ctypes.default_abi,
/*return*/ Types.off_t,
/*fd*/ Types.fd,
/*offset*/ Types.off_t,
/*whence*/ Types.int);
/*return*/ Type.off_t,
/*fd*/ Type.fd,
/*offset*/ Type.off_t,
/*whence*/ Type.int);
UnixFile.mkdir =
SysFile.mkdir =
declareFFI("mkdir", ctypes.default_abi,
/*return*/ Types.int,
/*path*/ Types.path,
/*mode*/ Types.int);
/*return*/ Type.int,
/*path*/ Type.path,
/*mode*/ Type.int);
UnixFile.mkstemp =
SysFile.mkstemp =
declareFFI("mkstemp", ctypes.default_abi,
/*return*/ Types.fd,
/*template*/Types.out_path);
/*return*/ Type.fd,
/*template*/Type.out_path);
UnixFile.open =
SysFile.open =
declareFFI("open", ctypes.default_abi,
/*return*/Types.negativeone_or_fd,
/*path*/ Types.path,
/*oflags*/Types.int,
/*mode*/ Types.int);
/*return*/Type.negativeone_or_fd,
/*path*/ Type.path,
/*oflags*/Type.int,
/*mode*/ Type.int);
UnixFile.opendir =
SysFile.opendir =
declareFFI("opendir", ctypes.default_abi,
/*return*/ Types.null_or_DIR_ptr,
/*path*/ Types.path);
/*return*/ Type.null_or_DIR_ptr,
/*path*/ Type.path);
UnixFile.pread =
SysFile.pread =
declareFFI("pread", ctypes.default_abi,
/*return*/ Types.negativeone_or_ssize_t,
/*fd*/ Types.fd,
/*buf*/ Types.void_t.out_ptr,
/*nbytes*/ Types.size_t,
/*offset*/ Types.off_t);
/*return*/ Type.negativeone_or_ssize_t,
/*fd*/ Type.fd,
/*buf*/ Type.void_t.out_ptr,
/*nbytes*/ Type.size_t,
/*offset*/ Type.off_t);
UnixFile.pwrite =
SysFile.pwrite =
declareFFI("pwrite", ctypes.default_abi,
/*return*/ Types.negativeone_or_ssize_t,
/*fd*/ Types.fd,
/*buf*/ Types.void_t.in_ptr,
/*nbytes*/ Types.size_t,
/*offset*/ Types.off_t);
/*return*/ Type.negativeone_or_ssize_t,
/*fd*/ Type.fd,
/*buf*/ Type.void_t.in_ptr,
/*nbytes*/ Type.size_t,
/*offset*/ Type.off_t);
UnixFile.read =
SysFile.read =
declareFFI("read", ctypes.default_abi,
/*return*/Types.negativeone_or_ssize_t,
/*fd*/ Types.fd,
/*buf*/ Types.void_t.out_ptr,
/*nbytes*/Types.size_t);
/*return*/Type.negativeone_or_ssize_t,
/*fd*/ Type.fd,
/*buf*/ Type.void_t.out_ptr,
/*nbytes*/Type.size_t);
UnixFile.posix_fadvise =
SysFile.posix_fadvise =
declareFFI("posix_fadvise", ctypes.default_abi,
/*return*/ Types.int,
/*fd*/ Types.fd,
/*offset*/ Types.off_t,
/*len*/ Types.off_t,
/*advise*/ Types.int);
/*return*/ Type.int,
/*fd*/ Type.fd,
/*offset*/ Type.off_t,
/*len*/ Type.off_t,
/*advise*/ Type.int);
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
// Special case for MacOS X 10.5+
// Symbol name "readdir" still exists but is used for a
// deprecated function that does not match the
// constants of |OS.Constants.libc|.
UnixFile.readdir =
// constants of |Const|.
SysFile.readdir =
declareFFI("readdir$INODE64", ctypes.default_abi,
/*return*/Types.null_or_dirent_ptr,
/*dir*/ Types.DIR.in_ptr); // For MacOS X
/*return*/Type.null_or_dirent_ptr,
/*dir*/ Type.DIR.in_ptr); // For MacOS X
} else {
UnixFile.readdir =
SysFile.readdir =
declareFFI("readdir", ctypes.default_abi,
/*return*/Types.null_or_dirent_ptr,
/*dir*/ Types.DIR.in_ptr); // Other Unices
/*return*/Type.null_or_dirent_ptr,
/*dir*/ Type.DIR.in_ptr); // Other Unices
}
UnixFile.rename =
SysFile.rename =
declareFFI("rename", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*old*/ Types.path,
/*new*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*old*/ Type.path,
/*new*/ Type.path);
UnixFile.rmdir =
SysFile.rmdir =
declareFFI("rmdir", ctypes.default_abi,
/*return*/ Types.int,
/*path*/ Types.path);
/*return*/ Type.int,
/*path*/ Type.path);
UnixFile.splice =
SysFile.splice =
declareFFI("splice", ctypes.default_abi,
/*return*/ Types.long,
/*fd_in*/ Types.fd,
/*off_in*/ Types.off_t.in_ptr,
/*fd_out*/ Types.fd,
/*off_out*/Types.off_t.in_ptr,
/*len*/ Types.size_t,
/*flags*/ Types.unsigned_int); // Linux/Android-specific
/*return*/ Type.long,
/*fd_in*/ Type.fd,
/*off_in*/ Type.off_t.in_ptr,
/*fd_out*/ Type.fd,
/*off_out*/Type.off_t.in_ptr,
/*len*/ Type.size_t,
/*flags*/ Type.unsigned_int); // Linux/Android-specific
UnixFile.symlink =
SysFile.symlink =
declareFFI("symlink", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*source*/ Types.path,
/*dest*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*source*/ Type.path,
/*dest*/ Type.path);
UnixFile.truncate =
SysFile.truncate =
declareFFI("truncate", ctypes.default_abi,
/*return*/Types.negativeone_or_nothing,
/*path*/ Types.path,
/*length*/ Types.off_t);
/*return*/Type.negativeone_or_nothing,
/*path*/ Type.path,
/*length*/ Type.off_t);
UnixFile.unlink =
SysFile.unlink =
declareFFI("unlink", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path);
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path);
UnixFile.write =
SysFile.write =
declareFFI("write", ctypes.default_abi,
/*return*/ Types.negativeone_or_ssize_t,
/*fd*/ Types.fd,
/*buf*/ Types.void_t.in_ptr,
/*nbytes*/ Types.size_t);
/*return*/ Type.negativeone_or_ssize_t,
/*fd*/ Type.fd,
/*buf*/ Type.void_t.in_ptr,
/*nbytes*/ Type.size_t);
// Weird cases that require special treatment
// OSes use a variety of hacks to differentiate between
// 32-bits and 64-bits versions of |stat|, |lstat|, |fstat|.
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
if (Const._DARWIN_FEATURE_64_BIT_INODE) {
// MacOS X 64-bits
UnixFile.stat =
SysFile.stat =
declareFFI("stat$INODE64", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr
);
UnixFile.lstat =
SysFile.lstat =
declareFFI("lstat$INODE64", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr
);
UnixFile.fstat =
SysFile.fstat =
declareFFI("fstat$INODE64", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.fd,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.fd,
/*buf*/ Type.stat.out_ptr
);
} else if (OS.Constants.libc._STAT_VER != undefined) {
const ver = OS.Constants.libc._STAT_VER;
let xstat_name, lxstat_name, fxstat_name
} else if (Const._STAT_VER != undefined) {
const ver = Const._STAT_VER;
let xstat_name, lxstat_name, fxstat_name;
if (OS.Constants.Sys.Name == "SunOS") {
// Solaris
xstat_name = "_xstat";
@ -557,51 +551,51 @@
let xstat =
declareFFI(xstat_name, ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*_stat_ver*/ Types.int,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr);
/*return*/ Type.negativeone_or_nothing,
/*_stat_ver*/ Type.int,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr);
let lxstat =
declareFFI(lxstat_name, ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*_stat_ver*/ Types.int,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr);
/*return*/ Type.negativeone_or_nothing,
/*_stat_ver*/ Type.int,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr);
let fxstat =
declareFFI(fxstat_name, ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*_stat_ver*/ Types.int,
/*fd*/ Types.fd,
/*buf*/ Types.stat.out_ptr);
/*return*/ Type.negativeone_or_nothing,
/*_stat_ver*/ Type.int,
/*fd*/ Type.fd,
/*buf*/ Type.stat.out_ptr);
UnixFile.stat = function stat(path, buf) {
SysFile.stat = function stat(path, buf) {
return xstat(ver, path, buf);
};
UnixFile.lstat = function stat(path, buf) {
SysFile.lstat = function stat(path, buf) {
return lxstat(ver, path, buf);
};
UnixFile.fstat = function stat(fd, buf) {
SysFile.fstat = function stat(fd, buf) {
return fxstat(ver, fd, buf);
};
} else {
// Mac OS X 32-bits, other Unix
UnixFile.stat =
SysFile.stat =
declareFFI("stat", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr
);
UnixFile.lstat =
SysFile.lstat =
declareFFI("lstat", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*path*/ Types.path,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*path*/ Type.path,
/*buf*/ Type.stat.out_ptr
);
UnixFile.fstat =
SysFile.fstat =
declareFFI("fstat", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fd*/ Types.fd,
/*buf*/ Types.stat.out_ptr
/*return*/ Type.negativeone_or_nothing,
/*fd*/ Type.fd,
/*buf*/ Type.stat.out_ptr
);
}
@ -610,14 +604,14 @@
let _pipe =
declareFFI("pipe", ctypes.default_abi,
/*return*/ Types.negativeone_or_nothing,
/*fds*/ new Type("two file descriptors",
/*return*/ Type.negativeone_or_nothing,
/*fds*/ new SharedAll.Type("two file descriptors",
ctypes.ArrayType(ctypes.int, 2)));
// A shared per-thread buffer used to communicate with |pipe|
let _pipebuf = new (ctypes.ArrayType(ctypes.int, 2))();
UnixFile.pipe = function pipe(array) {
SysFile.pipe = function pipe(array) {
let result = _pipe(_pipebuf);
if (result == -1) {
return result;
@ -627,6 +621,11 @@
return result;
};
};
exports.OS.Unix.File._init = init;
exports.OS.Unix = {
File: {
_init: init
}
};
})(this);
}

View File

@ -19,18 +19,19 @@
(function(exports) {
"use strict";
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
let Path = require("resource://gre/modules/osfile/ospath.jsm");
// exports.OS.Unix is created by osfile_unix_back.jsm
if (exports.OS && exports.OS.File) {
return; // Avoid double-initialization
}
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let Path = require("resource://gre/modules/osfile/ospath.jsm");
let SysAll = require("resource://gre/modules/osfile/osfile_unix_allthreads.jsm");
exports.OS.Unix.File._init();
let Const = exports.OS.Constants.libc;
let LOG = SharedAll.LOG.bind(SharedAll, "Unix front-end");
let Const = SharedAll.Constants.libc;
let UnixFile = exports.OS.Unix.File;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Unix front-end");
let Type = UnixFile.Type;
/**
* Representation of a file.
@ -269,7 +270,7 @@
* @return {bool} true if the file exists, false otherwise.
*/
File.exists = function Unix_exists(path) {
if (UnixFile.access(path, OS.Constants.libc.F_OK) == -1) {
if (UnixFile.access(path, Const.F_OK) == -1) {
return false;
} else {
return true;
@ -338,7 +339,7 @@
let omode = options.unixMode !== undefined ? options.unixMode : DEFAULT_UNIX_MODE_DIR;
let result = UnixFile.mkdir(path, omode);
if (result != -1 ||
options.ignoreExisting && ctypes.errno == OS.Constants.libc.EEXIST) {
options.ignoreExisting && ctypes.errno == Const.EEXIST) {
return;
}
throw new File.Error("makeDir");
@ -518,10 +519,10 @@
// We *might* be on a file system that does not support splice.
// Try again with a fallback pump.
if (total_read) {
source.setPosition(-total_read, OS.File.POS_CURRENT);
source.setPosition(-total_read, File.POS_CURRENT);
}
if (total_written) {
dest.setPosition(-total_written, OS.File.POS_CURRENT);
dest.setPosition(-total_written, File.POS_CURRENT);
}
return pump_userland(source, dest, options);
}
@ -620,7 +621,7 @@
this._dir = UnixFile.opendir(this._path);
if (this._dir == null) {
let error = ctypes.errno;
if (error != OS.Constants.libc.ENOENT) {
if (error != Const.ENOENT) {
throw new File.Error("DirectoryIterator", error);
}
this._exists = false;
@ -663,11 +664,11 @@
// |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));
isDir = (gStatData.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFDIR;
isSymLink = (gStatData.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFLNK;
isDir = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFDIR;
isSymLink = (gStatData.st_mode & Const.S_IFMT) == Const.S_IFLNK;
} else {
isDir = contents.d_type == OS.Constants.libc.DT_DIR;
isSymLink = contents.d_type == OS.Constants.libc.DT_LNK;
isDir = contents.d_type == Const.DT_DIR;
isSymLink = contents.d_type == Const.DT_LNK;
}
return new File.DirectoryIterator.Entry(isDir, isSymLink, name, this._path);
@ -713,9 +714,9 @@
this._parent = parent;
let path = Path.join(this._parent, name);
exports.OS.Shared.Unix.AbstractEntry.call(this, isDir, isSymLink, name, path);
SysAll.AbstractEntry.call(this, isDir, isSymLink, name, path);
};
File.DirectoryIterator.Entry.prototype = Object.create(exports.OS.Shared.Unix.AbstractEntry.prototype);
File.DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
/**
* Return a version of an instance of
@ -737,28 +738,28 @@
return serialized;
};
let gStatData = new OS.Shared.Type.stat.implementation();
let gStatData = new Type.stat.implementation();
let gStatDataPtr = gStatData.address();
let MODE_MASK = 4095 /*= 07777*/;
File.Info = function Info(stat) {
let isDir = (stat.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFDIR;
let isSymLink = (stat.st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFLNK;
let size = exports.OS.Shared.Type.size_t.importFromC(stat.st_size);
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.size_t.importFromC(stat.st_size);
let lastAccessDate = new Date(stat.st_atime * 1000);
let lastModificationDate = new Date(stat.st_mtime * 1000);
let unixLastStatusChangeDate = new Date(stat.st_ctime * 1000);
let unixOwner = exports.OS.Shared.Type.uid_t.importFromC(stat.st_uid);
let unixGroup = exports.OS.Shared.Type.gid_t.importFromC(stat.st_gid);
let unixMode = exports.OS.Shared.Type.mode_t.importFromC(stat.st_mode & MODE_MASK);
let unixOwner = Type.uid_t.importFromC(stat.st_uid);
let unixGroup = Type.gid_t.importFromC(stat.st_gid);
let unixMode = Type.mode_t.importFromC(stat.st_mode & MODE_MASK);
exports.OS.Shared.Unix.AbstractInfo.call(this, isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode);
SysAll.AbstractInfo.call(this, isDir, isSymLink, size, lastAccessDate,
lastModificationDate, unixLastStatusChangeDate,
unixOwner, unixGroup, unixMode);
// Some platforms (e.g. MacOS X, some BSDs) store a file creation date
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in OS.Constants.libc) {
if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in Const) {
let date = new Date(stat.st_birthtime * 1000);
/**
@ -773,7 +774,7 @@
this.macBirthDate = date;
}
};
File.Info.prototype = Object.create(exports.OS.Shared.Unix.AbstractInfo.prototype);
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
// Deprecated, use macBirthDate/winBirthDate instead
Object.defineProperty(File.Info.prototype, "creationDate", {
@ -895,11 +896,12 @@
}
File.Unix = exports.OS.Unix.File;
File.Error = exports.OS.Shared.Unix.Error;
File.Error = SysAll.Error;
exports.OS.File = File;
exports.OS.Shared.Type = Type;
Object.defineProperty(File, "POS_START", { value: OS.Shared.POS_START });
Object.defineProperty(File, "POS_CURRENT", { value: OS.Shared.POS_CURRENT });
Object.defineProperty(File, "POS_END", { value: OS.Shared.POS_END });
Object.defineProperty(File, "POS_START", { value: SysAll.POS_START });
Object.defineProperty(File, "POS_CURRENT", { value: SysAll.POS_CURRENT });
Object.defineProperty(File, "POS_END", { value: SysAll.POS_END });
})(this);
}

View File

@ -8,354 +8,371 @@
* of OS.File.
*
* It serves the following purposes:
* - open libc;
* - open kernel32;
* - define OS.Shared.Win.Error;
* - define a few constants and types that need to be defined on all platforms.
*
* This module can be:
* - opened from the main thread as a jsm module;
* - opened from a chrome worker through importScripts.
* - opened from a chrome worker through require().
*/
"use strict";
let SharedAll;
if (typeof Components != "undefined") {
let Cu = Components.utils;
// Module is opened as a jsm module
this.EXPORTED_SYMBOLS = ["OS"];
Components.utils.import("resource://gre/modules/ctypes.jsm");
Cu.import("resource://gre/modules/ctypes.jsm", this);
SharedAll = {};
Components.utils.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
} else {
Cu.import("resource://gre/modules/osfile/osfile_shared_allthreads.jsm", SharedAll);
this.exports = {};
} else if (typeof "module" != "undefined" && typeof "require" != "undefined") {
// Module is loaded with require()
SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
} else {
throw new Error("Please open this module with Component.utils.import or with require()");
}
(function(exports) {
"use strict";
if (exports.OS && exports.OS.Shared && exports.OS.Shared.Win) {
// Avoid double inclusion
return;
}
exports.OS = SharedAll.OS;
exports.OS.Shared.Win = {};
let LOG = SharedAll.LOG.bind(SharedAll, "Win", "allthreads");
let Const = SharedAll.Constants.Win;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win", "allthreads");
// Open libc
let libc;
try {
libc = ctypes.open("kernel32.dll");
} catch (ex) {
// Note: If you change the string here, please adapt consumers and
// tests accordingly
throw new Error("Could not open system library: " + ex.message);
}
exports.libc = libc;
// Open libc
let libc;
try {
libc = ctypes.open("kernel32.dll");
} catch (ex) {
// Note: If you change the string here, please adapt consumers and
// tests accordingly
throw new Error("Could not open system library: " + ex.message);
}
exports.OS.Shared.Win.libc = libc;
// Define declareFFI
let declareFFI = SharedAll.declareFFI.bind(null, libc);
exports.declareFFI = declareFFI;
// Define declareFFI
let declareFFI = OS.Shared.declareFFI.bind(null, libc);
exports.OS.Shared.Win.declareFFI = declareFFI;
// Define Error
let FormatMessage = libc.declare("FormatMessageW", ctypes.winapi_abi,
/*return*/ ctypes.uint32_t,
/*flags*/ ctypes.uint32_t,
/*source*/ ctypes.voidptr_t,
/*msgid*/ ctypes.uint32_t,
/*langid*/ ctypes.uint32_t,
/*buf*/ ctypes.jschar.ptr,
/*size*/ ctypes.uint32_t,
/*Arguments*/ctypes.voidptr_t
);
// Define Error
let FormatMessage = libc.declare("FormatMessageW", ctypes.winapi_abi,
/*return*/ ctypes.uint32_t,
/*flags*/ ctypes.uint32_t,
/*source*/ ctypes.voidptr_t,
/*msgid*/ ctypes.uint32_t,
/*langid*/ ctypes.uint32_t,
/*buf*/ ctypes.jschar.ptr,
/*size*/ ctypes.uint32_t,
/*Arguments*/ctypes.voidptr_t
/**
* A File-related error.
*
* To obtain a human-readable error message, use method |toString|.
* To determine the cause of the error, use the various |becauseX|
* getters. To determine the operation that failed, use field
* |operation|.
*
* Additionally, this implementation offers a field
* |winLastError|, which holds the OS-specific error
* constant. If you need this level of detail, you may match the value
* of this field against the error constants of |OS.Constants.Win|.
*
* @param {string=} operation The operation that failed. If unspecified,
* the name of the calling function is taken to be the operation that
* failed.
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
*
* @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;
};
OSError.prototype = Object.create(SharedAll.OSError.prototype);
OSError.prototype.toString = function toString() {
let buf = new (ctypes.ArrayType(ctypes.jschar, 1024))();
let result = FormatMessage(
Const.FORMAT_MESSAGE_FROM_SYSTEM |
Const.FORMAT_MESSAGE_IGNORE_INSERTS,
null,
/* The error number */ this.winLastError,
/* Default language */ 0,
/* Output buffer*/ buf,
/* Minimum size of buffer */ 1024,
/* Format args*/ null
);
if (!result) {
buf = "additional error " +
ctypes.winLastError +
" while fetching system error message";
}
return "Win error " + this.winLastError + " during operation "
+ this.operation + " (" + buf.readString() + ")";
};
/**
* |true| if the error was raised because a file or directory
* already exists, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseExists", {
get: function becauseExists() {
return this.winLastError == Const.ERROR_FILE_EXISTS ||
this.winLastError == Const.ERROR_ALREADY_EXISTS;
}
});
/**
* |true| if the error was raised because a file or directory
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.winLastError == Const.ERROR_FILE_NOT_FOUND;
}
});
/**
* |true| if the error was raised because a directory is not empty
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
get: function becauseNotEmpty() {
return this.winLastError == Const.ERROR_DIR_NOT_EMPTY;
}
});
/**
* |true| if the error was raised because a file or directory
* is closed, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseClosed", {
get: function becauseClosed() {
return this.winLastError == Const.ERROR_INVALID_HANDLE;
}
});
/**
* |true| if the error was raised because permission is denied to
* access a file or directory, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
get: function becauseAccessDenied() {
return this.winLastError == Const.ERROR_ACCESS_DENIED;
}
});
/**
* Serialize an instance of OSError to something that can be
* transmitted across threads (not necessarily a string).
*/
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
winLastError: error.winLastError
};
};
/**
* Deserialize a message back to an instance of OSError
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.winLastError);
};
exports.Error = OSError;
/**
* Code shared by implementation of File.Info on Windows
*
* @constructor
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, winBirthDate,
lastAccessDate, lastWriteDate) {
this._isDir = isDir;
this._isSymLink = isSymLink;
this._size = size;
this._winBirthDate = winBirthDate;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastWriteDate;
};
AbstractInfo.prototype = {
/**
* A File-related error.
* |true| if this file is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if this file is a symbolic link, |false| otherwise
*/
get isSymLink() {
return this._isSymLink;
},
/**
* The size of the file, in bytes.
*
* To obtain a human-readable error message, use method |toString|.
* To determine the cause of the error, use the various |becauseX|
* getters. To determine the operation that failed, use field
* |operation|.
* Note that the result may be |NaN| if the size of the file cannot be
* represented in JavaScript.
*
* Additionally, this implementation offers a field
* |winLastError|, which holds the OS-specific error
* constant. If you need this level of detail, you may match the value
* of this field against the error constants of |OS.Constants.Win|.
* @type {number}
*/
get size() {
return this._size;
},
// Deprecated
get creationDate() {
return this._winBirthDate;
},
/**
* The date of creation of this file.
*
* @param {string=} operation The operation that failed. If unspecified,
* the name of the calling function is taken to be the operation that
* failed.
* @param {number=} lastError The OS-specific constant detailing the
* reason of the error. If unspecified, this is fetched from the system
* status.
* @type {Date}
*/
get winBirthDate() {
return this._winBirthDate;
},
/**
* The date of last access to this file.
*
* @constructor
* @extends {OS.Shared.Error}
*/
let OSError = function OSError(operation, lastError) {
operation = operation || "unknown operation";
exports.OS.Shared.Error.call(this, operation);
this.winLastError = lastError || ctypes.winLastError;
};
OSError.prototype = new exports.OS.Shared.Error();
OSError.prototype.toString = function toString() {
let buf = new (ctypes.ArrayType(ctypes.jschar, 1024))();
let result = FormatMessage(
exports.OS.Constants.Win.FORMAT_MESSAGE_FROM_SYSTEM |
exports.OS.Constants.Win.FORMAT_MESSAGE_IGNORE_INSERTS,
null,
/* The error number */ this.winLastError,
/* Default language */ 0,
/* Output buffer*/ buf,
/* Minimum size of buffer */ 1024,
/* Format args*/ null
);
if (!result) {
buf = "additional error " +
ctypes.winLastError +
" while fetching system error message";
}
return "Win error " + this.winLastError + " during operation "
+ this.operation + " (" + buf.readString() + ")";
};
/**
* |true| if the error was raised because a file or directory
* already exists, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseExists", {
get: function becauseExists() {
return this.winLastError == exports.OS.Constants.Win.ERROR_FILE_EXISTS ||
this.winLastError == exports.OS.Constants.Win.ERROR_ALREADY_EXISTS;
}
});
/**
* |true| if the error was raised because a file or directory
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNoSuchFile", {
get: function becauseNoSuchFile() {
return this.winLastError == exports.OS.Constants.Win.ERROR_FILE_NOT_FOUND;
}
});
/**
* |true| if the error was raised because a directory is not empty
* does not exist, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseNotEmpty", {
get: function becauseNotEmpty() {
return this.winLastError == OS.Constants.Win.ERROR_DIR_NOT_EMPTY;
}
});
/**
* |true| if the error was raised because a file or directory
* is closed, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseClosed", {
get: function becauseClosed() {
return this.winLastError == exports.OS.Constants.Win.ERROR_INVALID_HANDLE;
}
});
/**
* |true| if the error was raised because permission is denied to
* access a file or directory, |false| otherwise.
*/
Object.defineProperty(OSError.prototype, "becauseAccessDenied", {
get: function becauseAccessDenied() {
return this.winLastError == exports.OS.Constants.Win.ERROR_ACCESS_DENIED;
}
});
/**
* Serialize an instance of OSError to something that can be
* transmitted across threads (not necessarily a string).
*/
OSError.toMsg = function toMsg(error) {
return {
operation: error.operation,
winLastError: error.winLastError
};
};
/**
* Deserialize a message back to an instance of OSError
*/
OSError.fromMsg = function fromMsg(msg) {
return new OSError(msg.operation, msg.winLastError);
};
exports.OS.Shared.Win.Error = OSError;
/**
* Code shared by implementation of File.Info on Windows
* Note that the definition of last access may depend on the underlying
* operating system and file system.
*
* @constructor
* @type {Date}
*/
let AbstractInfo = function AbstractInfo(isDir, isSymLink, size, winBirthDate,
lastAccessDate, lastWriteDate) {
this._isDir = isDir;
this._isSymLink = isSymLink;
this._size = size;
this._winBirthDate = winBirthDate;
this._lastAccessDate = lastAccessDate;
this._lastModificationDate = lastWriteDate;
};
AbstractInfo.prototype = {
/**
* |true| if this file is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if this file is a symbolic link, |false| otherwise
*/
get isSymLink() {
return this._isSymLink;
},
/**
* The size of the file, in bytes.
*
* Note that the result may be |NaN| if the size of the file cannot be
* represented in JavaScript.
*
* @type {number}
*/
get size() {
return this._size;
},
// Deprecated
get creationDate() {
return this._winBirthDate;
},
/**
* The date of creation of this file.
*
* @type {Date}
*/
get winBirthDate() {
return this._winBirthDate;
},
/**
* The date of last access to this file.
*
* Note that the definition of last access may depend on the underlying
* operating system and file system.
*
* @type {Date}
*/
get lastAccessDate() {
return this._lastAccessDate;
},
/**
* The date of last modification of this file.
*
* Note that the definition of last access may depend on the underlying
* operating system and file system.
*
* @type {Date}
*/
get lastModificationDate() {
return this._lastModificationDate;
}
};
exports.OS.Shared.Win.AbstractInfo = AbstractInfo;
get lastAccessDate() {
return this._lastAccessDate;
},
/**
* Code shared by implementation of File.DirectoryIterator.Entry on Windows
* The date of last modification of this file.
*
* @constructor
* Note that the definition of last access may depend on the underlying
* operating system and file system.
*
* @type {Date}
*/
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name,
winCreationDate, winLastWriteDate,
winLastAccessDate, path) {
this._isDir = isDir;
this._isSymLink = isSymLink;
this._name = name;
this._winCreationDate = winCreationDate;
this._winLastWriteDate = winLastWriteDate;
this._winLastAccessDate = winLastAccessDate;
this._path = path;
};
get lastModificationDate() {
return this._lastModificationDate;
}
};
exports.AbstractInfo = AbstractInfo;
AbstractEntry.prototype = {
/**
* |true| if the entry is a directory, |false| otherwise
*/
get isDir() {
return this._isDir;
},
/**
* |true| if the entry is a symbolic link, |false| otherwise
*/
get isSymLink() {
return this._isSymLink;
},
/**
* The name of the entry.
* @type {string}
*/
get name() {
return this._name;
},
/**
* The creation time of this file.
* @type {Date}
*/
get winCreationDate() {
return this._winCreationDate;
},
/**
* The last modification time of this file.
* @type {Date}
*/
get winLastWriteDate() {
return this._winLastWriteDate;
},
/**
* The last access time of this file.
* @type {Date}
*/
get winLastAccessDate() {
return this._winLastAccessDate;
},
/**
* The full path of the entry
* @type {string}
*/
get path() {
return this._path;
}
};
exports.OS.Shared.Win.AbstractEntry = AbstractEntry;
// Special constants that need to be defined on all platforms
Object.defineProperty(exports.OS.Shared, "POS_START", { value: exports.OS.Constants.Win.FILE_BEGIN });
Object.defineProperty(exports.OS.Shared, "POS_CURRENT", { value: exports.OS.Constants.Win.FILE_CURRENT });
Object.defineProperty(exports.OS.Shared, "POS_END", { value: exports.OS.Constants.Win.FILE_END });
// Special types that need to be defined for communication
// between threads
let Types = exports.OS.Shared.Type;
/**
* Code shared by implementation of File.DirectoryIterator.Entry on Windows
*
* @constructor
*/
let AbstractEntry = function AbstractEntry(isDir, isSymLink, name,
winCreationDate, winLastWriteDate,
winLastAccessDate, path) {
this._isDir = isDir;
this._isSymLink = isSymLink;
this._name = name;
this._winCreationDate = winCreationDate;
this._winLastWriteDate = winLastWriteDate;
this._winLastAccessDate = winLastAccessDate;
this._path = path;
};
AbstractEntry.prototype = {
/**
* Native paths
*
* Under Windows, expressed as wide strings
* |true| if the entry is a directory, |false| otherwise
*/
Types.path = Types.wstring.withName("[in] path");
Types.out_path = Types.out_wstring.withName("[out] path");
get isDir() {
return this._isDir;
},
/**
* |true| if the entry is a symbolic link, |false| otherwise
*/
get isSymLink() {
return this._isSymLink;
},
/**
* The name of the entry.
* @type {string}
*/
get name() {
return this._name;
},
/**
* The creation time of this file.
* @type {Date}
*/
get winCreationDate() {
return this._winCreationDate;
},
/**
* The last modification time of this file.
* @type {Date}
*/
get winLastWriteDate() {
return this._winLastWriteDate;
},
/**
* The last access time of this file.
* @type {Date}
*/
get winLastAccessDate() {
return this._winLastAccessDate;
},
/**
* The full path of the entry
* @type {string}
*/
get path() {
return this._path;
}
};
exports.AbstractEntry = AbstractEntry;
// Special constructors that need to be defined on all threads
OSError.closed = function closed(operation) {
return new OSError(operation, exports.OS.Constants.Win.ERROR_INVALID_HANDLE);
};
// Special constants that need to be defined on all platforms
OSError.exists = function exists(operation) {
return new OSError(operation, exports.OS.Constants.Win.ERROR_FILE_EXISTS);
};
exports.POS_START = Const.FILE_BEGIN;
exports.POS_CURRENT = Const.FILE_CURRENT;
exports.POS_END = Const.FILE_END;
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, exports.OS.Constants.Win.ERROR_FILE_NOT_FOUND);
};
})(this);
// Special types that need to be defined for communication
// between threads
let Type = Object.create(SharedAll.Type);
exports.Type = Type;
/**
* Native paths
*
* Under Windows, expressed as wide strings
*/
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.exists = function exists(operation) {
return new OSError(operation, Const.ERROR_FILE_EXISTS);
};
OSError.noSuchFile = function noSuchFile(operation) {
return new OSError(operation, Const.ERROR_FILE_NOT_FOUND);
};
let EXPORTED_SYMBOLS = [
"declareFFI",
"libc",
"Error",
"AbstractInfo",
"AbstractEntry",
"Type",
"POS_START",
"POS_CURRENT",
"POS_END"
];
//////////// Boilerplate
if (typeof Components != "undefined") {
this.EXPORTED_SYMBOLS = EXPORTED_SYMBOLS;
for (let symbol of EXPORTED_SYMBOLS) {
this[symbol] = exports[symbol];
}
}

View File

@ -34,11 +34,12 @@
if (exports.OS && exports.OS.Win && exports.OS.Win.File) {
return; // Avoid double initialization
}
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
exports.OS.Win.File = {};
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win", "back");
let libc = exports.OS.Shared.Win.libc;
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let SysAll = require("resource://gre/modules/osfile/osfile_win_allthreads.jsm");
let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "back");
let libc = SysAll.libc;
let Const = SharedAll.Constants.Win;
/**
* Initialize the Windows module.
@ -51,17 +52,14 @@
if (aDeclareFFI) {
declareFFI = aDeclareFFI.bind(null, libc);
} else {
declareFFI = exports.OS.Shared.Win.declareFFI;
declareFFI = SysAll.declareFFI;
}
// Shorthands
let OSWin = exports.OS.Win;
let WinFile = exports.OS.Win.File;
if (!exports.OS.Types) {
exports.OS.Types = {};
}
let Type = exports.OS.Shared.Type;
let Types = Type;
// Initialize types that require additional OS-specific
// support - either finalization or matching against
// OS-specific constants.
let Type = Object.create(SysAll.Type);
let SysFile = exports.OS.Win.File = { Type: Type };
// Initialize types
@ -69,10 +67,10 @@
* A C integer holding INVALID_HANDLE_VALUE in case of error or
* a file descriptor in case of success.
*/
Types.HANDLE =
Types.voidptr_t.withName("HANDLE");
Types.HANDLE.importFromC = function importFromC(maybe) {
if (Types.int.cast(maybe).value == INVALID_HANDLE) {
Type.HANDLE =
Type.voidptr_t.withName("HANDLE");
Type.HANDLE.importFromC = function importFromC(maybe) {
if (Type.int.cast(maybe).value == INVALID_HANDLE) {
// Ensure that API clients can effectively compare against
// Const.INVALID_HANDLE_VALUE. Without this cast,
// == would always return |false|.
@ -80,88 +78,88 @@
}
return ctypes.CDataFinalizer(maybe, this.finalizeHANDLE);
};
Types.HANDLE.finalizeHANDLE = function placeholder() {
Type.HANDLE.finalizeHANDLE = function placeholder() {
throw new Error("finalizeHANDLE should be implemented");
};
let INVALID_HANDLE = exports.OS.Constants.Win.INVALID_HANDLE_VALUE;
let INVALID_HANDLE = Const.INVALID_HANDLE_VALUE;
Types.file_HANDLE = Types.HANDLE.withName("file HANDLE");
exports.OS.Shared.defineLazyGetter(Types.file_HANDLE,
Type.file_HANDLE = Type.HANDLE.withName("file HANDLE");
SharedAll.defineLazyGetter(Type.file_HANDLE,
"finalizeHANDLE",
function() {
return _CloseHandle;
});
Types.find_HANDLE = Types.HANDLE.withName("find HANDLE");
exports.OS.Shared.defineLazyGetter(Types.find_HANDLE,
Type.find_HANDLE = Type.HANDLE.withName("find HANDLE");
SharedAll.defineLazyGetter(Type.find_HANDLE,
"finalizeHANDLE",
function() {
return _FindClose;
});
Types.DWORD = Types.int32_t.withName("DWORD");
Type.DWORD = Type.int32_t.withName("DWORD");
/**
* A C integer holding -1 in case of error or a positive integer
* in case of success.
*/
Types.negative_or_DWORD =
Types.DWORD.withName("negative_or_DWORD");
Type.negative_or_DWORD =
Type.DWORD.withName("negative_or_DWORD");
/**
* A C integer holding 0 in case of error or a positive integer
* in case of success.
*/
Types.zero_or_DWORD =
Types.DWORD.withName("zero_or_DWORD");
Type.zero_or_DWORD =
Type.DWORD.withName("zero_or_DWORD");
/**
* A C integer holding 0 in case of error, any other value in
* case of success.
*/
Types.zero_or_nothing =
Types.int.withName("zero_or_nothing");
Type.zero_or_nothing =
Type.int.withName("zero_or_nothing");
Types.SECURITY_ATTRIBUTES =
Types.void_t.withName("SECURITY_ATTRIBUTES");
Type.SECURITY_ATTRIBUTES =
Type.void_t.withName("SECURITY_ATTRIBUTES");
Types.FILETIME =
new Type("FILETIME",
Type.FILETIME =
new SharedAll.Type("FILETIME",
ctypes.StructType("FILETIME", [
{ lo: Types.DWORD.implementation },
{ hi: Types.DWORD.implementation }]));
{ lo: Type.DWORD.implementation },
{ hi: Type.DWORD.implementation }]));
Types.FindData =
new Type("FIND_DATA",
Type.FindData =
new SharedAll.Type("FIND_DATA",
ctypes.StructType("FIND_DATA", [
{ dwFileAttributes: ctypes.uint32_t },
{ ftCreationTime: Types.FILETIME.implementation },
{ ftLastAccessTime: Types.FILETIME.implementation },
{ ftLastWriteTime: Types.FILETIME.implementation },
{ nFileSizeHigh: Types.DWORD.implementation },
{ nFileSizeLow: Types.DWORD.implementation },
{ dwReserved0: Types.DWORD.implementation },
{ dwReserved1: Types.DWORD.implementation },
{ cFileName: ctypes.ArrayType(ctypes.jschar, exports.OS.Constants.Win.MAX_PATH) },
{ ftCreationTime: Type.FILETIME.implementation },
{ ftLastAccessTime: Type.FILETIME.implementation },
{ ftLastWriteTime: Type.FILETIME.implementation },
{ nFileSizeHigh: Type.DWORD.implementation },
{ nFileSizeLow: Type.DWORD.implementation },
{ dwReserved0: Type.DWORD.implementation },
{ dwReserved1: Type.DWORD.implementation },
{ cFileName: ctypes.ArrayType(ctypes.jschar, Const.MAX_PATH) },
{ cAlternateFileName: ctypes.ArrayType(ctypes.jschar, 14) }
]));
Types.FILE_INFORMATION =
new Type("FILE_INFORMATION",
Type.FILE_INFORMATION =
new SharedAll.Type("FILE_INFORMATION",
ctypes.StructType("FILE_INFORMATION", [
{ dwFileAttributes: ctypes.uint32_t },
{ ftCreationTime: Types.FILETIME.implementation },
{ ftLastAccessTime: Types.FILETIME.implementation },
{ ftLastWriteTime: Types.FILETIME.implementation },
{ ftCreationTime: Type.FILETIME.implementation },
{ ftLastAccessTime: Type.FILETIME.implementation },
{ ftLastWriteTime: Type.FILETIME.implementation },
{ dwVolumeSerialNumber: ctypes.uint32_t },
{ nFileSizeHigh: Types.DWORD.implementation },
{ nFileSizeLow: Types.DWORD.implementation },
{ nFileSizeHigh: Type.DWORD.implementation },
{ nFileSizeLow: Type.DWORD.implementation },
{ nNumberOfLinks: ctypes.uint32_t },
{ nFileIndex: ctypes.uint64_t }
]));
Types.SystemTime =
new Type("SystemTime",
Type.SystemTime =
new SharedAll.Type("SystemTime",
ctypes.StructType("SystemTime", [
{ wYear: ctypes.int16_t },
{ wMonth: ctypes.int16_t },
@ -175,12 +173,12 @@
// Special case: these functions are used by the
// finalizer
let _CloseHandle = WinFile._CloseHandle =
let _CloseHandle = SysFile._CloseHandle =
libc.declare("CloseHandle", ctypes.winapi_abi,
/*return */ctypes.bool,
/*handle*/ ctypes.voidptr_t);
WinFile.CloseHandle = function(fd) {
SysFile.CloseHandle = function(fd) {
if (fd == INVALID_HANDLE) {
return true;
} else {
@ -193,7 +191,7 @@
/*return */ctypes.bool,
/*handle*/ ctypes.voidptr_t);
WinFile.FindClose = function(handle) {
SysFile.FindClose = function(handle) {
if (handle == INVALID_HANDLE) {
return true;
} else {
@ -203,135 +201,140 @@
// Declare libc functions as functions of |OS.Win.File|
WinFile.CopyFile =
SysFile.CopyFile =
declareFFI("CopyFileW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*sourcePath*/ Types.path,
/*destPath*/ Types.path,
/*bailIfExist*/Types.bool);
/*return*/ Type.zero_or_nothing,
/*sourcePath*/ Type.path,
/*destPath*/ Type.path,
/*bailIfExist*/Type.bool);
WinFile.CreateDirectory =
SysFile.CreateDirectory =
declareFFI("CreateDirectoryW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*name*/ Types.jschar.in_ptr,
/*security*/Types.SECURITY_ATTRIBUTES.in_ptr);
/*return*/ Type.zero_or_nothing,
/*name*/ Type.jschar.in_ptr,
/*security*/Type.SECURITY_ATTRIBUTES.in_ptr);
WinFile.CreateFile =
SysFile.CreateFile =
declareFFI("CreateFileW", ctypes.winapi_abi,
/*return*/ Types.file_HANDLE,
/*name*/ Types.path,
/*access*/ Types.DWORD,
/*share*/ Types.DWORD,
/*security*/Types.SECURITY_ATTRIBUTES.in_ptr,
/*creation*/Types.DWORD,
/*flags*/ Types.DWORD,
/*template*/Types.HANDLE);
/*return*/ Type.file_HANDLE,
/*name*/ Type.path,
/*access*/ Type.DWORD,
/*share*/ Type.DWORD,
/*security*/Type.SECURITY_ATTRIBUTES.in_ptr,
/*creation*/Type.DWORD,
/*flags*/ Type.DWORD,
/*template*/Type.HANDLE);
WinFile.DeleteFile =
SysFile.DeleteFile =
declareFFI("DeleteFileW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*path*/ Types.path);
/*return*/ Type.zero_or_nothing,
/*path*/ Type.path);
WinFile.FileTimeToSystemTime =
SysFile.FileTimeToSystemTime =
declareFFI("FileTimeToSystemTime", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*filetime*/Types.FILETIME.in_ptr,
/*systime*/ Types.SystemTime.out_ptr);
/*return*/ Type.zero_or_nothing,
/*filetime*/Type.FILETIME.in_ptr,
/*systime*/ Type.SystemTime.out_ptr);
WinFile.FindFirstFile =
SysFile.FindFirstFile =
declareFFI("FindFirstFileW", ctypes.winapi_abi,
/*return*/ Types.find_HANDLE,
/*pattern*/Types.path,
/*data*/ Types.FindData.out_ptr);
/*return*/ Type.find_HANDLE,
/*pattern*/Type.path,
/*data*/ Type.FindData.out_ptr);
WinFile.FindNextFile =
SysFile.FindNextFile =
declareFFI("FindNextFileW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*prev*/ Types.find_HANDLE,
/*data*/ Types.FindData.out_ptr);
/*return*/ Type.zero_or_nothing,
/*prev*/ Type.find_HANDLE,
/*data*/ Type.FindData.out_ptr);
WinFile.FormatMessage =
SysFile.FormatMessage =
declareFFI("FormatMessageW", ctypes.winapi_abi,
/*return*/ Types.DWORD,
/*flags*/ Types.DWORD,
/*source*/ Types.void_t.in_ptr,
/*msgid*/ Types.DWORD,
/*langid*/ Types.DWORD,
/*buf*/ Types.out_wstring,
/*size*/ Types.DWORD,
/*Arguments*/Types.void_t.in_ptr
/*return*/ Type.DWORD,
/*flags*/ Type.DWORD,
/*source*/ Type.void_t.in_ptr,
/*msgid*/ Type.DWORD,
/*langid*/ Type.DWORD,
/*buf*/ Type.out_wstring,
/*size*/ Type.DWORD,
/*Arguments*/Type.void_t.in_ptr
);
WinFile.GetCurrentDirectory =
SysFile.GetCurrentDirectory =
declareFFI("GetCurrentDirectoryW", ctypes.winapi_abi,
/*return*/ Types.zero_or_DWORD,
/*length*/ Types.DWORD,
/*buf*/ Types.out_path
/*return*/ Type.zero_or_DWORD,
/*length*/ Type.DWORD,
/*buf*/ Type.out_path
);
WinFile.GetFileInformationByHandle =
SysFile.GetFileInformationByHandle =
declareFFI("GetFileInformationByHandle", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*handle*/ Types.HANDLE,
/*info*/ Types.FILE_INFORMATION.out_ptr);
/*return*/ Type.zero_or_nothing,
/*handle*/ Type.HANDLE,
/*info*/ Type.FILE_INFORMATION.out_ptr);
WinFile.MoveFileEx =
SysFile.MoveFileEx =
declareFFI("MoveFileExW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*sourcePath*/ Types.path,
/*destPath*/ Types.path,
/*flags*/ Types.DWORD
/*return*/ Type.zero_or_nothing,
/*sourcePath*/ Type.path,
/*destPath*/ Type.path,
/*flags*/ Type.DWORD
);
WinFile.ReadFile =
SysFile.ReadFile =
declareFFI("ReadFile", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*file*/ Types.HANDLE,
/*buffer*/ Types.voidptr_t,
/*nbytes*/ Types.DWORD,
/*nbytes_read*/Types.DWORD.out_ptr,
/*overlapped*/Types.void_t.inout_ptr // FIXME: Implement?
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE,
/*buffer*/ Type.voidptr_t,
/*nbytes*/ Type.DWORD,
/*nbytes_read*/Type.DWORD.out_ptr,
/*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
);
WinFile.RemoveDirectory =
SysFile.RemoveDirectory =
declareFFI("RemoveDirectoryW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*path*/ Types.path);
/*return*/ Type.zero_or_nothing,
/*path*/ Type.path);
WinFile.SetCurrentDirectory =
SysFile.SetCurrentDirectory =
declareFFI("SetCurrentDirectoryW", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*path*/ Types.path
/*return*/ Type.zero_or_nothing,
/*path*/ Type.path
);
WinFile.SetEndOfFile =
SysFile.SetEndOfFile =
declareFFI("SetEndOfFile", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*file*/ Types.HANDLE);
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE);
WinFile.SetFilePointer =
SysFile.SetFilePointer =
declareFFI("SetFilePointer", ctypes.winapi_abi,
/*return*/ Types.negative_or_DWORD,
/*file*/ Types.HANDLE,
/*distlow*/Types.long,
/*disthi*/ Types.long.in_ptr,
/*method*/ Types.DWORD);
/*return*/ Type.negative_or_DWORD,
/*file*/ Type.HANDLE,
/*distlow*/Type.long,
/*disthi*/ Type.long.in_ptr,
/*method*/ Type.DWORD);
WinFile.WriteFile =
SysFile.WriteFile =
declareFFI("WriteFile", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*file*/ Types.HANDLE,
/*buffer*/ Types.voidptr_t,
/*nbytes*/ Types.DWORD,
/*nbytes_wr*/Types.DWORD.out_ptr,
/*overlapped*/Types.void_t.inout_ptr // FIXME: Implement?
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE,
/*buffer*/ Type.voidptr_t,
/*nbytes*/ Type.DWORD,
/*nbytes_wr*/Type.DWORD.out_ptr,
/*overlapped*/Type.void_t.inout_ptr // FIXME: Implement?
);
WinFile.FlushFileBuffers =
SysFile.FlushFileBuffers =
declareFFI("FlushFileBuffers", ctypes.winapi_abi,
/*return*/ Types.zero_or_nothing,
/*file*/ Types.HANDLE);
/*return*/ Type.zero_or_nothing,
/*file*/ Type.HANDLE);
};
exports.OS.Win = {
File: {
_init: init
}
};
exports.OS.Win.File._init = init;
})(this);
}

View File

@ -19,18 +19,19 @@
(function(exports) {
"use strict";
exports.OS = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm").OS;
let Path = require("resource://gre/modules/osfile/ospath.jsm");
// exports.OS.Win is created by osfile_win_back.jsm
if (exports.OS && exports.OS.File) {
return; // Avoid double-initialization
}
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
let Path = require("resource://gre/modules/osfile/ospath.jsm");
let SysAll = require("resource://gre/modules/osfile/osfile_win_allthreads.jsm");
exports.OS.Win.File._init();
let Const = exports.OS.Constants.Win;
let WinFile = exports.OS.Win.File;
let LOG = OS.Shared.LOG.bind(OS.Shared, "Win front-end");
let Type = WinFile.Type;
// Mutable thread-global data
// In the Windows implementation, methods |read| and |write|
@ -47,7 +48,7 @@
let gBytesWrittenPtr = gBytesWritten.address();
// Same story for GetFileInformationByHandle
let gFileInfo = new OS.Shared.Type.FILE_INFORMATION.implementation();
let gFileInfo = new Type.FILE_INFORMATION.implementation();
let gFileInfoPtr = gFileInfo.address();
/**
@ -388,7 +389,7 @@
let result = WinFile.CreateDirectory(path, security);
if (result ||
options.ignoreExisting &&
ctypes.winLastError == OS.Constants.Win.ERROR_ALREADY_EXISTS) {
ctypes.winLastError == Const.ERROR_ALREADY_EXISTS) {
return;
}
throw new File.Error("makeDir");
@ -465,7 +466,7 @@
/**
* A global value used to receive data during time conversions.
*/
let gSystemTime = new OS.Shared.Type.SystemTime.implementation();
let gSystemTime = new Type.SystemTime.implementation();
let gSystemTimePtr = gSystemTime.address();
/**
@ -514,7 +515,7 @@
// Pre-open the first item.
this._first = true;
this._findData = new OS.Shared.Type.FindData.implementation();
this._findData = new Type.FindData.implementation();
this._findDataPtr = this._findData.address();
this._handle = WinFile.FindFirstFile(this._pattern, this._findDataPtr);
if (this._handle == Const.INVALID_HANDLE_VALUE) {
@ -523,12 +524,12 @@
this._findDataPtr = null;
if (error == Const.ERROR_FILE_NOT_FOUND) {
// Directory is empty, let's behave as if it were closed
LOG("Directory is empty");
SharedAll.LOG("Directory is empty");
this._closed = true;
this._exists = true;
} else if (error == Const.ERROR_PATH_NOT_FOUND) {
// Directory does not exist, let's throw if we attempt to walk it
LOG("Directory does not exist");
SharedAll.LOG("Directory does not exist");
this._closed = true;
this._exists = false;
} else {
@ -650,11 +651,11 @@
let path = Path.join(this._parent, name);
exports.OS.Shared.Win.AbstractEntry.call(this, isDir, isSymLink, name,
winCreationDate, winLastWriteDate,
winLastAccessDate, path);
SysAll.AbstractEntry.call(this, isDir, isSymLink, name,
winCreationDate, winLastWriteDate,
winLastAccessDate, path);
};
File.DirectoryIterator.Entry.prototype = Object.create(exports.OS.Shared.Win.AbstractEntry.prototype);
File.DirectoryIterator.Entry.prototype = Object.create(SysAll.AbstractEntry.prototype);
/**
* Return a version of an instance of
@ -695,13 +696,13 @@
let lastWriteDate = FILETIME_to_Date(stat.ftLastWriteTime);
let value = ctypes.UInt64.join(stat.nFileSizeHigh, stat.nFileSizeLow);
let size = exports.OS.Shared.Type.uint64_t.importFromC(value);
let size = Type.uint64_t.importFromC(value);
exports.OS.Shared.Win.AbstractInfo.call(this, isDir, isSymLink, size,
winBirthDate, lastAccessDate,
lastWriteDate);
SysAll.AbstractInfo.call(this, isDir, isSymLink, size,
winBirthDate, lastAccessDate,
lastWriteDate);
};
File.Info.prototype = Object.create(exports.OS.Shared.Win.AbstractInfo.prototype);
File.Info.prototype = Object.create(SysAll.AbstractInfo.prototype);
/**
* Return a version of an instance of File.Info that can be sent
@ -744,14 +745,14 @@
// All of the following is required to ensure that File.stat
// also works on directories.
const FILE_STAT_MODE = {
read:true
read: true
};
const FILE_STAT_OPTIONS = {
// Directories can be opened neither for reading(!) nor for writing
winAccess: 0,
// Directories can only be opened with backup semantics(!)
winFlags: OS.Constants.Win.FILE_FLAG_BACKUP_SEMANTICS,
winDisposition: OS.Constants.Win.OPEN_EXISTING
winFlags: Const.FILE_FLAG_BACKUP_SEMANTICS,
winDisposition: Const.OPEN_EXISTING
};
File.read = exports.OS.Shared.AbstractFile.read;
@ -763,35 +764,35 @@
* Get the current directory by getCurrentDirectory.
*/
File.getCurrentDirectory = function getCurrentDirectory() {
// This function is more complicated than one could hope.
//
// This is due to two facts:
// - the maximal length of a path under Windows is not completely
// specified (there is a constant MAX_PATH, but it is quite possible
// to create paths that are much larger, see bug 744413);
// - if we attempt to call |GetCurrentDirectory| with a buffer that
// is too short, it returns the length of the current directory, but
// this length might be insufficient by the time we can call again
// the function with a larger buffer, in the (unlikely byt possible)
// case in which the process changes directory to a directory with
// a longer name between both calls.
let buffer_size = 4096;
while (true) {
let array = new (ctypes.ArrayType(ctypes.jschar, buffer_size))();
// This function is more complicated than one could hope.
//
// This is due to two facts:
// - the maximal length of a path under Windows is not completely
// specified (there is a constant MAX_PATH, but it is quite possible
// to create paths that are much larger, see bug 744413);
// - if we attempt to call |GetCurrentDirectory| with a buffer that
// is too short, it returns the length of the current directory, but
// this length might be insufficient by the time we can call again
// the function with a larger buffer, in the (unlikely but possible)
// case in which the process changes directory to a directory with
// a longer name between both calls.
//
let buffer_size = 4096;
while (true) {
let array = new (ctypes.ArrayType(ctypes.jschar, buffer_size))();
let expected_size = throw_on_zero("getCurrentDirectory",
WinFile.GetCurrentDirectory(buffer_size, array)
);
if (expected_size <= buffer_size) {
return array.readString();
}
// At this point, we are in a case in which our buffer was not
// large enough to hold the name of the current directory.
// Consequently
// Note that, even in crazy scenarios, the loop will eventually
// converge, as the length of the paths cannot increase infinitely.
buffer_size = expected_size;
}
WinFile.GetCurrentDirectory(buffer_size, array)
);
if (expected_size <= buffer_size) {
return array.readString();
}
// At this point, we are in a case in which our buffer was not
// large enough to hold the name of the current directory.
// Consequently, we need to increase the size of the buffer.
// Note that, even in crazy scenarios, the loop will eventually
// converge, as the length of the paths cannot increase infinitely.
buffer_size = expected_size + 1 /* to store \0 */;
}
};
/**
@ -817,7 +818,7 @@
// Utility functions, used for error-handling
function error_or_file(maybe) {
if (maybe == exports.OS.Constants.Win.INVALID_HANDLE_VALUE) {
if (maybe == Const.INVALID_HANDLE_VALUE) {
throw new File.Error("open");
}
return new File(maybe);
@ -842,13 +843,12 @@
}
File.Win = exports.OS.Win.File;
File.Error = exports.OS.Shared.Win.Error;
File.Error = SysAll.Error;
exports.OS.File = File;
exports.OS.Shared.Type = Type;
exports.OS.Path = exports.Path;
Object.defineProperty(File, "POS_START", { value: OS.Shared.POS_START });
Object.defineProperty(File, "POS_CURRENT", { value: OS.Shared.POS_CURRENT });
Object.defineProperty(File, "POS_END", { value: OS.Shared.POS_END });
Object.defineProperty(File, "POS_START", { value: SysAll.POS_START });
Object.defineProperty(File, "POS_CURRENT", { value: SysAll.POS_CURRENT });
Object.defineProperty(File, "POS_END", { value: SysAll.POS_END });
})(this);
}

View File

@ -16,7 +16,6 @@ if (typeof Components != "undefined") {
#ifdef XP_WIN
importScripts(
"resource://gre/modules/workers/require.js",
"resource://gre/modules/osfile/osfile_win_allthreads.jsm",
"resource://gre/modules/osfile/osfile_win_back.jsm",
"resource://gre/modules/osfile/osfile_shared_front.jsm",
"resource://gre/modules/osfile/osfile_win_front.jsm"
@ -24,7 +23,6 @@ if (typeof Components != "undefined") {
#else
importScripts(
"resource://gre/modules/workers/require.js",
"resource://gre/modules/osfile/osfile_unix_allthreads.jsm",
"resource://gre/modules/osfile/osfile_unix_back.jsm",
"resource://gre/modules/osfile/osfile_shared_front.jsm",
"resource://gre/modules/osfile/osfile_unix_front.jsm"

View File

@ -61,6 +61,9 @@ let maketest = function(prefix, test) {
utils.info("Complete");
}, function catch_uncaught_errors(err) {
utils.fail("Uncaught error " + err);
if (err && typeof err == "object" && "message" in err) {
utils.fail("(" + err.message + ")");
}
if (err && typeof err == "object" && "stack" in err) {
utils.fail("at " + err.stack);
}
@ -924,12 +927,9 @@ let test_duration = maketest("duration", function duration(test) {
test.ok(copyOptions.outExecutionDuration >= backupDuration, "duration has increased 3");
OS.File.remove(pathDest);
OS.Shared.TEST = true;
// Testing an operation that doesn't take arguments at all
let file = yield OS.File.open(pathSource);
yield file.stat();
yield file.close();
Services.prefs.setBoolPref("toolkit.osfile.log", false);
});
});

View File

@ -4,7 +4,7 @@
function worker_handler(worker) {
worker.onerror = function(error) {
error.preventDefault();
ok(false, "error "+error);
ok(false, "Worker error " + error.message);
}
worker.onmessage = function(msg) {
ok(true, "MAIN: onmessage " + JSON.stringify(msg.data));

View File

@ -2,6 +2,10 @@
* http://creativecommons.org/publicdomain/zero/1.0/ */
importScripts('worker_test_osfile_shared.js');
importScripts("resource://gre/modules/workers/require.js");
let SharedAll = require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
SharedAll.Config.DEBUG = true;
function should_throw(f) {
try {
@ -59,9 +63,9 @@ function test_offsetby() {
}
// Walk through the array with offsetBy by 8 bits
let uint8 = OS.Shared.Type.uint8_t.in_ptr.implementation(buf);
let uint8 = SharedAll.Type.uint8_t.in_ptr.implementation(buf);
for (i = 0; i < LENGTH; ++i) {
let value = OS.Shared.offsetBy(uint8, i).contents;
let value = SharedAll.offsetBy(uint8, i).contents;
if (value != i%256) {
is(value, i % 256, "test_offsetby: Walking through array with offsetBy (8 bits)");
break;
@ -69,10 +73,10 @@ function test_offsetby() {
}
// Walk again by 16 bits
let uint16 = OS.Shared.Type.uint16_t.in_ptr.implementation(buf);
let uint16 = SharedAll.Type.uint16_t.in_ptr.implementation(buf);
let view2 = new Uint16Array(buf);
for (i = 0; i < LENGTH/2; ++i) {
let value = OS.Shared.offsetBy(uint16, i).contents;
let value = SharedAll.offsetBy(uint16, i).contents;
if (value != view2[i]) {
is(value, view2[i], "test_offsetby: Walking through array with offsetBy (16 bits)");
break;
@ -80,15 +84,15 @@ function test_offsetby() {
}
// Ensure that offsetBy(..., 0) is idempotent
let startptr = OS.Shared.offsetBy(uint8, 0);
let startptr2 = OS.Shared.offsetBy(startptr, 0);
let startptr = SharedAll.offsetBy(uint8, 0);
let startptr2 = SharedAll.offsetBy(startptr, 0);
is(startptr.toString(), startptr2.toString(), "test_offsetby: offsetBy(..., 0) is idmpotent");
// Ensure that offsetBy(ptr, ...) does not work if ptr is a void*
let ptr = ctypes.voidptr_t(0);
let exn;
try {
OS.Shared.Utils.offsetBy(ptr, 1);
SharedAll.offsetBy(ptr, 1);
} catch (x) {
exn = x;
}

View File

@ -145,6 +145,10 @@ function run_test()
do_print("Testing the presence of ospath.jsm");
let Scope = {};
Components.utils.import("resource://gre/modules/osfile/ospath.jsm", Scope);
try {
Components.utils.import("resource://gre/modules/osfile/ospath.jsm", Scope);
} catch (ex) {
// Can't load ospath
}
do_check_true(!!Scope.basename);
}