
Previously FSAC displayed some but not all errors and always rejected directories and devices. This has led most apps to ignore response errors in open/save actions or show redundant messages. Now FSAC displays all errors including fd failures and has the ability to silence messages for directories, devices and ENOENT, which some apps handle differently. Silenced directory and device errors now return files on success. A request's access mode is now stored in RequestData to format more accurate error messages from the user's perspective. Resolved promises don't require callback propagation so they're voided
99 lines
3.3 KiB
C++
99 lines
3.3 KiB
C++
/*
|
|
* Copyright (c) 2021, timmot <tiwwot@protonmail.com>
|
|
* Copyright (c) 2022, Mustafa Quraish <mustafa@serenityos.org>
|
|
*
|
|
* SPDX-License-Identifier: BSD-2-Clause
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <AK/HashMap.h>
|
|
#include <AK/String.h>
|
|
#include <FileSystemAccessServer/FileSystemAccessClientEndpoint.h>
|
|
#include <FileSystemAccessServer/FileSystemAccessServerEndpoint.h>
|
|
#include <LibCore/File.h>
|
|
#include <LibCore/Promise.h>
|
|
#include <LibCore/StandardPaths.h>
|
|
#include <LibGUI/FileTypeFilter.h>
|
|
#include <LibGUI/Window.h>
|
|
#include <LibIPC/ConnectionToServer.h>
|
|
|
|
namespace FileSystemAccessClient {
|
|
|
|
enum ErrorFlag : u32 {
|
|
Devices = 1 << 0,
|
|
Directories = 1 << 1,
|
|
NoEntries = 1 << 2,
|
|
|
|
None = 0,
|
|
};
|
|
|
|
class Client;
|
|
class File {
|
|
public:
|
|
File(Badge<Client>, NonnullOwnPtr<Core::File> stream, String filename)
|
|
: m_stream(move(stream))
|
|
, m_filename(filename)
|
|
{
|
|
}
|
|
|
|
Core::File& stream() const { return *m_stream; }
|
|
NonnullOwnPtr<Core::File> release_stream() { return move(m_stream); }
|
|
String filename() const { return m_filename; }
|
|
|
|
private:
|
|
NonnullOwnPtr<Core::File> m_stream;
|
|
String m_filename;
|
|
};
|
|
|
|
using Result = ErrorOr<File>;
|
|
|
|
class Client final
|
|
: public IPC::ConnectionToServer<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>
|
|
, public FileSystemAccessClientEndpoint {
|
|
IPC_CLIENT_CONNECTION(Client, "/tmp/session/%sid/portal/filesystemaccess"sv)
|
|
|
|
public:
|
|
Result request_file_read_only_approved(GUI::Window* parent_window, DeprecatedString const& path);
|
|
Result request_file(GUI::Window* parent_window, DeprecatedString const& path, Core::File::OpenMode requested_access);
|
|
Result open_file(GUI::Window* parent_window, DeprecatedString const& window_title = {}, StringView path = Core::StandardPaths::home_directory(), Core::File::OpenMode requested_access = Core::File::OpenMode::Read, Optional<Vector<GUI::FileTypeFilter>> const& = {});
|
|
Result save_file(GUI::Window* parent_window, DeprecatedString const& name, DeprecatedString const ext, Core::File::OpenMode requested_access = Core::File::OpenMode::Write | Core::File::OpenMode::Truncate);
|
|
|
|
void set_silence_errors(u32 flags) { m_silenced_errors = flags; }
|
|
u32 silenced_errors() const { return m_silenced_errors; }
|
|
|
|
bool is_silencing_devices() { return m_silenced_errors & ErrorFlag::Devices; }
|
|
bool is_silencing_directories() { return m_silenced_errors & ErrorFlag::Directories; }
|
|
bool is_silencing_nonexistent_entries() { return m_silenced_errors & ErrorFlag::NoEntries; }
|
|
|
|
static Client& the();
|
|
|
|
protected:
|
|
void die() override;
|
|
|
|
private:
|
|
explicit Client(NonnullOwnPtr<Core::LocalSocket> socket)
|
|
: IPC::ConnectionToServer<FileSystemAccessClientEndpoint, FileSystemAccessServerEndpoint>(*this, move(socket))
|
|
{
|
|
}
|
|
|
|
virtual void handle_prompt_end(i32 request_id, i32 error, Optional<IPC::File> const& fd, Optional<DeprecatedString> const& chosen_file) override;
|
|
|
|
int get_new_id();
|
|
Result handle_promise(int);
|
|
|
|
template<typename T>
|
|
using PromiseType = RefPtr<Core::Promise<T>>;
|
|
|
|
struct RequestData {
|
|
PromiseType<Result> promise;
|
|
GUI::Window* parent_window { nullptr };
|
|
Core::File::OpenMode mode { Core::File::OpenMode::NotOpen };
|
|
};
|
|
|
|
HashMap<int, RequestData> m_promises {};
|
|
int m_last_id { 0 };
|
|
u32 m_silenced_errors { ErrorFlag::None };
|
|
};
|
|
|
|
}
|