| Krzysztof Grobelny | 73da690 | 2020-09-24 13:42:04 +0200 | [diff] [blame] | 1 | #include "persistent_json_storage.hpp" | 
|  | 2 |  | 
|  | 3 | #include <phosphor-logging/log.hpp> | 
|  | 4 |  | 
|  | 5 | #include <fstream> | 
|  | 6 | #include <stdexcept> | 
|  | 7 |  | 
|  | 8 | PersistentJsonStorage::PersistentJsonStorage(const DirectoryPath& directory) : | 
|  | 9 | directory(directory) | 
|  | 10 | {} | 
|  | 11 |  | 
|  | 12 | void 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 |  | 
|  | 48 | bool 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 |  | 
|  | 69 | std::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 |  | 
|  | 94 | std::vector<interfaces::JsonStorage::FilePath> | 
| Wludzik, Jozef | e236279 | 2020-10-27 17:23:55 +0100 | [diff] [blame] | 95 | PersistentJsonStorage::list() const | 
| Krzysztof Grobelny | 73da690 | 2020-09-24 13:42:04 +0200 | [diff] [blame] | 96 | { | 
| Wludzik, Jozef | e236279 | 2020-10-27 17:23:55 +0100 | [diff] [blame] | 97 | std::vector<interfaces::JsonStorage::FilePath> result; | 
|  | 98 | if (!std::filesystem::exists(directory)) | 
| Krzysztof Grobelny | 73da690 | 2020-09-24 13:42:04 +0200 | [diff] [blame] | 99 | { | 
|  | 100 | return result; | 
|  | 101 | } | 
|  | 102 |  | 
| Wludzik, Jozef | e236279 | 2020-10-27 17:23:55 +0100 | [diff] [blame] | 103 | for (const auto& p : | 
|  | 104 | std::filesystem::recursive_directory_iterator(directory)) | 
| Krzysztof Grobelny | 73da690 | 2020-09-24 13:42:04 +0200 | [diff] [blame] | 105 | { | 
| Wludzik, Jozef | e236279 | 2020-10-27 17:23:55 +0100 | [diff] [blame] | 106 | if (p.is_regular_file()) | 
| Krzysztof Grobelny | 73da690 | 2020-09-24 13:42:04 +0200 | [diff] [blame] | 107 | { | 
| Wludzik, Jozef | e236279 | 2020-10-27 17:23:55 +0100 | [diff] [blame] | 108 | auto item = std::filesystem::relative(p.path(), directory); | 
|  | 109 | result.emplace_back(std::move(item)); | 
| Krzysztof Grobelny | 73da690 | 2020-09-24 13:42:04 +0200 | [diff] [blame] | 110 | } | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | return result; | 
|  | 114 | } | 
|  | 115 |  | 
|  | 116 | std::filesystem::path | 
|  | 117 | PersistentJsonStorage::join(const std::filesystem::path& left, | 
|  | 118 | const std::filesystem::path& right) | 
|  | 119 | { | 
|  | 120 | return left / right; | 
|  | 121 | } | 
|  | 122 |  | 
|  | 123 | void 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, Jozef | e236279 | 2020-10-27 17:23:55 +0100 | [diff] [blame] | 132 |  | 
|  | 133 | bool PersistentJsonStorage::exist(const FilePath& subPath) const | 
|  | 134 | { | 
|  | 135 | return std::filesystem::exists(join(directory, subPath)); | 
|  | 136 | } |