1 #include "utils/make_id_name.hpp" 2 3 #include "utils/dbus_path_utils.hpp" 4 5 #include <sdbusplus/exception.hpp> 6 7 #include <algorithm> 8 #include <system_error> 9 10 namespace utils 11 { 12 namespace details 13 { 14 15 size_t countDigits(size_t value) 16 { 17 size_t result = 1; 18 while (value >= 10) 19 { 20 ++result; 21 value /= 10; 22 } 23 return result; 24 } 25 26 std::string generateId(std::string_view idIn, std::string_view nameIn, 27 std::string_view defaultName, 28 const std::vector<std::string>& conflictIds) 29 { 30 verifyIdCharacters(idIn); 31 verifyIdPrefixes(idIn); 32 33 if (!idIn.empty() && !idIn.ends_with('/')) 34 { 35 if (std::find(conflictIds.begin(), conflictIds.end(), idIn) != 36 conflictIds.end()) 37 { 38 throw sdbusplus::exception::SdBusError( 39 static_cast<int>(std::errc::file_exists), "Duplicated id"); 40 } 41 return std::string(idIn); 42 } 43 44 const std::string prefixes(idIn); 45 46 std::string strippedId(nameIn); 47 if (strippedId.find_first_of(utils::constants::allowedCharactersInPath) == 48 std::string::npos) 49 { 50 strippedId = defaultName; 51 } 52 strippedId.erase( 53 std::remove_if( 54 strippedId.begin(), strippedId.end(), 55 [](char c) { 56 return c == '/' || 57 utils::constants::allowedCharactersInPath.find(c) == 58 std::string_view::npos; 59 }), 60 strippedId.end()); 61 62 size_t idx = 0; 63 std::string tmpId = 64 prefixes + strippedId.substr(0, constants::maxIdNameLength); 65 66 while (std::find(conflictIds.begin(), conflictIds.end(), tmpId) != 67 conflictIds.end()) 68 { 69 size_t digitsInIdx = countDigits(idx); 70 71 if (digitsInIdx > constants::maxIdNameLength) 72 { 73 throw sdbusplus::exception::SdBusError( 74 static_cast<int>(std::errc::file_exists), 75 "Unique indices are depleted"); 76 } 77 78 tmpId = prefixes + 79 strippedId.substr(0, constants::maxIdNameLength - digitsInIdx) + 80 std::to_string(idx); 81 ++idx; 82 } 83 84 return tmpId; 85 } 86 87 } // namespace details 88 89 std::pair<std::string, std::string> 90 makeIdName(std::string_view id, std::string_view name, 91 std::string_view defaultName, 92 const std::vector<std::string>& conflictIds) 93 { 94 if (name.length() > constants::maxIdNameLength) 95 { 96 throw errors::InvalidArgument("Name", "Too long."); 97 } 98 99 if (name.empty() && !id.ends_with('/')) 100 { 101 name = id; 102 103 if (auto pos = name.find_last_of("/"); pos != std::string::npos) 104 { 105 name = name.substr(pos + 1); 106 } 107 108 name = name.substr(0, constants::maxIdNameLength); 109 } 110 111 if (name.empty()) 112 { 113 name = defaultName; 114 } 115 116 return std::make_pair( 117 details::generateId(id, name, defaultName, conflictIds), 118 std::string{name}); 119 } 120 121 } // namespace utils 122