Backed out 7 changesets (bug 1677000) for perma failures on test_ioutils_read_write.html. CLOSED TREE

Backed out changeset 3521334cfc38 (bug 1677000)
Backed out changeset 737f380c2cf2 (bug 1677000)
Backed out changeset 9dba15fdfe1f (bug 1677000)
Backed out changeset b2fa1a061b15 (bug 1677000)
Backed out changeset a5d7845d3c0c (bug 1677000)
Backed out changeset 8e6081b0c07d (bug 1677000)
Backed out changeset 6592577cf0fa (bug 1677000)
This commit is contained in:
Razvan Maries 2020-12-09 07:34:21 +02:00
Родитель 9e4f4ac1b9
Коммит 9614a08d73
18 изменённых файлов: 208 добавлений и 192 удалений

Просмотреть файл

@ -920,7 +920,7 @@ add_task(async function testExtensionControlledHomepageUninstalledAddon() {
let jsonFileName = "extension-settings.json";
let storePath = PathUtils.join(await PathUtils.getProfileDir(), jsonFileName);
await IOUtils.writeUTF8(storePath, JSON.stringify(storeData));
await IOUtils.writeAtomicUTF8(storePath, JSON.stringify(storeData));
// Reload the ExtensionSettingsStore so it will read the file on disk. Don't
// finalize the current store since it will overwrite our file.

Просмотреть файл

@ -409,7 +409,8 @@ let BrowserUsageTelemetry = {
getTelemetryClientId: async () => ClientID.getClientID(),
getUpdateDirectory: () => Services.dirsvc.get("UpdRootD", Ci.nsIFile),
readProfileCountFile: async path => IOUtils.readUTF8(path),
writeProfileCountFile: async (path, data) => IOUtils.writeUTF8(path, data),
writeProfileCountFile: async (path, data) =>
IOUtils.writeAtomicUTF8(path, data),
},
_inited: false,

Просмотреть файл

@ -59,10 +59,10 @@ namespace IOUtils {
* @return Resolves with the number of bytes successfully written to the file,
* otherwise rejects with a DOMException.
*/
Promise<unsigned long long> write(DOMString path, Uint8Array data, optional WriteOptions options = {});
Promise<unsigned long long> writeAtomic(DOMString path, Uint8Array data, optional WriteAtomicOptions options = {});
/**
* Attempts to encode |string| to UTF-8, then safely write the result to a
* file at |path|. Works exactly like |write|.
* file at |path|. Works exactly like |writeAtomic|.
*
* @param path An absolute file path.
* @param string A string to encode to UTF-8 and write to the file at path.
@ -70,7 +70,7 @@ namespace IOUtils {
* @return Resolves with the number of bytes successfully written to the file,
* otherwise rejects with a DOMException.
*/
Promise<unsigned long long> writeUTF8(DOMString path, DOMString string, optional WriteOptions options = {});
Promise<unsigned long long> writeAtomicUTF8(DOMString path, DOMString string, optional WriteAtomicOptions options = {});
/**
* Moves the file from |sourcePath| to |destPath|, creating necessary parents.
* If |destPath| is a directory, then the source file will be moved into the
@ -205,10 +205,10 @@ dictionary ReadOptions : ReadUTF8Options {
};
/**
* Options to be passed to the |IOUtils.write| and |writeUTF8|
* Options to be passed to the |IOUtils.writeAtomic| and |writeAtomicUTF8|
* methods.
*/
dictionary WriteOptions {
dictionary WriteAtomicOptions {
/**
* If specified, backup the destination file to this path before writing.
*/

Просмотреть файл

@ -59,7 +59,8 @@
} \
} while (0)
namespace mozilla::dom {
namespace mozilla {
namespace dom {
// static helper functions
@ -136,6 +137,12 @@ MOZ_MUST_USE inline bool ToJSValue(
return ToJSValue(aCx, info, aValue);
}
#ifdef XP_WIN
constexpr char PathSeparator = u'\\';
#else
constexpr char PathSeparator = u'/';
#endif
// IOUtils implementation
/* static */
@ -149,6 +156,8 @@ Atomic<bool> IOUtils::sShutdownStarted = Atomic<bool>(false);
/* static */
template <typename OkT, typename Fn>
void IOUtils::RunOnBackgroundThread(Promise* aPromise, Fn aFunc) {
using MozPromiseT = MozPromise<OkT, IOError, true>;
nsCOMPtr<nsISerialEventTarget> bg = GetBackgroundEventTarget();
if (!bg) {
aPromise->MaybeRejectWithAbortError(
@ -156,19 +165,26 @@ void IOUtils::RunOnBackgroundThread(Promise* aPromise, Fn aFunc) {
return;
}
InvokeAsync(
bg, __func__,
[func = std::move(aFunc)]() {
Result<OkT, IOError> result = func();
if (result.isErr()) {
return IOPromise<OkT>::CreateAndReject(result.unwrapErr(), __func__);
}
return IOPromise<OkT>::CreateAndResolve(result.unwrap(), __func__);
})
InvokeAsync(bg, __func__,
[func = std::move(aFunc)]() {
Result<OkT, IOError> result = func();
if (result.isErr()) {
return MozPromiseT::CreateAndReject(result.unwrapErr(),
__func__);
}
return MozPromiseT::CreateAndResolve(result.unwrap(), __func__);
})
->Then(
GetCurrentSerialEventTarget(), __func__,
[promise = RefPtr(aPromise)](const OkT& ok) {
ResolveJSPromise(promise, ok);
if constexpr (std::is_same_v<OkT, nsTArray<uint8_t>>) {
TypedArrayCreator<Uint8Array> arr(ok);
promise->MaybeResolve(arr);
} else if constexpr (std::is_same_v<OkT, Ok>) {
promise->MaybeResolveWithUndefined();
} else {
promise->MaybeResolve(ok);
}
},
[promise = RefPtr(aPromise)](const IOError& err) {
RejectJSPromise(promise, err);
@ -203,6 +219,7 @@ already_AddRefed<Promise> IOUtils::Read(GlobalObject& aGlobal,
[file = std::move(file), toRead, decompress = aOptions.mDecompress]() {
return ReadSync(file, toRead, decompress);
});
return promise.forget();
}
@ -225,10 +242,9 @@ already_AddRefed<Promise> IOUtils::ReadUTF8(GlobalObject& aGlobal,
}
/* static */
already_AddRefed<Promise> IOUtils::Write(GlobalObject& aGlobal,
const nsAString& aPath,
const Uint8Array& aData,
const WriteOptions& aOptions) {
already_AddRefed<Promise> IOUtils::WriteAtomic(
GlobalObject& aGlobal, const nsAString& aPath, const Uint8Array& aData,
const WriteAtomicOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
NS_ENSURE_TRUE(!!promise, nullptr);
@ -245,24 +261,25 @@ already_AddRefed<Promise> IOUtils::Write(GlobalObject& aGlobal,
return promise.forget();
}
auto opts = InternalWriteOpts::FromBinding(aOptions);
auto opts = InternalWriteAtomicOpts::FromBinding(aOptions);
if (opts.isErr()) {
RejectJSPromise(promise, opts.unwrapErr());
return promise.forget();
}
RunOnBackgroundThread<uint32_t>(
promise, [file = std::move(file), buf = std::move(*buf),
opts = opts.unwrap()]() { return WriteSync(file, buf, opts); });
promise,
[file = std::move(file), buf = std::move(*buf), opts = opts.unwrap()]() {
return WriteAtomicSync(file, buf, opts);
});
return promise.forget();
}
/* static */
already_AddRefed<Promise> IOUtils::WriteUTF8(GlobalObject& aGlobal,
const nsAString& aPath,
const nsAString& aString,
const WriteOptions& aOptions) {
already_AddRefed<Promise> IOUtils::WriteAtomicUTF8(
GlobalObject& aGlobal, const nsAString& aPath, const nsAString& aString,
const WriteAtomicOptions& aOptions) {
MOZ_DIAGNOSTIC_ASSERT(XRE_IsParentProcess());
RefPtr<Promise> promise = CreateJSPromise(aGlobal);
NS_ENSURE_TRUE(!!promise, nullptr);
@ -278,16 +295,17 @@ already_AddRefed<Promise> IOUtils::WriteUTF8(GlobalObject& aGlobal,
return promise.forget();
}
auto opts = InternalWriteOpts::FromBinding(aOptions);
auto opts = InternalWriteAtomicOpts::FromBinding(aOptions);
if (opts.isErr()) {
RejectJSPromise(promise, opts.unwrapErr());
return promise.forget();
}
RunOnBackgroundThread<uint32_t>(
promise,
[file = std::move(file), utf8Str = std::move(utf8Str),
opts = opts.unwrap()]() { return WriteUTF8Sync(file, utf8Str, opts); });
promise, [file = std::move(file), utf8Str = std::move(utf8Str),
opts = opts.unwrap()]() {
return WriteAtomicUTF8Sync(file, utf8Str, opts);
});
return promise.forget();
}
@ -551,20 +569,8 @@ already_AddRefed<Promise> IOUtils::CreateJSPromise(GlobalObject& aGlobal) {
}
/* static */
template <typename T>
void IOUtils::ResolveJSPromise(Promise* aPromise, const T& aValue) {
if constexpr (std::is_same_v<T, nsTArray<uint8_t>>) {
TypedArrayCreator<Uint8Array> arr(aValue);
aPromise->MaybeResolve(arr);
} else if constexpr (std::is_same_v<T, Ok>) {
aPromise->MaybeResolveWithUndefined();
} else {
aPromise->MaybeResolve(aValue);
}
}
/* static */
void IOUtils::RejectJSPromise(Promise* aPromise, const IOError& aError) {
void IOUtils::RejectJSPromise(const RefPtr<Promise>& aPromise,
const IOError& aError) {
const auto& errMsg = aError.Message();
switch (aError.Code()) {
@ -736,9 +742,9 @@ Result<nsString, IOUtils::IOError> IOUtils::ReadUTF8Sync(
}
/* static */
Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync(
Result<uint32_t, IOUtils::IOError> IOUtils::WriteAtomicSync(
nsIFile* aFile, const Span<const uint8_t>& aByteArray,
const IOUtils::InternalWriteOpts& aOptions) {
const IOUtils::InternalWriteAtomicOpts& aOptions) {
MOZ_ASSERT(!NS_IsMainThread());
nsIFile* backupFile = aOptions.mBackupFile;
@ -863,15 +869,15 @@ Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync(
}
/* static */
Result<uint32_t, IOUtils::IOError> IOUtils::WriteUTF8Sync(
Result<uint32_t, IOUtils::IOError> IOUtils::WriteAtomicUTF8Sync(
nsIFile* aFile, const nsCString& aUTF8String,
const InternalWriteOpts& aOptions) {
const InternalWriteAtomicOpts& aOptions) {
MOZ_ASSERT(!NS_IsMainThread());
Span utf8Bytes(reinterpret_cast<const uint8_t*>(aUTF8String.get()),
aUTF8String.Length());
return WriteSync(aFile, utf8Bytes, aOptions);
return WriteAtomicSync(aFile, utf8Bytes, aOptions);
}
/* static */
@ -1385,9 +1391,10 @@ NS_IMETHODIMP IOUtilsShutdownBlocker::GetState(nsIPropertyBag** aState) {
return NS_OK;
}
Result<IOUtils::InternalWriteOpts, IOUtils::IOError>
IOUtils::InternalWriteOpts::FromBinding(const WriteOptions& aOptions) {
InternalWriteOpts opts;
Result<IOUtils::InternalWriteAtomicOpts, IOUtils::IOError>
IOUtils::InternalWriteAtomicOpts::FromBinding(
const WriteAtomicOptions& aOptions) {
InternalWriteAtomicOpts opts;
opts.mFlush = aOptions.mFlush;
opts.mNoOverwrite = aOptions.mNoOverwrite;
@ -1416,7 +1423,8 @@ IOUtils::InternalWriteOpts::FromBinding(const WriteOptions& aOptions) {
return opts;
}
} // namespace mozilla::dom
} // namespace dom
} // namespace mozilla
#undef REJECT_IF_SHUTTING_DOWN
#undef REJECT_IF_INIT_PATH_FAILED

Просмотреть файл

@ -63,15 +63,13 @@ class IOUtils final {
const nsAString& aPath,
const ReadUTF8Options& aOptions);
static already_AddRefed<Promise> Write(GlobalObject& aGlobal,
const nsAString& aPath,
const Uint8Array& aData,
const WriteOptions& aOptions);
static already_AddRefed<Promise> WriteAtomic(
GlobalObject& aGlobal, const nsAString& aPath, const Uint8Array& aData,
const WriteAtomicOptions& aOptions);
static already_AddRefed<Promise> WriteUTF8(GlobalObject& aGlobal,
const nsAString& aPath,
const nsAString& aString,
const WriteOptions& aOptions);
static already_AddRefed<Promise> WriteAtomicUTF8(
GlobalObject& aGlobal, const nsAString& aPath, const nsAString& aString,
const WriteAtomicOptions& aOptions);
static already_AddRefed<Promise> Move(GlobalObject& aGlobal,
const nsAString& aSourcePath,
@ -108,15 +106,14 @@ class IOUtils final {
static already_AddRefed<Promise> Exists(GlobalObject& aGlobal,
const nsAString& aPath);
static bool IsAbsolutePath(const nsAString& aPath);
private:
~IOUtils() = default;
template <typename T>
using IOPromise = MozPromise<T, IOError, true>;
friend class IOUtilsShutdownBlocker;
struct InternalFileInfo;
struct InternalWriteOpts;
struct InternalWriteAtomicOpts;
class MozLZ4;
static StaticDataMutex<StaticRefPtr<nsISerialEventTarget>>
@ -124,10 +121,6 @@ class IOUtils final {
static StaticRefPtr<nsIAsyncShutdownClient> sBarrier;
static Atomic<bool> sShutdownStarted;
template <typename OkT, typename Fn, typename... Args>
static RefPtr<IOUtils::IOPromise<OkT>> InvokeToIOPromise(Fn aFunc,
Args... aArgs);
static already_AddRefed<nsIAsyncShutdownClient> GetShutdownBarrier();
static already_AddRefed<nsISerialEventTarget> GetBackgroundEventTarget();
@ -149,15 +142,11 @@ class IOUtils final {
const InternalFileInfo& aInternalFileInfo,
JS::MutableHandle<JS::Value> aValue);
/**
* Resolves |aPromise| with an appropriate JS value for |aValue|.
*/
template <typename T>
static void ResolveJSPromise(Promise* aPromise, const T& aValue);
/**
* Rejects |aPromise| with an appropriate |DOMException| describing |aError|.
*/
static void RejectJSPromise(Promise* aPromise, const IOError& aError);
static void RejectJSPromise(const RefPtr<Promise>& aPromise,
const IOError& aError);
/**
* Attempts to read the entire file at |aPath| into a buffer.
@ -199,9 +188,9 @@ class IOUtils final {
* @return The number of bytes written to the file, or an error if the write
* failed or was incomplete.
*/
static Result<uint32_t, IOError> WriteSync(
static Result<uint32_t, IOError> WriteAtomicSync(
nsIFile* aFile, const Span<const uint8_t>& aByteArray,
const InternalWriteOpts& aOptions);
const InternalWriteAtomicOpts& aOptions);
/**
* Attempt to write the entirety of |aUTF8String| to the file at |aFile|.
@ -215,9 +204,23 @@ class IOUtils final {
* @return The number of bytes written to the file, or an error if the write
* failed or was incomplete.
*/
static Result<uint32_t, IOError> WriteUTF8Sync(
static Result<uint32_t, IOError> WriteAtomicUTF8Sync(
nsIFile* aFile, const nsCString& aUTF8String,
const InternalWriteOpts& aOptions);
const InternalWriteAtomicOpts& aOptions);
/**
* Attempts to write |aBytes| to the file pointed by |aFd|.
*
* @param aFd An open PRFileDesc for the destination file to be
* overwritten.
* @param aFile The location of the file.
* @param aBytes The data to write to the file.
*
* @return The number of bytes written to the file, or an error if the write
* failed or was incomplete.
*/
static Result<uint32_t, IOError> WriteSync(PRFileDesc* aFd, nsIFile* aFile,
const Span<const uint8_t>& aBytes);
/**
* Attempts to move the file located at |aSourceFile| to |aDestFile|.
@ -407,30 +410,30 @@ class IOUtils::IOError {
*/
struct IOUtils::InternalFileInfo {
nsString mPath;
FileType mType = FileType::Other;
uint64_t mSize = 0;
uint64_t mLastModified = 0;
FileType mType;
uint64_t mSize;
uint64_t mLastModified;
Maybe<uint64_t> mCreationTime;
uint32_t mPermissions = 0;
uint32_t mPermissions;
};
/**
* This is an easier to work with representation of a
* |mozilla::dom::WriteOptions| for private use in the |IOUtils|
* |mozilla::dom::WriteAtomicOptions| for private use in the |IOUtils|
* implementation.
*
* Because web IDL dictionaries are not easily copy/moveable, this class is
* used instead.
*/
struct IOUtils::InternalWriteOpts {
struct IOUtils::InternalWriteAtomicOpts {
RefPtr<nsIFile> mBackupFile;
bool mFlush;
bool mNoOverwrite;
RefPtr<nsIFile> mTmpFile;
bool mFlush = false;
bool mNoOverwrite = false;
bool mCompress = false;
bool mCompress;
static Result<InternalWriteOpts, IOUtils::IOError> FromBinding(
const WriteOptions& aOptions);
static Result<InternalWriteAtomicOpts, IOUtils::IOError> FromBinding(
const WriteAtomicOptions& aOptions);
};
/**

Просмотреть файл

@ -11,7 +11,7 @@ async function createFile(location, contents = "") {
if (typeof contents === "string") {
contents = new TextEncoder().encode(contents);
}
await IOUtils.write(location, contents);
await IOUtils.writeAtomic(location, contents);
const exists = await fileExists(location);
ok(exists, `Created temporary file at: ${location}`);
}

Просмотреть файл

@ -37,8 +37,12 @@ self.onmessage = async function(msg) {
// Write a file.
const tmpFileName = OS.Path.join(tmpDir, "test_ioutils_numbers.tmp");
const bytes = Uint8Array.of(...new Array(50).keys());
const bytesWritten = await IOUtils.write(tmpFileName, bytes);
is(bytesWritten, 50, "IOUtils::write can write entire byte array to file");
const bytesWritten = await IOUtils.writeAtomic(tmpFileName, bytes);
is(
bytesWritten,
50,
"IOUtils::writeAtomic can write entire byte array to file"
);
// Read it back.
let fileContents = await IOUtils.read(tmpFileName);
@ -63,7 +67,7 @@ self.onmessage = async function(msg) {
const src = OS.Path.join(tmpDir, "test_move_file_src.tmp");
const dest = OS.Path.join(tmpDir, "test_move_file_dest.tmp");
const bytes = Uint8Array.of(...new Array(50).keys());
await IOUtils.write(src, bytes);
await IOUtils.writeAtomic(src, bytes);
await IOUtils.move(src, dest);
ok(

Просмотреть файл

@ -40,25 +40,25 @@
let exists = await IOUtils.exists(tmpFileName);
ok(!exists, `File ${tmpFileName} should not exist before writing`);
await IOUtils.write(tmpFileName, untouchableContents);
await IOUtils.writeAtomic(tmpFileName, untouchableContents);
exists = await IOUtils.exists(tmpFileName);
ok(exists, `File ${tmpFileName} should exist after writing`);
const newContents = new TextEncoder().encode("Nah nah nah!\n");
await Assert.rejects(
IOUtils.write(tmpFileName, newContents, {
IOUtils.writeAtomic(tmpFileName, newContents, {
noOverwrite: true,
}),
/Refusing to overwrite the file at */,
"IOUtils::write rejects writing to existing file if overwrites are disabled"
"IOUtils::writeAtomic rejects writing to existing file if overwrites are disabled"
);
ok(
await fileHasBinaryContents(tmpFileName, untouchableContents),
"IOUtils::write doesn't change target file when overwrite is refused"
"IOUtils::writeAtomic doesn't change target file when overwrite is refused"
);
const bytesWritten = await IOUtils.write(
const bytesWritten = await IOUtils.writeAtomic(
tmpFileName,
newContents,
{ noOverwrite: false /* Default. */ }
@ -66,7 +66,7 @@
is(
bytesWritten,
newContents.length,
"IOUtils::write can overwrite files if specified"
"IOUtils::writeAtomic can overwrite files if specified"
);
await cleanup(tmpFileName);
@ -81,42 +81,42 @@
let destFileName = PathUtils.join(tmpDir, "test_write_with_backup_option.tmp");
let backupFileName = destFileName + ".backup";
let bytesWritten =
await IOUtils.write(destFileName, fileContents, {
await IOUtils.writeAtomic(destFileName, fileContents, {
backupFile: backupFileName,
});
ok(
await fileHasTextContents(destFileName, "Original file contents"),
"IOUtils::write creates a new file with the correct contents"
"IOUtils::writeAtomic creates a new file with the correct contents"
);
ok(
!await fileExists(backupFileName),
"IOUtils::write does not create a backup if the target file does not exist"
"IOUtils::writeAtomic does not create a backup if the target file does not exist"
);
is(
bytesWritten,
fileContents.length,
"IOUtils::write correctly writes to a new file without performing a backup"
"IOUtils::writeAtomic correctly writes to a new file without performing a backup"
);
info("Test backup file option with existing destination");
let newFileContents = new TextEncoder().encode("New file contents");
ok(await fileExists(destFileName), `Expected ${destFileName} to exist`);
bytesWritten =
await IOUtils.write(destFileName, newFileContents, {
await IOUtils.writeAtomic(destFileName, newFileContents, {
backupFile: backupFileName,
});
ok(
await fileHasTextContents(backupFileName, "Original file contents"),
"IOUtils::write can backup an existing file before writing"
"IOUtils::writeAtomic can backup an existing file before writing"
);
ok(
await fileHasTextContents(destFileName, "New file contents"),
"IOUtils::write can create the target with the correct contents"
"IOUtils::writeAtomic can create the target with the correct contents"
);
is(
bytesWritten,
newFileContents.length,
"IOUtils::write correctly writes to the target after taking a backup"
"IOUtils::writeAtomic correctly writes to the target after taking a backup"
);
await cleanup(destFileName, backupFileName);
@ -132,46 +132,46 @@
let backupFileName = destFileName + ".backup";
let tmpFileName = PathUtils.join(tmpDir, "temp_file.tmp");
let bytesWritten =
await IOUtils.write(destFileName, fileContents, {
await IOUtils.writeAtomic(destFileName, fileContents, {
backupFile: backupFileName,
tmpPath: tmpFileName,
});
ok(!await fileExists(tmpFileName), "IOUtils::write cleans up the tmpFile");
ok(!await fileExists(tmpFileName), "IOUtils::writeAtomic cleans up the tmpFile");
ok(
!await fileExists(backupFileName),
"IOUtils::write does not create a backup if the target file does not exist"
"IOUtils::writeAtomic does not create a backup if the target file does not exist"
);
ok(
await fileHasTextContents(destFileName, "Original file contents"),
"IOUtils::write can write to the destination when a temporary file is used"
"IOUtils::writeAtomic can write to the destination when a temporary file is used"
);
is(
bytesWritten,
fileContents.length,
"IOUtils::write can copy tmp file to destination without performing a backup"
"IOUtils::writeAtomic can copy tmp file to destination without performing a backup"
);
info("Test backup with tmp and backup file options, existing destination");
let newFileContents = new TextEncoder().encode("New file contents");
bytesWritten =
await IOUtils.write(destFileName, newFileContents, {
await IOUtils.writeAtomic(destFileName, newFileContents, {
backupFile: backupFileName,
tmpPath: tmpFileName,
});
ok(!await fileExists(tmpFileName), "IOUtils::write cleans up the tmpFile");
ok(!await fileExists(tmpFileName), "IOUtils::writeAtomic cleans up the tmpFile");
ok(
await fileHasTextContents(backupFileName, "Original file contents"),
"IOUtils::write can create a backup if the target file exists"
"IOUtils::writeAtomic can create a backup if the target file exists"
);
ok(
await fileHasTextContents(destFileName, "New file contents"),
"IOUtils::write can write to the destination when a temporary file is used"
"IOUtils::writeAtomic can write to the destination when a temporary file is used"
);
is(
bytesWritten,
newFileContents.length,
"IOUtils::write IOUtils::write can move tmp file to destination after performing a backup"
"IOUtils::writeAtomic IOUtils::writeAtomic can move tmp file to destination after performing a backup"
);
await cleanup(destFileName, backupFileName);
@ -182,11 +182,11 @@
const tmpFileName = PathUtils.join(tmpDir, "test_ioutils_partial_read.tmp");
const bytes = Uint8Array.of(...new Array(50).keys());
const bytesWritten = await IOUtils.write(tmpFileName, bytes);
const bytesWritten = await IOUtils.writeAtomic(tmpFileName, bytes);
is(
bytesWritten,
50,
"IOUtils::write can write entire byte array to file"
"IOUtils::writeAtomic can write entire byte array to file"
);
// Read just the first 10 bytes.
@ -213,11 +213,11 @@
const tmpFileName = PathUtils.join(tmpDir, "test_ioutils_empty.tmp");
const emptyByteArray = new Uint8Array(0);
const bytesWritten = await IOUtils.write(
const bytesWritten = await IOUtils.writeAtomic(
tmpFileName,
emptyByteArray
);
is(bytesWritten, 0, "IOUtils::write can create an empty file");
is(bytesWritten, 0, "IOUtils::writeAtomic can create an empty file");
// Trying to explicitly read nothing isn't useful, but it should still
// succeed.
@ -239,11 +239,11 @@
info("Test writing to a new binary file");
const tmpFileName = PathUtils.join(tmpDir, "test_ioutils_numbers.tmp");
const bytes = Uint8Array.of(...new Array(50).keys());
const bytesWritten = await IOUtils.write(tmpFileName, bytes);
const bytesWritten = await IOUtils.writeAtomic(tmpFileName, bytes);
is(
bytesWritten,
50,
"IOUtils::write can write entire byte array to file"
"IOUtils::writeAtomic can write entire byte array to file"
);
// Read it back.
@ -273,9 +273,9 @@
info("Test writing a file at a relative destination");
await Assert.rejects(
IOUtils.write(tmpFileName, bytes),
IOUtils.writeAtomic(tmpFileName, bytes),
/Could not parse path/,
"IOUtils::write only works with absolute paths"
"IOUtils::writeAtomic only works with absolute paths"
);
});
@ -286,7 +286,7 @@
await Assert.rejects(
IOUtils.read(tmpFileName),
/Could not parse path/,
"IOUtils::write only works with absolute paths"
"IOUtils::writeAtomic only works with absolute paths"
);
});
@ -296,7 +296,7 @@
info("Test writing lz4 encoded data");
const varyingBytes = Uint8Array.of(...new Array(50).keys());
let bytesWritten = await IOUtils.write(tmpFileName, varyingBytes, { compress: true });
let bytesWritten = await IOUtils.writeAtomic(tmpFileName, varyingBytes, { compress: true });
is(bytesWritten, 64, "Expected to write 64 bytes");
info("Test reading lz4 encoded data");
@ -305,7 +305,7 @@
info("Test writing lz4 compressed data");
const repeatedBytes = Uint8Array.of(...new Array(50).fill(1));
bytesWritten = await IOUtils.write(tmpFileName, repeatedBytes, { compress: true });
bytesWritten = await IOUtils.writeAtomic(tmpFileName, repeatedBytes, { compress: true });
is(bytesWritten, 23, "Expected 50 bytes to compress to 23 bytes");
info("Test reading lz4 encoded data");
@ -314,7 +314,7 @@
info("Test writing empty lz4 compressed data")
const empty = new Uint8Array();
bytesWritten = await IOUtils.write(tmpFileName, empty, { compress: true });
bytesWritten = await IOUtils.writeAtomic(tmpFileName, empty, { compress: true });
is(bytesWritten, 12, "Expected to write just the LZ4 header, with a content length of 0");
@ -337,8 +337,8 @@
info("Test OS.File and IOUtils write the same file with LZ4 compression enabled")
const repeatedBytes = Uint8Array.of(...new Array(50).fill(1));
let expectedBytes = 23;
let ioutilsBytes = await IOUtils.write(ioutilsTmpFile, repeatedBytes, { compress: true });
let osfileBytes = await OS.File.write(osfileTmpFile, repeatedBytes, { compression: "lz4" });
let ioutilsBytes = await IOUtils.writeAtomic(ioutilsTmpFile, repeatedBytes, { compress: true });
let osfileBytes = await OS.File.writeAtomic(osfileTmpFile, repeatedBytes, { compression: "lz4" });
is(ioutilsBytes, expectedBytes, "IOUtils writes the expected number of bytes for compression");
is(osfileBytes, ioutilsBytes, "OS.File and IOUtils write the same number of bytes for LZ4 compression");
@ -361,7 +361,7 @@
info("Test decompression with invalid options");
const varyingBytes = Uint8Array.of(...new Array(50).keys());
let bytesWritten = await IOUtils.write(tmpFileName, varyingBytes, { compress: true });
let bytesWritten = await IOUtils.writeAtomic(tmpFileName, varyingBytes, { compress: true });
is(bytesWritten, 64, "Expected to write 64 bytes");
await Assert.rejects(
IOUtils.read(tmpFileName, { maxBytes: 4, decompress: true }),
@ -378,7 +378,7 @@
info("Test decompression of non-lz4 data");
const repeatedBytes = Uint8Array.of(...new Array(50).fill(1));
await IOUtils.write(tmpFileName, repeatedBytes, { compress: false });
await IOUtils.writeAtomic(tmpFileName, repeatedBytes, { compress: false });
await Assert.rejects(
IOUtils.read(tmpFileName, { decompress: true }),
@ -398,7 +398,7 @@
info("Test decompression of short byte buffer");
const elevenBytes = Uint8Array.of(...new Array(11).fill(1));
await IOUtils.write(tmpFileName, elevenBytes, { compress: false });
await IOUtils.writeAtomic(tmpFileName, elevenBytes, { compress: false });
await Assert.rejects(
IOUtils.read(tmpFileName, { decompress: true }),
@ -410,7 +410,7 @@
const headerFor10bytes = [109, 111, 122, 76, 122, 52, 48, 0, 10, 0, 0, 0] // "mozlz40\0" + 4 byte length
const badContents = new Array(11).fill(255); // Bad leading byte, followed by uncompressed stream.
const goodHeaderBadContents = Uint8Array.of(...headerFor10bytes, ...badContents);
await IOUtils.write(tmpFileName, goodHeaderBadContents, { compress: false });
await IOUtils.writeAtomic(tmpFileName, goodHeaderBadContents, { compress: false });
await Assert.rejects(
IOUtils.read(tmpFileName, { decompress: true }),

Просмотреть файл

@ -40,7 +40,7 @@
const invalidUTF8File = OS.Path.join(tmpDir, "invalid_utf8.tmp");
// Deliberately write the invalid byte sequence to file.
await IOUtils.write(invalidUTF8File, invalidUTF8);
await IOUtils.writeAtomic(invalidUTF8File, invalidUTF8);
await Assert.rejects(
IOUtils.readUTF8(invalidUTF8File),
@ -55,22 +55,22 @@
// Make a new file, and try to write to it with overwrites disabled.
const tmpFileName = OS.Path.join(tmpDir, "test_ioutils_write_utf8_overwrite.tmp");
const untouchableContents = "Can't touch this!\n";
await IOUtils.writeUTF8(tmpFileName, untouchableContents);
await IOUtils.writeAtomicUTF8(tmpFileName, untouchableContents);
const newContents = "Nah nah nah!\n";
await Assert.rejects(
IOUtils.writeUTF8(tmpFileName, newContents, {
IOUtils.writeAtomicUTF8(tmpFileName, newContents, {
noOverwrite: true,
}),
/Refusing to overwrite the file at */,
"IOUtils::writeUTF8 rejects writing to existing file if overwrites are disabled"
"IOUtils::writeAtomicUTF8 rejects writing to existing file if overwrites are disabled"
);
ok(
await fileHasTextContents(tmpFileName, untouchableContents),
"IOUtils::writeUTF8 doesn't change target file when overwrite is refused"
"IOUtils::writeAtomicUTF8 doesn't change target file when overwrite is refused"
);
const bytesWritten = await IOUtils.writeUTF8(
const bytesWritten = await IOUtils.writeAtomicUTF8(
tmpFileName,
newContents,
{ noOverwrite: false /* Default. */ }
@ -78,11 +78,11 @@
is(
bytesWritten,
newContents.length,
"IOUtils::writeUTF8 can overwrite files if specified"
"IOUtils::writeAtomicUTF8 can overwrite files if specified"
);
ok(
await fileHasTextContents(tmpFileName, newContents),
"IOUtils::writeUTF8 overwrites with the expected contents"
"IOUtils::writeAtomicUTF8 overwrites with the expected contents"
);
await cleanup(tmpFileName);
@ -94,42 +94,42 @@
let destFileName = OS.Path.join(tmpDir, "test_write_utf8_with_backup_option.tmp");
let backupFileName = destFileName + ".backup";
let bytesWritten =
await IOUtils.writeUTF8(destFileName, fileContents, {
await IOUtils.writeAtomicUTF8(destFileName, fileContents, {
backupFile: backupFileName,
});
ok(
await fileHasTextContents(destFileName, "Original file contents"),
"IOUtils::writeUTF8 creates a new file with the correct contents"
"IOUtils::writeAtomicUTF8 creates a new file with the correct contents"
);
ok(
!await fileExists(backupFileName),
"IOUtils::writeUTF8 does not create a backup if the target file does not exist"
"IOUtils::writeAtomicUTF8 does not create a backup if the target file does not exist"
);
is(
bytesWritten,
fileContents.length,
"IOUtils::write correctly writes to a new file without performing a backup"
"IOUtils::writeAtomic correctly writes to a new file without performing a backup"
);
info("Test backup file option with existing destination");
let newFileContents = "New file contents";
ok(await fileExists(destFileName), `Expected ${destFileName} to exist`);
bytesWritten =
await IOUtils.writeUTF8(destFileName, newFileContents, {
await IOUtils.writeAtomicUTF8(destFileName, newFileContents, {
backupFile: backupFileName,
});
ok(
await fileHasTextContents(backupFileName, "Original file contents"),
"IOUtils::writeUTF8 can backup an existing file before writing"
"IOUtils::writeAtomicUTF8 can backup an existing file before writing"
);
ok(
await fileHasTextContents(destFileName, "New file contents"),
"IOUtils::writeUTF8 can create the target with the correct contents"
"IOUtils::writeAtomicUTF8 can create the target with the correct contents"
);
is(
bytesWritten,
newFileContents.length,
"IOUtils::writeUTF8 correctly writes to the target after taking a backup"
"IOUtils::writeAtomicUTF8 correctly writes to the target after taking a backup"
);
await cleanup(destFileName, backupFileName);
@ -142,46 +142,46 @@
let backupFileName = destFileName + ".backup";
let tmpFileName = OS.Path.join(tmpDir, "temp_file.tmp");
let bytesWritten =
await IOUtils.writeUTF8(destFileName, fileContents, {
await IOUtils.writeAtomicUTF8(destFileName, fileContents, {
backupFile: backupFileName,
tmpPath: tmpFileName,
});
ok(!await fileExists(tmpFileName), "IOUtils::writeUTF8 cleans up the tmpFile");
ok(!await fileExists(tmpFileName), "IOUtils::writeAtomicUTF8 cleans up the tmpFile");
ok(
!await fileExists(backupFileName),
"IOUtils::writeUTF8 does not create a backup if the target file does not exist"
"IOUtils::writeAtomicUTF8 does not create a backup if the target file does not exist"
);
ok(
await fileHasTextContents(destFileName, "Original file contents"),
"IOUtils::writeUTF8 can write to the destination when a temporary file is used"
"IOUtils::writeAtomicUTF8 can write to the destination when a temporary file is used"
);
is(
bytesWritten,
fileContents.length,
"IOUtils::writeUTF8 can copy tmp file to destination without performing a backup"
"IOUtils::writeAtomicUTF8 can copy tmp file to destination without performing a backup"
);
info("Test backup with tmp and backup file options, existing destination");
let newFileContents = "New file contents";
bytesWritten =
await IOUtils.writeUTF8(destFileName, newFileContents, {
await IOUtils.writeAtomicUTF8(destFileName, newFileContents, {
backupFile: backupFileName,
tmpPath: tmpFileName,
});
ok(!await fileExists(tmpFileName), "IOUtils::writeUTF8 cleans up the tmpFile");
ok(!await fileExists(tmpFileName), "IOUtils::writeAtomicUTF8 cleans up the tmpFile");
ok(
await fileHasTextContents(backupFileName, "Original file contents"),
"IOUtils::writeUTF8 can create a backup if the target file exists"
"IOUtils::writeAtomicUTF8 can create a backup if the target file exists"
);
ok(
await fileHasTextContents(destFileName, "New file contents"),
"IOUtils::writeUTF8 can write to the destination when a temporary file is used"
"IOUtils::writeAtomicUTF8 can write to the destination when a temporary file is used"
);
is(
bytesWritten,
newFileContents.length,
"IOUtils::writeUTF8 can move tmp file to destination after performing a backup"
"IOUtils::writeAtomicUTF8 can move tmp file to destination after performing a backup"
);
await cleanup(destFileName, backupFileName);
@ -190,11 +190,11 @@
add_task(async function test_empty_read_and_write_utf8() {
const tmpFileName = OS.Path.join(tmpDir, "test_ioutils_empty_utf8.tmp");
const emptyString = ""
const bytesWritten = await IOUtils.writeUTF8(
const bytesWritten = await IOUtils.writeAtomicUTF8(
tmpFileName,
emptyString
);
is(bytesWritten, 0, "IOUtils::writeUTF8 can create an empty file");
is(bytesWritten, 0, "IOUtils::writeAtomicUTF8 can create an empty file");
const nothing = await IOUtils.readUTF8(tmpFileName);
is(nothing.length, 0, "IOUtils::readUTF8 can read empty files");
@ -213,11 +213,11 @@
// ZWJ sequences.
const emoji = "☕️ ⚧️ 😀 🖖🏿 🤠 🏳️‍🌈 🥠 🏴‍☠️ 🪐";
const expectedBytes = 71;
const bytesWritten = await IOUtils.writeUTF8(tmpFileName, emoji);
const bytesWritten = await IOUtils.writeAtomicUTF8(tmpFileName, emoji);
is(
bytesWritten,
expectedBytes,
"IOUtils::writeUTF8 can write emoji to file"
"IOUtils::writeAtomicUTF8 can write emoji to file"
);
// Read it back.
@ -238,9 +238,9 @@
info("Test writing a file at a relative destination");
await Assert.rejects(
IOUtils.writeUTF8(tmpFileName, "foo"),
IOUtils.writeAtomicUTF8(tmpFileName, "foo"),
/Could not parse path/,
"IOUtils::writeUTF8 only works with absolute paths"
"IOUtils::writeAtomicUTF8 only works with absolute paths"
);
});
@ -261,7 +261,7 @@
info("Test writing lz4 encoded UTF-8 string");
const emoji = "☕️ ⚧️ 😀 🖖🏿 🤠 🏳️‍🌈 🥠 🏴‍☠️ 🪐";
let bytesWritten = await IOUtils.writeUTF8(tmpFileName, emoji, { compress: true });
let bytesWritten = await IOUtils.writeAtomicUTF8(tmpFileName, emoji, { compress: true });
is(bytesWritten, 83, "Expected to write 64 bytes");
info("Test reading lz4 encoded UTF-8 string");
@ -270,7 +270,7 @@
info("Test writing lz4 compressed UTF-8 string");
const lotsOfCoffee = new Array(24).fill("☕️").join(""); // ☕️ is 3 bytes in UTF-8: \0xe2 \0x98 \0x95
bytesWritten = await IOUtils.writeUTF8(tmpFileName, lotsOfCoffee, { compress: true });
bytesWritten = await IOUtils.writeAtomicUTF8(tmpFileName, lotsOfCoffee, { compress: true });
console.log(bytesWritten);
is(bytesWritten, 28, "Expected 72 bytes to compress to 28 bytes");
@ -280,7 +280,7 @@
info("Test writing empty lz4 compressed UTF-8 string")
const empty = "";
bytesWritten = await IOUtils.writeUTF8(tmpFileName, empty, { compress: true });
bytesWritten = await IOUtils.writeAtomicUTF8(tmpFileName, empty, { compress: true });
is(bytesWritten, 12, "Expected to write just the LZ4 header");
info("Test reading empty lz4 compressed UTF-8 string")
@ -299,8 +299,8 @@
info("Test OS.File and IOUtils write the same UTF-8 file with LZ4 compression enabled")
const emoji = "☕️ ⚧️ 😀 🖖🏿 🤠 🏳️‍🌈 🥠 🏴‍☠️ 🪐";
let expectedBytes = 83;
let ioutilsBytes = await IOUtils.writeUTF8(ioutilsTmpFile, emoji, { compress: true });
let osfileBytes = await OS.File.write(osfileTmpFile, emoji, { compression: "lz4" });
let ioutilsBytes = await IOUtils.writeAtomicUTF8(ioutilsTmpFile, emoji, { compress: true });
let osfileBytes = await OS.File.writeAtomic(osfileTmpFile, emoji, { compression: "lz4" });
is(ioutilsBytes, expectedBytes, "IOUtils writes the expected number of bytes for compression");
is(osfileBytes, ioutilsBytes, "OS.File and IOUtils write the same number of bytes for LZ4 compression");
@ -320,7 +320,7 @@
info("readUTF8 ignores the maxBytes option if provided");
const emoji = "☕️ ⚧️ 😀 🖖🏿 🤠 🏳️‍🌈 🥠 🏴‍☠️ 🪐";
let bytesWritten = await IOUtils.writeUTF8(tmpFileName, emoji, { compress: true });
let bytesWritten = await IOUtils.writeAtomicUTF8(tmpFileName, emoji, { compress: true });
is(bytesWritten, 83, "Expected to write 83 bytes");
let readData = await IOUtils.readUTF8(tmpFileName, { maxBytes: 4, decompress: true });
@ -334,7 +334,7 @@
info("Test decompression of non-lz4 UTF-8 string");
const repeatedBytes = Uint8Array.of(...new Array(50).fill(1));
await IOUtils.write(tmpFileName, repeatedBytes, { compress: false });
await IOUtils.writeAtomic(tmpFileName, repeatedBytes, { compress: false });
await Assert.rejects(
IOUtils.readUTF8(tmpFileName, { decompress: true }),
@ -344,7 +344,7 @@
info("Test UTF-8 decompression of short byte buffer");
const elevenBytes = Uint8Array.of(...new Array(11).fill(1));
await IOUtils.write(tmpFileName, elevenBytes, { compress: false });
await IOUtils.writeAtomic(tmpFileName, elevenBytes, { compress: false });
await Assert.rejects(
IOUtils.readUTF8(tmpFileName, { decompress: true }),
@ -356,7 +356,7 @@
const headerFor10bytes = [109, 111, 122, 76, 122, 52, 48, 0, 10, 0, 0, 0] // "mozlz40\0" + 4 byte length
const badContents = new Array(11).fill(255); // Bad leading byte, followed by uncompressed stream.
const goodHeaderBadContents = Uint8Array.of(...headerFor10bytes, ...badContents);
await IOUtils.write(tmpFileName, goodHeaderBadContents, { compress: false });
await IOUtils.writeAtomic(tmpFileName, goodHeaderBadContents, { compress: false });
await Assert.rejects(
IOUtils.readUTF8(tmpFileName, { decompress: true }),

Просмотреть файл

@ -25,7 +25,7 @@
add_task(async function test_create_and_remove_file() {
info("Test creating and removing a single file");
const tmpFileName = OS.Path.join(tmpDir, "test_ioutils_create_and_remove.tmp");
await IOUtils.write(tmpFileName, new Uint8Array(0));
await IOUtils.writeAtomic(tmpFileName, new Uint8Array(0));
ok(await fileExists(tmpFileName), `Expected file ${tmpFileName} to exist`);
await IOUtils.remove(tmpFileName);

Просмотреть файл

@ -18,7 +18,7 @@
const tempDir = await PathUtils.getTempDir();
const tempFile = PathUtils.join(tempDir, "setPermissions.tmp");
await IOUtils.writeUTF8(tempFile, "");
await IOUtils.writeAtomicUTF8(tempFile, "");
await IOUtils.setPermissions(tempFile, 0o421);
let stat = await IOUtils.stat(tempFile);

Просмотреть файл

@ -258,7 +258,7 @@ _ContextualIdentityService.prototype = {
};
let bytes = gTextEncoder.encode(JSON.stringify(object));
return IOUtils.write(this._path, bytes, {
return IOUtils.writeAtomic(this._path, bytes, {
tmpPath: this._path + ".tmp",
});
},

Просмотреть файл

@ -90,7 +90,7 @@ add_task(async function corruptedFile() {
);
// Let's create a corrupted file.
await IOUtils.writeUTF8(TEST_STORE_FILE_PATH, "{ vers", {
await IOUtils.writeAtomicUTF8(TEST_STORE_FILE_PATH, "{ vers", {
tmpPath: TEST_STORE_FILE_PATH + ".tmp",
});

Просмотреть файл

@ -168,7 +168,7 @@ DownloadStore.prototype = {
if (atLeastOneDownload) {
// Create or overwrite the file if there are downloads to save.
let bytes = gTextEncoder.encode(JSON.stringify(storeData));
await IOUtils.write(this.path, bytes, {
await IOUtils.writeAtomic(this.path, bytes, {
tmpPath: this.path + ".tmp",
});
} else {

Просмотреть файл

@ -122,7 +122,7 @@ add_task(async function test_save_reload() {
add_task(async function test_save_empty() {
let [, store] = await promiseNewListAndStore();
await IOUtils.write(store.path, new Uint8Array());
await IOUtils.writeAtomic(store.path, new Uint8Array());
await store.save();
@ -199,7 +199,7 @@ add_task(async function test_load_string_predefined() {
filePathLiteral +
"}]}";
await IOUtils.write(store.path, new TextEncoder().encode(string), {
await IOUtils.writeAtomic(store.path, new TextEncoder().encode(string), {
tmpPath: store.path + ".tmp",
});
@ -240,7 +240,7 @@ add_task(async function test_load_string_unrecognized() {
"}," +
'"saver":{"type":"copy"}}]}';
await IOUtils.write(store.path, new TextEncoder().encode(string), {
await IOUtils.writeAtomic(store.path, new TextEncoder().encode(string), {
tmpPath: store.path + ".tmp",
});
@ -264,7 +264,7 @@ add_task(async function test_load_string_malformed() {
'{"list":[{"source":null,"target":null},' +
'{"source":{"url":"about:blank"}}}';
await IOUtils.write(store.path, new TextEncoder().encode(string), {
await IOUtils.writeAtomic(store.path, new TextEncoder().encode(string), {
tmpPath: store.path + ".tmp",
});

Просмотреть файл

@ -320,7 +320,7 @@ var PlacesBackups = {
this._backupFiles.unshift(newFilePath);
}
let jsonString = await IOUtils.read(aFilePath);
await IOUtils.write(newFilePath, jsonString, {
await IOUtils.writeAtomic(newFilePath, jsonString, {
compress: true,
});
await limitBackups(aMaxBackup, this._backupFiles);

Просмотреть файл

@ -868,7 +868,7 @@ var AddonDatabase = {
addons: Array.from(this.DB.addons.values()),
};
await IOUtils.writeUTF8(this.jsonFile, JSON.stringify(json), {
await IOUtils.writeAtomicUTF8(this.jsonFile, JSON.stringify(json), {
tmpPath: `${this.jsonFile}.tmp`,
});
},

Просмотреть файл

@ -139,7 +139,7 @@ async function startProfilerAndTriggerFileIO({
info("Write to the file, but do so using a background thread.");
// IOUtils handles file operations using a background thread.
await IOUtils.write(path, new TextEncoder().encode("Test data."));
await IOUtils.writeAtomic(path, new TextEncoder().encode("Test data."));
const exists = await fileExists(path);
ok(exists, `Created temporary file at: ${path}`);