Merge m-c to inbound.

This commit is contained in:
Ryan VanderMeulen 2012-07-22 10:34:53 -04:00
commit 2c159d6099
10 changed files with 609 additions and 40 deletions

View File

@ -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();

View File

@ -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

View File

@ -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)) },

View File

@ -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) {

View File

@ -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))();

View File

@ -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.

View File

@ -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,

View File

@ -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.
*/

View File

@ -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:

View File

@ -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");
}