blob: 896c8a9c52fd105ca3e9bedb6ba6d4d91bf8fd79 [file] [log] [blame]
Krzysztof Grobelny73da6902020-09-24 13:42:04 +02001#include "persistent_json_storage.hpp"
2
3#include <phosphor-logging/log.hpp>
4
5#include <fstream>
6#include <stdexcept>
7
8PersistentJsonStorage::PersistentJsonStorage(const DirectoryPath& directory) :
9 directory(directory)
10{}
11
12void PersistentJsonStorage::store(const FilePath& filePath,
13 const nlohmann::json& data)
14{
15 try
16 {
17 const auto path = join(directory, filePath);
18 std::error_code ec;
19
20 phosphor::logging::log<phosphor::logging::level::DEBUG>(
Wludzik, Jozef982c5b52021-01-02 12:05:21 +010021 "Store to file", phosphor::logging::entry("PATH=%s", path.c_str()));
Krzysztof Grobelny73da6902020-09-24 13:42:04 +020022
23 std::filesystem::create_directories(path.parent_path(), ec);
24 if (ec)
25 {
26 throw std::runtime_error(
27 "Unable to create directory for file: " + path.string() +
28 ", ec=" + std::to_string(ec.value()) + ": " + ec.message());
29 }
30
31 std::ofstream file(path);
32 file << data;
33 if (!file)
34 {
35 throw std::runtime_error("Unable to create file: " + path.string());
36 }
37
38 limitPermissions(path.parent_path());
39 limitPermissions(path);
40 }
41 catch (...)
42 {
43 remove(filePath);
44 throw;
45 }
46}
47
48bool PersistentJsonStorage::remove(const FilePath& filePath)
49{
50 const auto path = join(directory, filePath);
51 std::error_code ec;
52
53 auto removed = std::filesystem::remove(path, ec);
54 if (!removed)
55 {
56 phosphor::logging::log<phosphor::logging::level::ERR>(
57 "Unable to remove file",
Wludzik, Jozef982c5b52021-01-02 12:05:21 +010058 phosphor::logging::entry("PATH=%s", path.c_str()),
59 phosphor::logging::entry("ERROR_CODE=%d", ec.value()));
Krzysztof Grobelny73da6902020-09-24 13:42:04 +020060 return false;
61 }
62
63 /* removes directory only if it is empty */
64 std::filesystem::remove(path.parent_path(), ec);
65
66 return true;
67}
68
69std::optional<nlohmann::json>
70 PersistentJsonStorage::load(const FilePath& filePath) const
71{
72 const auto path = join(directory, filePath);
73 if (!std::filesystem::exists(path))
74 {
75 return std::nullopt;
76 }
77
78 nlohmann::json result;
79
80 try
81 {
82 std::ifstream file(path);
83 file >> result;
84 }
85 catch (const std::exception& e)
86 {
87 phosphor::logging::log<phosphor::logging::level::ERR>(e.what());
88 return std::nullopt;
89 }
90
91 return result;
92}
93
94std::vector<interfaces::JsonStorage::FilePath>
Wludzik, Jozefe2362792020-10-27 17:23:55 +010095 PersistentJsonStorage::list() const
Krzysztof Grobelny73da6902020-09-24 13:42:04 +020096{
Wludzik, Jozefe2362792020-10-27 17:23:55 +010097 std::vector<interfaces::JsonStorage::FilePath> result;
98 if (!std::filesystem::exists(directory))
Krzysztof Grobelny73da6902020-09-24 13:42:04 +020099 {
100 return result;
101 }
102
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100103 for (const auto& p :
104 std::filesystem::recursive_directory_iterator(directory))
Krzysztof Grobelny73da6902020-09-24 13:42:04 +0200105 {
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100106 if (p.is_regular_file())
Krzysztof Grobelny73da6902020-09-24 13:42:04 +0200107 {
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100108 auto item = std::filesystem::relative(p.path(), directory);
109 result.emplace_back(std::move(item));
Krzysztof Grobelny73da6902020-09-24 13:42:04 +0200110 }
111 }
112
113 return result;
114}
115
116std::filesystem::path
117 PersistentJsonStorage::join(const std::filesystem::path& left,
118 const std::filesystem::path& right)
119{
120 return left / right;
121}
122
123void PersistentJsonStorage::limitPermissions(const std::filesystem::path& path)
124{
125 constexpr auto filePerms = std::filesystem::perms::owner_read |
126 std::filesystem::perms::owner_write;
127 constexpr auto dirPerms = filePerms | std::filesystem::perms::owner_exec;
128 std::filesystem::permissions(
129 path, std::filesystem::is_directory(path) ? dirPerms : filePerms,
130 std::filesystem::perm_options::replace);
131}
Wludzik, Jozefe2362792020-10-27 17:23:55 +0100132
133bool PersistentJsonStorage::exist(const FilePath& subPath) const
134{
135 return std::filesystem::exists(join(directory, subPath));
136}