blob: 1148622293747e5eda381b99e741f2974ad75dc9 [file] [log] [blame]
Szymon Dompke32305f12022-07-05 15:37:21 +02001#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
10namespace utils
11{
12namespace details
13{
14
15size_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
26std::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 }
Patrick Williams3a1c2972023-05-10 07:51:04 -050052 strippedId.erase(std::remove_if(
53 strippedId.begin(), strippedId.end(),
54 [](char c) {
55 return c == '/' || utils::constants::allowedCharactersInPath.find(c) ==
56 std::string_view::npos;
57 }),
58 strippedId.end());
Szymon Dompke32305f12022-07-05 15:37:21 +020059
60 size_t idx = 0;
Patrick Williams3a1c2972023-05-10 07:51:04 -050061 std::string tmpId = prefixes +
62 strippedId.substr(0, constants::maxIdNameLength);
Szymon Dompke32305f12022-07-05 15:37:21 +020063
64 while (std::find(conflictIds.begin(), conflictIds.end(), tmpId) !=
65 conflictIds.end())
66 {
67 size_t digitsInIdx = countDigits(idx);
68
69 if (digitsInIdx > constants::maxIdNameLength)
70 {
71 throw sdbusplus::exception::SdBusError(
72 static_cast<int>(std::errc::file_exists),
73 "Unique indices are depleted");
74 }
75
76 tmpId = prefixes +
77 strippedId.substr(0, constants::maxIdNameLength - digitsInIdx) +
78 std::to_string(idx);
79 ++idx;
80 }
81
82 return tmpId;
83}
84
85} // namespace details
86
87std::pair<std::string, std::string>
88 makeIdName(std::string_view id, std::string_view name,
89 std::string_view defaultName,
90 const std::vector<std::string>& conflictIds)
91{
92 if (name.length() > constants::maxIdNameLength)
93 {
Krzysztof Grobelny62c08e92022-09-16 10:28:53 +020094 throw errors::InvalidArgument("Name", "Too long.");
Szymon Dompke32305f12022-07-05 15:37:21 +020095 }
96
97 if (name.empty() && !id.ends_with('/'))
98 {
99 name = id;
100
101 if (auto pos = name.find_last_of("/"); pos != std::string::npos)
102 {
103 name = name.substr(pos + 1);
104 }
105
106 name = name.substr(0, constants::maxIdNameLength);
107 }
108
109 if (name.empty())
110 {
111 name = defaultName;
112 }
113
114 return std::make_pair(
115 details::generateId(id, name, defaultName, conflictIds),
116 std::string{name});
117}
118
119} // namespace utils