mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 965196 - [OS.File] Add an option |backupTo| to writeAtomic. r=Yoric
This commit is contained in:
parent
1798ca1941
commit
5a907508c4
@ -903,6 +903,11 @@ File.exists = function exists(path) {
|
||||
* if the system shuts down improperly (typically due to a kernel freeze
|
||||
* or a power failure) or if the device is disconnected before the buffer
|
||||
* is flushed, the file has more chances of not being corrupted.
|
||||
* - {string} backupTo - If specified, backup the destination file as |backupTo|.
|
||||
* Note that this function renames the destination file before overwriting it.
|
||||
* 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.
|
||||
|
@ -378,6 +378,11 @@ AbstractFile.read = function read(path, bytes, options = {}) {
|
||||
* If "lz4", compress the contents of the file atomically using lz4. For the
|
||||
* time being, the container format is specific to Mozilla and cannot be read
|
||||
* by means other than OS.File.read(..., { compression: "lz4"})
|
||||
* - {string} backupTo - If specified, backup the destination file as |backupTo|.
|
||||
* Note that this function renames the destination file before overwriting it.
|
||||
* 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 {number} The number of bytes actually written.
|
||||
*/
|
||||
@ -408,6 +413,13 @@ AbstractFile.writeAtomic =
|
||||
let bytesWritten = 0;
|
||||
|
||||
if (!options.tmpPath) {
|
||||
if (options.backupTo) {
|
||||
try {
|
||||
OS.File.move(path, options.backupTo, {noCopy: true});
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// The file doesn't exist, nothing to backup.
|
||||
}
|
||||
}
|
||||
// Just write, without any renaming trick
|
||||
let dest = OS.File.open(path, {write: true, truncate: true});
|
||||
try {
|
||||
@ -434,6 +446,14 @@ AbstractFile.writeAtomic =
|
||||
tmpFile.close();
|
||||
}
|
||||
|
||||
if (options.backupTo) {
|
||||
try {
|
||||
OS.File.move(path, options.backupTo, {noCopy: true});
|
||||
} catch (ex if ex.becauseNoSuchFile) {
|
||||
// The file doesn't exist, nothing to backup.
|
||||
}
|
||||
}
|
||||
|
||||
OS.File.move(options.tmpPath, path, {noCopy: true});
|
||||
return bytesWritten;
|
||||
};
|
||||
|
@ -0,0 +1,143 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
let {OS: {File, Path, Constants}} = Components.utils.import("resource://gre/modules/osfile.jsm", {});
|
||||
Components.utils.import("resource://gre/modules/Task.jsm");
|
||||
|
||||
/**
|
||||
* Remove all temporary files and back up files, including
|
||||
* test_backupTo_option_with_tmpPath.tmp
|
||||
* test_backupTo_option_with_tmpPath.tmp.backup
|
||||
* test_backupTo_option_without_tmpPath.tmp
|
||||
* test_backupTo_option_without_tmpPath.tmp.backup
|
||||
* test_non_backupTo_option.tmp
|
||||
* test_non_backupTo_option.tmp.backup
|
||||
* test_backupTo_option_without_destination_file.tmp
|
||||
* test_backupTo_option_without_destination_file.tmp.backup
|
||||
* test_backupTo_option_with_backup_file.tmp
|
||||
* test_backupTo_option_with_backup_file.tmp.backup
|
||||
*/
|
||||
function clearFiles() {
|
||||
return Task.spawn(function () {
|
||||
let files = ["test_backupTo_option_with_tmpPath.tmp",
|
||||
"test_backupTo_option_without_tmpPath.tmp",
|
||||
"test_non_backupTo_option.tmp",
|
||||
"test_backupTo_option_without_destination_file.tmp",
|
||||
"test_backupTo_option_with_backup_file.tmp"];
|
||||
for (let file of files) {
|
||||
let path = Path.join(Constants.Path.tmpDir, file);
|
||||
yield File.remove(path);
|
||||
yield File.remove(path + ".backup");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
||||
|
||||
add_task(function* init() {
|
||||
yield clearFiles();
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| specified
|
||||
* |tmpPath| specified
|
||||
* destination file exists
|
||||
* @result destination file will be backed up
|
||||
*/
|
||||
add_task(function* test_backupTo_option_with_tmpPath() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_backupTo_option_with_tmpPath.tmp");
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS, { tmpPath: path + ".tmp",
|
||||
backupTo: path + ".backup" });
|
||||
do_check_true((yield File.exists(path + ".backup")));
|
||||
let contents = yield File.read(path + ".backup");
|
||||
do_check_eq(DEFAULT_CONTENTS, (new TextDecoder()).decode(contents));
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| specified
|
||||
* |tmpPath| not specified
|
||||
* destination file exists
|
||||
* @result destination file will be backed up
|
||||
*/
|
||||
add_task(function* test_backupTo_option_without_tmpPath() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_backupTo_option_without_tmpPath.tmp");
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS, { backupTo: path + ".backup" });
|
||||
do_check_true((yield File.exists(path + ".backup")));
|
||||
let contents = yield File.read(path + ".backup");
|
||||
do_check_eq(DEFAULT_CONTENTS, (new TextDecoder()).decode(contents));
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| not specified
|
||||
* |tmpPath| not specified
|
||||
* destination file exists
|
||||
* @result destination file will not be backed up
|
||||
*/
|
||||
add_task(function* test_non_backupTo_option() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_non_backupTo_option.tmp");
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS);
|
||||
do_check_false((yield File.exists(path + ".backup")));
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| specified
|
||||
* |tmpPath| not specified
|
||||
* destination file not exists
|
||||
* @result no back up file exists
|
||||
*/
|
||||
add_task(function* test_backupTo_option_without_destination_file() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_backupTo_option_without_destination_file.tmp");
|
||||
yield File.remove(path);
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS, { backupTo: path + ".backup" });
|
||||
do_check_false((yield File.exists(path + ".backup")));
|
||||
});
|
||||
|
||||
/**
|
||||
* test when
|
||||
* |backupTo| specified
|
||||
* |tmpPath| not specified
|
||||
* backup file exists
|
||||
* destination file exists
|
||||
* @result destination file will be backed up
|
||||
*/
|
||||
add_task(function* test_backupTo_option_with_backup_file() {
|
||||
let DEFAULT_CONTENTS = "default contents" + Math.random();
|
||||
let WRITE_CONTENTS = "abc" + Math.random();
|
||||
let path = Path.join(Constants.Path.tmpDir,
|
||||
"test_backupTo_option_with_backup_file.tmp");
|
||||
yield File.writeAtomic(path, DEFAULT_CONTENTS);
|
||||
|
||||
yield File.writeAtomic(path + ".backup", new Uint8Array(1000));
|
||||
|
||||
yield File.writeAtomic(path, WRITE_CONTENTS, { backupTo: path + ".backup" });
|
||||
do_check_true((yield File.exists(path + ".backup")));
|
||||
let contents = yield File.read(path + ".backup");
|
||||
do_check_eq(DEFAULT_CONTENTS, (new TextDecoder()).decode(contents));
|
||||
});
|
||||
|
||||
add_task(function* cleanup() {
|
||||
yield clearFiles();
|
||||
});
|
@ -25,3 +25,4 @@ tail =
|
||||
[test_telemetry.js]
|
||||
[test_duration.js]
|
||||
[test_compression.js]
|
||||
[test_osfile_writeAtomic_backupTo_option.js]
|
||||
|
Loading…
Reference in New Issue
Block a user