diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-19 01:13:27 +0000 |
commit | 40a355a42d4a9444dc753c04c6608dade2f06a23 (patch) | |
tree | 871fc667d2de662f171103ce5ec067014ef85e61 /dom/system | |
parent | Adding upstream version 124.0.1. (diff) | |
download | firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.tar.xz firefox-40a355a42d4a9444dc753c04c6608dade2f06a23.zip |
Adding upstream version 125.0.1.upstream/125.0.1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/system')
-rw-r--r-- | dom/system/IOUtils.cpp | 956 | ||||
-rw-r--r-- | dom/system/IOUtils.h | 52 | ||||
-rw-r--r-- | dom/system/NetworkGeolocationProvider.sys.mjs | 2 | ||||
-rw-r--r-- | dom/system/PathUtils.h | 3 | ||||
-rw-r--r-- | dom/system/tests/ioutils/file_ioutils_worker.js | 2 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_copy_move.html | 18 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_dir_iteration.html | 4 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_mac_xattr.html | 6 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_mkdir.html | 8 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_read_write.html | 34 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_read_write_json.html | 4 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_read_write_utf8.html | 18 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_remove.html | 4 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html | 6 | ||||
-rw-r--r-- | dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html | 2 |
15 files changed, 635 insertions, 484 deletions
diff --git a/dom/system/IOUtils.cpp b/dom/system/IOUtils.cpp index 08e2173452..4b989c6c0c 100644 --- a/dom/system/IOUtils.cpp +++ b/dom/system/IOUtils.cpp @@ -79,17 +79,23 @@ # include "base/process_util.h" #endif -#define REJECT_IF_INIT_PATH_FAILED(_file, _path, _promise) \ +#define REJECT_IF_INIT_PATH_FAILED(_file, _path, _promise, _msg, ...) \ do { \ if (nsresult _rv = PathUtils::InitFileWithPath((_file), (_path)); \ NS_FAILED(_rv)) { \ - (_promise)->MaybeRejectWithOperationError( \ - FormatErrorMessage(_rv, "Could not parse path (%s)", \ - NS_ConvertUTF16toUTF8(_path).get())); \ + (_promise)->MaybeRejectWithOperationError(FormatErrorMessage( \ + _rv, _msg ": could not parse path", ##__VA_ARGS__)); \ return; \ } \ } while (0) +#define IOUTILS_TRY_WITH_CONTEXT(_expr, _fmt, ...) \ + do { \ + if (nsresult _rv = (_expr); NS_FAILED(_rv)) { \ + return Err(IOUtils::IOError(_rv, _fmt, ##__VA_ARGS__)); \ + } \ + } while (0) + static constexpr auto SHUTDOWN_ERROR = "IOUtils: Shutting down and refusing additional I/O tasks"_ns; @@ -121,34 +127,32 @@ static bool IsNotDirectory(nsresult aResult) { /** * Formats an error message and appends the error name to the end. */ -template <typename... Args> -static nsCString FormatErrorMessage(nsresult aError, const char* const aMessage, - Args... aArgs) { - nsPrintfCString msg(aMessage, aArgs...); +static nsCString MOZ_FORMAT_PRINTF(2, 3) + FormatErrorMessage(nsresult aError, const char* const aFmt, ...) { + nsAutoCString errorName; + GetErrorName(aError, errorName); - if (const char* errName = GetStaticErrorName(aError)) { - msg.AppendPrintf(": %s", errName); - } else { - // In the exceptional case where there is no error name, print the literal - // integer value of the nsresult as an upper case hex value so it can be - // located easily in searchfox. - msg.AppendPrintf(": 0x%" PRIX32, static_cast<uint32_t>(aError)); - } + nsCString msg; + + va_list ap; + va_start(ap, aFmt); + msg.AppendVprintf(aFmt, ap); + va_end(ap); - return std::move(msg); + msg.AppendPrintf(" (%s)", errorName.get()); + + return msg; } static nsCString FormatErrorMessage(nsresult aError, - const char* const aMessage) { - const char* errName = GetStaticErrorName(aError); - if (errName) { - return nsPrintfCString("%s: %s", aMessage, errName); - } - // In the exceptional case where there is no error name, print the literal - // integer value of the nsresult as an upper case hex value so it can be - // located easily in searchfox. - return nsPrintfCString("%s: 0x%" PRIX32, aMessage, - static_cast<uint32_t>(aError)); + const nsCString& aMessage) { + nsAutoCString errorName; + GetErrorName(aError, errorName); + + nsCString msg(aMessage); + msg.AppendPrintf(" (%s)", errorName.get()); + + return msg; } [[nodiscard]] inline bool ToJSValue( @@ -183,99 +187,82 @@ static void ResolveJSPromise(Promise* aPromise, T&& aValue) { } static void RejectJSPromise(Promise* aPromise, const IOUtils::IOError& aError) { - const auto& errMsg = aError.Message(); + const auto errMsg = FormatErrorMessage(aError.Code(), aError.Message()); switch (aError.Code()) { case NS_ERROR_FILE_UNRESOLVABLE_SYMLINK: - [[fallthrough]]; // to NS_ERROR_FILE_INVALID_PATH + [[fallthrough]]; case NS_ERROR_FILE_NOT_FOUND: - [[fallthrough]]; // to NS_ERROR_FILE_INVALID_PATH + [[fallthrough]]; case NS_ERROR_FILE_INVALID_PATH: - aPromise->MaybeRejectWithNotFoundError(errMsg.refOr("File not found"_ns)); + [[fallthrough]]; + case NS_ERROR_NOT_AVAILABLE: + aPromise->MaybeRejectWithNotFoundError(errMsg); break; + case NS_ERROR_FILE_IS_LOCKED: - [[fallthrough]]; // to NS_ERROR_FILE_ACCESS_DENIED + [[fallthrough]]; case NS_ERROR_FILE_ACCESS_DENIED: - aPromise->MaybeRejectWithNotAllowedError( - errMsg.refOr("Access was denied to the target file"_ns)); + aPromise->MaybeRejectWithNotAllowedError(errMsg); break; + case NS_ERROR_FILE_TOO_BIG: - aPromise->MaybeRejectWithNotReadableError( - errMsg.refOr("Target file is too big"_ns)); - break; + [[fallthrough]]; case NS_ERROR_FILE_NO_DEVICE_SPACE: - aPromise->MaybeRejectWithNotReadableError( - errMsg.refOr("Target device is full"_ns)); + [[fallthrough]]; + case NS_ERROR_FILE_DEVICE_FAILURE: + [[fallthrough]]; + case NS_ERROR_FILE_FS_CORRUPTED: + [[fallthrough]]; + case NS_ERROR_FILE_CORRUPTED: + aPromise->MaybeRejectWithNotReadableError(errMsg); break; + case NS_ERROR_FILE_ALREADY_EXISTS: - aPromise->MaybeRejectWithNoModificationAllowedError( - errMsg.refOr("Target file already exists"_ns)); + aPromise->MaybeRejectWithNoModificationAllowedError(errMsg); break; + case NS_ERROR_FILE_COPY_OR_MOVE_FAILED: - aPromise->MaybeRejectWithOperationError( - errMsg.refOr("Failed to copy or move the target file"_ns)); + [[fallthrough]]; + case NS_ERROR_FILE_NAME_TOO_LONG: + [[fallthrough]]; + case NS_ERROR_FILE_UNRECOGNIZED_PATH: + [[fallthrough]]; + case NS_ERROR_FILE_DIR_NOT_EMPTY: + aPromise->MaybeRejectWithOperationError(errMsg); break; + case NS_ERROR_FILE_READ_ONLY: - aPromise->MaybeRejectWithReadOnlyError( - errMsg.refOr("Target file is read only"_ns)); + aPromise->MaybeRejectWithReadOnlyError(errMsg); break; + case NS_ERROR_FILE_NOT_DIRECTORY: - [[fallthrough]]; // to NS_ERROR_FILE_DESTINATION_NOT_DIR + [[fallthrough]]; case NS_ERROR_FILE_DESTINATION_NOT_DIR: - aPromise->MaybeRejectWithInvalidAccessError( - errMsg.refOr("Target file is not a directory"_ns)); - break; + [[fallthrough]]; case NS_ERROR_FILE_IS_DIRECTORY: - aPromise->MaybeRejectWithInvalidAccessError( - errMsg.refOr("Target file is a directory"_ns)); - break; + [[fallthrough]]; case NS_ERROR_FILE_UNKNOWN_TYPE: - aPromise->MaybeRejectWithInvalidAccessError( - errMsg.refOr("Target file is of unknown type"_ns)); - break; - case NS_ERROR_FILE_NAME_TOO_LONG: - aPromise->MaybeRejectWithOperationError( - errMsg.refOr("Target file path is too long"_ns)); - break; - case NS_ERROR_FILE_UNRECOGNIZED_PATH: - aPromise->MaybeRejectWithOperationError( - errMsg.refOr("Target file path is not recognized"_ns)); - break; - case NS_ERROR_FILE_DIR_NOT_EMPTY: - aPromise->MaybeRejectWithOperationError( - errMsg.refOr("Target directory is not empty"_ns)); - break; - case NS_ERROR_FILE_DEVICE_FAILURE: - [[fallthrough]]; // to NS_ERROR_FILE_FS_CORRUPTED - case NS_ERROR_FILE_FS_CORRUPTED: - aPromise->MaybeRejectWithNotReadableError( - errMsg.refOr("Target file system may be corrupt or unavailable"_ns)); - break; - case NS_ERROR_FILE_CORRUPTED: - aPromise->MaybeRejectWithNotReadableError( - errMsg.refOr("Target file could not be read and may be corrupt"_ns)); + aPromise->MaybeRejectWithInvalidAccessError(errMsg); break; + case NS_ERROR_ILLEGAL_INPUT: - [[fallthrough]]; // NS_ERROR_ILLEGAL_VALUE + [[fallthrough]]; case NS_ERROR_ILLEGAL_VALUE: - aPromise->MaybeRejectWithDataError( - errMsg.refOr("Argument is not allowed"_ns)); - break; - case NS_ERROR_NOT_AVAILABLE: - aPromise->MaybeRejectWithNotFoundError(errMsg.refOr("Unavailable"_ns)); + aPromise->MaybeRejectWithDataError(errMsg); break; + case NS_ERROR_ABORT: - aPromise->MaybeRejectWithAbortError(errMsg.refOr("Operation aborted"_ns)); + aPromise->MaybeRejectWithAbortError(errMsg); break; + default: - aPromise->MaybeRejectWithUnknownError(FormatErrorMessage( - aError.Code(), errMsg.refOr("Unexpected error"_ns).get())); + aPromise->MaybeRejectWithUnknownError(errMsg); } } static void RejectShuttingDown(Promise* aPromise) { - RejectJSPromise(aPromise, - IOUtils::IOError(NS_ERROR_ABORT).WithMessage(SHUTDOWN_ERROR)); + RejectJSPromise(aPromise, IOUtils::IOError(NS_ERROR_ABORT, SHUTDOWN_ERROR)); } static bool AssertParentProcessWithCallerLocationImpl(GlobalObject& aGlobal, @@ -368,10 +355,20 @@ already_AddRefed<Promise> IOUtils::Read(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not read `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); Maybe<uint32_t> toRead = Nothing(); if (!aOptions.mMaxBytes.IsNull()) { + if (aOptions.mDecompress) { + RejectJSPromise( + promise, IOError(NS_ERROR_ILLEGAL_INPUT, + "Could not read `%s': the `maxBytes' and " + "`decompress' options are mutually exclusive", + file->HumanReadablePath().get())); + return; + } + if (aOptions.mMaxBytes.Value() == 0) { // Resolve with an empty buffer. nsTArray<uint8_t> arr(0); @@ -437,7 +434,8 @@ already_AddRefed<Promise> IOUtils::ReadUTF8(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not read `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<JsBuffer>( state->mEventQueue, promise, @@ -455,7 +453,8 @@ already_AddRefed<Promise> IOUtils::ReadJSON(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not read `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); RefPtr<StrongWorkerRef> workerRef; if (!NS_IsMainThread()) { @@ -476,8 +475,12 @@ already_AddRefed<Promise> IOUtils::ReadJSON(GlobalObject& aGlobal, file](JsBuffer&& aBuffer) { AutoJSAPI jsapi; if (NS_WARN_IF(!jsapi.Init(promise->GetGlobalObject()))) { - promise->MaybeRejectWithUnknownError( - "Could not initialize JS API"); + RejectJSPromise( + promise, + IOError( + NS_ERROR_DOM_UNKNOWN_ERR, + "Could not read `%s': could not initialize JS API", + file->HumanReadablePath().get())); return; } JSContext* cx = jsapi.cx(); @@ -486,7 +489,12 @@ already_AddRefed<Promise> IOUtils::ReadJSON(GlobalObject& aGlobal, cx, IOUtils::JsBuffer::IntoString(cx, std::move(aBuffer))); if (!jsonStr) { - RejectJSPromise(promise, IOError(NS_ERROR_OUT_OF_MEMORY)); + RejectJSPromise( + promise, + IOError( + NS_ERROR_OUT_OF_MEMORY, + "Could not read `%s': failed to allocate buffer", + file->HumanReadablePath().get())); return; } @@ -497,13 +505,11 @@ already_AddRefed<Promise> IOUtils::ReadJSON(GlobalObject& aGlobal, JS_ClearPendingException(cx); promise->MaybeReject(exn); } else { - RejectJSPromise( - promise, - IOError(NS_ERROR_DOM_UNKNOWN_ERR) - .WithMessage( - "ParseJSON threw an uncatchable exception " - "while parsing file(%s)", - file->HumanReadablePath().get())); + RejectJSPromise(promise, + IOError(NS_ERROR_DOM_UNKNOWN_ERR, + "Could not read `%s': ParseJSON " + "threw an uncatchable exception", + file->HumanReadablePath().get())); } return; @@ -526,25 +532,31 @@ already_AddRefed<Promise> IOUtils::Write(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not write to `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); Maybe<Buffer<uint8_t>> buf = aData.CreateFromData<Buffer<uint8_t>>(); if (buf.isNothing()) { - promise->MaybeRejectWithOperationError( - "Out of memory: Could not allocate buffer while writing to file"); + promise->MaybeRejectWithOperationError(nsPrintfCString( + "Could not write to `%s': could not allocate buffer", + file->HumanReadablePath().get())); return; } - auto opts = InternalWriteOpts::FromBinding(aOptions); - if (opts.isErr()) { - RejectJSPromise(promise, opts.unwrapErr()); + auto result = InternalWriteOpts::FromBinding(aOptions); + if (result.isErr()) { + RejectJSPromise( + promise, + IOError::WithCause(result.unwrapErr(), "Could not write to `%s'", + file->HumanReadablePath().get())); return; } DispatchAndResolve<uint32_t>( state->mEventQueue, promise, [file = std::move(file), buf = buf.extract(), - opts = opts.unwrap()]() { return WriteSync(file, buf, opts); }); + opts = result.unwrap()]() { return WriteSync(file, buf, opts); }); }); } @@ -557,18 +569,23 @@ already_AddRefed<Promise> IOUtils::WriteUTF8(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not write to `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); - auto opts = InternalWriteOpts::FromBinding(aOptions); - if (opts.isErr()) { - RejectJSPromise(promise, opts.unwrapErr()); + auto result = InternalWriteOpts::FromBinding(aOptions); + if (result.isErr()) { + RejectJSPromise( + promise, + IOError::WithCause(result.unwrapErr(), "Could not write to `%s'", + file->HumanReadablePath().get())); return; } DispatchAndResolve<uint32_t>( state->mEventQueue, promise, [file = std::move(file), str = nsCString(aString), - opts = opts.unwrap()]() { + opts = result.unwrap()]() { return WriteSync(file, AsBytes(Span(str)), opts); }); }); @@ -583,18 +600,27 @@ already_AddRefed<Promise> IOUtils::WriteJSON(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not write to `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); - auto opts = InternalWriteOpts::FromBinding(aOptions); - if (opts.isErr()) { - RejectJSPromise(promise, opts.unwrapErr()); + auto result = InternalWriteOpts::FromBinding(aOptions); + if (result.isErr()) { + RejectJSPromise( + promise, + IOError::WithCause(result.unwrapErr(), "Could not write to `%s'", + file->HumanReadablePath().get())); return; } - if (opts.inspect().mMode == WriteMode::Append || - opts.inspect().mMode == WriteMode::AppendOrCreate) { + auto opts = result.unwrap(); + + if (opts.mMode == WriteMode::Append || + opts.mMode == WriteMode::AppendOrCreate) { promise->MaybeRejectWithNotSupportedError( - "IOUtils.writeJSON does not support appending to files."_ns); + nsPrintfCString("Could not write to `%s': IOUtils.writeJSON does " + "not support appending to files.", + file->HumanReadablePath().get())); return; } @@ -608,10 +634,9 @@ already_AddRefed<Promise> IOUtils::WriteJSON(GlobalObject& aGlobal, JS_ClearPendingException(cx); promise->MaybeReject(exn); } else { - RejectJSPromise( - promise, - IOError(NS_ERROR_DOM_UNKNOWN_ERR) - .WithMessage("Could not serialize object to JSON")); + RejectJSPromise(promise, + IOError(NS_ERROR_DOM_UNKNOWN_ERR, + "Could not serialize object to JSON"_ns)); } return; } @@ -619,10 +644,13 @@ already_AddRefed<Promise> IOUtils::WriteJSON(GlobalObject& aGlobal, DispatchAndResolve<uint32_t>( state->mEventQueue, promise, [file = std::move(file), string = std::move(string), - opts = opts.unwrap()]() -> Result<uint32_t, IOError> { + opts = std::move(opts)]() -> Result<uint32_t, IOError> { nsAutoCString utf8Str; if (!CopyUTF16toUTF8(string, utf8Str, fallible)) { - return Err(IOError(NS_ERROR_OUT_OF_MEMORY)); + return Err(IOError( + NS_ERROR_OUT_OF_MEMORY, + "Failed to write to `%s': could not allocate buffer", + file->HumanReadablePath().get())); } return WriteSync(file, AsBytes(Span(utf8Str)), opts); }); @@ -638,10 +666,16 @@ already_AddRefed<Promise> IOUtils::Move(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> sourceFile = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise); + REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise, + "Could not move `%s' to `%s'", + NS_ConvertUTF16toUTF8(aSourcePath).get(), + NS_ConvertUTF16toUTF8(aDestPath).get()); nsCOMPtr<nsIFile> destFile = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise); + REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise, + "Could not move `%s' to `%s'", + NS_ConvertUTF16toUTF8(aSourcePath).get(), + NS_ConvertUTF16toUTF8(aDestPath).get()); DispatchAndResolve<Ok>( state->mEventQueue, promise, @@ -660,7 +694,9 @@ already_AddRefed<Promise> IOUtils::Remove(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not remove `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<Ok>( state->mEventQueue, promise, @@ -679,7 +715,9 @@ already_AddRefed<Promise> IOUtils::MakeDirectory( return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not make directory `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<Ok>(state->mEventQueue, promise, [file = std::move(file), @@ -699,7 +737,8 @@ already_AddRefed<Promise> IOUtils::Stat(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not stat `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<InternalFileInfo>( state->mEventQueue, promise, @@ -716,10 +755,16 @@ already_AddRefed<Promise> IOUtils::Copy(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> sourceFile = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise); + REJECT_IF_INIT_PATH_FAILED(sourceFile, aSourcePath, promise, + "Could not copy `%s' to `%s'", + NS_ConvertUTF16toUTF8(aSourcePath).get(), + NS_ConvertUTF16toUTF8(aDestPath).get()); nsCOMPtr<nsIFile> destFile = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise); + REJECT_IF_INIT_PATH_FAILED(destFile, aDestPath, promise, + "Could not copy `%s' to `%s'", + NS_ConvertUTF16toUTF8(aSourcePath).get(), + NS_ConvertUTF16toUTF8(aDestPath).get()); DispatchAndResolve<Ok>( state->mEventQueue, promise, @@ -736,7 +781,7 @@ already_AddRefed<Promise> IOUtils::SetAccessTime( GlobalObject& aGlobal, const nsAString& aPath, const Optional<int64_t>& aAccess, ErrorResult& aError) { return SetTime(aGlobal, aPath, aAccess, &nsIFile::SetLastAccessedTime, - aError); + "access", aError); } /* static */ @@ -744,7 +789,7 @@ already_AddRefed<Promise> IOUtils::SetModificationTime( GlobalObject& aGlobal, const nsAString& aPath, const Optional<int64_t>& aModification, ErrorResult& aError) { return SetTime(aGlobal, aPath, aModification, &nsIFile::SetLastModifiedTime, - aError); + "modification", aError); } /* static */ @@ -752,11 +797,14 @@ already_AddRefed<Promise> IOUtils::SetTime(GlobalObject& aGlobal, const nsAString& aPath, const Optional<int64_t>& aNewTime, IOUtils::SetTimeFn aSetTimeFn, + const char* const aTimeKind, ErrorResult& aError) { return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not set %s time on `%s'", aTimeKind, + NS_ConvertUTF16toUTF8(aPath).get()); int64_t newTime = aNewTime.WasPassed() ? aNewTime.Value() : PR_Now() / PR_USEC_PER_MSEC; @@ -775,7 +823,9 @@ already_AddRefed<Promise> IOUtils::GetChildren( return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not get children of `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<nsTArray<nsString>>( state->mEventQueue, promise, @@ -800,7 +850,9 @@ already_AddRefed<Promise> IOUtils::SetPermissions(GlobalObject& aGlobal, #endif nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not set permissions on `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<Ok>( state->mEventQueue, promise, @@ -817,7 +869,9 @@ already_AddRefed<Promise> IOUtils::Exists(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not determine if `%s' exists", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<bool>( state->mEventQueue, promise, @@ -853,14 +907,21 @@ already_AddRefed<Promise> IOUtils::CreateUnique(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aParent, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aParent, promise, "Could not create unique %s in `%s'", + aFileType == nsIFile::NORMAL_FILE_TYPE ? "file" : "directory", + NS_ConvertUTF16toUTF8(aParent).get()); if (nsresult rv = file->Append(aPrefix); NS_FAILED(rv)) { - RejectJSPromise(promise, - IOError(rv).WithMessage( - "Could not append prefix `%s' to parent `%s'", - NS_ConvertUTF16toUTF8(aPrefix).get(), - file->HumanReadablePath().get())); + RejectJSPromise( + promise, + IOError( + rv, + "Could not create unique %s: could not append prefix `%s' to " + "parent `%s'", + aFileType == nsIFile::NORMAL_FILE_TYPE ? "file" : "directory", + NS_ConvertUTF16toUTF8(aPrefix).get(), + file->HumanReadablePath().get())); return; } @@ -881,14 +942,14 @@ already_AddRefed<Promise> IOUtils::ComputeHexDigest( return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { if (!nssInitialized) { - RejectJSPromise(promise, - IOError(NS_ERROR_UNEXPECTED) - .WithMessage("Could not initialize NSS")); + RejectJSPromise(promise, IOError(NS_ERROR_UNEXPECTED, + "Could not initialize NSS"_ns)); return; } nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, "Could not hash `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<nsCString>(state->mEventQueue, promise, [file = std::move(file), aAlgorithm]() { @@ -907,7 +968,10 @@ already_AddRefed<Promise> IOUtils::GetWindowsAttributes(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED(file, aPath, promise, + "Could not get Windows file attributes of " + "`%s'", + NS_ConvertUTF16toUTF8(aPath).get()); RefPtr<StrongWorkerRef> workerRef; if (!NS_IsMainThread()) { @@ -945,7 +1009,10 @@ already_AddRefed<Promise> IOUtils::SetWindowsAttributes( return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not set Windows file attributes on `%s'", + NS_ConvertUTF16toUTF8(aPath).get()); uint32_t setAttrs = 0; uint32_t clearAttrs = 0; @@ -992,7 +1059,11 @@ already_AddRefed<Promise> IOUtils::HasMacXAttr(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not read the extended attribute `%s' from `%s'", + PromiseFlatCString(aAttr).get(), + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<bool>( state->mEventQueue, promise, @@ -1010,7 +1081,11 @@ already_AddRefed<Promise> IOUtils::GetMacXAttr(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not read extended attribute `%s' from `%s'", + PromiseFlatCString(aAttr).get(), + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<nsTArray<uint8_t>>( state->mEventQueue, promise, @@ -1029,16 +1104,21 @@ already_AddRefed<Promise> IOUtils::SetMacXAttr(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not set the extended attribute `%s' on `%s'", + PromiseFlatCString(aAttr).get(), + NS_ConvertUTF16toUTF8(aPath).get()); nsTArray<uint8_t> value; if (!aValue.AppendDataTo(value)) { RejectJSPromise( - promise, - IOError(NS_ERROR_OUT_OF_MEMORY) - .WithMessage( - "Could not allocate buffer to set extended attribute")); + promise, IOError(NS_ERROR_OUT_OF_MEMORY, + "Could not set extended attribute `%s' on `%s': " + "could not allocate buffer", + PromiseFlatCString(aAttr).get(), + file->HumanReadablePath().get())); return; } @@ -1058,7 +1138,11 @@ already_AddRefed<Promise> IOUtils::DelMacXAttr(GlobalObject& aGlobal, return WithPromiseAndState( aGlobal, aError, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); - REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); + REJECT_IF_INIT_PATH_FAILED( + file, aPath, promise, + "Could not delete extended attribute `%s' on `%s'", + PromiseFlatCString(aAttr).get(), + NS_ConvertUTF16toUTF8(aPath).get()); DispatchAndResolve<Ok>( state->mEventQueue, promise, @@ -1086,8 +1170,10 @@ already_AddRefed<Promise> IOUtils::GetFile( nsCOMPtr<nsIFile> parent; if (nsresult rv = file->GetParent(getter_AddRefs(parent)); NS_FAILED(rv)) { - RejectJSPromise(promise, IOError(rv).WithMessage( - "Could not get parent directory")); + RejectJSPromise(promise, IOError(rv, + "Could not get nsIFile for `%s': " + "could not get parent directory", + file->HumanReadablePath().get())); return; } @@ -1153,19 +1239,16 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync( nsIFile* aFile, const uint64_t aOffset, const Maybe<uint32_t> aMaxBytes, const bool aDecompress, IOUtils::BufferKind aBufferKind) { MOZ_ASSERT(!NS_IsMainThread()); - - if (aMaxBytes.isSome() && aDecompress) { - return Err( - IOError(NS_ERROR_ILLEGAL_INPUT) - .WithMessage( - "The `maxBytes` and `decompress` options are not compatible")); - } + // This is checked in IOUtils::Read. + MOZ_ASSERT(aMaxBytes.isNothing() || !aDecompress, + "maxBytes and decompress are mutually exclusive"); if (aOffset > static_cast<uint64_t>(INT64_MAX)) { - return Err(IOError(NS_ERROR_ILLEGAL_INPUT) - .WithMessage("Requested offset is too large (%" PRIu64 - " > %" PRId64 ")", - aOffset, INT64_MAX)); + return Err( + IOError(NS_ERROR_ILLEGAL_INPUT, + "Could not read `%s': requested offset is too large (%" PRIu64 + " > %" PRId64 ")", + aFile->HumanReadablePath().get(), aOffset, INT64_MAX)); } const int64_t offset = static_cast<int64_t>(aOffset); @@ -1174,8 +1257,12 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync( if (nsresult rv = stream->Init(aFile, PR_RDONLY | nsIFile::OS_READAHEAD, 0666, 0); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not open the file at %s", - aFile->HumanReadablePath().get())); + if (IsFileNotFound(rv)) { + return Err(IOError(rv, "Could not open `%s': file does not exist", + aFile->HumanReadablePath().get())); + } + return Err( + IOError(rv, "Could not open `%s'", aFile->HumanReadablePath().get())); } uint32_t bufSize = 0; @@ -1187,9 +1274,10 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync( int64_t rawStreamSize = -1; if (nsresult rv = stream->GetSize(&rawStreamSize); NS_FAILED(rv)) { - return Err(IOError(NS_ERROR_FILE_ACCESS_DENIED) - .WithMessage("Could not get info for the file at %s", - aFile->HumanReadablePath().get())); + return Err( + IOError(NS_ERROR_FILE_ACCESS_DENIED, + "Could not open `%s': could not stat file or directory", + aFile->HumanReadablePath().get())); } MOZ_RELEASE_ASSERT(rawStreamSize >= 0); @@ -1198,10 +1286,9 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync( bufSize = 0; } else { if (streamSize - offset > static_cast<int64_t>(UINT32_MAX)) { - return Err(IOError(NS_ERROR_FILE_TOO_BIG) - .WithMessage( - "Could not read the file at %s with offset %" PRIu32 - " because it is too large(size=%" PRIu64 " bytes)", + return Err(IOError(NS_ERROR_FILE_TOO_BIG, + "Could not read `%s' with offset %" PRIu64 + ": file is too large (%" PRIu64 " bytes)", aFile->HumanReadablePath().get(), offset, streamSize)); } @@ -1214,9 +1301,9 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync( if (offset > 0) { if (nsresult rv = stream->Seek(PR_SEEK_SET, offset); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not seek to position %" PRId64 " in file %s", offset, - aFile->HumanReadablePath().get())); + return Err(IOError( + rv, "Could not read `%s': could not seek to position %" PRId64, + aFile->HumanReadablePath().get(), offset)); } } @@ -1225,7 +1312,8 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync( if (bufSize > 0) { auto result = JsBuffer::Create(aBufferKind, bufSize); if (result.isErr()) { - return result.propagateErr(); + return Err(IOError::WithCause(result.unwrapErr(), "Could not read `%s'", + aFile->HumanReadablePath().get())); } buffer = result.unwrap(); Span<char> toRead = buffer.BeginWriting(); @@ -1241,9 +1329,9 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync( if (nsresult rv = stream->Read(toRead.Elements(), bytesToReadThisChunk, &bytesRead); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Encountered an unexpected error while reading file(%s)", - aFile->HumanReadablePath().get())); + return Err( + IOError(rv, "Could not read `%s': encountered an unexpected error", + aFile->HumanReadablePath().get())); } if (bytesRead == 0) { break; @@ -1257,7 +1345,13 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadSync( // Decompress the file contents, if required. if (aDecompress) { - return MozLZ4::Decompress(AsBytes(buffer.BeginReading()), aBufferKind); + auto result = + MozLZ4::Decompress(AsBytes(buffer.BeginReading()), aBufferKind); + if (result.isErr()) { + return Err(IOError::WithCause(result.unwrapErr(), "Could not read `%s'", + aFile->HumanReadablePath().get())); + } + return result; } return std::move(buffer); @@ -1273,11 +1367,9 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::ReadUTF8Sync( JsBuffer buffer = result.unwrap(); if (!IsUtf8(buffer.BeginReading())) { - return Err( - IOError(NS_ERROR_FILE_CORRUPTED) - .WithMessage( - "Could not read file(%s) because it is not UTF-8 encoded", - aFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_CORRUPTED, + "Could not read `%s': file is not UTF-8 encoded", + aFile->HumanReadablePath().get())); } return buffer; @@ -1293,14 +1385,16 @@ Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync( nsIFile* tempFile = aOptions.mTmpFile; bool exists = false; - MOZ_TRY(aFile->Exists(&exists)); + IOUTILS_TRY_WITH_CONTEXT( + aFile->Exists(&exists), + "Could not write to `%s': could not stat file or directory", + aFile->HumanReadablePath().get()); if (exists && aOptions.mMode == WriteMode::Create) { - return Err(IOError(NS_ERROR_FILE_ALREADY_EXISTS) - .WithMessage("Refusing to overwrite the file at %s\n" - "Specify `mode: \"overwrite\"` to allow " - "overwriting the destination", - aFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_ALREADY_EXISTS, + "Could not write to `%s': refusing to overwrite file, " + "`mode' is not \"overwrite\"", + aFile->HumanReadablePath().get())); } // If backupFile was specified, perform the backup as a move. @@ -1316,11 +1410,12 @@ Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync( bool noOverwrite = aOptions.mMode == WriteMode::Create; - if (MoveSync(toMove, backupFile, noOverwrite).isErr()) { - return Err(IOError(NS_ERROR_FILE_COPY_OR_MOVE_FAILED) - .WithMessage("Failed to backup the source file(%s) to %s", - aFile->HumanReadablePath().get(), - backupFile->HumanReadablePath().get())); + if (auto result = MoveSync(toMove, backupFile, noOverwrite); + result.isErr()) { + return Err(IOError::WithCause( + result.unwrapErr(), + "Could not write to `%s': failed to back up source file", + aFile->HumanReadablePath().get())); } } @@ -1369,11 +1464,13 @@ Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync( nsTArray<uint8_t> compressed; Span<const char> bytes; if (aOptions.mCompress) { - auto rv = MozLZ4::Compress(aByteArray); - if (rv.isErr()) { - return rv.propagateErr(); + auto result = MozLZ4::Compress(aByteArray); + if (result.isErr()) { + return Err(IOError::WithCause(result.unwrapErr(), + "Could not write to `%s'", + writeFile->HumanReadablePath().get())); } - compressed = rv.unwrap(); + compressed = result.unwrap(); bytes = Span(reinterpret_cast<const char*>(compressed.Elements()), compressed.Length()); } else { @@ -1388,9 +1485,9 @@ Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync( if (rv == nsresult::NS_ERROR_FILE_IS_DIRECTORY) { rv = NS_ERROR_FILE_ACCESS_DENIED; } - return Err( - IOError(rv).WithMessage("Could not open the file at %s for writing", - writeFile->HumanReadablePath().get())); + return Err(IOError( + rv, "Could not write to `%s': failed to open file for writing", + writeFile->HumanReadablePath().get())); } // nsFileRandomAccessStream::Write uses PR_Write under the hood, which @@ -1407,10 +1504,10 @@ Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync( if (nsresult rv = stream->Write(pendingBytes.Elements(), chunkSize, &bytesWritten); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not write chunk (size = %" PRIu32 - ") to file %s. The file may be corrupt.", - chunkSize, writeFile->HumanReadablePath().get())); + return Err(IOError(rv, + "Could not write to `%s': failed to write chunk; " + "the file may be corrupt", + writeFile->HumanReadablePath().get())); } pendingBytes = pendingBytes.From(bytesWritten); totalWritten += bytesWritten; @@ -1433,8 +1530,9 @@ Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync( bool isDir = false; if (nsresult rv = aFile->IsDirectory(&isDir); NS_FAILED(rv) && !IsFileNotFound(rv)) { - return Err(IOError(rv).WithMessage("Could not stat the file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError( + rv, "Could not write to `%s': could not stat file or directory", + aFile->HumanReadablePath().get())); } // If we attempt to write to a directory *without* a temp file, we get a @@ -1445,20 +1543,19 @@ Result<uint32_t, IOUtils::IOError> IOUtils::WriteSync( // inside the directory, which is not what we want. In this case, we are // just going to bail out early. if (isDir) { - return Err( - IOError(NS_ERROR_FILE_ACCESS_DENIED) - .WithMessage("Could not open the file at %s for writing", - aFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_ACCESS_DENIED, + "Could not write to `%s': file is a directory", + aFile->HumanReadablePath().get())); } } - if (MoveSync(writeFile, aFile, /* aNoOverwrite = */ false).isErr()) { - return Err( - IOError(NS_ERROR_FILE_COPY_OR_MOVE_FAILED) - .WithMessage( - "Could not move temporary file(%s) to destination(%s)", - writeFile->HumanReadablePath().get(), - aFile->HumanReadablePath().get())); + if (auto result = MoveSync(writeFile, aFile, /* aNoOverwrite = */ false); + result.isErr()) { + return Err(IOError::WithCause( + result.unwrapErr(), + "Could not write to `%s': could not move overwite with temporary " + "file", + aFile->HumanReadablePath().get())); } } } @@ -1474,13 +1571,18 @@ Result<Ok, IOUtils::IOError> IOUtils::MoveSync(nsIFile* aSourceFile, // Ensure the source file exists before continuing. If it doesn't exist, // subsequent operations can fail in different ways on different platforms. bool srcExists = false; - MOZ_TRY(aSourceFile->Exists(&srcExists)); + IOUTILS_TRY_WITH_CONTEXT( + aSourceFile->Exists(&srcExists), + "Could not move `%s' to `%s': could not stat source file or directory", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get()); + if (!srcExists) { return Err( - IOError(NS_ERROR_FILE_NOT_FOUND) - .WithMessage( - "Could not move source file(%s) because it does not exist", - aSourceFile->HumanReadablePath().get())); + IOError(NS_ERROR_FILE_NOT_FOUND, + "Could not move `%s' to `%s': source file does not exist", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get())); } return CopyOrMoveSync(&nsIFile::MoveToFollowingLinks, "move", aSourceFile, @@ -1497,28 +1599,35 @@ Result<Ok, IOUtils::IOError> IOUtils::CopySync(nsIFile* aSourceFile, // Ensure the source file exists before continuing. If it doesn't exist, // subsequent operations can fail in different ways on different platforms. bool srcExists; - MOZ_TRY(aSourceFile->Exists(&srcExists)); + IOUTILS_TRY_WITH_CONTEXT( + aSourceFile->Exists(&srcExists), + "Could not copy `%s' to `%s': could not stat source file or directory", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get()); + if (!srcExists) { return Err( - IOError(NS_ERROR_FILE_NOT_FOUND) - .WithMessage( - "Could not copy source file(%s) because it does not exist", - aSourceFile->HumanReadablePath().get())); + IOError(NS_ERROR_FILE_NOT_FOUND, + "Could not copy `%s' to `%s': source file does not exist", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get())); } // If source is a directory, fail immediately unless the recursive option is // true. bool srcIsDir = false; - MOZ_TRY(aSourceFile->IsDirectory(&srcIsDir)); + IOUTILS_TRY_WITH_CONTEXT( + aSourceFile->IsDirectory(&srcIsDir), + "Could not copy `%s' to `%s': could not stat source file or directory", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get()); + if (srcIsDir && !aRecursive) { - return Err( - IOError(NS_ERROR_FILE_COPY_OR_MOVE_FAILED) - .WithMessage( - "Refused to copy source directory(%s) to the destination(%s)\n" - "Specify the `recursive: true` option to allow copying " - "directories", - aSourceFile->HumanReadablePath().get(), - aDestFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_COPY_OR_MOVE_FAILED, + "Refused to copy directory `%s' to `%s': `recursive' is " + "false\n", + aSourceFile->HumanReadablePath().get(), + aDestFile->HumanReadablePath().get())); } return CopyOrMoveSync(&nsIFile::CopyToFollowingLinks, "copy", aSourceFile, @@ -1542,10 +1651,9 @@ Result<Ok, IOUtils::IOError> IOUtils::CopyOrMoveSync(CopyOrMoveFn aMethod, if (NS_SUCCEEDED(rv) && destIsDir) { rv = (aSource->*aMethod)(aDest, u""_ns); if (NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not %s source file(%s) to destination directory(%s)", - aMethodName, aSource->HumanReadablePath().get(), - aDest->HumanReadablePath().get())); + return Err(IOError(rv, "Could not %s `%s' to `%s'", aMethodName, + aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } return Ok(); } @@ -1554,7 +1662,9 @@ Result<Ok, IOUtils::IOError> IOUtils::CopyOrMoveSync(CopyOrMoveFn aMethod, if (!IsFileNotFound(rv)) { // It's ok if the dest file doesn't exist. Case 2 handles this below. // Bail out early for any other kind of error though. - return Err(IOError(rv)); + return Err(IOError(rv, "Could not %s `%s' to `%s'", aMethodName, + aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } destExists = false; } @@ -1564,37 +1674,41 @@ Result<Ok, IOUtils::IOError> IOUtils::CopyOrMoveSync(CopyOrMoveFn aMethod, // If the destination exists and the source is not a regular file, // then this may fail. if (aNoOverwrite && destExists) { - return Err( - IOError(NS_ERROR_FILE_ALREADY_EXISTS) - .WithMessage( - "Could not %s source file(%s) to destination(%s) because the " - "destination already exists and overwrites are not allowed\n" - "Specify the `noOverwrite: false` option to mitigate this " - "error", - aMethodName, aSource->HumanReadablePath().get(), - aDest->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_ALREADY_EXISTS, + "Could not %s `%s' to `%s': destination file exists and " + "`noOverwrite' is true", + aMethodName, aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } if (destExists && !destIsDir) { // If the source file is a directory, but the target is a file, abort early. // Different implementations of |CopyTo| and |MoveTo| seem to handle this // error case differently (or not at all), so we explicitly handle it here. bool srcIsDir = false; - MOZ_TRY(aSource->IsDirectory(&srcIsDir)); + IOUTILS_TRY_WITH_CONTEXT( + aSource->IsDirectory(&srcIsDir), + "Could not %s `%s' to `%s': could not stat source file or directory", + aMethodName, aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get()); if (srcIsDir) { - return Err(IOError(NS_ERROR_FILE_DESTINATION_NOT_DIR) - .WithMessage("Could not %s the source directory(%s) to " - "the destination(%s) because the destination " - "is not a directory", - aMethodName, - aSource->HumanReadablePath().get(), - aDest->HumanReadablePath().get())); + return Err(IOError( + NS_ERROR_FILE_DESTINATION_NOT_DIR, + "Could not %s directory `%s' to `%s': destination is not a directory", + aMethodName, aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } } - nsCOMPtr<nsIFile> destDir; + // We would have already thrown if the path was zero-length. nsAutoString destName; - MOZ_TRY(aDest->GetLeafName(destName)); - MOZ_TRY(aDest->GetParent(getter_AddRefs(destDir))); + MOZ_ALWAYS_SUCCEEDS(aDest->GetLeafName(destName)); + + nsCOMPtr<nsIFile> destDir; + IOUTILS_TRY_WITH_CONTEXT( + aDest->GetParent(getter_AddRefs(destDir)), + "Could not %s `%s` to `%s': path `%s' does not have a parent", + aMethodName, aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get(), aDest->HumanReadablePath().get()); // We know `destName` is a file and therefore must have a parent directory. MOZ_RELEASE_ASSERT(destDir); @@ -1603,9 +1717,9 @@ Result<Ok, IOUtils::IOError> IOUtils::CopyOrMoveSync(CopyOrMoveFn aMethod, // |MoveToFollowingLinks| will create it. rv = (aSource->*aMethod)(destDir, destName); if (NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not %s the source file(%s) to the destination(%s)", aMethodName, - aSource->HumanReadablePath().get(), aDest->HumanReadablePath().get())); + return Err(IOError(rv, "Could not %s `%s' to `%s'", aMethodName, + aSource->HumanReadablePath().get(), + aDest->HumanReadablePath().get())); } return Ok(); } @@ -1625,32 +1739,35 @@ Result<Ok, IOUtils::IOError> IOUtils::RemoveSync(nsIFile* aFile, return Ok(); } if (NS_FAILED(rv)) { - IOError err(rv); if (IsFileNotFound(rv)) { - return Err(err.WithMessage( - "Could not remove the file at %s because it does not exist.\n" - "Specify the `ignoreAbsent: true` option to mitigate this error", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not remove `%s': file does not exist", + aFile->HumanReadablePath().get())); } if (rv == NS_ERROR_FILE_DIR_NOT_EMPTY) { - return Err(err.WithMessage( - "Could not remove the non-empty directory at %s.\n" - "Specify the `recursive: true` option to mitigate this error", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, + "Could not remove `%s': the directory is not empty", + aFile->HumanReadablePath().get())); } #ifdef XP_WIN if (rv == NS_ERROR_FILE_ACCESS_DENIED && aRetryReadonly) { - MOZ_TRY(SetWindowsAttributesSync(aFile, 0, FILE_ATTRIBUTE_READONLY)); + if (auto result = + SetWindowsAttributesSync(aFile, 0, FILE_ATTRIBUTE_READONLY); + result.isErr()) { + return Err(IOError::WithCause( + result.unwrapErr(), + "Could not remove `%s': could not clear readonly attribute", + aFile->HumanReadablePath().get())); + } return RemoveSync(aFile, aIgnoreAbsent, aRecursive, /* aRetryReadonly = */ false); } #endif - return Err(err.WithMessage("Could not remove the file at %s", - aFile->HumanReadablePath().get())); + return Err( + IOError(rv, "Could not remove `%s'", aFile->HumanReadablePath().get())); } return Ok(); } @@ -1663,7 +1780,10 @@ Result<Ok, IOUtils::IOError> IOUtils::MakeDirectorySync(nsIFile* aFile, MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsIFile> parent; - MOZ_TRY(aFile->GetParent(getter_AddRefs(parent))); + IOUTILS_TRY_WITH_CONTEXT( + aFile->GetParent(getter_AddRefs(parent)), + "Could not make directory `%s': could not get parent directory", + aFile->HumanReadablePath().get()); if (!parent) { // If we don't have a parent directory, we were called with a // root directory. If the directory doesn't already exist (e.g., asking @@ -1677,7 +1797,11 @@ Result<Ok, IOUtils::IOError> IOUtils::MakeDirectorySync(nsIFile* aFile, // Otherwise, we fall through to `nsiFile::Create()` and let it fail there // instead. bool exists = false; - MOZ_TRY(aFile->Exists(&exists)); + IOUTILS_TRY_WITH_CONTEXT( + aFile->Exists(&exists), + "Could not make directory `%s': could not stat file or directory", + aFile->HumanReadablePath().get()); + if (exists) { return Ok(); } @@ -1692,13 +1816,16 @@ Result<Ok, IOUtils::IOError> IOUtils::MakeDirectorySync(nsIFile* aFile, // an existing file, since trying to create a directory where a regular // file exists may be indicative of a logic error. bool isDirectory; - MOZ_TRY(aFile->IsDirectory(&isDirectory)); + IOUTILS_TRY_WITH_CONTEXT( + aFile->IsDirectory(&isDirectory), + "Could not make directory `%s': could not stat file or directory", + aFile->HumanReadablePath().get()); + if (!isDirectory) { - return Err(IOError(NS_ERROR_FILE_NOT_DIRECTORY) - .WithMessage("Could not create directory because the " - "target file(%s) exists " - "and is not a directory", - aFile->HumanReadablePath().get())); + return Err(IOError(NS_ERROR_FILE_NOT_DIRECTORY, + "Could not create directory `%s': file exists and " + "is not a directory", + aFile->HumanReadablePath().get())); } // The directory exists. // The caller may suppress this error. @@ -1706,14 +1833,12 @@ Result<Ok, IOUtils::IOError> IOUtils::MakeDirectorySync(nsIFile* aFile, return Ok(); } // Otherwise, forward it. - return Err(IOError(rv).WithMessage( - "Could not create directory because it already exists at %s\n" - "Specify the `ignoreExisting: true` option to mitigate this " - "error", + return Err(IOError( + rv, "Could not create directory `%s': directory already exists", aFile->HumanReadablePath().get())); } - return Err(IOError(rv).WithMessage("Could not create directory at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not create directory `%s'", + aFile->HumanReadablePath().get())); } return Ok(); } @@ -1731,26 +1856,27 @@ Result<IOUtils::InternalFileInfo, IOUtils::IOError> IOUtils::StatSync( // Any subsequent errors are unexpected and will just be forwarded. nsresult rv = aFile->IsFile(&isRegular); if (NS_FAILED(rv)) { - IOError err(rv); if (IsFileNotFound(rv)) { - return Err( - err.WithMessage("Could not stat file(%s) because it does not exist", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not stat `%s': file does not exist", + aFile->HumanReadablePath().get())); } - return Err(err); + return Err( + IOError(rv, "Could not stat `%s'", aFile->HumanReadablePath().get())); } // Now we can populate the info object by querying the file. info.mType = FileType::Regular; if (!isRegular) { bool isDir = false; - MOZ_TRY(aFile->IsDirectory(&isDir)); + IOUTILS_TRY_WITH_CONTEXT(aFile->IsDirectory(&isDir), "Could not stat `%s'", + aFile->HumanReadablePath().get()); info.mType = isDir ? FileType::Directory : FileType::Other; } int64_t size = -1; if (info.mType == FileType::Regular) { - MOZ_TRY(aFile->GetFileSize(&size)); + IOUTILS_TRY_WITH_CONTEXT(aFile->GetFileSize(&size), "Could not stat `%s'", + aFile->HumanReadablePath().get()); } info.mSize = size; @@ -1759,18 +1885,27 @@ Result<IOUtils::InternalFileInfo, IOUtils::IOError> IOUtils::StatSync( info.mCreationTime.emplace(static_cast<int64_t>(creationTime)); } else if (NS_FAILED(rv) && rv != NS_ERROR_NOT_IMPLEMENTED) { // This field is only supported on some platforms. - return Err(IOError(rv)); + return Err( + IOError(rv, "Could not stat `%s'", aFile->HumanReadablePath().get())); } PRTime lastAccessed = 0; - MOZ_TRY(aFile->GetLastAccessedTime(&lastAccessed)); + IOUTILS_TRY_WITH_CONTEXT(aFile->GetLastAccessedTime(&lastAccessed), + "Could not stat `%s'", + aFile->HumanReadablePath().get()); + info.mLastAccessed = static_cast<int64_t>(lastAccessed); PRTime lastModified = 0; - MOZ_TRY(aFile->GetLastModifiedTime(&lastModified)); + IOUTILS_TRY_WITH_CONTEXT(aFile->GetLastModifiedTime(&lastModified), + "Could not stat `%s'", + aFile->HumanReadablePath().get()); + info.mLastModified = static_cast<int64_t>(lastModified); - MOZ_TRY(aFile->GetPermissions(&info.mPermissions)); + IOUTILS_TRY_WITH_CONTEXT(aFile->GetPermissions(&info.mPermissions), + "Could not stat `%s'", + aFile->HumanReadablePath().get()); return info; } @@ -1788,26 +1923,23 @@ Result<int64_t, IOUtils::IOError> IOUtils::SetTimeSync( // If it ever becomes possible to set a file time to 0, this check should be // removed, though this use case seems rare. if (aNewTime == 0) { - return Err( - IOError(NS_ERROR_ILLEGAL_VALUE) - .WithMessage( - "Refusing to set the modification time of file(%s) to 0.\n" - "To use the current system time, call `setModificationTime` " - "with no arguments", - aFile->HumanReadablePath().get())); + return Err(IOError( + NS_ERROR_ILLEGAL_VALUE, + "Refusing to set modification time of `%s' to 0: to use the current " + "system time, call `setModificationTime' with no arguments", + aFile->HumanReadablePath().get())); } nsresult rv = (aFile->*aSetTimeFn)(aNewTime); if (NS_FAILED(rv)) { - IOError err(rv); if (IsFileNotFound(rv)) { - return Err( - err.WithMessage("Could not set modification time of file(%s) " - "because it does not exist", - aFile->HumanReadablePath().get())); + return Err(IOError( + rv, "Could not set modification time of `%s': file does not exist", + aFile->HumanReadablePath().get())); } - return Err(err); + return Err(IOError(rv, "Could not set modification time of `%s'", + aFile->HumanReadablePath().get())); } return aNewTime; } @@ -1824,31 +1956,43 @@ Result<nsTArray<nsString>, IOUtils::IOError> IOUtils::GetChildrenSync( return children; } if (NS_FAILED(rv)) { - IOError err(rv); if (IsFileNotFound(rv)) { - return Err(err.WithMessage( - "Could not get children of file(%s) because it does not exist", + return Err(IOError( + rv, "Could not get children of `%s': directory does not exist", aFile->HumanReadablePath().get())); } if (IsNotDirectory(rv)) { - return Err(err.WithMessage( - "Could not get children of file(%s) because it is not a directory", - aFile->HumanReadablePath().get())); + return Err( + IOError(rv, "Could not get children of `%s': file is not a directory", + aFile->HumanReadablePath().get())); } - return Err(err); + return Err(IOError(rv, "Could not get children of `%s'", + aFile->HumanReadablePath().get())); } bool hasMoreElements = false; - MOZ_TRY(iter->HasMoreElements(&hasMoreElements)); + IOUTILS_TRY_WITH_CONTEXT( + iter->HasMoreElements(&hasMoreElements), + "Could not get children of `%s': could not iterate children", + aFile->HumanReadablePath().get()); + while (hasMoreElements) { nsCOMPtr<nsIFile> child; - MOZ_TRY(iter->GetNextFile(getter_AddRefs(child))); + IOUTILS_TRY_WITH_CONTEXT( + iter->GetNextFile(getter_AddRefs(child)), + "Could not get children of `%s': could not retrieve child file", + aFile->HumanReadablePath().get()); + if (child) { nsString path; - MOZ_TRY(child->GetPath(path)); + MOZ_ALWAYS_SUCCEEDS(child->GetPath(path)); children.AppendElement(path); } - MOZ_TRY(iter->HasMoreElements(&hasMoreElements)); + + IOUTILS_TRY_WITH_CONTEXT( + iter->HasMoreElements(&hasMoreElements), + "Could not get children of `%s': could not iterate children", + aFile->HumanReadablePath().get()); } return children; @@ -1859,7 +2003,10 @@ Result<Ok, IOUtils::IOError> IOUtils::SetPermissionsSync( nsIFile* aFile, const uint32_t aPermissions) { MOZ_ASSERT(!NS_IsMainThread()); - MOZ_TRY(aFile->SetPermissions(aPermissions)); + IOUTILS_TRY_WITH_CONTEXT(aFile->SetPermissions(aPermissions), + "Could not set permissions on `%s'", + aFile->HumanReadablePath().get()); + return Ok{}; } @@ -1868,7 +2015,8 @@ Result<bool, IOUtils::IOError> IOUtils::ExistsSync(nsIFile* aFile) { MOZ_ASSERT(!NS_IsMainThread()); bool exists = false; - MOZ_TRY(aFile->Exists(&exists)); + IOUTILS_TRY_WITH_CONTEXT(aFile->Exists(&exists), "Could not stat `%s'", + aFile->HumanReadablePath().get()); return exists; } @@ -1880,7 +2028,13 @@ Result<nsString, IOUtils::IOError> IOUtils::CreateUniqueSync( if (nsresult rv = aFile->CreateUnique(aFileType, aPermissions); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not create unique path")); + nsCOMPtr<nsIFile> aParent = nullptr; + MOZ_ALWAYS_SUCCEEDS(aFile->GetParent(getter_AddRefs(aParent))); + MOZ_RELEASE_ASSERT(aParent); + return Err( + IOError(rv, "Could not create unique %s in `%s'", + aFileType == nsIFile::NORMAL_FILE_TYPE ? "file" : "directory", + aParent->HumanReadablePath().get())); } nsString path; @@ -1914,24 +2068,25 @@ Result<nsCString, IOUtils::IOError> IOUtils::ComputeHexDigestSync( Digest digest; if (nsresult rv = digest.Begin(alg); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not hash file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not hash `%s': could not create digest", + aFile->HumanReadablePath().get())); } RefPtr<nsIInputStream> stream; if (nsresult rv = NS_NewLocalFileInputStream(getter_AddRefs(stream), aFile); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not open the file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not hash `%s': could not open for reading", + aFile->HumanReadablePath().get())); } char buffer[BUFFER_SIZE]; uint32_t read = 0; for (;;) { if (nsresult rv = stream->Read(buffer, BUFFER_SIZE, &read); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Encountered an unexpected error while reading file(%s)", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, + "Could not hash `%s': encountered an unexpected error " + "while reading file", + aFile->HumanReadablePath().get())); } if (read == 0) { break; @@ -1940,20 +2095,22 @@ Result<nsCString, IOUtils::IOError> IOUtils::ComputeHexDigestSync( if (nsresult rv = digest.Update(reinterpret_cast<unsigned char*>(buffer), read); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not hash file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not hash `%s': could not update digest", + aFile->HumanReadablePath().get())); } } AutoTArray<uint8_t, SHA512_LENGTH> rawDigest; if (nsresult rv = digest.End(rawDigest); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage("Could not hash file at %s", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not hash `%s': could not compute digest", + aFile->HumanReadablePath().get())); } nsCString hexDigest; if (!hexDigest.SetCapacity(2 * rawDigest.Length(), fallible)) { - return Err(IOError(NS_ERROR_OUT_OF_MEMORY)); + return Err(IOError(NS_ERROR_OUT_OF_MEMORY, + "Could not hash `%s': out of memory", + aFile->HumanReadablePath().get())); } const char HEX[] = "0123456789abcdef"; @@ -1977,9 +2134,8 @@ Result<uint32_t, IOUtils::IOError> IOUtils::GetWindowsAttributesSync( MOZ_ASSERT(file); if (nsresult rv = file->GetWindowsFileAttributes(&attrs); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not get Windows file attributes for the file at `%s'", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not get Windows file attributes for `%s'", + aFile->HumanReadablePath().get())); } return attrs; } @@ -1993,9 +2149,8 @@ Result<Ok, IOUtils::IOError> IOUtils::SetWindowsAttributesSync( if (nsresult rv = file->SetWindowsFileAttributes(aSetAttrs, aClearAttrs); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not set Windows file attributes for the file at `%s'", - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not set Windows file attributes for `%s'", + aFile->HumanReadablePath().get())); } return Ok{}; @@ -2013,9 +2168,8 @@ Result<bool, IOUtils::IOError> IOUtils::HasMacXAttrSync( bool hasAttr = false; if (nsresult rv = file->HasXAttr(aAttr, &hasAttr); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not read the extended attribute `%s' from the file `%s'", - aAttr.get(), aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not read extended attribute `%s' from `%s'", + aAttr.get(), aFile->HumanReadablePath().get())); } return hasAttr; @@ -2031,17 +2185,15 @@ Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::GetMacXAttrSync( nsTArray<uint8_t> value; if (nsresult rv = file->GetXAttr(aAttr, value); NS_FAILED(rv)) { - auto err = IOError(rv); - if (rv == NS_ERROR_NOT_AVAILABLE) { - return Err(err.WithMessage( - "The file `%s' does not have an extended attribute `%s'", - aFile->HumanReadablePath().get(), aAttr.get())); + return Err(IOError(rv, + "Could not get extended attribute `%s' from `%s': the " + "file does not have the attribute", + aAttr.get(), aFile->HumanReadablePath().get())); } - return Err(err.WithMessage( - "Could not read the extended attribute `%s' from the file `%s'", - aAttr.get(), aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not read extended attribute `%s' from `%s'", + aAttr.get(), aFile->HumanReadablePath().get())); } return value; @@ -2056,9 +2208,8 @@ Result<Ok, IOUtils::IOError> IOUtils::SetMacXAttrSync( MOZ_ASSERT(file); if (nsresult rv = file->SetXAttr(aAttr, aValue); NS_FAILED(rv)) { - return Err(IOError(rv).WithMessage( - "Could not set extended attribute `%s' on file `%s'", aAttr.get(), - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not set extended attribute `%s' on `%s'", + aAttr.get(), aFile->HumanReadablePath().get())); } return Ok{}; @@ -2073,17 +2224,15 @@ Result<Ok, IOUtils::IOError> IOUtils::DelMacXAttrSync(nsIFile* aFile, MOZ_ASSERT(file); if (nsresult rv = file->DelXAttr(aAttr); NS_FAILED(rv)) { - auto err = IOError(rv); - if (rv == NS_ERROR_NOT_AVAILABLE) { - return Err(err.WithMessage( - "The file `%s' does not have an extended attribute `%s'", - aFile->HumanReadablePath().get(), aAttr.get())); + return Err(IOError(rv, + "Could not delete extended attribute `%s' from " + "`%s': the file does not have the attribute", + aAttr.get(), aFile->HumanReadablePath().get())); } - return Err(IOError(rv).WithMessage( - "Could not delete extended attribute `%s' on file `%s'", aAttr.get(), - aFile->HumanReadablePath().get())); + return Err(IOError(rv, "Could not delete extended attribute `%s' from `%s'", + aAttr.get(), aFile->HumanReadablePath().get())); } return Ok{}; @@ -2374,8 +2523,8 @@ Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::MozLZ4::Compress( size_t worstCaseSize = Compression::LZ4::maxCompressedSize(aUncompressed.Length()) + HEADER_SIZE; if (!result.SetCapacity(worstCaseSize, fallible)) { - return Err(IOError(NS_ERROR_OUT_OF_MEMORY) - .WithMessage("Could not allocate buffer to compress data")); + return Err(IOError(NS_ERROR_OUT_OF_MEMORY, + "could not allocate buffer to compress data"_ns)); } result.AppendElements(Span(MAGIC_NUMBER.data(), MAGIC_NUMBER.size())); std::array<uint8_t, sizeof(uint32_t)> contentSizeBytes{}; @@ -2394,8 +2543,7 @@ Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::MozLZ4::Compress( aUncompressed.Length(), reinterpret_cast<char*>(result.Elements()) + HEADER_SIZE); if (!compressed) { - return Err( - IOError(NS_ERROR_UNEXPECTED).WithMessage("Could not compress data")); + return Err(IOError(NS_ERROR_UNEXPECTED, "could not compress data"_ns)); } result.SetLength(HEADER_SIZE + compressed); return result; @@ -2405,10 +2553,8 @@ Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::MozLZ4::Compress( Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::MozLZ4::Decompress( Span<const uint8_t> aFileContents, IOUtils::BufferKind aBufferKind) { if (aFileContents.LengthBytes() < HEADER_SIZE) { - return Err( - IOError(NS_ERROR_FILE_CORRUPTED) - .WithMessage( - "Could not decompress file because the buffer is too short")); + return Err(IOError(NS_ERROR_FILE_CORRUPTED, + "could not decompress file: buffer is too small"_ns)); } auto header = aFileContents.To(HEADER_SIZE); if (!std::equal(std::begin(MAGIC_NUMBER), std::end(MAGIC_NUMBER), @@ -2420,10 +2566,10 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::MozLZ4::Decompress( } magicStr.AppendPrintf("%02X", header.at(i)); - return Err(IOError(NS_ERROR_FILE_CORRUPTED) - .WithMessage("Could not decompress file because it has an " - "invalid LZ4 header (wrong magic number: '%s')", - magicStr.get())); + return Err(IOError(NS_ERROR_FILE_CORRUPTED, + "could not decompress file: invalid LZ4 header: wrong " + "magic number: `%s'", + magicStr.get())); } size_t numBytes = sizeof(uint32_t); Span<const uint8_t> sizeBytes = header.Last(numBytes); @@ -2435,7 +2581,9 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::MozLZ4::Decompress( auto contents = aFileContents.From(HEADER_SIZE); auto result = JsBuffer::Create(aBufferKind, expectedDecompressedSize); if (result.isErr()) { - return result.propagateErr(); + return Err(IOError::WithCause( + result.unwrapErr(), + "could not decompress file: could not allocate buffer"_ns)); } JsBuffer decompressed = result.unwrap(); @@ -2445,9 +2593,8 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::MozLZ4::Decompress( reinterpret_cast<char*>(decompressed.Elements()), expectedDecompressedSize, &actualSize)) { return Err( - IOError(NS_ERROR_FILE_CORRUPTED) - .WithMessage( - "Could not decompress file contents, the file may be corrupt")); + IOError(NS_ERROR_FILE_CORRUPTED, + "could not decompress file: the file may be corrupt"_ns)); } decompressed.SetLength(actualSize); return decompressed; @@ -2583,8 +2730,8 @@ IOUtils::InternalWriteOpts::FromBinding(const WriteOptions& aOptions) { if (nsresult rv = PathUtils::InitFileWithPath(opts.mBackupFile, aOptions.mBackupFile.Value()); NS_FAILED(rv)) { - return Err(IOUtils::IOError(rv).WithMessage( - "Could not parse path of backupFile (%s)", + return Err(IOUtils::IOError( + rv, "Could not parse path of backupFile `%s'", NS_ConvertUTF16toUTF8(aOptions.mBackupFile.Value()).get())); } } @@ -2594,8 +2741,8 @@ IOUtils::InternalWriteOpts::FromBinding(const WriteOptions& aOptions) { if (nsresult rv = PathUtils::InitFileWithPath(opts.mTmpFile, aOptions.mTmpPath.Value()); NS_FAILED(rv)) { - return Err(IOUtils::IOError(rv).WithMessage( - "Could not parse path of temp file (%s)", + return Err(IOUtils::IOError( + rv, "Could not parse path of temp file `%s'", NS_ConvertUTF16toUTF8(aOptions.mTmpPath.Value()).get())); } } @@ -2609,8 +2756,7 @@ Result<IOUtils::JsBuffer, IOUtils::IOError> IOUtils::JsBuffer::Create( IOUtils::BufferKind aBufferKind, size_t aCapacity) { JsBuffer buffer(aBufferKind, aCapacity); if (aCapacity != 0 && !buffer.mBuffer) { - return Err(IOError(NS_ERROR_OUT_OF_MEMORY) - .WithMessage("Could not allocate buffer")); + return Err(IOError(NS_ERROR_OUT_OF_MEMORY, "Could not allocate buffer"_ns)); } return buffer; } @@ -2787,8 +2933,8 @@ void SyncReadFile::ReadBytesInto(const Uint8Array& aDestArray, } if (nsresult rv = mStream->Seek(PR_SEEK_SET, aOffset); NS_FAILED(rv)) { - return aRv.ThrowOperationError( - FormatErrorMessage(rv, "Could not seek to position %lld", aOffset)); + return aRv.ThrowOperationError(FormatErrorMessage( + rv, "Could not seek to position %" PRId64, aOffset)); } Span<char> toRead = AsWritableChars(aData); @@ -2805,7 +2951,8 @@ void SyncReadFile::ReadBytesInto(const Uint8Array& aDestArray, &bytesRead); NS_FAILED(rv)) { return aRv.ThrowOperationError(FormatErrorMessage( - rv, "Encountered an unexpected error while reading file stream")); + rv, + "Encountered an unexpected error while reading file stream"_ns)); } if (bytesRead == 0) { return aRv.ThrowOperationError( @@ -2896,3 +3043,4 @@ uint32_t IOUtils::LaunchProcess(GlobalObject& aGlobal, } // namespace mozilla::dom #undef REJECT_IF_INIT_PATH_FAILED +#undef IOUTILS_TRY_WITH_CONTEXT diff --git a/dom/system/IOUtils.h b/dom/system/IOUtils.h index 82ea30eaa8..6acfcbfb24 100644 --- a/dom/system/IOUtils.h +++ b/dom/system/IOUtils.h @@ -69,8 +69,8 @@ class IOUtils final { }; template <typename T> - using PhaseArray = - EnumeratedArray<IOUtils::ShutdownPhase, IOUtils::ShutdownPhase::Count, T>; + using PhaseArray = EnumeratedArray<IOUtils::ShutdownPhase, T, + size_t(IOUtils::ShutdownPhase::Count)>; static already_AddRefed<Promise> Read(GlobalObject& aGlobal, const nsAString& aPath, @@ -148,6 +148,7 @@ class IOUtils final { const nsAString& aPath, const Optional<int64_t>& aNewTime, SetTimeFn aSetTimeFn, + const char* const aTimeKind, ErrorResult& aError); public: @@ -653,23 +654,34 @@ class IOUtils::EventQueue final { */ class IOUtils::IOError { public: - MOZ_IMPLICIT IOError(nsresult aCode) : mCode(aCode), mMessage(Nothing()) {} - - /** - * Replaces the message associated with this error. - */ - template <typename... Args> - IOError WithMessage(const char* const aMessage, Args... aArgs) { - mMessage.emplace(nsPrintfCString(aMessage, aArgs...)); - return *this; + IOError(nsresult aCode, const nsCString& aMsg) + : mCode(aCode), mMessage(aMsg) {} + + IOError(nsresult aCode, const char* const aFmt, ...) MOZ_FORMAT_PRINTF(3, 4) + : mCode(aCode) { + va_list ap; + va_start(ap, aFmt); + mMessage.AppendVprintf(aFmt, ap); + va_end(ap); } - IOError WithMessage(const char* const aMessage) { - mMessage.emplace(nsCString(aMessage)); - return *this; + + static IOError WithCause(const IOError& aCause, const nsCString& aMsg) { + IOError e(aCause.mCode, aMsg); + e.mMessage.AppendPrintf(": %s", aCause.mMessage.get()); + return e; } - IOError WithMessage(const nsCString& aMessage) { - mMessage.emplace(aMessage); - return *this; + + static IOError WithCause(const IOError& aCause, const char* const aFmt, ...) + MOZ_FORMAT_PRINTF(2, 3) { + va_list ap; + va_start(ap, aFmt); + + IOError e(aCause.mCode, EmptyCString()); + e.mMessage.AppendVprintf(aFmt, ap); + e.mMessage.AppendPrintf(": %s", aCause.mMessage.get()); + + va_end(ap); + return e; } /** @@ -678,13 +690,13 @@ class IOUtils::IOError { nsresult Code() const { return mCode; } /** - * Maybe returns a message associated with this error. + * Returns the message associated with this error. */ - const Maybe<nsCString>& Message() const { return mMessage; } + const nsCString& Message() const { return mMessage; } private: nsresult mCode; - Maybe<nsCString> mMessage; + nsCString mMessage; }; /** diff --git a/dom/system/NetworkGeolocationProvider.sys.mjs b/dom/system/NetworkGeolocationProvider.sys.mjs index 1bee69a282..2e929c066f 100644 --- a/dom/system/NetworkGeolocationProvider.sys.mjs +++ b/dom/system/NetworkGeolocationProvider.sys.mjs @@ -391,7 +391,7 @@ NetworkGeolocationProvider.prototype = { } }, - notify(timer) { + notify() { this.onStatus(false, "wifi-timeout"); this.sendLocationRequest(null); }, diff --git a/dom/system/PathUtils.h b/dom/system/PathUtils.h index ff01ddfc1e..1870d92f23 100644 --- a/dom/system/PathUtils.h +++ b/dom/system/PathUtils.h @@ -241,7 +241,8 @@ class PathUtils::DirectoryCache final { void ResolveWithDirectory(Promise* aPromise, const Directory aRequestedDir); template <typename T> - using DirectoryArray = EnumeratedArray<Directory, Directory::Count, T>; + using DirectoryArray = + EnumeratedArray<Directory, T, size_t(Directory::Count)>; DirectoryArray<nsString> mDirectories; DirectoryArray<MozPromiseHolder<PopulateDirectoriesPromise>> mPromises; diff --git a/dom/system/tests/ioutils/file_ioutils_worker.js b/dom/system/tests/ioutils/file_ioutils_worker.js index e367eb4d99..f8cf286f8e 100644 --- a/dom/system/tests/ioutils/file_ioutils_worker.js +++ b/dom/system/tests/ioutils/file_ioutils_worker.js @@ -14,7 +14,7 @@ importScripts("chrome://mochikit/content/tests/SimpleTest/WorkerSimpleTest.js"); importScripts("file_ioutils_test_fixtures.js"); -self.onmessage = async function (msg) { +self.onmessage = async function () { const tmpDir = await PathUtils.getTempDir(); // IOUtils functionality is the same when called from the main thread, or a diff --git a/dom/system/tests/ioutils/test_ioutils_copy_move.html b/dom/system/tests/ioutils/test_ioutils_copy_move.html index 408bb82f39..0761447bc6 100644 --- a/dom/system/tests/ioutils/test_ioutils_copy_move.html +++ b/dom/system/tests/ioutils/test_ioutils_copy_move.html @@ -24,7 +24,7 @@ info("Test moving a file to a relative destination"); await Assert.rejects( IOUtils.move(tmpFileName, dest), - /Could not parse path/, + /OperationError: Could not move `.*' to `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, "IOUtils::move only works with absolute paths" ); ok( @@ -56,7 +56,7 @@ // Test. await Assert.rejects( IOUtils.move(tmpFileName, destFileName, { noOverwrite: true }), - /Could not move source file\(.*\) to destination\(.*\) because the destination already exists and overwrites are not allowed/, + /Could not move `.*' to `.*': destination file exists and `noOverwrite' is true/, "IOUtils::move will refuse to move a file if overwrites are disabled" ); ok( @@ -161,7 +161,7 @@ // Test. await Assert.rejects( IOUtils.move(notExistsSrc, notExistsDest), - /Could not move source file\(.*\) because it does not exist/, + /NotFoundError: Could not move `.*' to `.*': source file does not exist/, "IOUtils::move throws if source file does not exist" ); ok( @@ -178,7 +178,7 @@ // Test. await Assert.rejects( IOUtils.move(srcDir, destFile), - /Could not move the source directory\(.*\) to the destination\(.*\) because the destination is not a directory/, + /InvalidAccessError: Could not move directory `.*' to `.*': destination is not a directory/, "IOUtils::move throws if try to move dir into an existing file" ); @@ -206,7 +206,7 @@ // Test. await Assert.rejects( IOUtils.copy(tmpFileName, destFileName, { noOverwrite: true }), - /Could not copy source file\(.*\) to destination\(.*\) because the destination already exists and overwrites are not allowed/, + /NoModificationAllowedError: Could not copy `.*' to `.*': destination file exists and `noOverwrite' is true/, "IOUtils::copy will refuse to copy to existing destination if overwrites are disabled" ); ok( @@ -311,7 +311,7 @@ // Test. await Assert.rejects( IOUtils.copy(notExistsSrc, notExistsDest), - /Could not copy source file\(.*\) because it does not exist/, + /NotFoundError: Could not copy `.*' to `.*': source file does not exist/, "IOUtils::copy throws if source file does not exist" ); ok( @@ -328,8 +328,8 @@ // Test. await Assert.rejects( IOUtils.copy(srcDir, destFile, { recursive: true }), - /Could not copy the source directory\(.*\) to the destination\(.*\) because the destination is not a directory/, - "IOUtils::copy throws if try to move dir into an existing file" + /InvalidAccessError: Could not copy directory `.*' to `.*': destination is not a directory/, + "IOUtils::copy throws when trying to move a directory into an existing file" ); ok(await fileHasTextContents(destFile, ""), "IOUtils::copy failure does not affect destination"); @@ -339,7 +339,7 @@ // Test. await Assert.rejects( IOUtils.copy(srcDir, notExistsDest, { recursive: false }), - /Refused to copy source directory\(.*\) to the destination\(.*\)/, + /OperationError: Refused to copy directory `.*' to `.*': `recursive' is false/, "IOUtils::copy throws if try to copy a directory with { recursive: false }" ); console.log(`${notExistsDest} exists?`, await IOUtils.exists(notExistsDest)) diff --git a/dom/system/tests/ioutils/test_ioutils_dir_iteration.html b/dom/system/tests/ioutils/test_ioutils_dir_iteration.html index 54168235b0..1e3653d876 100644 --- a/dom/system/tests/ioutils/test_ioutils_dir_iteration.html +++ b/dom/system/tests/ioutils/test_ioutils_dir_iteration.html @@ -21,7 +21,7 @@ await Assert.rejects( IOUtils.getChildren(notExists), - /Could not get children of file\(.*\) because it does not exist/, + /NotFoundError: Could not get children of `.*': directory does not exist/, "IOUtils::getChildren rejects if the file does not exist" ); ok(!await fileExists(notExists), `Expected ${notExists} not to exist`); @@ -31,7 +31,7 @@ let tmpFileName = PathUtils.join(PathUtils.tempDir, 'iterator_file.tmp'); await createFile(tmpFileName) await Assert.rejects(IOUtils.getChildren(tmpFileName), - /Could not get children of file\(.*\) because it is not a directory/, + /InvalidAccessError: Could not get children of `.*': file is not a directory/, "IOUtils::getChildren rejects if the file is not a dir" ); diff --git a/dom/system/tests/ioutils/test_ioutils_mac_xattr.html b/dom/system/tests/ioutils/test_ioutils_mac_xattr.html index 6af9b2e6f8..775490976e 100644 --- a/dom/system/tests/ioutils/test_ioutils_mac_xattr.html +++ b/dom/system/tests/ioutils/test_ioutils_mac_xattr.html @@ -36,7 +36,7 @@ info("Testing getting an attribute that does not exist"); await Assert.rejects( IOUtils.getMacXAttr(path, ATTR), - /NotFoundError: The file `.+' does not have an extended attribute/, + /NotFoundError: Could not get extended attribute `bogus.attr' from `.*': the file does not have the attribute/, "IOUtils::getMacXAttr rejects when the attribute does not exist" ); @@ -61,7 +61,7 @@ await IOUtils.delMacXAttr(path, ATTR); await Assert.rejects( IOUtils.getMacXAttr(path, ATTR), - /NotFoundError: The file `.+' does not have an extended attribute/, + /NotFoundError: Could not get extended attribute `bogus.attr' from `.*': the file does not have the attribute/, "IOUtils::delMacXAttr removes the attribute" ); @@ -73,7 +73,7 @@ info("Testing removing an attribute that does not exist"); await Assert.rejects( IOUtils.delMacXAttr(path, ATTR), - /NotFoundError: The file `.+' does not have an extended attribute/, + /NotFoundError: Could not delete extended attribute `bogus.attr' from `.*': the file does not have the attribute/, "IOUtils::delMacXAttr rejects when the attribute does not exist" ); diff --git a/dom/system/tests/ioutils/test_ioutils_mkdir.html b/dom/system/tests/ioutils/test_ioutils_mkdir.html index 6827b24cc6..e95873fd17 100644 --- a/dom/system/tests/ioutils/test_ioutils_mkdir.html +++ b/dom/system/tests/ioutils/test_ioutils_mkdir.html @@ -33,7 +33,7 @@ ); await Assert.rejects( IOUtils.makeDirectory(newDirectoryName, { ignoreExisting: false }), - /Could not create directory because it already exists at .*/, + /NoModificationAllowedError: Could not create directory `.*': directory already exists/, "IOUtils::makeDirectory can throw if the target dir exists" ) @@ -45,7 +45,7 @@ ); await Assert.rejects( IOUtils.makeDirectory(nestedDirName, { createAncestors: false }), - /Could not create directory at .*/, + /NotFoundError: Could not create directory `.*'/, "IOUtils::makeDirectory can fail if the target is missing parents" ); ok(!await IOUtils.exists(nestedDirName), `Expected ${nestedDirName} not to exist`); @@ -65,14 +65,14 @@ await Assert.rejects( IOUtils.makeDirectory(notADirFileName, { ignoreExisting: false }), - /Could not create directory because the target file\(.*\) exists and is not a directory/, + /InvalidAccessError: Could not create directory `.*': file exists and is not a directory/, "IOUtils::makeDirectory [ignoreExisting: false] throws when the target is an existing file" ); ok(await fileExists(notADirFileName), `Expected ${notADirFileName} to exist`); await Assert.rejects( IOUtils.makeDirectory(notADirFileName, { ignoreExisting: true }), - /Could not create directory because the target file\(.*\) exists and is not a directory/, + /InvalidAccessError: Could not create directory `.*': file exists and is not a directory/, "IOUtils::makeDirectory [ignoreExisting: true] throws when the target is an existing file" ); ok(await fileExists(notADirFileName), `Expected ${notADirFileName} to exist`); diff --git a/dom/system/tests/ioutils/test_ioutils_read_write.html b/dom/system/tests/ioutils/test_ioutils_read_write.html index 2243eb1eda..49232d464a 100644 --- a/dom/system/tests/ioutils/test_ioutils_read_write.html +++ b/dom/system/tests/ioutils/test_ioutils_read_write.html @@ -23,7 +23,7 @@ const doesNotExist = PathUtils.join(PathUtils.tempDir, "does_not_exist.tmp"); await Assert.rejects( IOUtils.read(doesNotExist), - /Could not open the file at .*/, + /NotFoundError: Could not open `.*': file does not exist/, "IOUtils::read rejects when file does not exist" ); }); @@ -46,7 +46,7 @@ IOUtils.write(tmpFileName, newContents, { mode: "create", }), - /Refusing to overwrite the file at */, + /NoModificationAllowedError: Could not write to `.*': refusing to overwrite file, `mode' is not "overwrite"/, "IOUtils::write rejects writing to existing file if overwrites are disabled" ); ok( @@ -285,7 +285,7 @@ info("Test writing a file at a relative destination"); await Assert.rejects( IOUtils.write(tmpFileName, bytes), - /Could not parse path/, + /OperationError: Could not write to `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, "IOUtils::write only works with absolute paths" ); }); @@ -296,8 +296,8 @@ info("Test reading a file at a relative destination"); await Assert.rejects( IOUtils.read(tmpFileName), - /Could not parse path/, - "IOUtils::write only works with absolute paths" + /OperationError: Could not read `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, + "IOUtils::read only works with absolute paths" ); }); @@ -348,7 +348,7 @@ is(bytesWritten, 64, "Expected to write 64 bytes"); await Assert.rejects( IOUtils.read(tmpFileName, { maxBytes: 4, decompress: true }), - /The `maxBytes` and `decompress` options are not compatible/, + /DataError: Could not read `.*': the `maxBytes' and `decompress' options are mutually exclusive/, "IOUtils::read rejects when maxBytes and decompress options are both used" ); @@ -364,17 +364,7 @@ await Assert.rejects( IOUtils.read(tmpFileName, { decompress: true }), - (actual) => { - is(actual.constructor, DOMException, - "rejection reason constructor for decompress with bad header"); - is(actual.name, "NotReadableError", - "rejection error name for decompress with bad header"); - ok(/Could not decompress file because it has an invalid LZ4 header \(wrong magic number: .*\)/ - .test(actual.message), - "rejection error message for decompress with bad header. Got " - + actual.message); - return true; - }, + /NotReadableError: Could not read `.*': could not decompress file: invalid LZ4 header: wrong magic number: `01 01 01 01 01 01 01 01 01 01 01 01' \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::read fails to decompress LZ4 data with a bad header" ); @@ -384,7 +374,7 @@ await Assert.rejects( IOUtils.read(tmpFileName, { decompress: true }), - /Could not decompress file because the buffer is too short/, + /NotReadableError: Could not read `.*': could not decompress file: buffer is too small \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::read fails to decompress LZ4 data with missing header" ); @@ -396,7 +386,7 @@ await Assert.rejects( IOUtils.read(tmpFileName, { decompress: true }), - /Could not decompress file contents, the file may be corrupt/, + /NotReadableError: Could not read `.*': could not decompress file: the file may be corrupt \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::read fails to read corrupt LZ4 contents with a correct header" ); @@ -411,11 +401,11 @@ await IOUtils.makeDirectory(fileName); await Assert.rejects( IOUtils.write(fileName, bytes), - /NotAllowedError: Could not open the file at .+ for writing/); + /NotAllowedError: Could not write to `.*': failed to open file for writing/); await Assert.rejects( IOUtils.write(fileName, bytes, { tmpPath }), - /NotAllowedError: Could not open the file at .+ for writing/); + /NotAllowedError: Could not write to `.*': file is a directory/); ok(!await IOUtils.exists(PathUtils.join(fileName, PathUtils.filename(tmpPath)))); }); @@ -509,7 +499,7 @@ await Assert.rejects( IOUtils.write(fileName, Uint8Array.of(5, 6, 7, 8, 9), { mode: "append" }), - /NotFoundError: Could not open the file at .*/ + /NotFoundError: Could not write to `.*': failed to open file for writing/ ); }); </script> diff --git a/dom/system/tests/ioutils/test_ioutils_read_write_json.html b/dom/system/tests/ioutils/test_ioutils_read_write_json.html index 0acb191e1b..a85a0c19a1 100644 --- a/dom/system/tests/ioutils/test_ioutils_read_write_json.html +++ b/dom/system/tests/ioutils/test_ioutils_read_write_json.html @@ -77,7 +77,7 @@ ok(!await IOUtils.exists(notExistsFilename), `${notExistsFilename} should not exist`); await Assert.rejects( IOUtils.readJSON(notExistsFilename), - /NotFoundError: Could not open the file at/, + /NotFoundError: Could not open `.*'/, "IOUtils::readJSON rejects when file does not exist" ); @@ -149,7 +149,7 @@ await Assert.rejects( IOUtils.writeJSON(filename, OBJECT, {mode: "append"}), - /NotSupportedError: IOUtils.writeJSON does not support appending to files/, + /NotSupportedError: Could not write to `.*': IOUtils.writeJSON does not support appending to files/, "IOUtils.writeJSON() cannot append" ); diff --git a/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html b/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html index cdea016732..e1a1864656 100644 --- a/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html +++ b/dom/system/tests/ioutils/test_ioutils_read_write_utf8.html @@ -26,7 +26,7 @@ const doesNotExist = PathUtils.join(PathUtils.tempDir, "does_not_exist.tmp"); await Assert.rejects( IOUtils.readUTF8(doesNotExist), - /Could not open the file at .*/, + /NotFoundError: Could not open `.*'/, "IOUtils::readUTF8 rejects when file does not exist" ); @@ -38,7 +38,7 @@ await Assert.rejects( IOUtils.readUTF8(invalidUTF8File), - /Could not read file\(.*\) because it is not UTF-8 encoded/, + /NotReadableError: Could not read `.*': file is not UTF-8 encoded/, "IOUtils::readUTF8 will reject when reading a file that is not valid UTF-8" ); @@ -56,7 +56,7 @@ IOUtils.writeUTF8(tmpFileName, newContents, { mode: "create", }), - /Refusing to overwrite the file at */, + /NoModificationAllowedError: Could not write to `.*': refusing to overwrite file, `mode' is not "overwrite"/, "IOUtils::writeUTF8 rejects writing to existing file if overwrites are disabled" ); ok( @@ -233,7 +233,7 @@ info("Test writing a file at a relative destination"); await Assert.rejects( IOUtils.writeUTF8(tmpFileName, "foo"), - /Could not parse path/, + /OperationError: Could not write to `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, "IOUtils::writeUTF8 only works with absolute paths" ); }); @@ -244,7 +244,7 @@ info("Test reading a file at a relative destination"); await Assert.rejects( IOUtils.readUTF8(tmpFileName), - /Could not parse path/, + /OperationError: Could not read `.*': could not parse path \(NS_ERROR_FILE_UNRECOGNIZED_PATH\)/, "IOUtils::readUTF8 only works with absolute paths" ); }); @@ -309,7 +309,7 @@ await Assert.rejects( IOUtils.readUTF8(tmpFileName, { decompress: true }), - /Could not decompress file because it has an invalid LZ4 header \(wrong magic number: .*\)/, + /NotReadableError: Could not read `.*': could not decompress file: invalid LZ4 header: wrong magic number: `01 01 01 01 01 01 01 01 01 01 01 01' \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::readUTF8 fails to decompress LZ4 data with a bad header" ); @@ -319,7 +319,7 @@ await Assert.rejects( IOUtils.readUTF8(tmpFileName, { decompress: true }), - /Could not decompress file because the buffer is too short/, + /NotReadableError: Could not read `.*': could not decompress file: buffer is too small \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::readUTF8 fails to decompress LZ4 data with missing header" ); @@ -331,7 +331,7 @@ await Assert.rejects( IOUtils.readUTF8(tmpFileName, { decompress: true }), - /Could not decompress file contents, the file may be corrupt/, + /NotReadableError: Could not read `.*': could not decompress file: the file may be corrupt \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::readUTF8 fails to read corrupt LZ4 contents with a correct header" ); @@ -342,7 +342,7 @@ } await Assert.rejects( IOUtils.readUTF8(tmpFileName, { decompress: true }), - /Could not decompress file because the buffer is too short/, + /NotReadableError: Could not read `.*': could not decompress file: buffer is too small \(NS_ERROR_FILE_CORRUPTED\)/, "IOUtils::readUTF8 fails to decompress empty files" ); diff --git a/dom/system/tests/ioutils/test_ioutils_remove.html b/dom/system/tests/ioutils/test_ioutils_remove.html index f368fc09d3..1d860a7871 100644 --- a/dom/system/tests/ioutils/test_ioutils_remove.html +++ b/dom/system/tests/ioutils/test_ioutils_remove.html @@ -43,7 +43,7 @@ await Assert.rejects( IOUtils.remove(tmpFileName, { ignoreAbsent: false }), - /Could not remove the file at .* because it does not exist/, + /NotFoundError: Could not remove `.*': file does not exist/, "IOUtils::remove can throw an error when target file is missing" ); ok(!await fileExists(tmpFileName), `Expected file ${tmpFileName} not to exist`); @@ -69,7 +69,7 @@ await Assert.rejects( IOUtils.remove(tmpParentDir, { recursive: false }), - /Could not remove the non-empty directory at .*/, + /OperationError: Could not remove `.*': the directory is not empty/, "IOUtils::remove fails if non-recursively removing directory with contents" ); diff --git a/dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html b/dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html index e508817a41..8a5b521742 100644 --- a/dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html +++ b/dom/system/tests/ioutils/test_ioutils_stat_set_modification_time.html @@ -76,7 +76,7 @@ await Assert.rejects( IOUtils.stat(notExistsFile), - /Could not stat file\(.*\) because it does not exist/, + /NotFoundError: Could not stat `.*': file does not exist/, "IOUtils::stat throws if the target file does not exist" ); }); @@ -214,7 +214,7 @@ await Assert.rejects( IOUtils.setModificationTime(notExistsFile), - /Could not set modification time of file\(.*\) because it does not exist/, + /Could not set modification time of `.*': file does not exist/, "IOUtils::setModificationTime throws if the target file does not exist" ); @@ -224,7 +224,7 @@ await Assert.rejects( IOUtils.setModificationTime(tempFileName, 0), - /Refusing to set the modification time of file\(.*\) to 0/, + /DataError: Refusing to set modification time of `.*' to 0: to use the current system time, call `setModificationTime' with no arguments/, "IOUtils::setModificationTime cannot set the file modification time to Epoch" ); diff --git a/dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html b/dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html index a5b72bd078..00219fd6fb 100644 --- a/dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html +++ b/dom/system/tests/ioutils/test_ioutils_windows_file_attributes.html @@ -48,7 +48,7 @@ await Assert.rejects( IOUtils.writeUTF8(filePath, "hello, world"), - /NotAllowedError: Could not open the file at .+ for writing/, + /NotAllowedError: Could not write to `.*': failed to open file for writing/, "IOUtils::writeUTF8 on a read-only file fails." ); |