From 26a029d407be480d791972afb5975cf62c9360a6 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 02:47:55 +0200 Subject: Adding upstream version 124.0.1. Signed-off-by: Daniel Baumann --- dom/filesystem/compat/CallbackRunnables.cpp | 280 +++++++++++ dom/filesystem/compat/CallbackRunnables.h | 118 +++++ dom/filesystem/compat/FileSystem.cpp | 60 +++ dom/filesystem/compat/FileSystem.h | 52 ++ dom/filesystem/compat/FileSystemDirectoryEntry.cpp | 92 ++++ dom/filesystem/compat/FileSystemDirectoryEntry.h | 73 +++ .../compat/FileSystemDirectoryReader.cpp | 181 +++++++ dom/filesystem/compat/FileSystemDirectoryReader.h | 60 +++ dom/filesystem/compat/FileSystemEntry.cpp | 80 +++ dom/filesystem/compat/FileSystemEntry.h | 67 +++ dom/filesystem/compat/FileSystemFileEntry.cpp | 94 ++++ dom/filesystem/compat/FileSystemFileEntry.h | 49 ++ .../compat/FileSystemRootDirectoryEntry.cpp | 138 ++++++ .../compat/FileSystemRootDirectoryEntry.h | 48 ++ .../compat/FileSystemRootDirectoryReader.cpp | 93 ++++ .../compat/FileSystemRootDirectoryReader.h | 38 ++ dom/filesystem/compat/moz.build | 30 ++ dom/filesystem/compat/tests/mochitest.toml | 11 + dom/filesystem/compat/tests/moz.build | 7 + dom/filesystem/compat/tests/script_entries.js | 47 ++ dom/filesystem/compat/tests/test_basic.html | 549 +++++++++++++++++++++ .../compat/tests/test_formSubmission.html | 271 ++++++++++ dom/filesystem/compat/tests/test_no_dnd.html | 84 ++++ 23 files changed, 2522 insertions(+) create mode 100644 dom/filesystem/compat/CallbackRunnables.cpp create mode 100644 dom/filesystem/compat/CallbackRunnables.h create mode 100644 dom/filesystem/compat/FileSystem.cpp create mode 100644 dom/filesystem/compat/FileSystem.h create mode 100644 dom/filesystem/compat/FileSystemDirectoryEntry.cpp create mode 100644 dom/filesystem/compat/FileSystemDirectoryEntry.h create mode 100644 dom/filesystem/compat/FileSystemDirectoryReader.cpp create mode 100644 dom/filesystem/compat/FileSystemDirectoryReader.h create mode 100644 dom/filesystem/compat/FileSystemEntry.cpp create mode 100644 dom/filesystem/compat/FileSystemEntry.h create mode 100644 dom/filesystem/compat/FileSystemFileEntry.cpp create mode 100644 dom/filesystem/compat/FileSystemFileEntry.h create mode 100644 dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp create mode 100644 dom/filesystem/compat/FileSystemRootDirectoryEntry.h create mode 100644 dom/filesystem/compat/FileSystemRootDirectoryReader.cpp create mode 100644 dom/filesystem/compat/FileSystemRootDirectoryReader.h create mode 100644 dom/filesystem/compat/moz.build create mode 100644 dom/filesystem/compat/tests/mochitest.toml create mode 100644 dom/filesystem/compat/tests/moz.build create mode 100644 dom/filesystem/compat/tests/script_entries.js create mode 100644 dom/filesystem/compat/tests/test_basic.html create mode 100644 dom/filesystem/compat/tests/test_formSubmission.html create mode 100644 dom/filesystem/compat/tests/test_no_dnd.html (limited to 'dom/filesystem/compat') diff --git a/dom/filesystem/compat/CallbackRunnables.cpp b/dom/filesystem/compat/CallbackRunnables.cpp new file mode 100644 index 0000000000..cbdd2f2f56 --- /dev/null +++ b/dom/filesystem/compat/CallbackRunnables.cpp @@ -0,0 +1,280 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "CallbackRunnables.h" +#include "mozilla/dom/Directory.h" +#include "mozilla/dom/DirectoryBinding.h" +#include "mozilla/dom/DOMException.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/FileBinding.h" +#include "mozilla/dom/FileSystem.h" +#include "mozilla/dom/FileSystemDirectoryReaderBinding.h" +#include "mozilla/dom/FileSystemFileEntry.h" +#include "mozilla/dom/FileSystemUtils.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/Unused.h" +#include "nsIGlobalObject.h" +#include "nsIFile.h" +#include "nsPIDOMWindow.h" + +#include "../GetFileOrDirectoryTask.h" + +namespace mozilla::dom { + +EntryCallbackRunnable::EntryCallbackRunnable(FileSystemEntryCallback* aCallback, + FileSystemEntry* aEntry) + : Runnable("EntryCallbackRunnable"), mCallback(aCallback), mEntry(aEntry) { + MOZ_ASSERT(aCallback); + MOZ_ASSERT(aEntry); +} + +NS_IMETHODIMP +EntryCallbackRunnable::Run() { + mCallback->Call(*mEntry); + return NS_OK; +} + +ErrorCallbackRunnable::ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject, + ErrorCallback* aCallback, + nsresult aError) + : Runnable("ErrorCallbackRunnable"), + mGlobal(aGlobalObject), + mCallback(aCallback), + mError(aError) { + MOZ_ASSERT(aGlobalObject); + MOZ_ASSERT(aCallback); + MOZ_ASSERT(NS_FAILED(aError)); +} + +NS_IMETHODIMP +ErrorCallbackRunnable::Run() { + RefPtr exception = DOMException::Create(mError); + mCallback->Call(*exception); + return NS_OK; +} + +EmptyEntriesCallbackRunnable::EmptyEntriesCallbackRunnable( + FileSystemEntriesCallback* aCallback) + : Runnable("EmptyEntriesCallbackRunnable"), mCallback(aCallback) { + MOZ_ASSERT(aCallback); +} + +NS_IMETHODIMP +EmptyEntriesCallbackRunnable::Run() { + Sequence> sequence; + mCallback->Call(sequence); + return NS_OK; +} + +GetEntryHelper::GetEntryHelper(FileSystemDirectoryEntry* aParentEntry, + Directory* aDirectory, + nsTArray& aParts, + FileSystem* aFileSystem, + FileSystemEntryCallback* aSuccessCallback, + ErrorCallback* aErrorCallback, + FileSystemDirectoryEntry::GetInternalType aType) + : mParentEntry(aParentEntry), + mDirectory(aDirectory), + mParts(aParts.Clone()), + mFileSystem(aFileSystem), + mSuccessCallback(aSuccessCallback), + mErrorCallback(aErrorCallback), + mType(aType) { + MOZ_ASSERT(aParentEntry); + MOZ_ASSERT(aDirectory); + MOZ_ASSERT(!aParts.IsEmpty()); + MOZ_ASSERT(aFileSystem); + MOZ_ASSERT(aSuccessCallback || aErrorCallback); +} + +GetEntryHelper::~GetEntryHelper() = default; + +namespace { + +nsresult DOMPathToRealPath(Directory* aDirectory, const nsAString& aPath, + nsIFile** aFile) { + nsString relativePath; + relativePath = aPath; + + // Trim white spaces. + static const char kWhitespace[] = "\b\t\r\n "; + relativePath.Trim(kWhitespace); + + nsTArray parts; + if (!FileSystemUtils::IsValidRelativeDOMPath(relativePath, parts)) { + return NS_ERROR_DOM_FILESYSTEM_INVALID_PATH_ERR; + } + + nsCOMPtr file; + nsresult rv = aDirectory->GetInternalNsIFile()->Clone(getter_AddRefs(file)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + for (uint32_t i = 0; i < parts.Length(); ++i) { + rv = file->AppendRelativePath(parts[i]); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + file.forget(aFile); + return NS_OK; +} + +} // namespace + +void GetEntryHelper::Run() { + MOZ_ASSERT(!mParts.IsEmpty()); + + nsCOMPtr realPath; + nsresult error = + DOMPathToRealPath(mDirectory, mParts[0], getter_AddRefs(realPath)); + + ErrorResult rv; + RefPtr fs = mDirectory->GetFileSystem(rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + Error(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + + RefPtr task = + GetFileOrDirectoryTaskChild::Create(fs, realPath, rv); + if (NS_WARN_IF(rv.Failed())) { + rv.SuppressException(); + Error(NS_ERROR_DOM_INVALID_STATE_ERR); + return; + } + + task->SetError(error); + task->Start(); + + RefPtr promise = task->GetPromise(); + + mParts.RemoveElementAt(0); + promise->AppendNativeHandler(this); +} + +void GetEntryHelper::ResolvedCallback(JSContext* aCx, + JS::Handle aValue, + ErrorResult& aRv) { + if (NS_WARN_IF(!aValue.isObject())) { + return; + } + + JS::Rooted obj(aCx, &aValue.toObject()); + + // This is not the last part of the path. + if (!mParts.IsEmpty()) { + ContinueRunning(obj); + return; + } + + CompleteOperation(obj); +} + +void GetEntryHelper::CompleteOperation(JSObject* aObj) { + MOZ_ASSERT(mParts.IsEmpty()); + + if (mType == FileSystemDirectoryEntry::eGetFile) { + RefPtr file; + if (NS_FAILED(UNWRAP_OBJECT(File, aObj, file))) { + Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR); + return; + } + + RefPtr entry = new FileSystemFileEntry( + mParentEntry->GetParentObject(), file, mParentEntry, mFileSystem); + mSuccessCallback->Call(*entry); + return; + } + + MOZ_ASSERT(mType == FileSystemDirectoryEntry::eGetDirectory); + + RefPtr directory; + if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) { + Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR); + return; + } + + RefPtr entry = new FileSystemDirectoryEntry( + mParentEntry->GetParentObject(), directory, mParentEntry, mFileSystem); + mSuccessCallback->Call(*entry); +} + +void GetEntryHelper::ContinueRunning(JSObject* aObj) { + MOZ_ASSERT(!mParts.IsEmpty()); + + RefPtr directory; + if (NS_FAILED(UNWRAP_OBJECT(Directory, aObj, directory))) { + Error(NS_ERROR_DOM_TYPE_MISMATCH_ERR); + return; + } + + RefPtr entry = new FileSystemDirectoryEntry( + mParentEntry->GetParentObject(), directory, mParentEntry, mFileSystem); + + // Update the internal values. + mParentEntry = entry; + mDirectory = directory; + + Run(); +} + +void GetEntryHelper::RejectedCallback(JSContext* aCx, + JS::Handle aValue, + ErrorResult& aRv) { + Error(NS_ERROR_DOM_NOT_FOUND_ERR); +} + +void GetEntryHelper::Error(nsresult aError) { + MOZ_ASSERT(NS_FAILED(aError)); + + if (mErrorCallback) { + RefPtr runnable = new ErrorCallbackRunnable( + mParentEntry->GetParentObject(), mErrorCallback, aError); + + FileSystemUtils::DispatchRunnable(mParentEntry->GetParentObject(), + runnable.forget()); + } +} + +NS_IMPL_ISUPPORTS0(GetEntryHelper); + +/* static */ +void FileSystemEntryCallbackHelper::Call( + nsIGlobalObject* aGlobalObject, + const Optional>& aEntryCallback, + FileSystemEntry* aEntry) { + MOZ_ASSERT(aGlobalObject); + MOZ_ASSERT(aEntry); + + if (aEntryCallback.WasPassed()) { + RefPtr runnable = + new EntryCallbackRunnable(&aEntryCallback.Value(), aEntry); + + FileSystemUtils::DispatchRunnable(aGlobalObject, runnable.forget()); + } +} + +/* static */ +void ErrorCallbackHelper::Call( + nsIGlobalObject* aGlobal, + const Optional>& aErrorCallback, + nsresult aError) { + MOZ_ASSERT(aGlobal); + MOZ_ASSERT(NS_FAILED(aError)); + + if (aErrorCallback.WasPassed()) { + RefPtr runnable = + new ErrorCallbackRunnable(aGlobal, &aErrorCallback.Value(), aError); + + FileSystemUtils::DispatchRunnable(aGlobal, runnable.forget()); + } +} + +} // namespace mozilla::dom diff --git a/dom/filesystem/compat/CallbackRunnables.h b/dom/filesystem/compat/CallbackRunnables.h new file mode 100644 index 0000000000..e2e1c47913 --- /dev/null +++ b/dom/filesystem/compat/CallbackRunnables.h @@ -0,0 +1,118 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_ErrorCallbackRunnable_h +#define mozilla_dom_ErrorCallbackRunnable_h + +#include "FileSystemDirectoryEntry.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/PromiseNativeHandler.h" +#include "nsThreadUtils.h" + +class nsIGlobalObject; + +namespace mozilla::dom { + +class FileSystemEntriesCallback; + +class EntryCallbackRunnable final : public Runnable { + public: + EntryCallbackRunnable(FileSystemEntryCallback* aCallback, + FileSystemEntry* aEntry); + + // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See + // bug 1535398. + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override; + + private: + const RefPtr mCallback; + const RefPtr mEntry; +}; + +class ErrorCallbackRunnable final : public Runnable { + public: + ErrorCallbackRunnable(nsIGlobalObject* aGlobalObject, + ErrorCallback* aCallback, nsresult aError); + + // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See + // bug 1535398. + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override; + + private: + nsCOMPtr mGlobal; + const RefPtr mCallback; + nsresult mError; +}; + +class EmptyEntriesCallbackRunnable final : public Runnable { + public: + explicit EmptyEntriesCallbackRunnable(FileSystemEntriesCallback* aCallback); + + // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See + // bug 1535398. + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override; + + private: + const RefPtr mCallback; +}; + +class GetEntryHelper final : public PromiseNativeHandler { + public: + NS_DECL_ISUPPORTS + + GetEntryHelper(FileSystemDirectoryEntry* aParentEntry, Directory* aDirectory, + nsTArray& aParts, FileSystem* aFileSystem, + FileSystemEntryCallback* aSuccessCallback, + ErrorCallback* aErrorCallback, + FileSystemDirectoryEntry::GetInternalType aType); + + void Run(); + + MOZ_CAN_RUN_SCRIPT + virtual void ResolvedCallback(JSContext* aCx, JS::Handle aValue, + ErrorResult& aRv) override; + + virtual void RejectedCallback(JSContext* aCx, JS::Handle aValue, + ErrorResult& aRv) override; + + private: + ~GetEntryHelper(); + + void Error(nsresult aError); + + void ContinueRunning(JSObject* aObj); + + MOZ_CAN_RUN_SCRIPT void CompleteOperation(JSObject* aObj); + + RefPtr mParentEntry; + RefPtr mDirectory; + nsTArray mParts; + RefPtr mFileSystem; + + const RefPtr mSuccessCallback; + RefPtr mErrorCallback; + + FileSystemDirectoryEntry::GetInternalType mType; +}; + +class FileSystemEntryCallbackHelper { + public: + static void Call( + nsIGlobalObject* aGlobalObject, + const Optional>& aEntryCallback, + FileSystemEntry* aEntry); +}; + +class ErrorCallbackHelper { + public: + static void Call(nsIGlobalObject* aGlobal, + const Optional>& aErrorCallback, + nsresult aError); +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_CallbackRunnables_h diff --git a/dom/filesystem/compat/FileSystem.cpp b/dom/filesystem/compat/FileSystem.cpp new file mode 100644 index 0000000000..734b3ec600 --- /dev/null +++ b/dom/filesystem/compat/FileSystem.cpp @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileSystem.h" +#include "FileSystemRootDirectoryEntry.h" +#include "mozilla/dom/FileSystemBinding.h" +#include "nsIDUtils.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileSystem, mParent, mRoot) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(FileSystem) +NS_IMPL_CYCLE_COLLECTING_RELEASE(FileSystem) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystem) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +/* static */ +already_AddRefed FileSystem::Create(nsIGlobalObject* aGlobalObject) + +{ + MOZ_ASSERT(aGlobalObject); + + nsID id; + nsresult rv = nsID::GenerateUUIDInPlace(id); + if (NS_WARN_IF(NS_FAILED(rv))) { + return nullptr; + } + + NSID_TrimBracketsUTF16 name(id); + + RefPtr fs = new FileSystem(aGlobalObject, name); + + return fs.forget(); +} + +FileSystem::FileSystem(nsIGlobalObject* aGlobal, const nsAString& aName) + : mParent(aGlobal), mName(aName) { + MOZ_ASSERT(aGlobal); +} + +FileSystem::~FileSystem() = default; + +JSObject* FileSystem::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return FileSystem_Binding::Wrap(aCx, this, aGivenProto); +} + +void FileSystem::CreateRoot(const Sequence>& aEntries) { + MOZ_ASSERT(!mRoot); + mRoot = new FileSystemRootDirectoryEntry(mParent, aEntries, this); +} + +} // namespace mozilla::dom diff --git a/dom/filesystem/compat/FileSystem.h b/dom/filesystem/compat/FileSystem.h new file mode 100644 index 0000000000..92cb563ef4 --- /dev/null +++ b/dom/filesystem/compat/FileSystem.h @@ -0,0 +1,52 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FileSystem_h +#define mozilla_dom_FileSystem_h + +#include "mozilla/Attributes.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "nsCycleCollectionParticipant.h" +#include "nsWrapperCache.h" + +class nsIGlobalObject; + +namespace mozilla::dom { + +class FileSystemDirectoryEntry; +class FileSystemEntry; +class OwningFileOrDirectory; + +class FileSystem final : public nsISupports, public nsWrapperCache { + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(FileSystem) + + static already_AddRefed Create(nsIGlobalObject* aGlobalObject); + + nsIGlobalObject* GetParentObject() const { return mParent; } + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + void GetName(nsAString& aName) const { aName = mName; } + + FileSystemDirectoryEntry* Root() const { return mRoot; } + + void CreateRoot(const Sequence>& aEntries); + + private: + explicit FileSystem(nsIGlobalObject* aGlobalObject, const nsAString& aName); + ~FileSystem(); + + nsCOMPtr mParent; + RefPtr mRoot; + nsString mName; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_FileSystem_h diff --git a/dom/filesystem/compat/FileSystemDirectoryEntry.cpp b/dom/filesystem/compat/FileSystemDirectoryEntry.cpp new file mode 100644 index 0000000000..7358f997f0 --- /dev/null +++ b/dom/filesystem/compat/FileSystemDirectoryEntry.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileSystemDirectoryEntry.h" +#include "CallbackRunnables.h" +#include "FileSystemDirectoryReader.h" +#include "mozilla/dom/Directory.h" +#include "mozilla/dom/FileSystemDirectoryEntryBinding.h" +#include "mozilla/dom/FileSystemUtils.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemDirectoryEntry, FileSystemEntry, + mDirectory) + +NS_IMPL_ADDREF_INHERITED(FileSystemDirectoryEntry, FileSystemEntry) +NS_IMPL_RELEASE_INHERITED(FileSystemDirectoryEntry, FileSystemEntry) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemDirectoryEntry) +NS_INTERFACE_MAP_END_INHERITING(FileSystemEntry) + +FileSystemDirectoryEntry::FileSystemDirectoryEntry( + nsIGlobalObject* aGlobal, Directory* aDirectory, + FileSystemDirectoryEntry* aParentEntry, FileSystem* aFileSystem) + : FileSystemEntry(aGlobal, aParentEntry, aFileSystem), + mDirectory(aDirectory) { + MOZ_ASSERT(aGlobal); +} + +FileSystemDirectoryEntry::~FileSystemDirectoryEntry() = default; + +JSObject* FileSystemDirectoryEntry::WrapObject( + JSContext* aCx, JS::Handle aGivenProto) { + return FileSystemDirectoryEntry_Binding::Wrap(aCx, this, aGivenProto); +} + +void FileSystemDirectoryEntry::GetName(nsAString& aName, + ErrorResult& aRv) const { + MOZ_ASSERT(mDirectory); + mDirectory->GetName(aName, aRv); +} + +void FileSystemDirectoryEntry::GetFullPath(nsAString& aPath, + ErrorResult& aRv) const { + MOZ_ASSERT(mDirectory); + mDirectory->GetPath(aPath, aRv); +} + +already_AddRefed +FileSystemDirectoryEntry::CreateReader() { + MOZ_ASSERT(mDirectory); + + RefPtr reader = + new FileSystemDirectoryReader(this, Filesystem(), mDirectory); + return reader.forget(); +} + +void FileSystemDirectoryEntry::GetInternal( + const nsAString& aPath, const FileSystemFlags& aFlag, + const Optional>& aSuccessCallback, + const Optional>& aErrorCallback, + GetInternalType aType) { + MOZ_ASSERT(mDirectory); + + if (!aSuccessCallback.WasPassed() && !aErrorCallback.WasPassed()) { + return; + } + + if (aFlag.mCreate) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + NS_ERROR_DOM_SECURITY_ERR); + return; + } + + nsTArray parts; + if (!FileSystemUtils::IsValidRelativeDOMPath(aPath, parts)) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + NS_ERROR_DOM_NOT_FOUND_ERR); + return; + } + + RefPtr helper = new GetEntryHelper( + this, mDirectory, parts, Filesystem(), + aSuccessCallback.WasPassed() ? &aSuccessCallback.Value() : nullptr, + aErrorCallback.WasPassed() ? &aErrorCallback.Value() : nullptr, aType); + helper->Run(); +} + +} // namespace mozilla::dom diff --git a/dom/filesystem/compat/FileSystemDirectoryEntry.h b/dom/filesystem/compat/FileSystemDirectoryEntry.h new file mode 100644 index 0000000000..1b772691e1 --- /dev/null +++ b/dom/filesystem/compat/FileSystemDirectoryEntry.h @@ -0,0 +1,73 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FileSystemDirectoryEntry_h +#define mozilla_dom_FileSystemDirectoryEntry_h + +#include "mozilla/dom/FileSystemEntry.h" + +namespace mozilla::dom { + +class Directory; +class FileSystemDirectoryReader; + +class FileSystemDirectoryEntry : public FileSystemEntry { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileSystemDirectoryEntry, + FileSystemEntry) + + FileSystemDirectoryEntry(nsIGlobalObject* aGlobalObject, + Directory* aDirectory, + FileSystemDirectoryEntry* aParentEntry, + FileSystem* aFileSystem); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + virtual bool IsDirectory() const override { return true; } + + virtual void GetName(nsAString& aName, ErrorResult& aRv) const override; + + virtual void GetFullPath(nsAString& aFullPath, + ErrorResult& aRv) const override; + + virtual already_AddRefed CreateReader(); + + void GetFile( + const Optional& aPath, const FileSystemFlags& aFlag, + const Optional>& aSuccessCallback, + const Optional>& aErrorCallback) { + GetInternal(aPath.WasPassed() ? aPath.Value() : u""_ns, aFlag, + aSuccessCallback, aErrorCallback, eGetFile); + } + + void GetDirectory( + const Optional& aPath, const FileSystemFlags& aFlag, + const Optional>& aSuccessCallback, + const Optional>& aErrorCallback) { + GetInternal(aPath.WasPassed() ? aPath.Value() : u""_ns, aFlag, + aSuccessCallback, aErrorCallback, eGetDirectory); + } + + enum GetInternalType { eGetFile, eGetDirectory }; + + virtual void GetInternal( + const nsAString& aPath, const FileSystemFlags& aFlag, + const Optional>& aSuccessCallback, + const Optional>& aErrorCallback, + GetInternalType aType); + + protected: + virtual ~FileSystemDirectoryEntry(); + + private: + RefPtr mDirectory; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_FileSystemDirectoryEntry_h diff --git a/dom/filesystem/compat/FileSystemDirectoryReader.cpp b/dom/filesystem/compat/FileSystemDirectoryReader.cpp new file mode 100644 index 0000000000..533faae413 --- /dev/null +++ b/dom/filesystem/compat/FileSystemDirectoryReader.cpp @@ -0,0 +1,181 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileSystemDirectoryReader.h" +#include "CallbackRunnables.h" +#include "FileSystemFileEntry.h" +#include "js/Array.h" // JS::NewArrayObject +#include "js/PropertyAndElement.h" // JS_GetElement +#include "mozilla/dom/FileBinding.h" +#include "mozilla/dom/FileSystem.h" +#include "mozilla/dom/FileSystemDirectoryReaderBinding.h" +#include "mozilla/dom/FileSystemUtils.h" +#include "mozilla/dom/Directory.h" +#include "mozilla/dom/DirectoryBinding.h" +#include "mozilla/dom/Promise.h" +#include "mozilla/dom/PromiseNativeHandler.h" + +namespace mozilla::dom { + +namespace { + +class PromiseHandler final : public PromiseNativeHandler { + public: + NS_DECL_ISUPPORTS + + PromiseHandler(FileSystemDirectoryEntry* aParentEntry, + FileSystem* aFileSystem, + FileSystemEntriesCallback* aSuccessCallback, + ErrorCallback* aErrorCallback) + : mParentEntry(aParentEntry), + mFileSystem(aFileSystem), + mSuccessCallback(aSuccessCallback), + mErrorCallback(aErrorCallback) { + MOZ_ASSERT(aParentEntry); + MOZ_ASSERT(aFileSystem); + MOZ_ASSERT(aSuccessCallback); + } + + MOZ_CAN_RUN_SCRIPT + virtual void ResolvedCallback(JSContext* aCx, JS::Handle aValue, + ErrorResult& aRv) override { + if (NS_WARN_IF(!aValue.isObject())) { + return; + } + + JS::Rooted obj(aCx, &aValue.toObject()); + + uint32_t length; + if (NS_WARN_IF(!JS::GetArrayLength(aCx, obj, &length))) { + return; + } + + Sequence> sequence; + if (NS_WARN_IF(!sequence.SetLength(length, fallible))) { + return; + } + + for (uint32_t i = 0; i < length; ++i) { + JS::Rooted value(aCx); + if (NS_WARN_IF(!JS_GetElement(aCx, obj, i, &value))) { + return; + } + + if (NS_WARN_IF(!value.isObject())) { + return; + } + + JS::Rooted valueObj(aCx, &value.toObject()); + + RefPtr file; + if (NS_SUCCEEDED(UNWRAP_OBJECT(File, valueObj, file))) { + RefPtr entry = new FileSystemFileEntry( + mParentEntry->GetParentObject(), file, mParentEntry, mFileSystem); + sequence[i] = entry; + continue; + } + + RefPtr directory; + if (NS_WARN_IF( + NS_FAILED(UNWRAP_OBJECT(Directory, valueObj, directory)))) { + return; + } + + RefPtr entry = + new FileSystemDirectoryEntry(mParentEntry->GetParentObject(), + directory, mParentEntry, mFileSystem); + sequence[i] = entry; + } + + mSuccessCallback->Call(sequence); + } + + virtual void RejectedCallback(JSContext* aCx, JS::Handle aValue, + ErrorResult& aRv) override { + if (mErrorCallback) { + RefPtr runnable = new ErrorCallbackRunnable( + mParentEntry->GetParentObject(), mErrorCallback, + NS_ERROR_DOM_INVALID_STATE_ERR); + + FileSystemUtils::DispatchRunnable(mParentEntry->GetParentObject(), + runnable.forget()); + } + } + + private: + ~PromiseHandler() = default; + + RefPtr mParentEntry; + RefPtr mFileSystem; + const RefPtr mSuccessCallback; + RefPtr mErrorCallback; +}; + +NS_IMPL_ISUPPORTS0(PromiseHandler); + +} // anonymous namespace + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileSystemDirectoryReader, mParentEntry, + mDirectory, mFileSystem) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(FileSystemDirectoryReader) +NS_IMPL_CYCLE_COLLECTING_RELEASE(FileSystemDirectoryReader) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemDirectoryReader) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +FileSystemDirectoryReader::FileSystemDirectoryReader( + FileSystemDirectoryEntry* aParentEntry, FileSystem* aFileSystem, + Directory* aDirectory) + : mParentEntry(aParentEntry), + mFileSystem(aFileSystem), + mDirectory(aDirectory), + mAlreadyRead(false) { + MOZ_ASSERT(aParentEntry); + MOZ_ASSERT(aFileSystem); +} + +FileSystemDirectoryReader::~FileSystemDirectoryReader() = default; + +JSObject* FileSystemDirectoryReader::WrapObject( + JSContext* aCx, JS::Handle aGivenProto) { + return FileSystemDirectoryReader_Binding::Wrap(aCx, this, aGivenProto); +} + +void FileSystemDirectoryReader::ReadEntries( + FileSystemEntriesCallback& aSuccessCallback, + const Optional>& aErrorCallback, + ErrorResult& aRv) { + MOZ_ASSERT(mDirectory); + + if (mAlreadyRead) { + RefPtr runnable = + new EmptyEntriesCallbackRunnable(&aSuccessCallback); + + FileSystemUtils::DispatchRunnable(GetParentObject(), runnable.forget()); + return; + } + + // This object can be used only once. + mAlreadyRead = true; + + ErrorResult rv; + RefPtr promise = mDirectory->GetFilesAndDirectories(rv); + if (NS_WARN_IF(rv.Failed())) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + rv.StealNSResult()); + return; + } + + RefPtr handler = new PromiseHandler( + mParentEntry, mFileSystem, &aSuccessCallback, + aErrorCallback.WasPassed() ? &aErrorCallback.Value() : nullptr); + promise->AppendNativeHandler(handler); +} + +} // namespace mozilla::dom diff --git a/dom/filesystem/compat/FileSystemDirectoryReader.h b/dom/filesystem/compat/FileSystemDirectoryReader.h new file mode 100644 index 0000000000..90274943b4 --- /dev/null +++ b/dom/filesystem/compat/FileSystemDirectoryReader.h @@ -0,0 +1,60 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FileSystemDirectoryReader_h +#define mozilla_dom_FileSystemDirectoryReader_h + +#include "mozilla/Attributes.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/FileSystemDirectoryEntry.h" +#include "nsCycleCollectionParticipant.h" +#include "nsWrapperCache.h" + +namespace mozilla { +class ErrorResult; + +namespace dom { + +class Directory; +class FileSystem; +class FileSystemEntriesCallback; + +class FileSystemDirectoryReader : public nsISupports, public nsWrapperCache { + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(FileSystemDirectoryReader) + + explicit FileSystemDirectoryReader(FileSystemDirectoryEntry* aDirectoryEntry, + FileSystem* aFileSystem, + Directory* aDirectory); + + nsIGlobalObject* GetParentObject() const { + return mParentEntry->GetParentObject(); + } + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + virtual void ReadEntries( + FileSystemEntriesCallback& aSuccessCallback, + const Optional>& aErrorCallback, + ErrorResult& aRv); + + protected: + virtual ~FileSystemDirectoryReader(); + + private: + RefPtr mParentEntry; + RefPtr mFileSystem; + RefPtr mDirectory; + + bool mAlreadyRead; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_FileSystemDirectoryReader_h diff --git a/dom/filesystem/compat/FileSystemEntry.cpp b/dom/filesystem/compat/FileSystemEntry.cpp new file mode 100644 index 0000000000..3a69e2537a --- /dev/null +++ b/dom/filesystem/compat/FileSystemEntry.cpp @@ -0,0 +1,80 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileSystemEntry.h" +#include "CallbackRunnables.h" +#include "FileSystem.h" +#include "FileSystemDirectoryEntry.h" +#include "FileSystemFileEntry.h" +#include "mozilla/dom/FileSystemEntryBinding.h" +#include "mozilla/dom/UnionTypes.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(FileSystemEntry, mParent, mParentEntry, + mFileSystem) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(FileSystemEntry) +NS_IMPL_CYCLE_COLLECTING_RELEASE(FileSystemEntry) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemEntry) + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +/* static */ +already_AddRefed FileSystemEntry::Create( + nsIGlobalObject* aGlobalObject, + const OwningFileOrDirectory& aFileOrDirectory, FileSystem* aFileSystem) { + MOZ_ASSERT(aGlobalObject); + MOZ_ASSERT(aFileSystem); + + RefPtr entry; + if (aFileOrDirectory.IsFile()) { + entry = new FileSystemFileEntry(aGlobalObject, aFileOrDirectory.GetAsFile(), + nullptr, aFileSystem); + } else { + MOZ_ASSERT(aFileOrDirectory.IsDirectory()); + entry = new FileSystemDirectoryEntry( + aGlobalObject, aFileOrDirectory.GetAsDirectory(), nullptr, aFileSystem); + } + + return entry.forget(); +} + +FileSystemEntry::FileSystemEntry(nsIGlobalObject* aGlobal, + FileSystemEntry* aParentEntry, + FileSystem* aFileSystem) + : mParent(aGlobal), mParentEntry(aParentEntry), mFileSystem(aFileSystem) { + MOZ_ASSERT(aGlobal); + MOZ_ASSERT(aFileSystem); +} + +FileSystemEntry::~FileSystemEntry() = default; + +JSObject* FileSystemEntry::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return FileSystemEntry_Binding::Wrap(aCx, this, aGivenProto); +} + +void FileSystemEntry::GetParent( + const Optional>& aSuccessCallback, + const Optional>& aErrorCallback) { + if (!aSuccessCallback.WasPassed() && !aErrorCallback.WasPassed()) { + return; + } + + if (mParentEntry) { + FileSystemEntryCallbackHelper::Call(GetParentObject(), aSuccessCallback, + mParentEntry); + return; + } + + FileSystemEntryCallbackHelper::Call(GetParentObject(), aSuccessCallback, + this); +} + +} // namespace mozilla::dom diff --git a/dom/filesystem/compat/FileSystemEntry.h b/dom/filesystem/compat/FileSystemEntry.h new file mode 100644 index 0000000000..2275c600a9 --- /dev/null +++ b/dom/filesystem/compat/FileSystemEntry.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FileSystemEntry_h +#define mozilla_dom_FileSystemEntry_h + +#include "mozilla/Attributes.h" +#include "mozilla/dom/BindingDeclarations.h" +#include "mozilla/dom/FileSystemBinding.h" +#include "nsCycleCollectionParticipant.h" +#include "nsIGlobalObject.h" +#include "nsWrapperCache.h" + +namespace mozilla { +class ErrorResult; + +namespace dom { + +class FileSystem; +class OwningFileOrDirectory; + +class FileSystemEntry : public nsISupports, public nsWrapperCache { + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_WRAPPERCACHE_CLASS(FileSystemEntry) + + static already_AddRefed Create( + nsIGlobalObject* aGlobalObject, + const OwningFileOrDirectory& aFileOrDirectory, FileSystem* aFileSystem); + + nsIGlobalObject* GetParentObject() const { return mParent; } + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + virtual bool IsFile() const { return false; } + + virtual bool IsDirectory() const { return false; } + + virtual void GetName(nsAString& aName, ErrorResult& aRv) const = 0; + + virtual void GetFullPath(nsAString& aFullPath, ErrorResult& aRv) const = 0; + + void GetParent( + const Optional>& aSuccessCallback, + const Optional>& aErrorCallback); + + FileSystem* Filesystem() const { return mFileSystem; } + + protected: + FileSystemEntry(nsIGlobalObject* aGlobalObject, FileSystemEntry* aParentEntry, + FileSystem* aFileSystem); + virtual ~FileSystemEntry(); + + private: + nsCOMPtr mParent; + RefPtr mParentEntry; + RefPtr mFileSystem; +}; + +} // namespace dom +} // namespace mozilla + +#endif // mozilla_dom_FileSystemEntry_h diff --git a/dom/filesystem/compat/FileSystemFileEntry.cpp b/dom/filesystem/compat/FileSystemFileEntry.cpp new file mode 100644 index 0000000000..59216641cc --- /dev/null +++ b/dom/filesystem/compat/FileSystemFileEntry.cpp @@ -0,0 +1,94 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileSystemFileEntry.h" +#include "CallbackRunnables.h" +#include "mozilla/dom/File.h" +#include "mozilla/dom/FileSystemUtils.h" +#include "mozilla/dom/MultipartBlobImpl.h" +#include "mozilla/dom/FileSystemFileEntryBinding.h" + +namespace mozilla::dom { + +namespace { + +class FileCallbackRunnable final : public Runnable { + public: + FileCallbackRunnable(FileCallback* aCallback, File* aFile) + : Runnable("FileCallbackRunnable"), mCallback(aCallback), mFile(aFile) { + MOZ_ASSERT(aCallback); + MOZ_ASSERT(aFile); + } + + // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See + // bug 1535398. + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override { + // Here we clone the File object. + + RefPtr file = File::Create(mFile->GetParentObject(), mFile->Impl()); + mCallback->Call(*file); + return NS_OK; + } + + private: + const RefPtr mCallback; + RefPtr mFile; +}; + +} // anonymous namespace + +NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemFileEntry, FileSystemEntry, mFile) + +NS_IMPL_ADDREF_INHERITED(FileSystemFileEntry, FileSystemEntry) +NS_IMPL_RELEASE_INHERITED(FileSystemFileEntry, FileSystemEntry) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemFileEntry) +NS_INTERFACE_MAP_END_INHERITING(FileSystemEntry) + +FileSystemFileEntry::FileSystemFileEntry(nsIGlobalObject* aGlobal, File* aFile, + FileSystemDirectoryEntry* aParentEntry, + FileSystem* aFileSystem) + : FileSystemEntry(aGlobal, aParentEntry, aFileSystem), mFile(aFile) { + MOZ_ASSERT(aGlobal); + MOZ_ASSERT(mFile); +} + +FileSystemFileEntry::~FileSystemFileEntry() = default; + +JSObject* FileSystemFileEntry::WrapObject(JSContext* aCx, + JS::Handle aGivenProto) { + return FileSystemFileEntry_Binding::Wrap(aCx, this, aGivenProto); +} + +void FileSystemFileEntry::GetName(nsAString& aName, ErrorResult& aRv) const { + mFile->GetName(aName); +} + +void FileSystemFileEntry::GetFullPath(nsAString& aPath, + ErrorResult& aRv) const { + mFile->Impl()->GetDOMPath(aPath); + if (aPath.IsEmpty()) { + // We're under the root directory. webkitRelativePath + // (implemented as GetPath) is for cases when file is selected because its + // ancestor directory is selected. But that is not the case here, so need to + // manually prepend '/'. + nsAutoString name; + mFile->GetName(name); + aPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL); + aPath.Append(name); + } +} + +void FileSystemFileEntry::GetFile( + FileCallback& aSuccessCallback, + const Optional>& aErrorCallback) const { + RefPtr runnable = + new FileCallbackRunnable(&aSuccessCallback, mFile); + + FileSystemUtils::DispatchRunnable(GetParentObject(), runnable.forget()); +} + +} // namespace mozilla::dom diff --git a/dom/filesystem/compat/FileSystemFileEntry.h b/dom/filesystem/compat/FileSystemFileEntry.h new file mode 100644 index 0000000000..1fe244a66b --- /dev/null +++ b/dom/filesystem/compat/FileSystemFileEntry.h @@ -0,0 +1,49 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FileSystemFileEntry_h +#define mozilla_dom_FileSystemFileEntry_h + +#include "mozilla/dom/FileSystemEntry.h" + +namespace mozilla::dom { + +class File; +class FileCallback; +class FileSystemDirectoryEntry; + +class FileSystemFileEntry final : public FileSystemEntry { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileSystemFileEntry, FileSystemEntry) + + FileSystemFileEntry(nsIGlobalObject* aGlobalObject, File* aFile, + FileSystemDirectoryEntry* aParentEntry, + FileSystem* aFileSystem); + + virtual JSObject* WrapObject(JSContext* aCx, + JS::Handle aGivenProto) override; + + virtual bool IsFile() const override { return true; } + + virtual void GetName(nsAString& aName, ErrorResult& aRv) const override; + + virtual void GetFullPath(nsAString& aFullPath, + ErrorResult& aRv) const override; + + void GetFile( + FileCallback& aSuccessCallback, + const Optional>& aErrorCallback) const; + + private: + ~FileSystemFileEntry(); + + RefPtr mFile; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_FileSystemFileEntry_h diff --git a/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp b/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp new file mode 100644 index 0000000000..fad6243d15 --- /dev/null +++ b/dom/filesystem/compat/FileSystemRootDirectoryEntry.cpp @@ -0,0 +1,138 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileSystemRootDirectoryEntry.h" +#include "FileSystemRootDirectoryReader.h" +#include "mozilla/dom/FileSystemUtils.h" +#include "CallbackRunnables.h" +#include "nsReadableUtils.h" + +namespace mozilla::dom { + +NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemRootDirectoryEntry, + FileSystemDirectoryEntry, mEntries) + +NS_IMPL_ADDREF_INHERITED(FileSystemRootDirectoryEntry, FileSystemDirectoryEntry) +NS_IMPL_RELEASE_INHERITED(FileSystemRootDirectoryEntry, + FileSystemDirectoryEntry) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemRootDirectoryEntry) +NS_INTERFACE_MAP_END_INHERITING(FileSystemDirectoryEntry) + +FileSystemRootDirectoryEntry::FileSystemRootDirectoryEntry( + nsIGlobalObject* aGlobal, Sequence> aEntries, + FileSystem* aFileSystem) + : FileSystemDirectoryEntry(aGlobal, nullptr, nullptr, aFileSystem), + mEntries(std::move(aEntries)) { + MOZ_ASSERT(aGlobal); +} + +FileSystemRootDirectoryEntry::~FileSystemRootDirectoryEntry() = default; + +void FileSystemRootDirectoryEntry::GetName(nsAString& aName, + ErrorResult& aRv) const { + aName.Truncate(); +} + +void FileSystemRootDirectoryEntry::GetFullPath(nsAString& aPath, + ErrorResult& aRv) const { + aPath.AssignLiteral(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL); +} + +already_AddRefed +FileSystemRootDirectoryEntry::CreateReader() { + RefPtr reader = + new FileSystemRootDirectoryReader(this, Filesystem(), mEntries); + return reader.forget(); +} + +void FileSystemRootDirectoryEntry::GetInternal( + const nsAString& aPath, const FileSystemFlags& aFlag, + const Optional>& aSuccessCallback, + const Optional>& aErrorCallback, + GetInternalType aType) { + if (!aSuccessCallback.WasPassed() && !aErrorCallback.WasPassed()) { + return; + } + + if (aFlag.mCreate) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + NS_ERROR_DOM_SECURITY_ERR); + return; + } + + nsTArray parts; + if (!FileSystemUtils::IsValidRelativeDOMPath(aPath, parts)) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + NS_ERROR_DOM_NOT_FOUND_ERR); + return; + } + + MOZ_ASSERT(!parts.IsEmpty()); + + RefPtr entry; + for (uint32_t i = 0; i < mEntries.Length(); ++i) { + ErrorResult rv; + nsAutoString name; + mEntries[i]->GetName(name, rv); + + if (NS_WARN_IF(rv.Failed())) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + rv.StealNSResult()); + return; + } + + if (name == parts[0]) { + entry = mEntries[i]; + break; + } + } + + // Not found. + if (!entry) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + NS_ERROR_DOM_NOT_FOUND_ERR); + return; + } + + // No subdirectory in the path. + if (parts.Length() == 1) { + if ((entry->IsFile() && aType == eGetDirectory) || + (entry->IsDirectory() && aType == eGetFile)) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + NS_ERROR_DOM_TYPE_MISMATCH_ERR); + return; + } + + if (aSuccessCallback.WasPassed()) { + RefPtr runnable = + new EntryCallbackRunnable(&aSuccessCallback.Value(), entry); + + FileSystemUtils::DispatchRunnable(GetParentObject(), runnable.forget()); + } + return; + } + + // Subdirectories, but this is a file. + if (entry->IsFile()) { + ErrorCallbackHelper::Call(GetParentObject(), aErrorCallback, + NS_ERROR_DOM_NOT_FOUND_ERR); + return; + } + + // Let's recreate a path without the first directory. + nsAutoString path; + StringJoinAppend( + path, + NS_LITERAL_STRING_FROM_CSTRING(FILESYSTEM_DOM_PATH_SEPARATOR_LITERAL), + Span{parts}.From(1)); + + auto* directoryEntry = static_cast(entry.get()); + directoryEntry->GetInternal(path, aFlag, aSuccessCallback, aErrorCallback, + aType); +} + +} // namespace mozilla::dom diff --git a/dom/filesystem/compat/FileSystemRootDirectoryEntry.h b/dom/filesystem/compat/FileSystemRootDirectoryEntry.h new file mode 100644 index 0000000000..b6ffb976b8 --- /dev/null +++ b/dom/filesystem/compat/FileSystemRootDirectoryEntry.h @@ -0,0 +1,48 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FileSystemRootDirectoryEntry_h +#define mozilla_dom_FileSystemRootDirectoryEntry_h + +#include "mozilla/dom/FileSystemDirectoryEntry.h" + +namespace mozilla::dom { + +class FileSystemRootDirectoryEntry final : public FileSystemDirectoryEntry { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileSystemRootDirectoryEntry, + FileSystemDirectoryEntry) + + FileSystemRootDirectoryEntry(nsIGlobalObject* aGlobalObject, + Sequence> aEntries, + FileSystem* aFileSystem); + + virtual void GetName(nsAString& aName, ErrorResult& aRv) const override; + + virtual void GetFullPath(nsAString& aFullPath, + ErrorResult& aRv) const override; + + virtual already_AddRefed CreateReader() override; + + private: + ~FileSystemRootDirectoryEntry(); + + virtual void GetInternal( + const nsAString& aPath, const FileSystemFlags& aFlag, + const Optional>& aSuccessCallback, + const Optional>& aErrorCallback, + GetInternalType aType) override; + + void Error(const Optional>& aErrorCallback, + nsresult aError) const; + + Sequence> mEntries; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_FileSystemRootDirectoryEntry_h diff --git a/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp b/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp new file mode 100644 index 0000000000..5d30f0c1cb --- /dev/null +++ b/dom/filesystem/compat/FileSystemRootDirectoryReader.cpp @@ -0,0 +1,93 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileSystemRootDirectoryReader.h" +#include "CallbackRunnables.h" +#include "nsIGlobalObject.h" +#include "mozilla/dom/FileSystemDirectoryReaderBinding.h" +#include "mozilla/dom/FileSystemUtils.h" + +namespace mozilla::dom { + +namespace { + +class EntriesCallbackRunnable final : public Runnable { + public: + EntriesCallbackRunnable(FileSystemEntriesCallback* aCallback, + const Sequence>& aEntries) + : Runnable("EntriesCallbackRunnable"), + mCallback(aCallback), + mEntries(aEntries) { + MOZ_ASSERT(aCallback); + } + + // MOZ_CAN_RUN_SCRIPT_BOUNDARY until Runnable::Run is MOZ_CAN_RUN_SCRIPT. See + // bug 1535398. + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD Run() override { + Sequence> entries; + for (uint32_t i = 0; i < mEntries.Length(); ++i) { + if (!entries.AppendElement(mEntries[i].forget(), fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + } + + mCallback->Call(entries); + return NS_OK; + } + + private: + const RefPtr mCallback; + Sequence> mEntries; +}; + +} // anonymous namespace + +NS_IMPL_CYCLE_COLLECTION_INHERITED(FileSystemRootDirectoryReader, + FileSystemDirectoryReader, mEntries) + +NS_IMPL_ADDREF_INHERITED(FileSystemRootDirectoryReader, + FileSystemDirectoryReader) +NS_IMPL_RELEASE_INHERITED(FileSystemRootDirectoryReader, + FileSystemDirectoryReader) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FileSystemRootDirectoryReader) +NS_INTERFACE_MAP_END_INHERITING(FileSystemDirectoryReader) + +FileSystemRootDirectoryReader::FileSystemRootDirectoryReader( + FileSystemDirectoryEntry* aParentEntry, FileSystem* aFileSystem, + const Sequence>& aEntries) + : FileSystemDirectoryReader(aParentEntry, aFileSystem, nullptr), + mEntries(aEntries), + mAlreadyRead(false) { + MOZ_ASSERT(aParentEntry); + MOZ_ASSERT(aFileSystem); +} + +FileSystemRootDirectoryReader::~FileSystemRootDirectoryReader() = default; + +void FileSystemRootDirectoryReader::ReadEntries( + FileSystemEntriesCallback& aSuccessCallback, + const Optional>& aErrorCallback, + ErrorResult& aRv) { + if (mAlreadyRead) { + RefPtr runnable = + new EmptyEntriesCallbackRunnable(&aSuccessCallback); + + aRv = + FileSystemUtils::DispatchRunnable(GetParentObject(), runnable.forget()); + return; + } + + // This object can be used only once. + mAlreadyRead = true; + + RefPtr runnable = + new EntriesCallbackRunnable(&aSuccessCallback, mEntries); + + aRv = FileSystemUtils::DispatchRunnable(GetParentObject(), runnable.forget()); +} + +} // namespace mozilla::dom diff --git a/dom/filesystem/compat/FileSystemRootDirectoryReader.h b/dom/filesystem/compat/FileSystemRootDirectoryReader.h new file mode 100644 index 0000000000..7429de8a9c --- /dev/null +++ b/dom/filesystem/compat/FileSystemRootDirectoryReader.h @@ -0,0 +1,38 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_dom_FileSystemRootDirectoryReader_h +#define mozilla_dom_FileSystemRootDirectoryReader_h + +#include "FileSystemDirectoryReader.h" + +namespace mozilla::dom { + +class FileSystemRootDirectoryReader final : public FileSystemDirectoryReader { + public: + NS_DECL_ISUPPORTS_INHERITED + NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(FileSystemRootDirectoryReader, + FileSystemDirectoryReader) + + explicit FileSystemRootDirectoryReader( + FileSystemDirectoryEntry* aParentEntry, FileSystem* aFileSystem, + const Sequence>& aEntries); + + virtual void ReadEntries( + FileSystemEntriesCallback& aSuccessCallback, + const Optional>& aErrorCallback, + ErrorResult& aRv) override; + + private: + ~FileSystemRootDirectoryReader(); + + Sequence> mEntries; + bool mAlreadyRead; +}; + +} // namespace mozilla::dom + +#endif // mozilla_dom_FileSystemRootDirectoryReader_h diff --git a/dom/filesystem/compat/moz.build b/dom/filesystem/compat/moz.build new file mode 100644 index 0000000000..6757a73d9e --- /dev/null +++ b/dom/filesystem/compat/moz.build @@ -0,0 +1,30 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +TEST_DIRS += ["tests"] + +EXPORTS.mozilla.dom += [ + "FileSystem.h", + "FileSystemDirectoryEntry.h", + "FileSystemDirectoryReader.h", + "FileSystemEntry.h", + "FileSystemFileEntry.h", +] + +UNIFIED_SOURCES += [ + "CallbackRunnables.cpp", + "FileSystem.cpp", + "FileSystemDirectoryEntry.cpp", + "FileSystemDirectoryReader.cpp", + "FileSystemEntry.cpp", + "FileSystemFileEntry.cpp", + "FileSystemRootDirectoryEntry.cpp", + "FileSystemRootDirectoryReader.cpp", +] + +FINAL_LIBRARY = "xul" + +include("/ipc/chromium/chromium-config.mozbuild") diff --git a/dom/filesystem/compat/tests/mochitest.toml b/dom/filesystem/compat/tests/mochitest.toml new file mode 100644 index 0000000000..3414a7433a --- /dev/null +++ b/dom/filesystem/compat/tests/mochitest.toml @@ -0,0 +1,11 @@ +[DEFAULT] +support-files = [ + "script_entries.js", + "!/dom/html/test/form_submit_server.sjs", +] + +["test_basic.html"] + +["test_formSubmission.html"] + +["test_no_dnd.html"] diff --git a/dom/filesystem/compat/tests/moz.build b/dom/filesystem/compat/tests/moz.build new file mode 100644 index 0000000000..2f41008128 --- /dev/null +++ b/dom/filesystem/compat/tests/moz.build @@ -0,0 +1,7 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +MOCHITEST_MANIFESTS += ["mochitest.toml"] diff --git a/dom/filesystem/compat/tests/script_entries.js b/dom/filesystem/compat/tests/script_entries.js new file mode 100644 index 0000000000..7f52fe6bf2 --- /dev/null +++ b/dom/filesystem/compat/tests/script_entries.js @@ -0,0 +1,47 @@ +/* eslint-env mozilla/chrome-script */ +// eslint-disable-next-line mozilla/reject-importGlobalProperties +Cu.importGlobalProperties(["File", "Directory"]); +var tmpFile, tmpDir; + +addMessageListener("entries.open", function (e) { + tmpFile = Services.dirsvc + .QueryInterface(Ci.nsIProperties) + .get("TmpD", Ci.nsIFile); + tmpFile.append("file.txt"); + tmpFile.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + + tmpDir = Services.dirsvc + .QueryInterface(Ci.nsIProperties) + .get("TmpD", Ci.nsIFile); + + tmpDir.append("dir-test"); + tmpDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o700); + + var file1 = tmpDir.clone(); + file1.append("foo.txt"); + file1.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + + var dir1 = tmpDir.clone(); + dir1.append("subdir"); + dir1.create(Ci.nsIFile.DIRECTORY_TYPE, 0o700); + + var file2 = dir1.clone(); + file2.append("bar..txt"); // Note the double .. + file2.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o600); + + var dir2 = dir1.clone(); + dir2.append("subsubdir"); + dir2.create(Ci.nsIFile.DIRECTORY_TYPE, 0o700); + + File.createFromNsIFile(tmpFile).then(function (file) { + sendAsyncMessage("entries.opened", { + data: [new Directory(tmpDir.path), file], + }); + }); +}); + +addMessageListener("entries.delete", function (e) { + tmpFile.remove(true); + tmpDir.remove(true); + sendAsyncMessage("entries.deleted"); +}); diff --git a/dom/filesystem/compat/tests/test_basic.html b/dom/filesystem/compat/tests/test_basic.html new file mode 100644 index 0000000000..4ad0c37d67 --- /dev/null +++ b/dom/filesystem/compat/tests/test_basic.html @@ -0,0 +1,549 @@ + + + + Test for Blink FileSystem API - subset + + + + + + + + + diff --git a/dom/filesystem/compat/tests/test_formSubmission.html b/dom/filesystem/compat/tests/test_formSubmission.html new file mode 100644 index 0000000000..2447e7a071 --- /dev/null +++ b/dom/filesystem/compat/tests/test_formSubmission.html @@ -0,0 +1,271 @@ + + + + Test for Directory form submission + + + + + + + + +
+
+ + + + diff --git a/dom/filesystem/compat/tests/test_no_dnd.html b/dom/filesystem/compat/tests/test_no_dnd.html new file mode 100644 index 0000000000..c49dd5d40f --- /dev/null +++ b/dom/filesystem/compat/tests/test_no_dnd.html @@ -0,0 +1,84 @@ + + + + Test for Blink FileSystem API - no DND == no webkitEntries + + + + + + + + -- cgit v1.2.3