Bug 1063635 Part 2 - Call native writeAtomic code instead of JS backend when applicable,
MozReview-Commit-ID: fiIS2xPc2r
--- a/toolkit/components/osfile/modules/osfile_async_front.jsm
+++ b/toolkit/components/osfile/modules/osfile_async_front.jsm
@@ -1179,32 +1179,40 @@ File.exists = function exists(path) {
* If the process or the operating system freezes or crashes
* during the short window between these operations,
* the destination file will have been moved to its backup.
*
* @return {promise}
* @resolves {number} The number of bytes actually written.
*/
File.writeAtomic = function writeAtomic(path, buffer, options = {}) {
+ const useNativeImplementation = nativeWheneverAvailable && !options.compression;
// Copy |options| to avoid modifying the original object but preserve the
// reference to |outExecutionDuration|, |outSerializationDuration| option if it is passed.
options = clone(options, ["outExecutionDuration", "outSerializationDuration"]);
- // As options.tmpPath is a path, we need to encode it as |Type.path| message
- if ("tmpPath" in options) {
+ // As options.tmpPath is a path, we need to encode it as |Type.path| message, but only
+ // if we are not using the native implementation.
+ if ("tmpPath" in options && !useNativeImplementation) {
options.tmpPath = Type.path.toMsg(options.tmpPath);
};
if (isTypedArray(buffer) && (!("bytes" in options))) {
options.bytes = buffer.byteLength;
};
let refObj = {};
+ let promise;
TelemetryStopwatch.start("OSFILE_WRITEATOMIC_JANK_MS", refObj);
- let promise = Scheduler.post("writeAtomic",
+ if (useNativeImplementation) {
+ promise = Scheduler.push(() => Native.writeAtomic(path, buffer, options));
+ }
+ else {
+ promise = Scheduler.post("writeAtomic",
[Type.path.toMsg(path),
Type.void_t.in_ptr.toMsg(buffer),
options], [options, buffer, path]);
+ }
TelemetryStopwatch.finish("OSFILE_WRITEATOMIC_JANK_MS", refObj);
return promise;
};
File.removeDir = function(path, options = {}) {
return Scheduler.post("removeDir",
[Type.path.toMsg(path), options], path);
};
--- a/toolkit/components/osfile/modules/osfile_native.jsm
+++ b/toolkit/components/osfile/modules/osfile_native.jsm
@@ -62,8 +62,48 @@ this.read = function(path, options = {})
resolve(success.result);
},
function onError(operation, oserror) {
reject(new SysAll.Error(operation, oserror, path));
}
);
});
};
+
+this.writeAtomic = function(path, buffer, options = {}) {
+ // Sanity check on types of options
+ if ("encoding" in options && typeof options.encoding !== "string") {
+ return Promise.reject(new TypeError("Invalid type for option encoding"));
+ }
+ if ("compression" in options && typeof options.compression !== "string") {
+ return Promise.reject(new TypeError("Invalid type for option compression"));
+ }
+ if ("tmpPath" in options && typeof options.tmpPath !== "string") {
+ return Promise.reject(new TypeError("Invalid type for option tmpPath"));
+ }
+ if ("backupTo" in options && typeof options.backupTo !== "string") {
+ return Promise.reject(new TypeError("Invalid type for option backupTo"));
+ }
+ if ("bytes" in options && typeof options.bytes !== "number") {
+ return Promise.reject(new TypeError("Invalid type for option bytes"));
+ }
+ if ("noOverwrite" in options && typeof options.noOverwrite !== "boolean") {
+ return Promise.reject(new TypeError("Invalid type for option noOverwrite"));
+ }
+ if ("flush" in options && typeof options.flush !== "boolean") {
+ return Promise.reject(new TypeError("Invalid type for option flush"));
+ }
+
+ return new Promise((resolve, reject) => {
+ Internals.writeAtomic(
+ path,
+ buffer,
+ options,
+ function onSuccess(success) {
+ success.QueryInterface(Ci.nsINativeOSFileResult);
+ resolve(success.result);
+ },
+ function onError(operation, oserror) {
+ reject(new SysAll.Error(operation, oserror, path));
+ }
+ );
+ });
+};