mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-01-15 06:20:41 +00:00
Bug 771617 - Refactoring to better share code between implementations of OS.File. r=froydnj
This commit is contained in:
parent
c8d9e67334
commit
e7229b5ea3
@ -39,3 +39,4 @@ libs::
|
||||
$(NSINSTALL) $(srcdir)/ospath_win_back.jsm $(FINAL_TARGET)/modules/osfile
|
||||
$(NSINSTALL) $(srcdir)/osfile_win_back.jsm $(FINAL_TARGET)/modules/osfile
|
||||
$(NSINSTALL) $(srcdir)/osfile_win_front.jsm $(FINAL_TARGET)/modules/osfile
|
||||
$(NSINSTALL) $(srcdir)/osfile_shared_front.jsm $(FINAL_TARGET)/modules/osfile
|
||||
|
@ -905,74 +905,5 @@
|
||||
}
|
||||
return Strings.importWString(decoded);
|
||||
};
|
||||
|
||||
/**
|
||||
* Specific tools that don't really fit anywhere.
|
||||
*/
|
||||
let _aux = {};
|
||||
exports.OS.Shared._aux = _aux;
|
||||
|
||||
/**
|
||||
* Utility function shared by implementations of |OS.File.open|:
|
||||
* extract read/write/trunc/create/existing flags from a |mode|
|
||||
* object.
|
||||
*
|
||||
* @param {*=} mode An object that may contain fields |read|,
|
||||
* |write|, |truncate|, |create|, |existing|. These fields
|
||||
* are interpreted only if true-ish.
|
||||
* @return {{read:bool, write:bool, trunc:bool, create:bool,
|
||||
* existing:bool}} an object recapitulating the options set
|
||||
* by |mode|.
|
||||
* @throws {TypeError} If |mode| contains other fields, or
|
||||
* if it contains both |create| and |truncate|, or |create|
|
||||
* and |existing|.
|
||||
*/
|
||||
_aux.normalizeOpenMode = function normalizeOpenMode(mode) {
|
||||
let result = {
|
||||
read: false,
|
||||
write: false,
|
||||
trunc: false,
|
||||
create: false,
|
||||
existing: false
|
||||
};
|
||||
for (let key in mode) {
|
||||
if (!mode[key]) continue; // Only interpret true-ish keys
|
||||
switch (key) {
|
||||
case "read":
|
||||
result.read = true;
|
||||
break;
|
||||
case "write":
|
||||
result.write = true;
|
||||
break;
|
||||
case "truncate": // fallthrough
|
||||
case "trunc":
|
||||
result.trunc = true;
|
||||
result.write = true;
|
||||
break;
|
||||
case "create":
|
||||
result.create = true;
|
||||
result.write = true;
|
||||
break;
|
||||
case "existing": // fallthrough
|
||||
case "exist":
|
||||
result.existing = true;
|
||||
break;
|
||||
default:
|
||||
throw new TypeError("Mode " + key + " not understood");
|
||||
}
|
||||
}
|
||||
// Reject opposite modes
|
||||
if (result.existing && result.create) {
|
||||
throw new TypeError("Cannot specify both existing:true and create:true");
|
||||
}
|
||||
if (result.trunc && result.create) {
|
||||
throw new TypeError("Cannot specify both trunc:true and create:true");
|
||||
}
|
||||
// Handle read/write
|
||||
if (!result.write) {
|
||||
result.read = true;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
})(this);
|
||||
}
|
||||
|
106
toolkit/components/osfile/osfile_shared_front.jsm
Normal file
106
toolkit/components/osfile/osfile_shared_front.jsm
Normal file
@ -0,0 +1,106 @@
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
/**
|
||||
* Code shared by OS.File front-ends.
|
||||
*
|
||||
* This code is meant to be included by another library. It is also meant to
|
||||
* be executed only on a worker thread.
|
||||
*/
|
||||
|
||||
if (typeof Components != "undefined") {
|
||||
throw new Error("osfile_shared_front.jsm cannot be used from the main thread");
|
||||
}
|
||||
(function(exports) {
|
||||
|
||||
/**
|
||||
* Code shared by implementations of File.
|
||||
*
|
||||
* @param {*} fd An OS-specific file handle.
|
||||
* @constructor
|
||||
*/
|
||||
let AbstractFile = function AbstractFile(fd) {
|
||||
this._fd = fd;
|
||||
};
|
||||
|
||||
AbstractFile.prototype = {
|
||||
/**
|
||||
* Return the file handle.
|
||||
*
|
||||
* @throw OS.File.Error if the file has been closed.
|
||||
*/
|
||||
get fd() {
|
||||
if (this._fd) {
|
||||
return this._fd;
|
||||
}
|
||||
throw OS.File.Error.closed();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Utility function shared by implementations of |OS.File.open|:
|
||||
* extract read/write/trunc/create/existing flags from a |mode|
|
||||
* object.
|
||||
*
|
||||
* @param {*=} mode An object that may contain fields |read|,
|
||||
* |write|, |truncate|, |create|, |existing|. These fields
|
||||
* are interpreted only if true-ish.
|
||||
* @return {{read:bool, write:bool, trunc:bool, create:bool,
|
||||
* existing:bool}} an object recapitulating the options set
|
||||
* by |mode|.
|
||||
* @throws {TypeError} If |mode| contains other fields, or
|
||||
* if it contains both |create| and |truncate|, or |create|
|
||||
* and |existing|.
|
||||
*/
|
||||
AbstractFile.normalizeOpenMode = function normalizeOpenMode(mode) {
|
||||
let result = {
|
||||
read: false,
|
||||
write: false,
|
||||
trunc: false,
|
||||
create: false,
|
||||
existing: false
|
||||
};
|
||||
for (let key in mode) {
|
||||
if (!mode[key]) continue; // Only interpret true-ish keys
|
||||
switch (key) {
|
||||
case "read":
|
||||
result.read = true;
|
||||
break;
|
||||
case "write":
|
||||
result.write = true;
|
||||
break;
|
||||
case "truncate": // fallthrough
|
||||
case "trunc":
|
||||
result.trunc = true;
|
||||
result.write = true;
|
||||
break;
|
||||
case "create":
|
||||
result.create = true;
|
||||
result.write = true;
|
||||
break;
|
||||
case "existing": // fallthrough
|
||||
case "exist":
|
||||
result.existing = true;
|
||||
break;
|
||||
default:
|
||||
throw new TypeError("Mode " + key + " not understood");
|
||||
}
|
||||
}
|
||||
// Reject opposite modes
|
||||
if (result.existing && result.create) {
|
||||
throw new TypeError("Cannot specify both existing:true and create:true");
|
||||
}
|
||||
if (result.trunc && result.create) {
|
||||
throw new TypeError("Cannot specify both trunc:true and create:true");
|
||||
}
|
||||
// Handle read/write
|
||||
if (!result.write) {
|
||||
result.read = true;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
exports.OS.Shared.AbstractFile = AbstractFile;
|
||||
})(this);
|
@ -131,6 +131,15 @@ if (typeof Components != "undefined") {
|
||||
return this.unixErrno == OS.Constants.libc.ENOTEMPTY;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* is closed, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseClosed", {
|
||||
get: function becauseClosed() {
|
||||
return this.unixErrno == OS.Constants.libc.EBADF;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Serialize an instance of OSError to something that can be
|
||||
@ -169,4 +178,9 @@ if (typeof Components != "undefined") {
|
||||
*/
|
||||
Types.path = Types.cstring.withName("[in] path");
|
||||
Types.out_path = Types.out_cstring.withName("[out] path");
|
||||
|
||||
// Special constructors that need to be defined on all threads
|
||||
OSError.closed = function closed(operation) {
|
||||
return new OSError(operation, OS.Constants.libc.EBADF);
|
||||
};
|
||||
})(this);
|
||||
|
@ -178,7 +178,7 @@
|
||||
// Declare libc functions as functions of |OS.Unix.File|
|
||||
|
||||
// Finalizer-related functions
|
||||
let _close =
|
||||
let _close = UnixFile._close =
|
||||
libc.declare("close", ctypes.default_abi,
|
||||
/*return */ctypes.int,
|
||||
/*fd*/ ctypes.int);
|
||||
|
@ -18,6 +18,7 @@
|
||||
}
|
||||
importScripts("resource://gre/modules/osfile/osfile_unix_back.jsm");
|
||||
importScripts("resource://gre/modules/osfile/ospath_unix_back.jsm");
|
||||
importScripts("resource://gre/modules/osfile/osfile_shared_front.jsm");
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
|
||||
@ -40,133 +41,122 @@
|
||||
* @constructor
|
||||
*/
|
||||
let File = function File(fd) {
|
||||
this._fd = fd;
|
||||
exports.OS.Shared.AbstractFile.call(this, fd);
|
||||
this._closeResult = null;
|
||||
};
|
||||
File.prototype = {
|
||||
/**
|
||||
* If the file is open, this returns the file descriptor.
|
||||
* Otherwise, throw a |File.Error|.
|
||||
*/
|
||||
get fd() {
|
||||
return this._fd;
|
||||
},
|
||||
File.prototype = Object.create(exports.OS.Shared.AbstractFile.prototype);
|
||||
|
||||
// Placeholder getter, used to replace |get fd| once
|
||||
// the file is closed.
|
||||
_nofd: function nofd(operation) {
|
||||
operation = operation || "unknown operation";
|
||||
throw new File.Error(operation, Const.EBADF);
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the file.
|
||||
*
|
||||
* This method has no effect if the file is already closed. However,
|
||||
* if the first call to |close| has thrown an error, further calls
|
||||
* will throw the same error.
|
||||
*
|
||||
* @throws File.Error If closing the file revealed an error that could
|
||||
* not be reported earlier.
|
||||
*/
|
||||
close: function close() {
|
||||
if (this._fd) {
|
||||
let fd = this._fd;
|
||||
this._fd = null;
|
||||
delete this.fd;
|
||||
Object.defineProperty(this, "fd", {get: File.prototype._nofd});
|
||||
// Call |close(fd)|, detach finalizer
|
||||
if (UnixFile.close(fd) == -1) {
|
||||
this._closeResult = new File.Error("close", ctypes.errno);
|
||||
}
|
||||
/**
|
||||
* Close the file.
|
||||
*
|
||||
* This method has no effect if the file is already closed. However,
|
||||
* if the first call to |close| has thrown an error, further calls
|
||||
* will throw the same error.
|
||||
*
|
||||
* @throws File.Error If closing the file revealed an error that could
|
||||
* not be reported earlier.
|
||||
*/
|
||||
File.prototype.close = function close() {
|
||||
if (this._fd) {
|
||||
let fd = this._fd;
|
||||
this._fd = null;
|
||||
// Call |close(fd)|, detach finalizer if any
|
||||
// (|fd| may not be a CDataFinalizer if it has been
|
||||
// instantiated from a controller thread).
|
||||
let result = UnixFile._close(fd);
|
||||
if (typeof fd == "object" && "forget" in fd) {
|
||||
fd.forget();
|
||||
}
|
||||
if (this._closeResult) {
|
||||
throw this._closeResult;
|
||||
if (result == -1) {
|
||||
this._closeResult = new File.Error("close");
|
||||
}
|
||||
return;
|
||||
},
|
||||
_closeResult: null,
|
||||
|
||||
/**
|
||||
* Read some bytes from a file.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer A buffer for holding the data
|
||||
* once it is read.
|
||||
* @param {number} nbytes The number of bytes to read. It must not
|
||||
* exceed the size of |buffer| in bytes but it may exceed the number
|
||||
* of bytes unread in the file.
|
||||
* @param {*=} options Additional options for reading. Ignored in
|
||||
* this implementation.
|
||||
*
|
||||
* @return {number} The number of bytes effectively read. If zero,
|
||||
* the end of the file has been reached.
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
read: function read(buffer, nbytes, options) {
|
||||
return throw_on_negative("read",
|
||||
UnixFile.read(this.fd, buffer, nbytes)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Write some bytes to a file.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer A buffer holding the data that must be
|
||||
* written.
|
||||
* @param {number} nbytes The number of bytes to write. It must not
|
||||
* exceed the size of |buffer| in bytes.
|
||||
* @param {*=} options Additional options for writing. Ignored in
|
||||
* this implementation.
|
||||
*
|
||||
* @return {number} The number of bytes effectively written.
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
write: function write(buffer, nbytes, options) {
|
||||
return throw_on_negative("write",
|
||||
UnixFile.write(this.fd, buffer, nbytes)
|
||||
);
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the current position in the file.
|
||||
*/
|
||||
getPosition: function getPosition(pos) {
|
||||
return this.setPosition(0, File.POS_CURRENT);
|
||||
},
|
||||
|
||||
/**
|
||||
* Change the current position in the file.
|
||||
*
|
||||
* @param {number} pos The new position. Whether this position
|
||||
* is considered from the current position, from the start of
|
||||
* the file or from the end of the file is determined by
|
||||
* argument |whence|. Note that |pos| may exceed the length of
|
||||
* the file.
|
||||
* @param {number=} whence The reference position. If omitted
|
||||
* or |OS.File.POS_START|, |pos| is relative to the start of the
|
||||
* file. If |OS.File.POS_CURRENT|, |pos| is relative to the
|
||||
* current position in the file. If |OS.File.POS_END|, |pos| is
|
||||
* relative to the end of the file.
|
||||
*
|
||||
* @return The new position in the file.
|
||||
*/
|
||||
setPosition: function setPosition(pos, whence) {
|
||||
if (whence === undefined) {
|
||||
whence = Const.SEEK_START;
|
||||
}
|
||||
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);
|
||||
}
|
||||
if (this._closeResult) {
|
||||
throw this._closeResult;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read some bytes from a file.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer A buffer for holding the data
|
||||
* once it is read.
|
||||
* @param {number} nbytes The number of bytes to read. It must not
|
||||
* exceed the size of |buffer| in bytes but it may exceed the number
|
||||
* of bytes unread in the file.
|
||||
* @param {*=} options Additional options for reading. Ignored in
|
||||
* this implementation.
|
||||
*
|
||||
* @return {number} The number of bytes effectively read. If zero,
|
||||
* the end of the file has been reached.
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
File.prototype.read = function read(buffer, nbytes, options) {
|
||||
return throw_on_negative("read",
|
||||
UnixFile.read(this.fd, buffer, nbytes)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Write some bytes to a file.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer A buffer holding the data that must be
|
||||
* written.
|
||||
* @param {number} nbytes The number of bytes to write. It must not
|
||||
* exceed the size of |buffer| in bytes.
|
||||
* @param {*=} options Additional options for writing. Ignored in
|
||||
* this implementation.
|
||||
*
|
||||
* @return {number} The number of bytes effectively written.
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
File.prototype.write = function write(buffer, nbytes, options) {
|
||||
return throw_on_negative("write",
|
||||
UnixFile.write(this.fd, buffer, nbytes)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current position in the file.
|
||||
*/
|
||||
File.prototype.getPosition = function getPosition(pos) {
|
||||
return this.setPosition(0, File.POS_CURRENT);
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the current position in the file.
|
||||
*
|
||||
* @param {number} pos The new position. Whether this position
|
||||
* is considered from the current position, from the start of
|
||||
* the file or from the end of the file is determined by
|
||||
* argument |whence|. Note that |pos| may exceed the length of
|
||||
* the file.
|
||||
* @param {number=} whence The reference position. If omitted
|
||||
* or |OS.File.POS_START|, |pos| is relative to the start of the
|
||||
* file. If |OS.File.POS_CURRENT|, |pos| is relative to the
|
||||
* current position in the file. If |OS.File.POS_END|, |pos| is
|
||||
* relative to the end of the file.
|
||||
*
|
||||
* @return The new position in the file.
|
||||
*/
|
||||
File.prototype.setPosition = function setPosition(pos, whence) {
|
||||
if (whence === undefined) {
|
||||
whence = Const.SEEK_START;
|
||||
}
|
||||
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.
|
||||
*/
|
||||
File.prototype.stat = function stat() {
|
||||
throw_on_negative("stat", UnixFile.fstat(this.fd, gStatDataPtr));
|
||||
return new File.Info(gStatData);
|
||||
};
|
||||
|
||||
|
||||
@ -226,7 +216,7 @@
|
||||
if (options.unixFlags) {
|
||||
flags = options.unixFlags;
|
||||
} else {
|
||||
mode = OS.Shared._aux.normalizeOpenMode(mode);
|
||||
mode = OS.Shared.AbstractFile.normalizeOpenMode(mode);
|
||||
// Handle read/write
|
||||
if (!mode.write) {
|
||||
flags = Const.O_RDONLY;
|
||||
|
@ -141,6 +141,15 @@ if (typeof Components != "undefined") {
|
||||
return this.winLastError == OS.Constants.Win.ERROR_DIR_NOT_EMPTY;
|
||||
}
|
||||
});
|
||||
/**
|
||||
* |true| if the error was raised because a file or directory
|
||||
* is closed, |false| otherwise.
|
||||
*/
|
||||
Object.defineProperty(OSError.prototype, "becauseClosed", {
|
||||
get: function becauseClosed() {
|
||||
return this.winLastError == exports.OS.Constants.Win.INVALID_HANDLE_VALUE;
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Serialize an instance of OSError to something that can be
|
||||
@ -179,4 +188,10 @@ if (typeof Components != "undefined") {
|
||||
*/
|
||||
Types.path = Types.wstring.withName("[in] path");
|
||||
Types.out_path = Types.out_wstring.withName("[out] path");
|
||||
|
||||
// Special constructors that need to be defined on all threads
|
||||
OSError.closed = function closed(operation) {
|
||||
return new OSError(operation, exports.OS.Constants.Win.INVALID_HANDLE_VALUE);
|
||||
};
|
||||
|
||||
})(this);
|
||||
|
@ -177,7 +177,7 @@
|
||||
|
||||
// Special case: these functions are used by the
|
||||
// finalizer
|
||||
let _CloseHandle =
|
||||
let _CloseHandle = WinFile._CloseHandle =
|
||||
libc.declare("CloseHandle", ctypes.winapi_abi,
|
||||
/*return */ctypes.bool,
|
||||
/*handle*/ ctypes.voidptr_t);
|
||||
|
@ -16,9 +16,9 @@
|
||||
throw new Error("osfile_win_front.jsm cannot be used from the main thread yet");
|
||||
}
|
||||
|
||||
importScripts("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
|
||||
importScripts("resource://gre/modules/osfile/osfile_win_back.jsm");
|
||||
importScripts("resource://gre/modules/osfile/ospath_win_back.jsm");
|
||||
importScripts("resource://gre/modules/osfile/osfile_shared_front.jsm");
|
||||
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
@ -60,139 +60,126 @@
|
||||
* @constructor
|
||||
*/
|
||||
let File = function File(fd) {
|
||||
this._fd = fd;
|
||||
exports.OS.Shared.AbstractFile.call(this, fd);
|
||||
this._closeResult = null;
|
||||
};
|
||||
File.prototype = {
|
||||
/**
|
||||
* If the file is open, this returns the file descriptor.
|
||||
* Otherwise, throw a |File.Error|.
|
||||
*/
|
||||
get fd() {
|
||||
return this._fd;
|
||||
},
|
||||
File.prototype = Object.create(exports.OS.Shared.AbstractFile.prototype);
|
||||
|
||||
// Placeholder getter, used to replace |get fd| once
|
||||
// the file is closed.
|
||||
_nofd: function nofd(operation) {
|
||||
operation = operation ||
|
||||
this._nofd.caller.name ||
|
||||
"unknown operation";
|
||||
throw new File.Error(operation, Const.INVALID_HANDLE_VALUE);
|
||||
},
|
||||
|
||||
/**
|
||||
* Close the file.
|
||||
*
|
||||
* This method has no effect if the file is already closed. However,
|
||||
* if the first call to |close| has thrown an error, further calls
|
||||
* will throw the same error.
|
||||
*
|
||||
* @throws File.Error If closing the file revealed an error that could
|
||||
* not be reported earlier.
|
||||
*/
|
||||
close: function close() {
|
||||
if (this._fd) {
|
||||
let fd = this._fd;
|
||||
this._fd = null;
|
||||
delete this.fd;
|
||||
Object.defineProperty(this, "fd", {get: File.prototype._nofd});
|
||||
// Call CloseHandle(fd), detach finalizer
|
||||
if (fd.dispose() == 0) {
|
||||
this._closeResult = new File.Error("close", ctypes.errno);
|
||||
}
|
||||
/**
|
||||
* Close the file.
|
||||
*
|
||||
* This method has no effect if the file is already closed. However,
|
||||
* if the first call to |close| has thrown an error, further calls
|
||||
* will throw the same error.
|
||||
*
|
||||
* @throws File.Error If closing the file revealed an error that could
|
||||
* not be reported earlier.
|
||||
*/
|
||||
File.prototype.close = function close() {
|
||||
if (this._fd) {
|
||||
let fd = this._fd;
|
||||
this._fd = null;
|
||||
// Call |close(fd)|, detach finalizer if any
|
||||
// (|fd| may not be a CDataFinalizer if it has been
|
||||
// instantiated from a controller thread).
|
||||
let result = WinFile._CloseHandle(fd);
|
||||
if (typeof fd == "object" && "forget" in fd) {
|
||||
fd.forget();
|
||||
}
|
||||
if (this._closeResult) {
|
||||
throw this._closeResult;
|
||||
if (result == -1) {
|
||||
this._closeResult = new File.Error("close");
|
||||
}
|
||||
return;
|
||||
},
|
||||
_closeResult: null,
|
||||
|
||||
/**
|
||||
* Read some bytes from a file.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer A buffer for holding the data
|
||||
* once it is read.
|
||||
* @param {number} nbytes The number of bytes to read. It must not
|
||||
* exceed the size of |buffer| in bytes but it may exceed the number
|
||||
* of bytes unread in the file.
|
||||
* @param {*=} options Additional options for reading. Ignored in
|
||||
* this implementation.
|
||||
*
|
||||
* @return {number} The number of bytes effectively read. If zero,
|
||||
* the end of the file has been reached.
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
read: function read(buffer, nbytes, options) {
|
||||
// |gBytesReadPtr| is a pointer to |gBytesRead|.
|
||||
throw_on_zero("read",
|
||||
WinFile.ReadFile(this.fd, buffer, nbytes, gBytesReadPtr, null)
|
||||
);
|
||||
return gBytesRead.value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Write some bytes to a file.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer A buffer holding the data that must be
|
||||
* written.
|
||||
* @param {number} nbytes The number of bytes to write. It must not
|
||||
* exceed the size of |buffer| in bytes.
|
||||
* @param {*=} options Additional options for writing. Ignored in
|
||||
* this implementation.
|
||||
*
|
||||
* @return {number} The number of bytes effectively written.
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
write: function write(buffer, nbytes, options) {
|
||||
// |gBytesWrittenPtr| is a pointer to |gBytesWritten|.
|
||||
throw_on_zero("write",
|
||||
WinFile.WriteFile(this.fd, buffer, nbytes, gBytesWrittenPtr, null)
|
||||
);
|
||||
return gBytesWritten.value;
|
||||
},
|
||||
|
||||
/**
|
||||
* Return the current position in the file.
|
||||
*/
|
||||
getPosition: function getPosition(pos) {
|
||||
return this.setPosition(0, File.POS_CURRENT);
|
||||
},
|
||||
|
||||
/**
|
||||
* Change the current position in the file.
|
||||
*
|
||||
* @param {number} pos The new position. Whether this position
|
||||
* is considered from the current position, from the start of
|
||||
* the file or from the end of the file is determined by
|
||||
* argument |whence|. Note that |pos| may exceed the length of
|
||||
* the file.
|
||||
* @param {number=} whence The reference position. If omitted
|
||||
* or |OS.File.POS_START|, |pos| is relative to the start of the
|
||||
* file. If |OS.File.POS_CURRENT|, |pos| is relative to the
|
||||
* current position in the file. If |OS.File.POS_END|, |pos| is
|
||||
* relative to the end of the file.
|
||||
*
|
||||
* @return The new position in the file.
|
||||
*/
|
||||
setPosition: function setPosition(pos, whence) {
|
||||
if (whence === undefined) {
|
||||
whence = Const.FILE_BEGIN;
|
||||
}
|
||||
return throw_on_negative("setPosition",
|
||||
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);
|
||||
}
|
||||
if (this._closeResult) {
|
||||
throw this._closeResult;
|
||||
}
|
||||
return;
|
||||
};
|
||||
|
||||
/**
|
||||
* Read some bytes from a file.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer A buffer for holding the data
|
||||
* once it is read.
|
||||
* @param {number} nbytes The number of bytes to read. It must not
|
||||
* exceed the size of |buffer| in bytes but it may exceed the number
|
||||
* of bytes unread in the file.
|
||||
* @param {*=} options Additional options for reading. Ignored in
|
||||
* this implementation.
|
||||
*
|
||||
* @return {number} The number of bytes effectively read. If zero,
|
||||
* the end of the file has been reached.
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
File.prototype.read = function read(buffer, nbytes, options) {
|
||||
// |gBytesReadPtr| is a pointer to |gBytesRead|.
|
||||
throw_on_zero("read",
|
||||
WinFile.ReadFile(this.fd, buffer, nbytes, gBytesReadPtr, null)
|
||||
);
|
||||
return gBytesRead.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Write some bytes to a file.
|
||||
*
|
||||
* @param {ArrayBuffer} buffer A buffer holding the data that must be
|
||||
* written.
|
||||
* @param {number} nbytes The number of bytes to write. It must not
|
||||
* exceed the size of |buffer| in bytes.
|
||||
* @param {*=} options Additional options for writing. Ignored in
|
||||
* this implementation.
|
||||
*
|
||||
* @return {number} The number of bytes effectively written.
|
||||
* @throws {OS.File.Error} In case of I/O error.
|
||||
*/
|
||||
File.prototype.write = function write(buffer, nbytes, options) {
|
||||
// |gBytesWrittenPtr| is a pointer to |gBytesWritten|.
|
||||
throw_on_zero("write",
|
||||
WinFile.WriteFile(this.fd, buffer, nbytes, gBytesWrittenPtr, null)
|
||||
);
|
||||
return gBytesWritten.value;
|
||||
};
|
||||
|
||||
/**
|
||||
* Return the current position in the file.
|
||||
*/
|
||||
File.prototype.getPosition = function getPosition(pos) {
|
||||
return this.setPosition(0, File.POS_CURRENT);
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the current position in the file.
|
||||
*
|
||||
* @param {number} pos The new position. Whether this position
|
||||
* is considered from the current position, from the start of
|
||||
* the file or from the end of the file is determined by
|
||||
* argument |whence|. Note that |pos| may exceed the length of
|
||||
* the file.
|
||||
* @param {number=} whence The reference position. If omitted
|
||||
* or |OS.File.POS_START|, |pos| is relative to the start of the
|
||||
* file. If |OS.File.POS_CURRENT|, |pos| is relative to the
|
||||
* current position in the file. If |OS.File.POS_END|, |pos| is
|
||||
* relative to the end of the file.
|
||||
*
|
||||
* @return The new position in the file.
|
||||
*/
|
||||
File.prototype.setPosition = function setPosition(pos, whence) {
|
||||
if (whence === undefined) {
|
||||
whence = Const.FILE_BEGIN;
|
||||
}
|
||||
return throw_on_negative("setPosition",
|
||||
WinFile.SetFilePointer(this.fd, pos, null, whence));
|
||||
};
|
||||
|
||||
/**
|
||||
* Fetch the information on the file.
|
||||
*
|
||||
* @return File.Info The information on |this| file.
|
||||
*/
|
||||
File.prototype.stat = function stat() {
|
||||
throw_on_zero("stat",
|
||||
WinFile.GetFileInformationByHandle(this.fd, gFileInfoPtr));
|
||||
return new File.Info(gFileInfo);
|
||||
};
|
||||
|
||||
// Constant used to normalize options.
|
||||
@ -279,7 +266,7 @@
|
||||
throw new TypeError("OS.File.open requires either both options " +
|
||||
"winAccess and winDisposition or neither");
|
||||
} else {
|
||||
mode = OS.Shared._aux.normalizeOpenMode(mode);
|
||||
mode = OS.Shared.AbstractFile.normalizeOpenMode(mode);
|
||||
if (mode.read) {
|
||||
access |= Const.GENERIC_READ;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user