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
countDigits(size_t value)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
generateId(std::string_view idIn,std::string_view nameIn,std::string_view defaultName,const std::vector<std::string> & conflictIds)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(std::remove_if(strippedId.begin(), strippedId.end(),
53 [](char c) {
54 return c == '/' || utils::constants::allowedCharactersInPath.find(c) ==
55 std::string_view::npos;
56 }),
57 strippedId.end());
58
59 size_t idx = 0;
60 std::string tmpId = prefixes +
61 strippedId.substr(0, constants::maxIdNameLength);
62
63 while (std::find(conflictIds.begin(), conflictIds.end(), tmpId) !=
64 conflictIds.end())
65 {
66 size_t digitsInIdx = countDigits(idx);
67
68 if (digitsInIdx > constants::maxIdNameLength)
69 {
70 throw sdbusplus::exception::SdBusError(
71 static_cast<int>(std::errc::file_exists),
72 "Unique indices are depleted");
73 }
74
75 tmpId = prefixes +
76 strippedId.substr(0, constants::maxIdNameLength - digitsInIdx) +
77 std::to_string(idx);
78 ++idx;
79 }
80
81 return tmpId;
82 }
83
84 } // namespace details
85
86 std::pair<std::string, std::string>
makeIdName(std::string_view id,std::string_view name,std::string_view defaultName,const std::vector<std::string> & conflictIds)87 makeIdName(std::string_view id, std::string_view name,
88 std::string_view defaultName,
89 const std::vector<std::string>& conflictIds)
90 {
91 if (name.length() > constants::maxIdNameLength)
92 {
93 throw errors::InvalidArgument("Name", "Too long.");
94 }
95
96 if (name.empty() && !id.ends_with('/'))
97 {
98 name = id;
99
100 if (auto pos = name.find_last_of("/"); pos != std::string::npos)
101 {
102 name = name.substr(pos + 1);
103 }
104
105 name = name.substr(0, constants::maxIdNameLength);
106 }
107
108 if (name.empty())
109 {
110 name = defaultName;
111 }
112
113 return std::make_pair(
114 details::generateId(id, name, defaultName, conflictIds),
115 std::string{name});
116 }
117
118 } // namespace utils
119