1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-24 20:27:35 +00:00

LibCore: Support using a file descriptor for opening ConfigFile

This patch adds support for opening a ConfigFile using a file
descriptor rather than trying to open a the file by name directly.

In contrast to the previous implementation, ConfigFile now always keeps
a reference to an open File and does not reopen it for writing.

This requires providing an additional argument to open functions if a
file gets opened based on its name and the user of the api intends to
write to the file in the future.
This commit is contained in:
networkException 2021-08-19 01:23:31 +02:00 committed by Andreas Kling
parent dee3b7b8c9
commit 2ea2d026c2
2 changed files with 50 additions and 31 deletions

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Jakob-Niklas See <git@nwex.de>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -13,35 +14,52 @@
namespace Core { namespace Core {
NonnullRefPtr<ConfigFile> ConfigFile::get_for_lib(const String& lib_name) NonnullRefPtr<ConfigFile> ConfigFile::get_for_lib(String const& lib_name, AllowWriting allow_altering)
{ {
String directory = StandardPaths::config_directory(); String directory = StandardPaths::config_directory();
auto path = String::formatted("{}/lib/{}.ini", directory, lib_name); auto path = String::formatted("{}/lib/{}.ini", directory, lib_name);
return adopt_ref(*new ConfigFile(path)); return adopt_ref(*new ConfigFile(path, allow_altering));
} }
NonnullRefPtr<ConfigFile> ConfigFile::get_for_app(const String& app_name) NonnullRefPtr<ConfigFile> ConfigFile::get_for_app(String const& app_name, AllowWriting allow_altering)
{ {
String directory = StandardPaths::config_directory(); String directory = StandardPaths::config_directory();
auto path = String::formatted("{}/{}.ini", directory, app_name); auto path = String::formatted("{}/{}.ini", directory, app_name);
return adopt_ref(*new ConfigFile(path)); return adopt_ref(*new ConfigFile(path, allow_altering));
} }
NonnullRefPtr<ConfigFile> ConfigFile::get_for_system(const String& app_name) NonnullRefPtr<ConfigFile> ConfigFile::get_for_system(String const& app_name, AllowWriting allow_altering)
{ {
auto path = String::formatted("/etc/{}.ini", app_name); auto path = String::formatted("/etc/{}.ini", app_name);
return adopt_ref(*new ConfigFile(path)); return adopt_ref(*new ConfigFile(path, allow_altering));
} }
NonnullRefPtr<ConfigFile> ConfigFile::open(const String& path) NonnullRefPtr<ConfigFile> ConfigFile::open(String const& filename, AllowWriting allow_altering)
{ {
return adopt_ref(*new ConfigFile(path)); return adopt_ref(*new ConfigFile(filename, allow_altering));
} }
ConfigFile::ConfigFile(const String& filename) NonnullRefPtr<ConfigFile> ConfigFile::open(String const& filename, int fd)
: m_filename(filename)
{ {
return adopt_ref(*new ConfigFile(filename, fd));
}
ConfigFile::ConfigFile(const String& filename, AllowWriting allow_altering)
: m_file(File::construct(filename))
{
if (!m_file->open(allow_altering == AllowWriting::Yes ? OpenMode::ReadWrite : OpenMode::ReadOnly))
return;
reparse();
}
ConfigFile::ConfigFile(String const& filename, int fd)
: m_file(File::construct(filename))
{
if (!m_file->open(fd, OpenMode::ReadWrite, File::ShouldCloseFileDescriptor::Yes))
return;
reparse(); reparse();
} }
@ -54,14 +72,10 @@ void ConfigFile::reparse()
{ {
m_groups.clear(); m_groups.clear();
auto file = File::construct(m_filename);
if (!file->open(OpenMode::ReadOnly))
return;
HashMap<String, String>* current_group = nullptr; HashMap<String, String>* current_group = nullptr;
while (file->can_read_line()) { while (m_file->can_read_line()) {
auto line = file->read_line(); auto line = m_file->read_line();
auto* cp = line.characters(); auto* cp = line.characters();
while (*cp && (*cp == ' ' || *cp == '\t' || *cp == '\n')) while (*cp && (*cp == ' ' || *cp == '\t' || *cp == '\n'))
@ -149,19 +163,15 @@ bool ConfigFile::sync()
if (!m_dirty) if (!m_dirty)
return true; return true;
FILE* fp = fopen(m_filename.characters(), "wb"); m_file->truncate(0);
if (!fp)
return false;
for (auto& it : m_groups) { for (auto& it : m_groups) {
outln(fp, "[{}]", it.key); m_file->write(String::formatted("[{}]\n", it.key));
for (auto& jt : it.value) for (auto& jt : it.value)
outln(fp, "{}={}", jt.key, jt.value); m_file->write(String::formatted("{}={}\n", jt.key, jt.value));
outln(fp); m_file->write("\n");
} }
fclose(fp);
m_dirty = false; m_dirty = false;
return true; return true;
} }

View file

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
* Copyright (c) 2021, Jakob-Niklas See <git@nwex.de>
* *
* SPDX-License-Identifier: BSD-2-Clause * SPDX-License-Identifier: BSD-2-Clause
*/ */
@ -11,16 +12,23 @@
#include <AK/RefPtr.h> #include <AK/RefPtr.h>
#include <AK/String.h> #include <AK/String.h>
#include <AK/Vector.h> #include <AK/Vector.h>
#include <LibCore/File.h>
#include <LibGfx/Color.h> #include <LibGfx/Color.h>
namespace Core { namespace Core {
class ConfigFile : public RefCounted<ConfigFile> { class ConfigFile : public RefCounted<ConfigFile> {
public: public:
static NonnullRefPtr<ConfigFile> get_for_lib(const String& lib_name); enum class AllowWriting {
static NonnullRefPtr<ConfigFile> get_for_app(const String& app_name); Yes,
static NonnullRefPtr<ConfigFile> get_for_system(const String& app_name); No,
static NonnullRefPtr<ConfigFile> open(const String& path); };
static NonnullRefPtr<ConfigFile> get_for_lib(String const& lib_name, AllowWriting = AllowWriting::No);
static NonnullRefPtr<ConfigFile> get_for_app(String const& app_name, AllowWriting = AllowWriting::No);
static NonnullRefPtr<ConfigFile> get_for_system(String const& app_name, AllowWriting = AllowWriting::No);
static NonnullRefPtr<ConfigFile> open(String const& filename, AllowWriting = AllowWriting::No);
static NonnullRefPtr<ConfigFile> open(String const& filename, int fd);
~ConfigFile(); ~ConfigFile();
bool has_group(const String&) const; bool has_group(const String&) const;
@ -49,14 +57,15 @@ public:
void remove_group(const String& group); void remove_group(const String& group);
void remove_entry(const String& group, const String& key); void remove_entry(const String& group, const String& key);
String filename() const { return m_filename; } String filename() const { return m_file->filename(); }
private: private:
explicit ConfigFile(const String& filename); explicit ConfigFile(String const& filename, AllowWriting);
explicit ConfigFile(String const& filename, int fd);
void reparse(); void reparse();
String m_filename; NonnullRefPtr<File> m_file;
HashMap<String, HashMap<String, String>> m_groups; HashMap<String, HashMap<String, String>> m_groups;
bool m_dirty { false }; bool m_dirty { false };
}; };