Loading dom/chrome-webidl/IOUtils.webidl +42 −1 Original line number Diff line number Diff line Loading @@ -235,8 +235,49 @@ namespace IOUtils { * @return A promise that resolves is the attributes were set successfully. */ Promise<void> setWindowsAttributes(DOMString path, optional WindowsFileAttributes attrs = {}); #elif defined(XP_MACOSX) /** * Return whether or not the file has a specific extended attribute. * * @param path An absolute path. * @param attr The attribute to check for. * * @return A promise that resolves to whether or not the file has an extended * attribute, or rejects with an error. */ Promise<boolean> hasMacXAttr(DOMString path, UTF8String attr); /** * Return the value of an extended attribute for a file. * * @param path An absolute path. * @param attr The attribute to get the value of. * * @return A promise that resolves to the value of the extended attribute, or * rejects with an error. */ Promise<Uint8Array> getMacXAttr(DOMString path, UTF8String attr); /** * Set the extended attribute on a file. * * @param path An absolute path. * @param attr The attribute to set. * @param value The value of the attribute to set. * * @return A promise that resolves to whether or not the file has an extended * attribute, or rejects with an error. */ Promise<void> setMacXAttr(DOMString path, UTF8String attr, Uint8Array value); /** * Delete the extended attribute on a file. * * @param path An absolute path. * @param attr The attribute to delete. * * @return A promise that resolves if the attribute was deleted, or rejects * with an error. */ Promise<void> delMacXAttr(DOMString path, UTF8String attr); #endif }; [Exposed=Window] Loading dom/system/IOUtils.cpp +165 −1 Original line number Diff line number Diff line Loading @@ -59,6 +59,8 @@ #if defined(XP_WIN) # include "nsILocalFileWin.h" #elif defined(XP_MACOSX) # include "nsILocalFileMac.h" #endif #define REJECT_IF_INIT_PATH_FAILED(_file, _path, _promise) \ Loading Loading @@ -156,6 +158,9 @@ template <typename T> static void ResolveJSPromise(Promise* aPromise, T&& aValue) { if constexpr (std::is_same_v<T, Ok>) { aPromise->MaybeResolveWithUndefined(); } else if constexpr (std::is_same_v<T, nsTArray<uint8_t>>) { TypedArrayCreator<Uint8Array> array(aValue); aPromise->MaybeResolve(array); } else { aPromise->MaybeResolve(std::forward<T>(aValue)); } Loading Loading @@ -242,6 +247,9 @@ static void RejectJSPromise(Promise* aPromise, const IOUtils::IOError& aError) { aPromise->MaybeRejectWithDataError( errMsg.refOr("Argument is not allowed"_ns)); break; case NS_ERROR_NOT_AVAILABLE: aPromise->MaybeRejectWithNotFoundError(errMsg.refOr("Unavailable"_ns)); break; case NS_ERROR_ABORT: aPromise->MaybeRejectWithAbortError(errMsg.refOr("Operation aborted"_ns)); break; Loading Loading @@ -777,6 +785,74 @@ already_AddRefed<Promise> IOUtils::SetWindowsAttributes( }); } #elif defined(XP_MACOSX) /* static */ already_AddRefed<Promise> IOUtils::HasMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr) { return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); DispatchAndResolve<nsTArray<uint8_t>>( state->mEventQueue, promise, [file = std::move(file), attr = nsCString(aAttr)]() { return HasMacXAttrSync(file, attr); }); }); } /* static */ already_AddRefed<Promise> IOUtils::GetMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr) { return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); DispatchAndResolve<nsTArray<uint8_t>>( state->mEventQueue, promise, [file = std::move(file), attr = nsCString(aAttr)]() { return GetMacXAttrSync(file, attr); }); }); } /* static */ already_AddRefed<Promise> IOUtils::SetMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr, const Uint8Array& aValue) { return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); nsTArray<uint8_t> value(aValue.Data(), aValue.Length()); DispatchAndResolve<Ok>(state->mEventQueue, promise, [file = std::move(file), attr = nsCString(aAttr), value = std::move(value)] { return SetMacXAttrSync(file, attr, value); }); }); } /* static */ already_AddRefed<Promise> IOUtils::DelMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr) { return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); DispatchAndResolve<Ok>(state->mEventQueue, promise, [file = std::move(file), attr = nsCString(aAttr)] { return DelMacXAttrSync(file, attr); }); }); } #endif /* static */ Loading Loading @@ -1538,7 +1614,95 @@ Result<Ok, IOUtils::IOError> IOUtils::SetWindowsAttributesSync( return Ok{}; } #endif // XP_WIN #elif defined(XP_MACOSX) /* static */ Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::GetMacXAttrSync( nsIFile* aFile, const nsCString& aAttr) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsILocalFileMac> file = do_QueryInterface(aFile); MOZ_ASSERT(file); bool hasAttr; 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 hasAttr; } /* static */ Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::GetMacXAttrSync( nsIFile* aFile, const nsCString& aAttr) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsILocalFileMac> file = do_QueryInterface(aFile); MOZ_ASSERT(file); 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(err.WithMessage( "Could not read the extended attribute `%s' from the file `%s'", aAttr.get(), aFile->HumanReadablePath().get())); } return value; } /* static */ Result<Ok, IOUtils::IOError> IOUtils::SetMacXAttrSync( nsIFile* aFile, const nsCString& aAttr, const nsTArray<uint8_t>& aValue) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsILocalFileMac> file = do_QueryInterface(aFile); 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 Ok{}; } /* static */ Result<Ok, IOUtils::IOError> IOUtils::DelMacXAttrSync(nsIFile* aFile, const nsCString& aAttr) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsILocalFileMac> file = do_QueryInterface(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).WithMessage( "Could not delete extended attribute `%s' on file `%s'", aAttr.get(), aFile->HumanReadablePath().get())); } return Ok{}; } #endif /* static */ void IOUtils::GetProfileBeforeChange(GlobalObject& aGlobal, Loading dom/system/IOUtils.h +25 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,20 @@ class IOUtils final { static already_AddRefed<Promise> SetWindowsAttributes( GlobalObject& aGlobal, const nsAString& aPath, const mozilla::dom::WindowsFileAttributes& aAttrs); #elif defined(XP_MACOSX) static already_AddRefed<Promise> HasMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr); static already_AddRefed<Promise> GetMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr); static already_AddRefed<Promise> SetMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr, const Uint8Array& aValue); static already_AddRefed<Promise> DelMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr); #endif static void GetProfileBeforeChange(GlobalObject& aGlobal, Loading Loading @@ -401,6 +415,17 @@ class IOUtils final { */ static Result<Ok, IOError> SetWindowsAttributesSync( nsIFile* aFile, const uint32_t aSetAttrs, const uint32_t aClearAttrs); #elif defined(XP_MACOSX) static Result<bool, IOError> HasMacXAttrSync(GlobalObject& aGlobal, nsIFile* aFile, const nsCString& aAttr); static Result<nsTArray<uint8_t>, IOError> GetMacXAttrSync( nsIFile* aFile, const nsCString& aAttr); static Result<Ok, IOError> SetMacXAttrSync(nsIFile* aFile, const nsCString& aAttr, const nsTArray<uint8_t>& aValue); static Result<Ok, IOError> DelMacXAttrSync(nsIFile* aFile, const nsCString& aAttr); #endif enum class EventQueueStatus { Loading dom/system/tests/ioutils/chrome.ini +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ support-files = [test_ioutils.html] [test_ioutils_copy_move.html] [test_ioutils_dir_iteration.html] [test_ioutils_mac_xattr.html] skip-if = (os != "mac") [test_ioutils_mkdir.html] [test_ioutils_read_write.html] [test_ioutils_read_write_json.html] Loading dom/system/tests/ioutils/test_ioutils_mac_xattr.html 0 → 100644 +85 −0 Original line number Diff line number Diff line <!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Test the IOUtils file I/O API</title> <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> <script src="file_ioutils_test_fixtures.js"></script> <script> "use strict"; const { Assert } = ChromeUtils.import("resource://testing-common/Assert.jsm"); const { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm"); const ATTR = "bogus.attr"; add_task(async function getSetWindowsAttributes() { const bogus = new TextEncoder().encode("bogus"); const tmpDir = PathUtils.join(await PathUtils.getTempDir(), "ioutils-macos-xattr.tmp.d"); await createDir(tmpDir) const path = PathUtils.join(tmpDir, "file.tmp"); await IOUtils.writeUTF8(path, ""); ok( !await IOUtils.hasMacXAttr(path, ATTR), "File does not have an extended attribute at creation" ); 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/, "IOUtils::getMacXAttr rejects when the attribute does not exist" ); info("Testing setting an attribute"); await IOUtils.setMacXAttr(ATTR, new TextEncoder().encode("bogus")); ok( await IOUtils.hasMacXAttr(path, ATTR), "File has extended attribute after setting" ); { info("Testing getting an attribute") const value = await IOUtils.getMacXAttr(ATTR); Assert.equal(value, bogus, "Attribute value should match"); } info("Testing removing an attribute"); await IOUtils.delMacXAttr(ATTR); await Assert.rejects( IOUtils.getMacXAttr(path, ATTR), /NotFoundError: The file `.+' does not have an extended attribute/, "IOUtils::delMacXAttr removes the attribute" ); ok( await IOUtils.hasMacXAttr(path, ATTR), "File does not have extended attribute after removing" ); info("Testing removing an attribute that does not exist"); await Assert.rejects( await IOUtils.delMacXAttr(ATTR), /NotFoundError: The file `.+' does not have an extended attribute/, "IOUtils::delMacXAttr rejects when the attribute does not exist" ); await cleanup(tmpDir); }); </script> </head> <body> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"></pre> </body> </html> Loading
dom/chrome-webidl/IOUtils.webidl +42 −1 Original line number Diff line number Diff line Loading @@ -235,8 +235,49 @@ namespace IOUtils { * @return A promise that resolves is the attributes were set successfully. */ Promise<void> setWindowsAttributes(DOMString path, optional WindowsFileAttributes attrs = {}); #elif defined(XP_MACOSX) /** * Return whether or not the file has a specific extended attribute. * * @param path An absolute path. * @param attr The attribute to check for. * * @return A promise that resolves to whether or not the file has an extended * attribute, or rejects with an error. */ Promise<boolean> hasMacXAttr(DOMString path, UTF8String attr); /** * Return the value of an extended attribute for a file. * * @param path An absolute path. * @param attr The attribute to get the value of. * * @return A promise that resolves to the value of the extended attribute, or * rejects with an error. */ Promise<Uint8Array> getMacXAttr(DOMString path, UTF8String attr); /** * Set the extended attribute on a file. * * @param path An absolute path. * @param attr The attribute to set. * @param value The value of the attribute to set. * * @return A promise that resolves to whether or not the file has an extended * attribute, or rejects with an error. */ Promise<void> setMacXAttr(DOMString path, UTF8String attr, Uint8Array value); /** * Delete the extended attribute on a file. * * @param path An absolute path. * @param attr The attribute to delete. * * @return A promise that resolves if the attribute was deleted, or rejects * with an error. */ Promise<void> delMacXAttr(DOMString path, UTF8String attr); #endif }; [Exposed=Window] Loading
dom/system/IOUtils.cpp +165 −1 Original line number Diff line number Diff line Loading @@ -59,6 +59,8 @@ #if defined(XP_WIN) # include "nsILocalFileWin.h" #elif defined(XP_MACOSX) # include "nsILocalFileMac.h" #endif #define REJECT_IF_INIT_PATH_FAILED(_file, _path, _promise) \ Loading Loading @@ -156,6 +158,9 @@ template <typename T> static void ResolveJSPromise(Promise* aPromise, T&& aValue) { if constexpr (std::is_same_v<T, Ok>) { aPromise->MaybeResolveWithUndefined(); } else if constexpr (std::is_same_v<T, nsTArray<uint8_t>>) { TypedArrayCreator<Uint8Array> array(aValue); aPromise->MaybeResolve(array); } else { aPromise->MaybeResolve(std::forward<T>(aValue)); } Loading Loading @@ -242,6 +247,9 @@ static void RejectJSPromise(Promise* aPromise, const IOUtils::IOError& aError) { aPromise->MaybeRejectWithDataError( errMsg.refOr("Argument is not allowed"_ns)); break; case NS_ERROR_NOT_AVAILABLE: aPromise->MaybeRejectWithNotFoundError(errMsg.refOr("Unavailable"_ns)); break; case NS_ERROR_ABORT: aPromise->MaybeRejectWithAbortError(errMsg.refOr("Operation aborted"_ns)); break; Loading Loading @@ -777,6 +785,74 @@ already_AddRefed<Promise> IOUtils::SetWindowsAttributes( }); } #elif defined(XP_MACOSX) /* static */ already_AddRefed<Promise> IOUtils::HasMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr) { return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); DispatchAndResolve<nsTArray<uint8_t>>( state->mEventQueue, promise, [file = std::move(file), attr = nsCString(aAttr)]() { return HasMacXAttrSync(file, attr); }); }); } /* static */ already_AddRefed<Promise> IOUtils::GetMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr) { return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); DispatchAndResolve<nsTArray<uint8_t>>( state->mEventQueue, promise, [file = std::move(file), attr = nsCString(aAttr)]() { return GetMacXAttrSync(file, attr); }); }); } /* static */ already_AddRefed<Promise> IOUtils::SetMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr, const Uint8Array& aValue) { return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); nsTArray<uint8_t> value(aValue.Data(), aValue.Length()); DispatchAndResolve<Ok>(state->mEventQueue, promise, [file = std::move(file), attr = nsCString(aAttr), value = std::move(value)] { return SetMacXAttrSync(file, attr, value); }); }); } /* static */ already_AddRefed<Promise> IOUtils::DelMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr) { return WithPromiseAndState(aGlobal, [&](Promise* promise, auto& state) { nsCOMPtr<nsIFile> file = new nsLocalFile(); REJECT_IF_INIT_PATH_FAILED(file, aPath, promise); DispatchAndResolve<Ok>(state->mEventQueue, promise, [file = std::move(file), attr = nsCString(aAttr)] { return DelMacXAttrSync(file, attr); }); }); } #endif /* static */ Loading Loading @@ -1538,7 +1614,95 @@ Result<Ok, IOUtils::IOError> IOUtils::SetWindowsAttributesSync( return Ok{}; } #endif // XP_WIN #elif defined(XP_MACOSX) /* static */ Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::GetMacXAttrSync( nsIFile* aFile, const nsCString& aAttr) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsILocalFileMac> file = do_QueryInterface(aFile); MOZ_ASSERT(file); bool hasAttr; 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 hasAttr; } /* static */ Result<nsTArray<uint8_t>, IOUtils::IOError> IOUtils::GetMacXAttrSync( nsIFile* aFile, const nsCString& aAttr) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsILocalFileMac> file = do_QueryInterface(aFile); MOZ_ASSERT(file); 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(err.WithMessage( "Could not read the extended attribute `%s' from the file `%s'", aAttr.get(), aFile->HumanReadablePath().get())); } return value; } /* static */ Result<Ok, IOUtils::IOError> IOUtils::SetMacXAttrSync( nsIFile* aFile, const nsCString& aAttr, const nsTArray<uint8_t>& aValue) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsILocalFileMac> file = do_QueryInterface(aFile); 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 Ok{}; } /* static */ Result<Ok, IOUtils::IOError> IOUtils::DelMacXAttrSync(nsIFile* aFile, const nsCString& aAttr) { MOZ_ASSERT(!NS_IsMainThread()); nsCOMPtr<nsILocalFileMac> file = do_QueryInterface(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).WithMessage( "Could not delete extended attribute `%s' on file `%s'", aAttr.get(), aFile->HumanReadablePath().get())); } return Ok{}; } #endif /* static */ void IOUtils::GetProfileBeforeChange(GlobalObject& aGlobal, Loading
dom/system/IOUtils.h +25 −0 Original line number Diff line number Diff line Loading @@ -131,6 +131,20 @@ class IOUtils final { static already_AddRefed<Promise> SetWindowsAttributes( GlobalObject& aGlobal, const nsAString& aPath, const mozilla::dom::WindowsFileAttributes& aAttrs); #elif defined(XP_MACOSX) static already_AddRefed<Promise> HasMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr); static already_AddRefed<Promise> GetMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr); static already_AddRefed<Promise> SetMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr, const Uint8Array& aValue); static already_AddRefed<Promise> DelMacXAttr(GlobalObject& aGlobal, const nsAString& aPath, const nsACString& aAttr); #endif static void GetProfileBeforeChange(GlobalObject& aGlobal, Loading Loading @@ -401,6 +415,17 @@ class IOUtils final { */ static Result<Ok, IOError> SetWindowsAttributesSync( nsIFile* aFile, const uint32_t aSetAttrs, const uint32_t aClearAttrs); #elif defined(XP_MACOSX) static Result<bool, IOError> HasMacXAttrSync(GlobalObject& aGlobal, nsIFile* aFile, const nsCString& aAttr); static Result<nsTArray<uint8_t>, IOError> GetMacXAttrSync( nsIFile* aFile, const nsCString& aAttr); static Result<Ok, IOError> SetMacXAttrSync(nsIFile* aFile, const nsCString& aAttr, const nsTArray<uint8_t>& aValue); static Result<Ok, IOError> DelMacXAttrSync(nsIFile* aFile, const nsCString& aAttr); #endif enum class EventQueueStatus { Loading
dom/system/tests/ioutils/chrome.ini +2 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,8 @@ support-files = [test_ioutils.html] [test_ioutils_copy_move.html] [test_ioutils_dir_iteration.html] [test_ioutils_mac_xattr.html] skip-if = (os != "mac") [test_ioutils_mkdir.html] [test_ioutils_read_write.html] [test_ioutils_read_write_json.html] Loading
dom/system/tests/ioutils/test_ioutils_mac_xattr.html 0 → 100644 +85 −0 Original line number Diff line number Diff line <!-- Any copyright is dedicated to the Public Domain. - http://creativecommons.org/publicdomain/zero/1.0/ --> <!DOCTYPE HTML> <html> <head> <meta charset="utf-8"> <title>Test the IOUtils file I/O API</title> <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> <link rel="stylesheet" href="chrome://mochikit/content/tests/SimpleTest/test.css" /> <script src="file_ioutils_test_fixtures.js"></script> <script> "use strict"; const { Assert } = ChromeUtils.import("resource://testing-common/Assert.jsm"); const { FileUtils } = ChromeUtils.import("resource://gre/modules/FileUtils.jsm"); const ATTR = "bogus.attr"; add_task(async function getSetWindowsAttributes() { const bogus = new TextEncoder().encode("bogus"); const tmpDir = PathUtils.join(await PathUtils.getTempDir(), "ioutils-macos-xattr.tmp.d"); await createDir(tmpDir) const path = PathUtils.join(tmpDir, "file.tmp"); await IOUtils.writeUTF8(path, ""); ok( !await IOUtils.hasMacXAttr(path, ATTR), "File does not have an extended attribute at creation" ); 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/, "IOUtils::getMacXAttr rejects when the attribute does not exist" ); info("Testing setting an attribute"); await IOUtils.setMacXAttr(ATTR, new TextEncoder().encode("bogus")); ok( await IOUtils.hasMacXAttr(path, ATTR), "File has extended attribute after setting" ); { info("Testing getting an attribute") const value = await IOUtils.getMacXAttr(ATTR); Assert.equal(value, bogus, "Attribute value should match"); } info("Testing removing an attribute"); await IOUtils.delMacXAttr(ATTR); await Assert.rejects( IOUtils.getMacXAttr(path, ATTR), /NotFoundError: The file `.+' does not have an extended attribute/, "IOUtils::delMacXAttr removes the attribute" ); ok( await IOUtils.hasMacXAttr(path, ATTR), "File does not have extended attribute after removing" ); info("Testing removing an attribute that does not exist"); await Assert.rejects( await IOUtils.delMacXAttr(ATTR), /NotFoundError: The file `.+' does not have an extended attribute/, "IOUtils::delMacXAttr rejects when the attribute does not exist" ); await cleanup(tmpDir); }); </script> </head> <body> <p id="display"></p> <div id="content" style="display: none"></div> <pre id="test"></pre> </body> </html>