blob: 8fb3fe9369f7131d1b540698fa738a228050020a [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>(
21 "Store to file", phosphor::logging::entry("path=%s", path.c_str()));
22
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",
58 phosphor::logging::entry("path=%s, ec= %lu: %s", path.c_str(),
59 ec.value(), ec.message().c_str()));
60 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>
95 PersistentJsonStorage::list(const DirectoryPath& subDirectory) const
96{
97 auto result = std::vector<FilePath>();
98 const auto path = join(directory, subDirectory);
99
100 if (!std::filesystem::exists(path))
101 {
102 return result;
103 }
104
105 for (const auto& p : std::filesystem::directory_iterator(path))
106 {
107 if (std::filesystem::is_directory(p.path()))
108 {
109 for (auto& item : list(DirectoryPath(p.path())))
110 {
111 result.emplace_back(std::move(item));
112 }
113 }
114 else
115 {
116 const auto item = std::filesystem::relative(
117 p.path().parent_path(), std::filesystem::path{directory});
118
119 if (std::find(result.begin(), result.end(), item) == result.end())
120 {
121 result.emplace_back(item);
122 }
123 }
124 }
125
126 return result;
127}
128
129std::filesystem::path
130 PersistentJsonStorage::join(const std::filesystem::path& left,
131 const std::filesystem::path& right)
132{
133 return left / right;
134}
135
136void PersistentJsonStorage::limitPermissions(const std::filesystem::path& path)
137{
138 constexpr auto filePerms = std::filesystem::perms::owner_read |
139 std::filesystem::perms::owner_write;
140 constexpr auto dirPerms = filePerms | std::filesystem::perms::owner_exec;
141 std::filesystem::permissions(
142 path, std::filesystem::is_directory(path) ? dirPerms : filePerms,
143 std::filesystem::perm_options::replace);
144}