mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge m-c to fx-team
This commit is contained in:
commit
647b0f1dc7
@ -1023,7 +1023,7 @@ pref("services.sync.prefs.sync.xpinstall.whitelist.required", true);
|
||||
pref("devtools.errorconsole.enabled", false);
|
||||
|
||||
// Developer toolbar and GCLI preferences
|
||||
pref("devtools.toolbar.enabled", false);
|
||||
pref("devtools.toolbar.enabled", true);
|
||||
pref("devtools.toolbar.visible", false);
|
||||
pref("devtools.gcli.allowSet", false);
|
||||
pref("devtools.commands.dir", "");
|
||||
|
@ -519,7 +519,6 @@
|
||||
autocheck="false"
|
||||
hidden="true"
|
||||
label="&devToolbarMenu.label;"
|
||||
accesskey="&devToolbarMenu.accesskey;"
|
||||
key="key_devToolbar"
|
||||
command="Tools:DevToolbar"/>
|
||||
<menuitem id="webConsole"
|
||||
|
@ -225,13 +225,6 @@
|
||||
#endif
|
||||
<key id="key_openAddons" key="&addons.commandkey;" command="Tools:Addons" modifiers="accel,shift"/>
|
||||
<key id="key_errorConsole" key="&errorConsoleCmd.commandkey;" oncommand="toJavaScriptConsole();" modifiers="accel,shift" disabled="true"/>
|
||||
<key id="key_devToolbar" key="&devToolbar.commandkey;" command="Tools:DevToolbar"
|
||||
#ifdef XP_MACOSX
|
||||
modifiers="accel,alt"
|
||||
#else
|
||||
modifiers="accel,shift"
|
||||
#endif
|
||||
/>
|
||||
<key id="key_webConsole" key="&webConsoleCmd.commandkey;" oncommand="HUDConsoleUI.toggleHUD();"
|
||||
#ifdef XP_MACOSX
|
||||
modifiers="accel,alt"
|
||||
|
@ -6868,6 +6868,10 @@ FocusManager.prototype._checkShow = function() {
|
||||
* available inputs
|
||||
*/
|
||||
FocusManager.prototype._shouldShowTooltip = function() {
|
||||
if (!this._hasFocus) {
|
||||
return { visible: false, reason: '!hasFocus' };
|
||||
}
|
||||
|
||||
if (eagerHelper.value === Eagerness.NEVER) {
|
||||
return { visible: false, reason: 'eagerHelper !== NEVER' };
|
||||
}
|
||||
@ -6896,6 +6900,10 @@ FocusManager.prototype._shouldShowTooltip = function() {
|
||||
* available inputs
|
||||
*/
|
||||
FocusManager.prototype._shouldShowOutput = function() {
|
||||
if (!this._hasFocus) {
|
||||
return { visible: false, reason: '!hasFocus' };
|
||||
}
|
||||
|
||||
if (this._recentOutput) {
|
||||
return { visible: true, reason: 'recentOutput' };
|
||||
}
|
||||
|
@ -179,6 +179,9 @@ DeveloperToolbar.prototype._onload = function DT_onload()
|
||||
scratchpad: null
|
||||
});
|
||||
|
||||
this.display.focusManager.addMonitoredElement(this.outputPanel._frame);
|
||||
this.display.focusManager.addMonitoredElement(this._element);
|
||||
|
||||
this.display.onVisibilityChange.add(this.outputPanel._visibilityChanged, this.outputPanel);
|
||||
this.display.onVisibilityChange.add(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
|
||||
this.display.onOutput.add(this.outputPanel._outputChanged, this.outputPanel);
|
||||
@ -187,7 +190,6 @@ DeveloperToolbar.prototype._onload = function DT_onload()
|
||||
this._chromeWindow.getBrowser().tabContainer.addEventListener("TabClose", this, false);
|
||||
this._chromeWindow.getBrowser().addEventListener("load", this, true);
|
||||
this._chromeWindow.getBrowser().addEventListener("beforeunload", this, true);
|
||||
this._chromeWindow.addEventListener("resize", this, false);
|
||||
|
||||
this._initErrorsCount(this._chromeWindow.getBrowser().selectedTab);
|
||||
|
||||
@ -307,11 +309,13 @@ DeveloperToolbar.prototype.destroy = function DT_destroy()
|
||||
this._chromeWindow.getBrowser().tabContainer.removeEventListener("TabSelect", this, false);
|
||||
this._chromeWindow.getBrowser().removeEventListener("load", this, true);
|
||||
this._chromeWindow.getBrowser().removeEventListener("beforeunload", this, true);
|
||||
this._chromeWindow.removeEventListener("resize", this, false);
|
||||
|
||||
let tabs = this._chromeWindow.getBrowser().tabs;
|
||||
Array.prototype.forEach.call(tabs, this._stopErrorsCount, this);
|
||||
|
||||
this.display.focusManager.removeMonitoredElement(this.outputPanel._frame);
|
||||
this.display.focusManager.removeMonitoredElement(this._element);
|
||||
|
||||
this.display.onVisibilityChange.remove(this.outputPanel._visibilityChanged, this.outputPanel);
|
||||
this.display.onVisibilityChange.remove(this.tooltipPanel._visibilityChanged, this.tooltipPanel);
|
||||
this.display.onOutput.remove(this.outputPanel._outputChanged, this.outputPanel);
|
||||
@ -368,9 +372,6 @@ DeveloperToolbar.prototype.handleEvent = function DT_handleEvent(aEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (aEvent.type == "resize") {
|
||||
this.outputPanel._resize();
|
||||
}
|
||||
else if (aEvent.type == "TabClose") {
|
||||
this._stopErrorsCount(aEvent.target);
|
||||
}
|
||||
@ -812,7 +813,7 @@ TooltipPanel.prototype._resize = function TP_resize()
|
||||
}
|
||||
|
||||
let offset = 10 + Math.floor(this._dimensions.start * AVE_CHAR_WIDTH);
|
||||
this._frame.style.marginLeft = offset + "px";
|
||||
this._panel.style.marginLeft = offset + "px";
|
||||
|
||||
/*
|
||||
// Bug 744906: UX review - Not sure if we want this code to fatten connector
|
||||
|
2
browser/devtools/shared/test/browser_toolbar_tooltip.js
Executable file → Normal file
2
browser/devtools/shared/test/browser_toolbar_tooltip.js
Executable file → Normal file
@ -40,6 +40,6 @@ function runTest() {
|
||||
}
|
||||
|
||||
function getLeftMargin() {
|
||||
let style = DeveloperToolbar.tooltipPanel._frame.style.marginLeft;
|
||||
let style = DeveloperToolbar.tooltipPanel._panel.style.marginLeft;
|
||||
return parseInt(style.slice(0, -2), 10);
|
||||
}
|
||||
|
@ -237,8 +237,6 @@ These should match what Safari and other Apple applications use on OS X Lion. --
|
||||
|
||||
<!ENTITY devToolbarCloseButton.tooltiptext "Close Developer Toolbar">
|
||||
<!ENTITY devToolbarMenu.label "Developer Toolbar">
|
||||
<!ENTITY devToolbarMenu.accesskey "v">
|
||||
<!ENTITY devToolbar.commandkey "v">
|
||||
|
||||
<!ENTITY webConsoleButton.label "Web Console">
|
||||
<!ENTITY inspectorButton.label "Inspector">
|
||||
|
@ -2398,6 +2398,7 @@ html|*#gcli-output-frame {
|
||||
#gcli-tooltip {
|
||||
border-width: 0;
|
||||
background-color: transparent;
|
||||
-moz-appearance: none;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
margin-top: -1px;
|
||||
margin-left: 8px;
|
||||
width: 20px;
|
||||
height: 0;
|
||||
height: 10px;
|
||||
border-left: 1px solid hsl(210,11%,10%);
|
||||
border-right: 1px solid hsl(210,11%,10%);
|
||||
background-color: hsl(210,11%,16%);
|
||||
|
@ -3139,6 +3139,7 @@ html|*#gcli-output-frame {
|
||||
#gcli-tooltip {
|
||||
border-width: 0;
|
||||
background-color: transparent;
|
||||
-moz-appearance: none;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
|
@ -32,10 +32,11 @@
|
||||
margin-top: -1px;
|
||||
margin-left: 8px;
|
||||
width: 20px;
|
||||
height: 0;
|
||||
height: 10px;
|
||||
border-left: 1px solid hsl(210,11%,10%);
|
||||
border-right: 1px solid hsl(210,11%,10%);
|
||||
background-color: hsl(210,11%,16%);
|
||||
background-image: url(background-noise-toolbar.png);
|
||||
}
|
||||
|
||||
.gcli-tt-description,
|
||||
|
@ -3073,6 +3073,7 @@ html|*#gcli-output-frame {
|
||||
#gcli-tooltip {
|
||||
border-width: 0;
|
||||
background-color: transparent;
|
||||
-moz-appearance: none;
|
||||
margin-bottom: -2px;
|
||||
}
|
||||
|
||||
|
@ -2584,6 +2584,37 @@ nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static PLDHashOperator
|
||||
CloneSessionStorages(nsCStringHashKey::KeyType aKey, nsIDOMStorage* aStorage,
|
||||
void* aUserArg)
|
||||
{
|
||||
nsIDocShell *docShell = static_cast<nsIDocShell*>(aUserArg);
|
||||
nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(aStorage);
|
||||
|
||||
if (pistorage) {
|
||||
nsCOMPtr<nsIDOMStorage> storage = pistorage->Clone();
|
||||
docShell->AddSessionStorage(pistorage->Principal(), storage);
|
||||
}
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::CloneSessionStoragesTo(nsIDocShell* aDocShell)
|
||||
{
|
||||
aDocShell->ClearSessionStorages();
|
||||
mStorages.EnumerateRead(CloneSessionStorages, aDocShell);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::ClearSessionStorages()
|
||||
{
|
||||
mStorages.Clear();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetCurrentDocumentChannel(nsIChannel** aResult)
|
||||
{
|
||||
|
@ -39,7 +39,7 @@ interface nsIWebBrowserPrint;
|
||||
interface nsIVariant;
|
||||
interface nsIPrivacyTransitionObserver;
|
||||
|
||||
[scriptable, uuid(6f60ac96-fa2c-41a5-92b4-29aaadbd7a7b)]
|
||||
[scriptable, builtinclass, uuid(89ea9f32-18ec-413b-9e2c-ce9a4c851b1c)]
|
||||
interface nsIDocShell : nsISupports
|
||||
{
|
||||
/**
|
||||
@ -434,6 +434,19 @@ interface nsIDocShell : nsISupports
|
||||
*/
|
||||
void addSessionStorage(in nsIPrincipal principal, in nsIDOMStorage storage);
|
||||
|
||||
/**
|
||||
* Clones all session storage objects and attaches them to the given docshell.
|
||||
* Useful when duplicating tabs and their states.
|
||||
*
|
||||
* @param docShell the docshell to clone the sessionstorage objects to
|
||||
*/
|
||||
void cloneSessionStoragesTo(in nsIDocShell docShell);
|
||||
|
||||
/**
|
||||
* Removes all WebApps session storage objects attached to the docshell.
|
||||
*/
|
||||
void clearSessionStorages();
|
||||
|
||||
/**
|
||||
* Gets the channel for the currently loaded document, if any.
|
||||
* For a new document load, this will be the channel of the previous document
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
#include "unistd.h"
|
||||
#include "dirent.h"
|
||||
#endif // defined(XP_UNIX)
|
||||
|
||||
#if defined(XP_MACOSX)
|
||||
@ -264,6 +265,19 @@ static dom::ConstantSpec gLibcProperties[] =
|
||||
#endif // defined(EWOULDBLOCK)
|
||||
INT_CONSTANT(EXDEV),
|
||||
|
||||
#if defined(DT_UNKNOWN)
|
||||
// Constants for |readdir|
|
||||
INT_CONSTANT(DT_UNKNOWN),
|
||||
INT_CONSTANT(DT_FIFO),
|
||||
INT_CONSTANT(DT_CHR),
|
||||
INT_CONSTANT(DT_DIR),
|
||||
INT_CONSTANT(DT_BLK),
|
||||
INT_CONSTANT(DT_REG),
|
||||
INT_CONSTANT(DT_LNK),
|
||||
INT_CONSTANT(DT_SOCK),
|
||||
INT_CONSTANT(DT_WHT),
|
||||
#endif // defined(DT_UNKNOWN)
|
||||
|
||||
// Constants used to define data structures
|
||||
//
|
||||
// Many data structures have different fields/sizes/etc. on
|
||||
@ -274,9 +288,40 @@ static dom::ConstantSpec gLibcProperties[] =
|
||||
|
||||
#if defined(XP_UNIX)
|
||||
// The size of |mode_t|.
|
||||
{"OSFILE_SIZEOF_MODE_T", INT_TO_JSVAL(sizeof (mode_t)) },
|
||||
{ "OSFILE_SIZEOF_MODE_T", INT_TO_JSVAL(sizeof (mode_t)) },
|
||||
|
||||
// Defining |dirent|.
|
||||
// Size
|
||||
{ "OSFILE_SIZEOF_DIRENT", INT_TO_JSVAL(sizeof (dirent)) },
|
||||
|
||||
// Offset of field |d_name|.
|
||||
{ "OSFILE_OFFSETOF_DIRENT_D_NAME", INT_TO_JSVAL(offsetof (struct dirent, d_name)) },
|
||||
// An upper bound to the length of field |d_name| of struct |dirent|.
|
||||
// (may not be exact, depending on padding).
|
||||
{ "OSFILE_SIZEOF_DIRENT_D_NAME", INT_TO_JSVAL(sizeof (struct dirent) - offsetof (struct dirent, d_name)) },
|
||||
|
||||
#if defined(DT_UNKNOWN)
|
||||
// Position of field |d_type| in |dirent|
|
||||
// Not strictly posix, but seems defined on all platforms
|
||||
// except mingw32.
|
||||
{ "OSFILE_OFFSETOF_DIRENT_D_TYPE", INT_TO_JSVAL(offsetof (struct dirent, d_type)) },
|
||||
#endif // defined(DT_UNKNOWN)
|
||||
|
||||
#endif // defined(XP_UNIX)
|
||||
|
||||
|
||||
// System configuration
|
||||
|
||||
// Under MacOSX, to avoid using deprecated functions that do not
|
||||
// match the constants we define in this object (including
|
||||
// |sizeof|/|offsetof| stuff, but not only), for a number of
|
||||
// functions, we need to adapt the name of the symbols we are using,
|
||||
// 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)
|
||||
|
||||
PROP_END
|
||||
};
|
||||
|
||||
@ -296,6 +341,9 @@ static dom::ConstantSpec gWinProperties[] =
|
||||
INT_CONSTANT(FORMAT_MESSAGE_FROM_SYSTEM),
|
||||
INT_CONSTANT(FORMAT_MESSAGE_IGNORE_INSERTS),
|
||||
|
||||
// The max length of paths
|
||||
INT_CONSTANT(MAX_PATH),
|
||||
|
||||
// CreateFile desired access
|
||||
INT_CONSTANT(GENERIC_ALL),
|
||||
INT_CONSTANT(GENERIC_EXECUTE),
|
||||
@ -319,6 +367,7 @@ static dom::ConstantSpec gWinProperties[] =
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
|
||||
|
||||
// CreateFile error constant
|
||||
@ -336,14 +385,19 @@ static dom::ConstantSpec gWinProperties[] =
|
||||
// SetFilePointer error constant
|
||||
INT_CONSTANT(INVALID_SET_FILE_POINTER),
|
||||
|
||||
// File attributes
|
||||
INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
|
||||
|
||||
|
||||
// MoveFile flags
|
||||
INT_CONSTANT(MOVEFILE_COPY_ALLOWED),
|
||||
INT_CONSTANT(MOVEFILE_REPLACE_EXISTING),
|
||||
|
||||
// Errors
|
||||
INT_CONSTANT(ERROR_ACCESS_DENIED),
|
||||
INT_CONSTANT(ERROR_FILE_EXISTS),
|
||||
INT_CONSTANT(ERROR_FILE_NOT_FOUND),
|
||||
INT_CONSTANT(ERROR_ACCESS_DENIED),
|
||||
INT_CONSTANT(ERROR_NO_MORE_FILES),
|
||||
|
||||
PROP_END
|
||||
};
|
||||
|
@ -440,6 +440,147 @@
|
||||
ctypes.ssize_t,
|
||||
projector(ctypes.ssize_t, true));
|
||||
|
||||
|
||||
/**
|
||||
* Utility class, used to build a |struct| type
|
||||
* from a set of field names, types and offsets.
|
||||
*
|
||||
* @param {string} name The name of the |struct| type.
|
||||
* @param {number} size The total size of the |struct| type in bytes.
|
||||
*/
|
||||
function HollowStructure(name, size) {
|
||||
if (!name) {
|
||||
throw new TypeError("HollowStructure expects a name");
|
||||
}
|
||||
if (!size || size < 0) {
|
||||
throw new TypeError("HollowStructure expects a (positive) size");
|
||||
}
|
||||
|
||||
// A mapping from offsets in the struct to name/type pairs
|
||||
// (or nothing if no field starts at that offset).
|
||||
this.offset_to_field_info = [];
|
||||
|
||||
// The name of the struct
|
||||
this.name = name;
|
||||
|
||||
// The size of the struct, in bytes
|
||||
this.size = size;
|
||||
|
||||
// The number of paddings inserted so far.
|
||||
// Used to give distinct names to padding fields.
|
||||
this._paddings = 0;
|
||||
}
|
||||
HollowStructure.prototype = {
|
||||
/**
|
||||
* Add a field at a given offset.
|
||||
*
|
||||
* @param {number} offset The offset at which to insert the field.
|
||||
* @param {string} name The name of the field.
|
||||
* @param {CType|Type} type The type of the field.
|
||||
*/
|
||||
add_field_at: function add_field_at(offset, name, type) {
|
||||
if (offset === null) {
|
||||
throw new TypeError("add_field_at requires a non-null offset");
|
||||
}
|
||||
if (!name) {
|
||||
throw new TypeError("add_field_at requires a non-null name");
|
||||
}
|
||||
if (!type) {
|
||||
throw new TypeError("add_field_at requires a non-null type");
|
||||
}
|
||||
if (type instanceof Type) {
|
||||
type = type.implementation;
|
||||
}
|
||||
if (this.offset_to_field_info[offset]) {
|
||||
throw new Error("HollowStructure " + this.name +
|
||||
" already has a field at offset " + offset);
|
||||
}
|
||||
if (offset + type.size > this.size) {
|
||||
throw new Error("HollowStructure " + this.name +
|
||||
" cannot place a value of type " + type +
|
||||
" at offset " + offset +
|
||||
" without exceeding its size of " + this.size);
|
||||
}
|
||||
let field = {name: name, type:type};
|
||||
this.offset_to_field_info[offset] = field;
|
||||
},
|
||||
|
||||
/**
|
||||
* Create a pseudo-field that will only serve as padding.
|
||||
*
|
||||
* @param {number} size The number of bytes in the field.
|
||||
* @return {Object} An association field-name => field-type,
|
||||
* as expected by |ctypes.StructType|.
|
||||
*/
|
||||
_makePaddingField: function makePaddingField(size) {
|
||||
let field = ({});
|
||||
field["padding_" + this._paddings] =
|
||||
ctypes.ArrayType(ctypes.uint8_t, size);
|
||||
this._paddings++;
|
||||
return field;
|
||||
},
|
||||
|
||||
/**
|
||||
* Convert this |HollowStructure| into a |Type|.
|
||||
*/
|
||||
getType: function getType() {
|
||||
// Contents of the structure, in the format expected
|
||||
// by ctypes.StructType.
|
||||
let struct = [];
|
||||
|
||||
let i = 0;
|
||||
while (i < this.size) {
|
||||
let currentField = this.offset_to_field_info[i];
|
||||
if (!currentField) {
|
||||
// No field was specified at this offset, we need to
|
||||
// introduce some padding.
|
||||
|
||||
// Firstly, determine how many bytes of padding
|
||||
let padding_length = 1;
|
||||
while (i + padding_length < this.size
|
||||
&& !this.offset_to_field_info[i + padding_length]) {
|
||||
++padding_length;
|
||||
}
|
||||
|
||||
// Then add the padding
|
||||
struct.push(this._makePaddingField(padding_length));
|
||||
|
||||
// And proceed
|
||||
i += padding_length;
|
||||
} else {
|
||||
// We have a field at this offset.
|
||||
|
||||
// Firstly, ensure that we do not have two overlapping fields
|
||||
for (let j = 1; j < currentField.type.size; ++j) {
|
||||
let candidateField = this.offset_to_field_info[i + j];
|
||||
if (candidateField) {
|
||||
throw new Error("Fields " + currentField.name +
|
||||
" and " + candidateField.name +
|
||||
" overlap at position " + (i + j));
|
||||
}
|
||||
}
|
||||
|
||||
// Then add the field
|
||||
let field = ({});
|
||||
field[currentField.name] = currentField.type;
|
||||
struct.push(field);
|
||||
|
||||
// And proceed
|
||||
i += currentField.type.size;
|
||||
}
|
||||
}
|
||||
let result = new Type(this.name, ctypes.StructType(this.name, struct));
|
||||
if (result.implementation.size != this.size) {
|
||||
throw new Error("Wrong size for type " + this.name +
|
||||
": expected " + this.size +
|
||||
", found " + result.implementation.size +
|
||||
" (" + result.implementation.toSource() + ")");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
exports.OS.Shared.HollowStructure = HollowStructure;
|
||||
|
||||
/**
|
||||
* Declare a function through js-ctypes
|
||||
*
|
||||
@ -473,6 +614,10 @@
|
||||
let argtypes = [];
|
||||
for (let i = 3; i < arguments.length; ++i) {
|
||||
let current = arguments[i];
|
||||
if (!current) {
|
||||
throw new TypeError("Missing type for argument " + ( i - 3 ) +
|
||||
" of symbol " + symbol);
|
||||
}
|
||||
if (!current.implementation) {
|
||||
throw new TypeError("Missing implementation for argument " + (i - 3)
|
||||
+ " of symbol " + symbol
|
||||
|
@ -46,7 +46,7 @@
|
||||
|
||||
// Open libc
|
||||
let libc;
|
||||
let libc_candidates = [ "libSystem.dylib",
|
||||
let libc_candidates = [ "libsystem.B.dylib",
|
||||
"libc.so.6",
|
||||
"libc.so" ];
|
||||
for (let i = 0; i < libc_candidates.length; ++i) {
|
||||
@ -150,6 +150,47 @@
|
||||
Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_MODE_T),
|
||||
{name: {value: "mode_t"}});
|
||||
|
||||
|
||||
Types.DIR =
|
||||
new Type("DIR",
|
||||
ctypes.StructType("DIR"));
|
||||
|
||||
Types.null_or_DIR_ptr =
|
||||
new Type("null_or_DIR*",
|
||||
Types.DIR.out_ptr.implementation,
|
||||
function(dir, operation) {
|
||||
if (dir == null || dir.isNull()) {
|
||||
return null;
|
||||
}
|
||||
return ctypes.CDataFinalizer(dir, _close_dir);
|
||||
});
|
||||
|
||||
// Structure |dirent|
|
||||
// Building this type is rather complicated, as its layout varies between
|
||||
// variants of Unix. For this reason, we rely on a number of constants
|
||||
// (computed in C from the C data structures) that give us the layout.
|
||||
// The structure we compute looks like
|
||||
// { int8_t[...] before_d_type; // ignored content
|
||||
// int8_t d_type ;
|
||||
// int8_t[...] before_d_name; // ignored content
|
||||
// char[...] d_name;
|
||||
// };
|
||||
{
|
||||
let dirent = new OS.Shared.HollowStructure("dirent",
|
||||
OS.Constants.libc.OSFILE_SIZEOF_DIRENT);
|
||||
dirent.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_TYPE,
|
||||
"d_type", ctypes.uint8_t);
|
||||
dirent.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_DIRENT_D_NAME,
|
||||
"d_name", ctypes.ArrayType(ctypes.char, OS.Constants.libc.OSFILE_SIZEOF_DIRENT_D_NAME));
|
||||
|
||||
// We now have built |dirent|.
|
||||
Types.dirent = dirent.getType();
|
||||
LOG("dirent is: " + Types.dirent.implementation.toSource());
|
||||
}
|
||||
Types.null_or_dirent_ptr =
|
||||
new Type("null_of_dirent",
|
||||
Types.dirent.out_ptr.implementation);
|
||||
|
||||
// Declare libc functions as functions of |OS.Unix.File|
|
||||
|
||||
// Finalizer-related functions
|
||||
@ -163,6 +204,16 @@
|
||||
return fd.dispose();
|
||||
};
|
||||
|
||||
let _close_dir =
|
||||
libc.declare("closedir", ctypes.default_abi,
|
||||
/*return */ctypes.int,
|
||||
/*dirp*/ Types.DIR.in_ptr.implementation);
|
||||
|
||||
UnixFile.closedir = function closedir(fd) {
|
||||
// Detach the finalizer and call |_close_dir|.
|
||||
return fd.dispose();
|
||||
};
|
||||
|
||||
UnixFile.free =
|
||||
libc.declare("free", ctypes.default_abi,
|
||||
/*return*/ ctypes.void_t,
|
||||
@ -284,6 +335,12 @@
|
||||
/*offset*/ Types.off_t,
|
||||
/*whence*/ Types.int);
|
||||
|
||||
UnixFile.mkdir =
|
||||
declareFFI("mkdir", ctypes.default_abi,
|
||||
/*return*/ Types.int,
|
||||
/*path*/ Types.string,
|
||||
/*mode*/ Types.int);
|
||||
|
||||
UnixFile.mkstemp =
|
||||
declareFFI("mkstemp", ctypes.default_abi,
|
||||
/*return*/ Types.null_or_string,
|
||||
@ -296,6 +353,11 @@
|
||||
/*oflags*/Types.int,
|
||||
/*mode*/ Types.int);
|
||||
|
||||
UnixFile.opendir =
|
||||
declareFFI("opendir", ctypes.default_abi,
|
||||
/*return*/ Types.null_or_DIR_ptr,
|
||||
/*path*/ Types.string);
|
||||
|
||||
UnixFile.pread =
|
||||
declareFFI("pread", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_ssize_t,
|
||||
@ -319,12 +381,33 @@
|
||||
/*buf*/ Types.char.out_ptr,
|
||||
/*nbytes*/Types.size_t);
|
||||
|
||||
if (OS.Constants.libc._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 =
|
||||
declareFFI("readdir$INODE64", ctypes.default_abi,
|
||||
/*return*/Types.null_or_dirent_ptr,
|
||||
/*dir*/ Types.DIR.in_ptr); // For MacOS X
|
||||
} else {
|
||||
UnixFile.readdir =
|
||||
declareFFI("readdir", ctypes.default_abi,
|
||||
/*return*/Types.null_or_dirent_ptr,
|
||||
/*dir*/ Types.DIR.in_ptr); // Other Unices
|
||||
}
|
||||
|
||||
UnixFile.rename =
|
||||
declareFFI("rename", ctypes.default_abi,
|
||||
/*return*/ Types.negativeone_or_nothing,
|
||||
/*old*/ Types.string,
|
||||
/*new*/ Types.string);
|
||||
|
||||
UnixFile.rmdir =
|
||||
declareFFI("rmdir", ctypes.default_abi,
|
||||
/*return*/ Types.int,
|
||||
/*path*/ Types.string);
|
||||
|
||||
UnixFile.splice =
|
||||
declareFFI("splice", ctypes.default_abi,
|
||||
/*return*/ Types.long,
|
||||
|
@ -590,6 +590,112 @@
|
||||
|
||||
} // End of definition of copy/move
|
||||
|
||||
/**
|
||||
* Iterate on one directory.
|
||||
*
|
||||
* This iterator will not enter subdirectories.
|
||||
*
|
||||
* @param {string} path The directory upon which to iterate.
|
||||
* @param {*=} options Ignored in this implementation.
|
||||
*
|
||||
* @throws {File.Error} If |path| does not represent a directory or
|
||||
* if the directory cannot be iterated.
|
||||
* @constructor
|
||||
*/
|
||||
File.DirectoryIterator = function DirectoryIterator(path, options) {
|
||||
let dir = throw_on_null("DirectoryIterator", UnixFile.opendir(path));
|
||||
this._dir = dir;
|
||||
this._path = path;
|
||||
};
|
||||
File.DirectoryIterator.prototype = {
|
||||
__iterator__: function __iterator__() {
|
||||
return this;
|
||||
},
|
||||
/**
|
||||
* Return the next entry in the directory, if any such entry is
|
||||
* available.
|
||||
*
|
||||
* Skip special directories "." and "..".
|
||||
*
|
||||
* @return {File.Entry} The next entry in the directory.
|
||||
* @throws {StopIteration} Once all files in the directory have been
|
||||
* encountered.
|
||||
*/
|
||||
next: function next() {
|
||||
if (!this._dir) {
|
||||
throw StopIteration;
|
||||
}
|
||||
for (let entry = UnixFile.readdir(this._dir);
|
||||
entry != null && !entry.isNull();
|
||||
entry = UnixFile.readdir(this._dir)) {
|
||||
let contents = entry.contents;
|
||||
if (contents.d_type == OS.Constants.libc.DT_DIR) {
|
||||
let name = contents.d_name.readString();
|
||||
if (name == "." || name == "..") {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
return new File.DirectoryIterator.Entry(contents, this._path);
|
||||
}
|
||||
this.close();
|
||||
throw StopIteration;
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the iterator and recover all resources.
|
||||
* You should call this once you have finished iterating on a directory.
|
||||
*/
|
||||
close: function close() {
|
||||
if (!this._dir) return;
|
||||
UnixFile.closedir(this._dir);
|
||||
this._dir = null;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* An entry in a directory.
|
||||
*/
|
||||
File.DirectoryIterator.Entry = function Entry(unix_entry, parent) {
|
||||
// Copy the relevant part of |unix_entry| to ensure that
|
||||
// our data is not overwritten prematurely.
|
||||
this._d_type = unix_entry.d_type;
|
||||
this._name = unix_entry.d_name.readString();
|
||||
this._parent = parent;
|
||||
};
|
||||
File.DirectoryIterator.Entry.prototype = {
|
||||
/**
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
return this._d_type == OS.Constants.libc.DT_DIR;
|
||||
},
|
||||
|
||||
/**
|
||||
* |true| if the entry is a symbolic link, |false| otherwise
|
||||
*/
|
||||
get isLink() {
|
||||
return this._d_type == OS.Constants.libc.DT_LNK;
|
||||
},
|
||||
|
||||
/**
|
||||
* The name of the entry.
|
||||
* @type {string}
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
|
||||
/**
|
||||
* The full path to the entry.
|
||||
*/
|
||||
get path() {
|
||||
delete this.path;
|
||||
let path = OS.Unix.Path.join(this._parent, this.name);
|
||||
Object.defineProperty(this, "path", {value: path});
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Get/set the current directory.
|
||||
@ -601,11 +707,10 @@
|
||||
);
|
||||
},
|
||||
get: function() {
|
||||
let path = UnixFile.getwd(null);
|
||||
if (path.isNull()) {
|
||||
throw new File.Error("getwd");
|
||||
}
|
||||
return ctypes.CDataFinalizer(path, UnixFile.free);
|
||||
let path = UnixFile.get_current_dir_name?UnixFile.get_current_dir_name():
|
||||
UnixFile.getwd_auto(null);
|
||||
throw_on_null("curDir",path);
|
||||
return path.readString();
|
||||
}
|
||||
}
|
||||
);
|
||||
@ -638,6 +743,13 @@
|
||||
return result;
|
||||
}
|
||||
|
||||
function throw_on_null(operation, result) {
|
||||
if (result == null || (result.isNull && result.isNull())) {
|
||||
throw new File.Error(operation);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
File.POS_START = exports.OS.Constants.libc.SEEK_SET;
|
||||
File.POS_CURRENT = exports.OS.Constants.libc.SEEK_CUR;
|
||||
File.POS_END = exports.OS.Constants.libc.SEEK_END;
|
||||
|
@ -94,6 +94,24 @@
|
||||
}
|
||||
return ctypes.CDataFinalizer(maybe, _CloseHandle);
|
||||
});
|
||||
|
||||
/**
|
||||
* A C integer holding INVALID_HANDLE_VALUE in case of error or
|
||||
* a file descriptor in case of success.
|
||||
*/
|
||||
Types.maybe_find_HANDLE =
|
||||
new Type("maybe_find_HANDLE",
|
||||
Types.HANDLE.implementation,
|
||||
function (maybe) {
|
||||
if (ctypes.cast(maybe, ctypes.int).value == invalid_handle) {
|
||||
// Ensure that API clients can effectively compare against
|
||||
// Const.INVALID_HANDLE_VALUE. Without this cast,
|
||||
// == would always return |false|.
|
||||
return invalid_handle;
|
||||
}
|
||||
return ctypes.CDataFinalizer(maybe, _FindClose);
|
||||
});
|
||||
|
||||
let invalid_handle = exports.OS.Constants.Win.INVALID_HANDLE_VALUE;
|
||||
|
||||
Types.DWORD = Types.int32_t;
|
||||
@ -122,6 +140,40 @@
|
||||
new Type("zero_or_nothing",
|
||||
Types.bool.implementation);
|
||||
|
||||
Types.FILETIME =
|
||||
new Type("FILETIME",
|
||||
ctypes.StructType("FILETIME", [
|
||||
{ lo: Types.DWORD.implementation },
|
||||
{ hi: Types.DWORD.implementation }]));
|
||||
|
||||
Types.FindData =
|
||||
new 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) },
|
||||
{ cAlternateFileName: ctypes.ArrayType(ctypes.jschar, 14) }
|
||||
]));
|
||||
|
||||
Types.SystemTime =
|
||||
new Type("SystemTime",
|
||||
ctypes.StructType("SystemTime", [
|
||||
{ wYear: ctypes.int16_t },
|
||||
{ wMonth: ctypes.int16_t },
|
||||
{ wDayOfWeek: ctypes.int16_t },
|
||||
{ wDay: ctypes.int16_t },
|
||||
{ wHour: ctypes.int16_t },
|
||||
{ wMinute: ctypes.int16_t },
|
||||
{ wSecond: ctypes.int16_t },
|
||||
{ wMilliSeconds: ctypes.int16_t }
|
||||
]));
|
||||
|
||||
// Special case: these functions are used by the
|
||||
// finalizer
|
||||
let _CloseHandle =
|
||||
@ -133,6 +185,15 @@
|
||||
return fd.dispose(); // Returns the value of |CloseHandle|.
|
||||
};
|
||||
|
||||
let _FindClose =
|
||||
libc.declare("CloseHandle", ctypes.winapi_abi,
|
||||
/*return */ctypes.bool,
|
||||
/*handle*/ ctypes.voidptr_t);
|
||||
|
||||
WinFile.FindClose = function(handle) {
|
||||
return handle.dispose(); // Returns the value of |CloseHandle|.
|
||||
};
|
||||
|
||||
// Declare libc functions as functions of |OS.Win.File|
|
||||
|
||||
WinFile.CopyFile =
|
||||
@ -158,6 +219,24 @@
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*path*/ Types.jschar.in_ptr);
|
||||
|
||||
WinFile.FileTimeToSystemTime =
|
||||
declareFFI("FileTimeToSystemTime", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*filetime*/Types.FILETIME.in_ptr,
|
||||
/*systime*/ Types.SystemTime.out_ptr);
|
||||
|
||||
WinFile.FindFirstFile =
|
||||
declareFFI("FindFirstFileW", ctypes.winapi_abi,
|
||||
/*return*/ Types.maybe_find_HANDLE,
|
||||
/*pattern*/Types.jschar.in_ptr,
|
||||
/*data*/ Types.FindData.out_ptr);
|
||||
|
||||
WinFile.FindNextFile =
|
||||
declareFFI("FindNextFileW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*prev*/ Types.HANDLE,
|
||||
/*data*/ Types.FindData.out_ptr);
|
||||
|
||||
WinFile.FormatMessage =
|
||||
declareFFI("FormatMessageW", ctypes.winapi_abi,
|
||||
/*return*/ Types.DWORD,
|
||||
@ -195,6 +274,11 @@
|
||||
/*overlapped*/Types.void_t.inout_ptr // FIXME: Implement?
|
||||
);
|
||||
|
||||
WinFile.RemoveDirectory =
|
||||
declareFFI("RemoveDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
/*path*/ Types.jschar.in_ptr);
|
||||
|
||||
WinFile.SetCurrentDirectory =
|
||||
declareFFI("SetCurrentDirectoryW", ctypes.winapi_abi,
|
||||
/*return*/ Types.zero_or_nothing,
|
||||
|
@ -453,12 +453,230 @@
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* A global value used to receive data during a
|
||||
* |FindFirstFile|/|FindNextFile|.
|
||||
*/
|
||||
let gFindData = new OS.Shared.Type.FindData.implementation();
|
||||
let gFindDataPtr = gFindData.address();
|
||||
|
||||
/**
|
||||
* A global value used to receive data during time conversions.
|
||||
*/
|
||||
let gSystemTime = new OS.Shared.Type.SystemTime.implementation();
|
||||
let gSystemTimePtr = gSystemTime.address();
|
||||
|
||||
/**
|
||||
* 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(),
|
||||
gSystemTimePtr));
|
||||
return new Date(gSystemTime.wYear, gSystemTime.wMonth,
|
||||
gSystemTime.wDay, gSystemTime.wHour,
|
||||
gSystemTime.wMinute, gSystemTime.wSecond,
|
||||
gSystemTime.wMilliSeconds);
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterate on one directory.
|
||||
*
|
||||
* This iterator will not enter subdirectories.
|
||||
*
|
||||
* @param {string} path The directory upon which to iterate.
|
||||
* @param {*=} options Ignored in this implementation.
|
||||
*
|
||||
* @throws {File.Error} If |path| does not represent a directory or
|
||||
* if the directory cannot be iterated.
|
||||
* @constructor
|
||||
*/
|
||||
File.DirectoryIterator = function DirectoryIterator(path, options) {
|
||||
if (options && options.winPattern) {
|
||||
this._pattern = path + "\\" + options.winPattern;
|
||||
} else {
|
||||
this._pattern = path + "\\*";
|
||||
}
|
||||
this._handle = null;
|
||||
this._path = path;
|
||||
this._started = false;
|
||||
};
|
||||
File.DirectoryIterator.prototype = {
|
||||
__iterator__: function __iterator__() {
|
||||
return this;
|
||||
},
|
||||
|
||||
/**
|
||||
* Fetch the next entry in the directory.
|
||||
*
|
||||
* @return null If we have reached the end of the directory.
|
||||
*/
|
||||
_next: function _next() {
|
||||
// Iterator is not fully initialized yet. Finish
|
||||
// initialization.
|
||||
if (!this._started) {
|
||||
this._started = true;
|
||||
this._handle = WinFile.FindFirstFile(this._pattern, gFindDataPtr);
|
||||
if (this._handle == null) {
|
||||
let error = ctypes.winLastError;
|
||||
if (error == Const.ERROR_FILE_NOT_FOUND) {
|
||||
this.close();
|
||||
return null;
|
||||
} else {
|
||||
throw new File.Error("iter (FindFirstFile)", error);
|
||||
}
|
||||
}
|
||||
return gFindData;
|
||||
}
|
||||
|
||||
// We have closed this iterator already.
|
||||
if (!this._handle) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (WinFile.FindNextFile(this._handle, gFindDataPtr)) {
|
||||
return gFindData;
|
||||
} else {
|
||||
let error = ctypes.winLastError;
|
||||
this.close();
|
||||
if (error == Const.ERROR_NO_MORE_FILES) {
|
||||
return null;
|
||||
} else {
|
||||
throw new File.Error("iter (FindNextFile)", error);
|
||||
}
|
||||
}
|
||||
},
|
||||
/**
|
||||
* Return the next entry in the directory, if any such entry is
|
||||
* available.
|
||||
*
|
||||
* Skip special directories "." and "..".
|
||||
*
|
||||
* @return {File.Entry} The next entry in the directory.
|
||||
* @throws {StopIteration} Once all files in the directory have been
|
||||
* encountered.
|
||||
*/
|
||||
next: function next() {
|
||||
// FIXME: If we start supporting "\\?\"-prefixed paths, do not forget
|
||||
// that "." and ".." are absolutely normal file names if _path starts
|
||||
// with such prefix
|
||||
for (let entry = this._next(); entry != null; entry = this._next()) {
|
||||
let name = entry.cFileName.readString();
|
||||
if (name == "." || name == "..") {
|
||||
continue;
|
||||
}
|
||||
return new File.DirectoryIterator.Entry(entry, this._path);
|
||||
}
|
||||
throw StopIteration;
|
||||
},
|
||||
close: function close() {
|
||||
if (!this._handle) {
|
||||
return;
|
||||
}
|
||||
WinFile.FindClose(this._handle);
|
||||
this._handle = null;
|
||||
}
|
||||
};
|
||||
File.DirectoryIterator.Entry = function Entry(win_entry, parent) {
|
||||
// Copy the relevant part of |win_entry| to ensure that
|
||||
// our data is not overwritten prematurely.
|
||||
if (!win_entry.dwFileAttributes) {
|
||||
throw new TypeError();
|
||||
}
|
||||
this._dwFileAttributes = win_entry.dwFileAttributes;
|
||||
this._name = win_entry.cFileName.readString();
|
||||
if (!this._name) {
|
||||
throw new TypeError("Empty name");
|
||||
}
|
||||
this._ftCreationTime = win_entry.ftCreationTime;
|
||||
if (!win_entry.ftCreationTime) {
|
||||
throw new TypeError();
|
||||
}
|
||||
this._ftLastAccessTime = win_entry.ftLastAccessTime;
|
||||
if (!win_entry.ftLastAccessTime) {
|
||||
throw new TypeError();
|
||||
}
|
||||
this._ftLastWriteTime = win_entry.ftLastWriteTime;
|
||||
if (!win_entry.ftLastWriteTime) {
|
||||
throw new TypeError();
|
||||
}
|
||||
if (!parent) {
|
||||
throw new TypeError("Empty parent");
|
||||
}
|
||||
this._parent = parent;
|
||||
};
|
||||
File.DirectoryIterator.Entry.prototype = {
|
||||
/**
|
||||
* |true| if the entry is a directory, |false| otherwise
|
||||
*/
|
||||
get isDir() {
|
||||
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;
|
||||
},
|
||||
/**
|
||||
* The name of the entry.
|
||||
* @type {string}
|
||||
*/
|
||||
get name() {
|
||||
return this._name;
|
||||
},
|
||||
/**
|
||||
* The creation time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winCreationTime() {
|
||||
let date = FILETIME_to_Date(this._ftCreationTime);
|
||||
delete this.winCreationTime;
|
||||
Object.defineProperty(this, "winCreationTime", {value: date});
|
||||
return date;
|
||||
},
|
||||
/**
|
||||
* The last modification time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winLastWriteTime() {
|
||||
let date = FILETIME_to_Date(this._ftLastWriteTime);
|
||||
delete this.winLastWriteTime;
|
||||
Object.defineProperty(this, "winLastWriteTime", {value: date});
|
||||
return date;
|
||||
},
|
||||
/**
|
||||
* The last access time of this file.
|
||||
* @type {Date}
|
||||
*/
|
||||
get winLastAccessTime() {
|
||||
let date = FILETIME_to_Date(this._ftLastAccessTime);
|
||||
delete this.winLastAccessTime;
|
||||
Object.defineProperty(this, "winLastAccessTime", {value: date});
|
||||
return date;
|
||||
},
|
||||
/**
|
||||
* The full path to the entry.
|
||||
* @type {string}
|
||||
*/
|
||||
get path() {
|
||||
delete this.path;
|
||||
let path = OS.Win.Path.join(this._parent, this.name);
|
||||
Object.defineProperty(this, "path", {value: path});
|
||||
return path;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get/set the current directory.
|
||||
*/
|
||||
Object.defineProperty(File, "curDir", {
|
||||
set: function(path) {
|
||||
throw_on_zero("set curDir",
|
||||
throw_on_zero("set curDir",
|
||||
WinFile.SetCurrentDirectory(path));
|
||||
},
|
||||
get: function() {
|
||||
|
@ -20,6 +20,7 @@ self.onmessage = function(msg) {
|
||||
test_copy_existing_file();
|
||||
test_read_write_file();
|
||||
test_move_file();
|
||||
test_iter_dir();
|
||||
} catch (x) {
|
||||
log("Catching error: " + x);
|
||||
log("Stack: " + x.stack);
|
||||
@ -198,3 +199,63 @@ function test_move_file()
|
||||
}
|
||||
|
||||
|
||||
function test_iter_dir()
|
||||
{
|
||||
ok(true, "test_iter_dir: Starting");
|
||||
|
||||
// Create a file, to be sure that it exists
|
||||
let tmp_file_name = "test_osfile_front.tmp";
|
||||
let tmp_file = OS.File.open(tmp_file_name, {write: true, trunc:true});
|
||||
tmp_file.close();
|
||||
|
||||
let parent = OS.File.curDir;
|
||||
ok(true, "test_iter_dir: directory " + parent);
|
||||
let iterator = new OS.File.DirectoryIterator(parent);
|
||||
ok(true, "test_iter_dir: iterator created");
|
||||
let encountered_tmp_file = false;
|
||||
for (let entry in iterator) {
|
||||
// Checking that |name| can be decoded properly
|
||||
ok(true, "test_iter_dir: encountering entry " + entry.name);
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
let file;
|
||||
let success = true;
|
||||
try {
|
||||
file = OS.File.open(entry.path);
|
||||
} catch (x) {
|
||||
if (x.becauseNoSuchFile) {
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
if (file) {
|
||||
file.close();
|
||||
}
|
||||
ok(success, "test_iter_dir: Entry " + entry.path + " exists");
|
||||
|
||||
if (OS.Win) {
|
||||
let year = new Date().getFullYear();
|
||||
let creation = entry.winCreationTime;
|
||||
ok(creation, "test_iter_dir: Windows creation date exists: " + creation);
|
||||
ok(creation.getFullYear() >= year - 1 && creation.getFullYear() <= year, "test_iter_dir: consistent creation date");
|
||||
|
||||
let lastWrite = entry.winLastWriteTime;
|
||||
ok(lastWrite, "test_iter_dir: Windows lastWrite date exists: " + lastWrite);
|
||||
ok(lastWrite.getFullYear() >= year - 1 && lastWrite.getFullYear() <= year, "test_iter_dir: consistent lastWrite date");
|
||||
|
||||
let lastAccess = entry.winLastAccessTime;
|
||||
ok(lastAccess, "test_iter_dir: Windows lastAccess date exists: " + lastAccess);
|
||||
ok(lastAccess.getFullYear() >= year - 1 && lastAccess.getFullYear() <= year, "test_iter_dir: consistent lastAccess date");
|
||||
}
|
||||
|
||||
}
|
||||
ok(encountered_tmp_file, "test_iter_dir: We have found the temporary file");
|
||||
|
||||
ok(true, "test_iter_dir: Cleaning up");
|
||||
iterator.close();
|
||||
ok(true, "test_iter_dir: Complete");
|
||||
}
|
||||
|
@ -18,6 +18,7 @@ XPCOMUtils.defineLazyServiceGetter(this, "gDirService",
|
||||
var FileUtils = {
|
||||
MODE_RDONLY : 0x01,
|
||||
MODE_WRONLY : 0x02,
|
||||
MODE_RDWR : 0x04,
|
||||
MODE_CREATE : 0x08,
|
||||
MODE_APPEND : 0x10,
|
||||
MODE_TRUNCATE : 0x20,
|
||||
|
Loading…
Reference in New Issue
Block a user