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> 95 PersistentJsonStorage::list() const 96 { 97 std::vector<interfaces::JsonStorage::FilePath> result; 98 if (!std::filesystem::exists(directory)) 99 { 100 return result; 101 } 102 103 for (const auto& p : 104 std::filesystem::recursive_directory_iterator(directory)) 105 { 106 if (p.is_regular_file()) 107 { 108 auto item = std::filesystem::relative(p.path(), directory); 109 result.emplace_back(std::move(item)); 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 } 132 133 bool PersistentJsonStorage::exist(const FilePath& subPath) const 134 { 135 return std::filesystem::exists(join(directory, subPath)); 136 } 137