mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-25 22:01:30 +00:00
Merge m-c to inbound.
This commit is contained in:
commit
2c159d6099
@ -4862,10 +4862,17 @@ function toggleSidebar(commandID, forceOpen) {
|
||||
|
||||
if (sidebarBroadcaster.getAttribute("checked") == "true") {
|
||||
if (!forceOpen) {
|
||||
// Replace the document currently displayed in the sidebar with about:blank
|
||||
// so that we can free memory by unloading the page. We need to explicitly
|
||||
// create a new content viewer because the old one doesn't get destroyed
|
||||
// until about:blank has loaded (which does not happen as long as the
|
||||
// element is hidden).
|
||||
sidebar.setAttribute("src", "about:blank");
|
||||
sidebar.docShell.createAboutBlankContentViewer(null);
|
||||
|
||||
sidebarBroadcaster.removeAttribute("checked");
|
||||
sidebarBox.setAttribute("sidebarcommand", "");
|
||||
sidebarTitle.value = "";
|
||||
sidebar.setAttribute("src", "about:blank");
|
||||
sidebarBox.hidden = true;
|
||||
sidebarSplitter.hidden = true;
|
||||
content.focus();
|
||||
|
@ -426,7 +426,7 @@ class ShutdownLeakLogger(object):
|
||||
DOM windows (that are still around after test suite shutdown, despite running
|
||||
the GC) to the tests that created them and prints leak statistics.
|
||||
"""
|
||||
MAX_LEAK_COUNT = 5
|
||||
MAX_LEAK_COUNT = 3
|
||||
|
||||
def __init__(self, logger):
|
||||
self.logger = logger
|
||||
|
@ -10,6 +10,7 @@
|
||||
#if defined(XP_UNIX)
|
||||
#include "unistd.h"
|
||||
#include "dirent.h"
|
||||
#include "sys/stat.h"
|
||||
#endif // defined(XP_UNIX)
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
@ -277,6 +278,18 @@ static dom::ConstantSpec gLibcProperties[] =
|
||||
INT_CONSTANT(DT_SOCK),
|
||||
#endif // defined(DT_UNKNOWN)
|
||||
|
||||
#if defined(S_IFIFO)
|
||||
// Constants for |stat|
|
||||
INT_CONSTANT(S_IFMT),
|
||||
INT_CONSTANT(S_IFIFO),
|
||||
INT_CONSTANT(S_IFCHR),
|
||||
INT_CONSTANT(S_IFDIR),
|
||||
INT_CONSTANT(S_IFBLK),
|
||||
INT_CONSTANT(S_IFREG),
|
||||
INT_CONSTANT(S_IFLNK),
|
||||
INT_CONSTANT(S_IFSOCK),
|
||||
#endif // defined(S_IFIFO)
|
||||
|
||||
// Constants used to define data structures
|
||||
//
|
||||
// Many data structures have different fields/sizes/etc. on
|
||||
@ -289,6 +302,15 @@ static dom::ConstantSpec gLibcProperties[] =
|
||||
// The size of |mode_t|.
|
||||
{ "OSFILE_SIZEOF_MODE_T", INT_TO_JSVAL(sizeof (mode_t)) },
|
||||
|
||||
// The size of |gid_t|.
|
||||
{ "OSFILE_SIZEOF_GID_T", INT_TO_JSVAL(sizeof (gid_t)) },
|
||||
|
||||
// The size of |uid_t|.
|
||||
{ "OSFILE_SIZEOF_UID_T", INT_TO_JSVAL(sizeof (uid_t)) },
|
||||
|
||||
// The size of |time_t|.
|
||||
{ "OSFILE_SIZEOF_TIME_T", INT_TO_JSVAL(sizeof (time_t)) },
|
||||
|
||||
// Defining |dirent|.
|
||||
// Size
|
||||
{ "OSFILE_SIZEOF_DIRENT", INT_TO_JSVAL(sizeof (dirent)) },
|
||||
@ -306,9 +328,30 @@ static dom::ConstantSpec gLibcProperties[] =
|
||||
{ "OSFILE_OFFSETOF_DIRENT_D_TYPE", INT_TO_JSVAL(offsetof (struct dirent, d_type)) },
|
||||
#endif // defined(DT_UNKNOWN)
|
||||
|
||||
|
||||
// Defining |stat|
|
||||
|
||||
{ "OSFILE_SIZEOF_STAT", INT_TO_JSVAL(sizeof (struct stat)) },
|
||||
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_MODE", INT_TO_JSVAL(offsetof (struct stat, st_mode)) },
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_UID", INT_TO_JSVAL(offsetof (struct stat, st_uid)) },
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_GID", INT_TO_JSVAL(offsetof (struct stat, st_gid)) },
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_SIZE", INT_TO_JSVAL(offsetof (struct stat, st_size)) },
|
||||
|
||||
#if defined(HAVE_ST_ATIMESPEC)
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_ATIME", INT_TO_JSVAL(offsetof (struct stat, st_atimespec)) },
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_MTIME", INT_TO_JSVAL(offsetof (struct stat, st_mtimespec)) },
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_CTIME", INT_TO_JSVAL(offsetof (struct stat, st_ctimespec)) },
|
||||
#else
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_ATIME", INT_TO_JSVAL(offsetof (struct stat, st_atime)) },
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_MTIME", INT_TO_JSVAL(offsetof (struct stat, st_mtime)) },
|
||||
{ "OSFILE_OFFSETOF_STAT_ST_CTIME", INT_TO_JSVAL(offsetof (struct stat, st_ctime)) },
|
||||
#endif // defined(HAVE_ST_ATIME)
|
||||
|
||||
#endif // defined(XP_UNIX)
|
||||
|
||||
|
||||
|
||||
// System configuration
|
||||
|
||||
// Under MacOSX, to avoid using deprecated functions that do not
|
||||
@ -318,8 +361,13 @@ static dom::ConstantSpec gLibcProperties[] =
|
||||
// whenever macro _DARWIN_FEATURE_64_BIT_INODE is set. We export
|
||||
// this value to be able to do so from JavaScript.
|
||||
#if defined(_DARWIN_FEATURE_64_BIT_INODE)
|
||||
{ "_DARWIN_FEATURE_64_BIT_INODE", INT_TO_JSVAL(1) },
|
||||
#endif // defind(_DARWIN_FEATURE_64_BIT_INODE)
|
||||
{ "_DARWIN_FEATURE_64_BIT_INODE", INT_TO_JSVAL(1) },
|
||||
#endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
|
||||
|
||||
// Similar feature for Linux
|
||||
#if defined(_STAT_VER)
|
||||
INT_CONSTANT(_STAT_VER),
|
||||
#endif // defined(_STAT_VER)
|
||||
|
||||
PROP_END
|
||||
};
|
||||
@ -368,6 +416,7 @@ static dom::ConstantSpec gWinProperties[] =
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
|
||||
INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),
|
||||
|
||||
// CreateFile error constant
|
||||
{ "INVALID_HANDLE_VALUE", INT_TO_JSVAL(INT_PTR(INVALID_HANDLE_VALUE)) },
|
||||
|
@ -151,16 +151,23 @@
|
||||
/**
|
||||
* Attach a finalizer to a type.
|
||||
*/
|
||||
releaseWith: function(finalizer) {
|
||||
releaseWith: function releaseWith(finalizer) {
|
||||
let parent = this;
|
||||
let type = new Type("[auto " + finalizer +"] " + this.name,
|
||||
this.implementation,
|
||||
function (value, operation) {
|
||||
function release(value, operation) {
|
||||
return ctypes.CDataFinalizer(
|
||||
parent.convert_from_c(value, operation),
|
||||
finalizer);
|
||||
});
|
||||
return type;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return an alias to a type with a different name.
|
||||
*/
|
||||
withName: function withName(name) {
|
||||
return Object.create(this, {name: {value: name}});
|
||||
}
|
||||
};
|
||||
|
||||
@ -177,12 +184,7 @@
|
||||
return parseInt(x.toString(), 10);
|
||||
};
|
||||
let projectLargeUInt = function projectLargeUInt(x) {
|
||||
if (ctypes.UInt64.hi(x)) {
|
||||
throw new Error("Number too large " + x +
|
||||
"(unsigned, hi: " + ctypes.UInt64.hi(x) +
|
||||
", lo:" + ctypes.UInt64.lo(x) + ")");
|
||||
}
|
||||
return ctypes.UInt64.lo(x);
|
||||
return parseInt(x.toString(), 10);
|
||||
};
|
||||
let projectValue = function projectValue(x) {
|
||||
if (!(x instanceof ctypes.CData)) {
|
||||
@ -479,7 +481,7 @@
|
||||
* @param {CType|Type} type The type of the field.
|
||||
*/
|
||||
add_field_at: function add_field_at(offset, name, type) {
|
||||
if (offset === null) {
|
||||
if (offset == null) {
|
||||
throw new TypeError("add_field_at requires a non-null offset");
|
||||
}
|
||||
if (!name) {
|
||||
|
@ -146,10 +146,14 @@
|
||||
/**
|
||||
* Type |mode_t|
|
||||
*/
|
||||
Types.mode_t = Object.create(
|
||||
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_MODE_T),
|
||||
{name: {value: "mode_t"}});
|
||||
Types.mode_t =
|
||||
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_MODE_T).withName("mode_t");
|
||||
|
||||
/**
|
||||
* Type |time_t|
|
||||
*/
|
||||
Types.time_t =
|
||||
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_TIME_T).withName("time_t");
|
||||
|
||||
Types.DIR =
|
||||
new Type("DIR",
|
||||
@ -191,6 +195,36 @@
|
||||
new Type("null_of_dirent",
|
||||
Types.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", ctypes.int);
|
||||
stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_GID,
|
||||
"st_gid", ctypes.int);
|
||||
|
||||
// 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(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_SIZE,
|
||||
"st_size", Types.size_t.implementation);
|
||||
Types.stat = stat.getType();
|
||||
}
|
||||
|
||||
|
||||
// Declare libc functions as functions of |OS.Unix.File|
|
||||
|
||||
// Finalizer-related functions
|
||||
@ -315,6 +349,22 @@
|
||||
/*fd*/ Types.fd,
|
||||
/*length*/ Types.off_t);
|
||||
|
||||
if (OS.Constants.libc._DARWIN_FEATURE_64_BIT_INODE) {
|
||||
UnixFile.fstat =
|
||||
declareFFI("fstat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
);
|
||||
} else {
|
||||
UnixFile.fstat =
|
||||
declareFFI("fstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
);
|
||||
}
|
||||
|
||||
UnixFile.lchown =
|
||||
declareFFI("lchown", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
@ -449,13 +499,88 @@
|
||||
|
||||
// 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) {
|
||||
// MacOS X 64-bits
|
||||
UnixFile.stat =
|
||||
declareFFI("stat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.string,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
);
|
||||
UnixFile.lstat =
|
||||
declareFFI("lstat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.string,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
);
|
||||
UnixFile.fstat =
|
||||
declareFFI("fstat$INODE64", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
);
|
||||
} else if (OS.Constants.libc._STAT_VER != undefined) {
|
||||
const ver = OS.Constants.libc._STAT_VER;
|
||||
// Linux, all widths
|
||||
let xstat =
|
||||
declareFFI("__xstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Types.int,
|
||||
/*path*/ Types.string,
|
||||
/*buf*/ Types.stat.out_ptr);
|
||||
let lxstat =
|
||||
declareFFI("__lxstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Types.int,
|
||||
/*path*/ Types.string,
|
||||
/*buf*/ Types.stat.out_ptr);
|
||||
let fxstat =
|
||||
declareFFI("__fxstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*_stat_ver*/ Types.int,
|
||||
/*fd*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr);
|
||||
|
||||
UnixFile.stat = function stat(path, buf) {
|
||||
return xstat(ver, path, buf);
|
||||
};
|
||||
UnixFile.lstat = function stat(path, buf) {
|
||||
return lxstat(ver, path, buf);
|
||||
};
|
||||
UnixFile.fstat = function stat(fd, buf) {
|
||||
return fxstat(ver, fd, buf);
|
||||
};
|
||||
} else {
|
||||
// Mac OS X 32-bits, other Unix
|
||||
UnixFile.stat =
|
||||
declareFFI("stat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.string,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
);
|
||||
UnixFile.lstat =
|
||||
declareFFI("lstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*path*/ Types.string,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
);
|
||||
UnixFile.fstat =
|
||||
declareFFI("fstat", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fd*/ Types.fd,
|
||||
/*buf*/ Types.stat.out_ptr
|
||||
);
|
||||
}
|
||||
|
||||
// We cannot make a C array of CDataFinalizer, so
|
||||
// pipe cannot be directly defined as a C function.
|
||||
|
||||
let _pipe =
|
||||
declareFFI("pipe", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*fds*/ Types.int.out_ptr);
|
||||
libc.declare("pipe", ctypes.default_abi,
|
||||
/*return*/ ctypes.int,
|
||||
/*fds*/ ctypes.ArrayType(ctypes.int, 2));
|
||||
|
||||
// A shared per-thread buffer used to communicate with |pipe|
|
||||
let _pipebuf = new (ctypes.ArrayType(ctypes.int, 2))();
|
||||
|
@ -160,6 +160,16 @@
|
||||
return throw_on_negative("setPosition",
|
||||
UnixFile.lseek(this.fd, pos, whence)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch the information on the file.
|
||||
*
|
||||
* @return File.Info The information on |this| file.
|
||||
*/
|
||||
stat: function stat() {
|
||||
throw_on_negative("stat", UnixFile.fstat(this.fd, gStatDataPtr));
|
||||
return new File.Info(gStatData);
|
||||
}
|
||||
};
|
||||
|
||||
@ -674,7 +684,7 @@
|
||||
/**
|
||||
* |true| if the entry is a symbolic link, |false| otherwise
|
||||
*/
|
||||
get isLink() {
|
||||
get isSymLink() {
|
||||
return this._d_type == OS.Constants.libc.DT_LNK;
|
||||
},
|
||||
|
||||
@ -697,6 +707,126 @@
|
||||
}
|
||||
};
|
||||
|
||||
let gStatData = new OS.Shared.Type.stat.implementation();
|
||||
let gStatDataPtr = gStatData.address();
|
||||
let MODE_MASK = 4095 /*= 07777*/;
|
||||
File.Info = function Info(stat) {
|
||||
this._st_mode = stat.st_mode;
|
||||
this._st_uid = stat.st_uid;
|
||||
this._st_gid = stat.st_gid;
|
||||
this._st_atime = stat.st_atime;
|
||||
this._st_mtime = stat.st_mtime;
|
||||
this._st_ctime = stat.st_ctime;
|
||||
this._st_size = stat.st_size;
|
||||
};
|
||||
File.Info.prototype = {
|
||||
/**
|
||||
* |true| if this file is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return (this._st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFDIR;
|
||||
},
|
||||
/**
|
||||
* |true| if this file is a symbolink link, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return (this._st_mode & OS.Constants.libc.S_IFMT) == OS.Constants.libc.S_IFLNK;
|
||||
},
|
||||
/**
|
||||
* 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() {
|
||||
delete this.size;
|
||||
let size;
|
||||
try {
|
||||
size = OS.Shared.projectValue(this._st_size);
|
||||
} catch(x) {
|
||||
LOG("get size error", x);
|
||||
size = NaN;
|
||||
}
|
||||
Object.defineProperty(this, "size", { value: size });
|
||||
return size;
|
||||
},
|
||||
/**
|
||||
* The date of creation of this file
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
get creationDate() {
|
||||
delete this.creationDate;
|
||||
let date = new Date(this._st_ctime * 1000);
|
||||
Object.defineProperty(this, "creationDate", { value: date });
|
||||
return date;
|
||||
},
|
||||
/**
|
||||
* 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() {
|
||||
delete this.lastAccessDate;
|
||||
let date = new Date(this._st_atime * 1000);
|
||||
Object.defineProperty(this, "lastAccessDate", {value: date});
|
||||
return date;
|
||||
},
|
||||
/**
|
||||
* Return the date of last modification of this file.
|
||||
*/
|
||||
get lastModificationDate() {
|
||||
delete this.lastModificationDate;
|
||||
let date = new Date(this._st_mtime * 1000);
|
||||
Object.defineProperty(this, "lastModificationDate", {value: date});
|
||||
return date;
|
||||
},
|
||||
/**
|
||||
* Return the Unix owner of this file.
|
||||
*/
|
||||
get unixOwner() {
|
||||
return this._st_uid;
|
||||
},
|
||||
/**
|
||||
* Return the Unix group of this file.
|
||||
*/
|
||||
get unixGroup() {
|
||||
return this._st_gid;
|
||||
},
|
||||
/**
|
||||
* Return the Unix mode of this file.
|
||||
*/
|
||||
get unixMode() {
|
||||
return this._st_mode & MODE_MASK;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch the information on a file.
|
||||
*
|
||||
* @param {string} path The full name of the file to open.
|
||||
* @param {*=} options Additional options. In this implementation:
|
||||
*
|
||||
* - {bool} unixNoFollowingLinks If set and |true|, if |path|
|
||||
* represents a symbolic link, the call will return the information
|
||||
* of the link itself, rather than that of the target file.
|
||||
*
|
||||
* @return {File.Information}
|
||||
*/
|
||||
File.stat = function stat(path, options) {
|
||||
options = options || noOptions;
|
||||
if (options.unixNoFollowingLinks) {
|
||||
throw_on_negative("stat", UnixFile.lstat(path, gStatDataPtr));
|
||||
} else {
|
||||
throw_on_negative("stat", UnixFile.stat(path, gStatDataPtr));
|
||||
}
|
||||
return new File.Info(gStatData);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get/set the current directory.
|
||||
|
@ -145,7 +145,7 @@
|
||||
ctypes.StructType("FILETIME", [
|
||||
{ lo: Types.DWORD.implementation },
|
||||
{ hi: Types.DWORD.implementation }]));
|
||||
|
||||
|
||||
Types.FindData =
|
||||
new Type("FIND_DATA",
|
||||
ctypes.StructType("FIND_DATA", [
|
||||
@ -160,7 +160,21 @@
|
||||
{ cFileName: ctypes.ArrayType(ctypes.jschar, exports.OS.Constants.Win.MAX_PATH) },
|
||||
{ cAlternateFileName: ctypes.ArrayType(ctypes.jschar, 14) }
|
||||
]));
|
||||
|
||||
|
||||
Types.FILE_INFORMATION =
|
||||
new Type("FILE_INFORMATION",
|
||||
ctypes.StructType("FILE_INFORMATION", [
|
||||
{ dwFileAttributes: ctypes.uint32_t },
|
||||
{ ftCreationTime: Types.FILETIME.implementation },
|
||||
{ ftLastAccessTime: Types.FILETIME.implementation },
|
||||
{ ftLastWriteTime: Types.FILETIME.implementation },
|
||||
{ dwVolumeSerialNumber: ctypes.uint32_t },
|
||||
{ nFileSizeHigh: Types.DWORD.implementation },
|
||||
{ nFileSizeLow: Types.DWORD.implementation },
|
||||
{ nNumberOfLinks: ctypes.uint32_t },
|
||||
{ nFileIndex: ctypes.uint64_t }
|
||||
]));
|
||||
|
||||
Types.SystemTime =
|
||||
new Type("SystemTime",
|
||||
ctypes.StructType("SystemTime", [
|
||||
@ -256,6 +270,12 @@
|
||||
/*buf*/ Types.jschar.out_ptr
|
||||
);
|
||||
|
||||
WinFile.GetFileInformationByHandle =
|
||||
declareFFI("GetFileInformationByHandle", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*handle*/ Types.HANDLE,
|
||||
/*info*/ Types.FILE_INFORMATION.out_ptr);
|
||||
|
||||
WinFile.MoveFileEx =
|
||||
declareFFI("MoveFileExW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
|
@ -46,6 +46,10 @@
|
||||
let gBytesWritten = new ctypes.int32_t(-1);
|
||||
let gBytesWrittenPtr = gBytesWritten.address();
|
||||
|
||||
// Same story for GetFileInformationByHandle
|
||||
let gFileInfo = new OS.Shared.Type.FILE_INFORMATION.implementation();
|
||||
let gFileInfoPtr = gFileInfo.address();
|
||||
|
||||
/**
|
||||
* Representation of a file.
|
||||
*
|
||||
@ -179,7 +183,18 @@
|
||||
// OS.File.POS_END == OS.Constants.Win.FILE_END
|
||||
whence = (whence == undefined)?Const.FILE_BEGIN:whence;
|
||||
return throw_on_negative("setPosition",
|
||||
WinFile.SetFilePointer(this.fd, pos, null, whence));
|
||||
WinFile.SetFilePointer(this.fd, pos, null, whence));
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch the information on the file.
|
||||
*
|
||||
* @return File.Info The information on |this| file.
|
||||
*/
|
||||
stat: function stat() {
|
||||
throw_on_zero("stat",
|
||||
WinFile.GetFileInformationByHandle(this.fd, gFileInfoPtr));
|
||||
return new File.Info(gFileInfo);
|
||||
}
|
||||
};
|
||||
|
||||
@ -321,7 +336,7 @@
|
||||
*/
|
||||
File.open = function Win_open(path, mode, options) {
|
||||
options = options || noOptions;
|
||||
|
||||
mode = mode || noOptions;
|
||||
let share = options.winShare || DEFAULT_SHARE;
|
||||
let security = options.winSecurity || null;
|
||||
let flags = options.winFlags || DEFAULT_FLAGS;
|
||||
@ -471,17 +486,21 @@
|
||||
* Utility function: convert a FILETIME to a JavaScript Date.
|
||||
*/
|
||||
let FILETIME_to_Date = function FILETIME_to_Date(fileTime) {
|
||||
LOG("fileTimeToDate:", fileTime);
|
||||
if (fileTime == null) {
|
||||
throw new TypeError("Expecting a non-null filetime");
|
||||
}
|
||||
LOG("fileTimeToDate normalized:", fileTime);
|
||||
throw_on_zero("FILETIME_to_Date", WinFile.FileTimeToSystemTime(fileTime.address(),
|
||||
throw_on_zero("FILETIME_to_Date",
|
||||
WinFile.FileTimeToSystemTime(fileTime.address(),
|
||||
gSystemTimePtr));
|
||||
return new Date(gSystemTime.wYear, gSystemTime.wMonth,
|
||||
gSystemTime.wDay, gSystemTime.wHour,
|
||||
gSystemTime.wMinute, gSystemTime.wSecond,
|
||||
gSystemTime.wMilliSeconds);
|
||||
// Windows counts hours, minutes, seconds from UTC,
|
||||
// JS counts from local time, so we need to go through UTC.
|
||||
let utc = Date.UTC(gSystemTime.wYear,
|
||||
gSystemTime.wMonth - 1
|
||||
/*Windows counts months from 1, JS from 0*/,
|
||||
gSystemTime.wDay, gSystemTime.wHour,
|
||||
gSystemTime.wMinute, gSystemTime.wSecond,
|
||||
gSystemTime.wMilliSeconds);
|
||||
return new Date(utc);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -615,13 +634,13 @@
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return this._dwFileAttributes & Const.FILE_ATTRIBUTE_DIRECTORY;
|
||||
return !!(this._dwFileAttributes & Const.FILE_ATTRIBUTE_DIRECTORY);
|
||||
},
|
||||
/**
|
||||
* |true| if the entry is a symbolic link, |false| otherwise
|
||||
*/
|
||||
get isLink() {
|
||||
return this._dwFileAttributes & Const.FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
get isSymLink() {
|
||||
return !!(this._dwFileAttributes & Const.FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
},
|
||||
/**
|
||||
* The name of the entry.
|
||||
@ -672,6 +691,129 @@
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Information on a file.
|
||||
*
|
||||
* To obtain the latest information on a file, use |File.stat|
|
||||
* (for an unopened file) or |File.prototype.stat| (for an
|
||||
* already opened file).
|
||||
*
|
||||
* @constructor
|
||||
*/
|
||||
File.Info = function Info(stat) {
|
||||
this._dwFileAttributes = stat.dwFileAttributes;
|
||||
this._ftCreationTime = stat.ftCreationTime;
|
||||
this._ftLastAccessTime = stat.ftLastAccessTime;
|
||||
this._ftLastWriteTime = stat.ftLastAccessTime;
|
||||
this._nFileSizeHigh = stat.nFileSizeHigh;
|
||||
this._nFileSizeLow = stat.nFileSizeLow;
|
||||
};
|
||||
File.Info.prototype = {
|
||||
/**
|
||||
* |true| if this file is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return !!(this._dwFileAttributes & Const.FILE_ATTRIBUTE_DIRECTORY);
|
||||
},
|
||||
/**
|
||||
* |true| if this file is a symbolink link, |false| otherwise
|
||||
*/
|
||||
get isSymLink() {
|
||||
return !!(this._dwFileAttributes & Const.FILE_ATTRIBUTE_REPARSE_POINT);
|
||||
},
|
||||
/**
|
||||
* 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() {
|
||||
try {
|
||||
return OS.Shared.projectValue(
|
||||
ctypes.uint64_t("" +
|
||||
this._nFileSizeHigh +
|
||||
this._nFileSizeLow));
|
||||
} catch (x) {
|
||||
return NaN;
|
||||
}
|
||||
},
|
||||
/**
|
||||
* The date of creation of this file
|
||||
*
|
||||
* @type {Date}
|
||||
*/
|
||||
get creationDate() {
|
||||
delete this.creationDate;
|
||||
let date = FILETIME_to_Date(this._ftCreationTime);
|
||||
Object.defineProperty(this, "creationDate", { value: date });
|
||||
return date;
|
||||
},
|
||||
/**
|
||||
* 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() {
|
||||
delete this.lastAccess;
|
||||
let date = FILETIME_to_Date(this._ftLastAccessTime);
|
||||
Object.defineProperty(this, "lastAccessDate", { value: date });
|
||||
return date;
|
||||
},
|
||||
/**
|
||||
* Return 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() {
|
||||
delete this.lastModification;
|
||||
let date = FILETIME_to_Date(this._ftLastWriteTime);
|
||||
Object.defineProperty(this, "lastModificationDate", { value: date });
|
||||
return date;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch the information on a file.
|
||||
*
|
||||
* Performance note: if you have opened the file already,
|
||||
* method |File.prototype.stat| is generally much faster
|
||||
* than method |File.stat|.
|
||||
*
|
||||
* Platform-specific note: under Windows, if the file is
|
||||
* already opened without sharing of the read capability,
|
||||
* this function will fail.
|
||||
*
|
||||
* @return {File.Information}
|
||||
*/
|
||||
File.stat = function stat(path) {
|
||||
let file = File.open(path, FILE_STAT_MODE, FILE_STAT_OPTIONS);
|
||||
try {
|
||||
return file.stat();
|
||||
} finally {
|
||||
file.close();
|
||||
}
|
||||
};
|
||||
// All of the following is required to ensure that File.stat
|
||||
// also works on directories.
|
||||
const FILE_STAT_MODE = {
|
||||
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
|
||||
};
|
||||
|
||||
/**
|
||||
* Get/set the current directory.
|
||||
*/
|
||||
|
@ -27,7 +27,6 @@ function test() {
|
||||
ok(false, "error "+error);
|
||||
}
|
||||
worker.onmessage = function(msg) {
|
||||
ok(true, "MAIN: onmessage "+JSON.stringify(msg));
|
||||
switch (msg.data.kind) {
|
||||
case "is":
|
||||
return SimpleTest.is(msg.data.a, msg.data.b, msg.data.description);
|
||||
@ -36,6 +35,7 @@ function test() {
|
||||
case "ok":
|
||||
return SimpleTest.ok(msg.data.condition, msg.data.description);
|
||||
case "finish":
|
||||
worker.terminate();
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
default:
|
||||
|
@ -9,9 +9,9 @@ function send(message) {
|
||||
self.postMessage(message);
|
||||
}
|
||||
|
||||
self.onmessage = function(msg) {
|
||||
self.onmessage = function(msg) {
|
||||
log("ignored message "+JSON.stringify(msg.data));
|
||||
self.onmessage = function onmessage_start(msg) {
|
||||
self.onmessage = function onmessage_ignored(msg) {
|
||||
log("ignored message " + JSON.stringify(msg.data));
|
||||
};
|
||||
try {
|
||||
test_init();
|
||||
@ -21,6 +21,7 @@ self.onmessage = function(msg) {
|
||||
test_read_write_file();
|
||||
test_move_file();
|
||||
test_iter_dir();
|
||||
test_info();
|
||||
} catch (x) {
|
||||
log("Catching error: " + x);
|
||||
log("Stack: " + x.stack);
|
||||
@ -143,7 +144,7 @@ function test_read_write_file()
|
||||
bytesAvailable = source.read(buf, 4096)) {
|
||||
let bytesWritten = dest.write(buf, bytesAvailable);
|
||||
if (bytesWritten != bytesAvailable) {
|
||||
eq(bytesWritten, bytesAvailable, "test_read_write_file: writing all bytes");
|
||||
is(bytesWritten, bytesAvailable, "test_read_write_file: writing all bytes");
|
||||
}
|
||||
}
|
||||
|
||||
@ -220,7 +221,7 @@ function test_iter_dir()
|
||||
if (entry.name == tmp_file_name) {
|
||||
encountered_tmp_file = true;
|
||||
isnot(entry.isDir, "test_iter_dir: The temporary file is not a directory");
|
||||
isnot(entry.isLink, "test_iter_dir: The temporary file is not a link");
|
||||
isnot(entry.isSymLink, "test_iter_dir: The temporary file is not a link");
|
||||
}
|
||||
|
||||
let file;
|
||||
@ -259,3 +260,96 @@ function test_iter_dir()
|
||||
iterator.close();
|
||||
ok(true, "test_iter_dir: Complete");
|
||||
}
|
||||
|
||||
function test_info() {
|
||||
ok(true, "test_info: Starting");
|
||||
|
||||
let filename = "test_info.tmp";
|
||||
let size = 261;// An arbitrary file length
|
||||
let start = new Date();
|
||||
|
||||
// Cleanup any leftover from previous tests
|
||||
try {
|
||||
OS.File.remove(filename);
|
||||
ok(true, "test_info: Cleaned up previous garbage");
|
||||
} catch (x) {
|
||||
if (!x.becauseNoSuchFile) {
|
||||
throw x;
|
||||
}
|
||||
ok(true, "test_info: No previous garbage");
|
||||
}
|
||||
|
||||
let file = OS.File.open(filename, {trunc: true});
|
||||
let buf = new ArrayBuffer(size);
|
||||
file.write(buf, size);
|
||||
file.close();
|
||||
|
||||
// Test OS.File.stat on new file
|
||||
let info = OS.File.stat(filename);
|
||||
ok(!!info, "test_info: info acquired");
|
||||
ok(!info.isDir, "test_info: file is not a directory");
|
||||
is(info.isSymLink, false, "test_info: file is not a link");
|
||||
is(info.size.toString(), size, "test_info: correct size");
|
||||
|
||||
let stop = new Date();
|
||||
|
||||
// We round down/up by 1s as file system precision is lower than Date precision
|
||||
let startMs = start.getTime() - 1000;
|
||||
let stopMs = stop.getTime() + 1000;
|
||||
|
||||
let birth = info.creationDate;
|
||||
ok(birth.getTime() <= stopMs,
|
||||
"test_info: file was created before now - " + stop + ", " + birth);
|
||||
// Note: Previous versions of this test checked whether the file has
|
||||
// been created after the start of the test. Unfortunately, this sometimes
|
||||
// failed under Windows, in specific circumstances: if the file has been
|
||||
// removed at the start of the test and recreated immediately, the Windows
|
||||
// file system detects this and decides that the file was actually truncated
|
||||
// rather than recreated, hence that it should keep its previous creation date.
|
||||
// Debugging hilarity ensues.
|
||||
|
||||
let change = info.lastModificationDate;
|
||||
ok(change.getTime() >= startMs
|
||||
&& change.getTime() <= stopMs,
|
||||
"test_info: file has changed between the start of the test and now - " + start + ", " + stop + ", " + change);
|
||||
|
||||
// Test OS.File.prototype.stat on new file
|
||||
file = OS.File.open(filename);
|
||||
try {
|
||||
info = file.stat();
|
||||
} finally {
|
||||
file.close();
|
||||
}
|
||||
|
||||
ok(!!info, "test_info: info acquired 2");
|
||||
ok(!info.isDir, "test_info: file is not a directory 2");
|
||||
ok(!info.isSymLink, "test_info: file is not a link 2");
|
||||
is(info.size.toString(), size, "test_info: correct size 2");
|
||||
|
||||
stop = new Date();
|
||||
|
||||
// We round down/up by 1s as file system precision is lower than Date precision
|
||||
startMs = start.getTime() - 1000;
|
||||
stopMs = stop.getTime() + 1000;
|
||||
|
||||
birth = info.creationDate;
|
||||
ok(birth.getTime() <= stopMs,
|
||||
"test_info: file 2 was created between the start of the test and now - " + start + ", " + stop + ", " + birth);
|
||||
|
||||
let access = info.lastModificationDate;
|
||||
ok(access.getTime() >= startMs
|
||||
&& access.getTime() <= stopMs,
|
||||
"test_info: file 2 was accessed between the start of the test and now - " + start + ", " + stop + ", " + access);
|
||||
|
||||
change = info.lastModificationDate;
|
||||
ok(change.getTime() >= startMs
|
||||
&& change.getTime() <= stopMs,
|
||||
"test_info: file 2 has changed between the start of the test and now - " + start + ", " + stop + ", " + change);
|
||||
|
||||
// Test OS.File.stat on directory
|
||||
info = OS.File.stat(OS.File.curDir);
|
||||
ok(!!info, "test_info: info on directory acquired");
|
||||
ok(info.isDir, "test_info: directory is a directory");
|
||||
|
||||
ok(true, "test_info: Complete");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user