Parcourir la source

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.
networkException il y a 4 ans
Parent
commit
2ea2d026c2

+ 34 - 24
Userland/Libraries/LibCore/ConfigFile.cpp

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

+ 16 - 7
Userland/Libraries/LibCore/ConfigFile.h

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