Branch data Line data Source code
1 : : /* SPDX-License-Identifier: LGPL-2.1+ */
2 : :
3 : : #include <errno.h>
4 : : #include <fcntl.h>
5 : : #include <unistd.h>
6 : :
7 : : #include "fd-util.h"
8 : : #include "fs-util.h"
9 : : #include "hexdecoct.h"
10 : : #include "id128-util.h"
11 : : #include "io-util.h"
12 : : #include "stdio-util.h"
13 : :
14 : 12 : char *id128_to_uuid_string(sd_id128_t id, char s[37]) {
15 : 12 : unsigned n, k = 0;
16 : :
17 [ - + ]: 12 : assert(s);
18 : :
19 : : /* Similar to sd_id128_to_string() but formats the result as UUID instead of plain hex chars */
20 : :
21 [ + + ]: 204 : for (n = 0; n < 16; n++) {
22 : :
23 [ + + + + ]: 192 : if (IN_SET(n, 4, 6, 8, 10))
24 : 48 : s[k++] = '-';
25 : :
26 : 192 : s[k++] = hexchar(id.bytes[n] >> 4);
27 : 192 : s[k++] = hexchar(id.bytes[n] & 0xF);
28 : : }
29 : :
30 [ - + ]: 12 : assert(k == 36);
31 : :
32 : 12 : s[k] = 0;
33 : :
34 : 12 : return s;
35 : : }
36 : :
37 : 7084 : bool id128_is_valid(const char *s) {
38 : : size_t i, l;
39 : :
40 [ - + ]: 7084 : assert(s);
41 : :
42 : 7084 : l = strlen(s);
43 [ + + ]: 7084 : if (l == 32) {
44 : :
45 : : /* Plain formatted 128bit hex string */
46 : :
47 [ + + ]: 176880 : for (i = 0; i < l; i++) {
48 : 171520 : char c = s[i];
49 : :
50 [ + - + + : 171520 : if (!(c >= '0' && c <= '9') &&
+ - ]
51 [ - + # # ]: 59764 : !(c >= 'a' && c <= 'z') &&
52 [ # # ]: 0 : !(c >= 'A' && c <= 'Z'))
53 : 0 : return false;
54 : : }
55 : :
56 [ + + ]: 1724 : } else if (l == 36) {
57 : :
58 : : /* Formatted UUID */
59 : :
60 [ + + ]: 148 : for (i = 0; i < l; i++) {
61 : 144 : char c = s[i];
62 : :
63 [ + + + + ]: 144 : if (IN_SET(i, 8, 13, 18, 23)) {
64 [ - + ]: 16 : if (c != '-')
65 : 0 : return false;
66 : : } else {
67 [ + - + + : 128 : if (!(c >= '0' && c <= '9') &&
+ - ]
68 [ - + # # ]: 24 : !(c >= 'a' && c <= 'z') &&
69 [ # # ]: 0 : !(c >= 'A' && c <= 'Z'))
70 : 0 : return false;
71 : : }
72 : : }
73 : :
74 : : } else
75 : 1720 : return false;
76 : :
77 : 5364 : return true;
78 : : }
79 : :
80 : 204 : int id128_read_fd(int fd, Id128Format f, sd_id128_t *ret) {
81 : : char buffer[36 + 2];
82 : : ssize_t l;
83 : :
84 [ - + ]: 204 : assert(fd >= 0);
85 [ - + ]: 204 : assert(f < _ID128_FORMAT_MAX);
86 : :
87 : : /* Reads an 128bit ID from a file, which may either be in plain format (32 hex digits), or in UUID format, both
88 : : * optionally followed by a newline and nothing else. ID files should really be newline terminated, but if they
89 : : * aren't that's OK too, following the rule of "Be conservative in what you send, be liberal in what you
90 : : * accept". */
91 : :
92 : 204 : l = loop_read(fd, buffer, sizeof(buffer), false); /* we expect a short read of either 32/33 or 36/37 chars */
93 [ - + ]: 204 : if (l < 0)
94 : 0 : return (int) l;
95 [ - + ]: 204 : if (l == 0) /* empty? */
96 : 0 : return -ENOMEDIUM;
97 : :
98 [ + + + + : 204 : switch (l) {
- ]
99 : :
100 : 88 : case 33: /* plain UUID with trailing newline */
101 [ - + ]: 88 : if (buffer[32] != '\n')
102 : 0 : return -EINVAL;
103 : :
104 : : _fallthrough_;
105 : : case 32: /* plain UUID without trailing newline */
106 [ + + ]: 96 : if (f == ID128_UUID)
107 : 8 : return -EINVAL;
108 : :
109 : 88 : buffer[32] = 0;
110 : 88 : break;
111 : :
112 : 100 : case 37: /* RFC UUID with trailing newline */
113 [ - + ]: 100 : if (buffer[36] != '\n')
114 : 0 : return -EINVAL;
115 : :
116 : : _fallthrough_;
117 : : case 36: /* RFC UUID without trailing newline */
118 [ + + ]: 108 : if (f == ID128_PLAIN)
119 : 8 : return -EINVAL;
120 : :
121 : 100 : buffer[36] = 0;
122 : 100 : break;
123 : :
124 : 0 : default:
125 : 0 : return -EINVAL;
126 : : }
127 : :
128 : 188 : return sd_id128_from_string(buffer, ret);
129 : : }
130 : :
131 : 160 : int id128_read(const char *p, Id128Format f, sd_id128_t *ret) {
132 : 160 : _cleanup_close_ int fd = -1;
133 : :
134 : 160 : fd = open(p, O_RDONLY|O_CLOEXEC|O_NOCTTY);
135 [ - + ]: 160 : if (fd < 0)
136 : 0 : return -errno;
137 : :
138 : 160 : return id128_read_fd(fd, f, ret);
139 : : }
140 : :
141 : 8 : int id128_write_fd(int fd, Id128Format f, sd_id128_t id, bool do_sync) {
142 : : char buffer[36 + 2];
143 : : size_t sz;
144 : : int r;
145 : :
146 [ - + ]: 8 : assert(fd >= 0);
147 [ - + ]: 8 : assert(f < _ID128_FORMAT_MAX);
148 : :
149 [ + + ]: 8 : if (f != ID128_UUID) {
150 : 4 : sd_id128_to_string(id, buffer);
151 : 4 : buffer[32] = '\n';
152 : 4 : sz = 33;
153 : : } else {
154 : 4 : id128_to_uuid_string(id, buffer);
155 : 4 : buffer[36] = '\n';
156 : 4 : sz = 37;
157 : : }
158 : :
159 : 8 : r = loop_write(fd, buffer, sz, false);
160 [ - + ]: 8 : if (r < 0)
161 : 0 : return r;
162 : :
163 [ - + ]: 8 : if (do_sync) {
164 [ # # ]: 0 : if (fsync(fd) < 0)
165 : 0 : return -errno;
166 : :
167 : 0 : r = fsync_directory_of_file(fd);
168 [ # # ]: 0 : if (r < 0)
169 : 0 : return r;
170 : : }
171 : :
172 : 8 : return 0;
173 : : }
174 : :
175 : 0 : int id128_write(const char *p, Id128Format f, sd_id128_t id, bool do_sync) {
176 : 0 : _cleanup_close_ int fd = -1;
177 : :
178 : 0 : fd = open(p, O_WRONLY|O_CREAT|O_CLOEXEC|O_NOCTTY|O_TRUNC, 0444);
179 [ # # ]: 0 : if (fd < 0)
180 : 0 : return -errno;
181 : :
182 : 0 : return id128_write_fd(fd, f, id, do_sync);
183 : : }
184 : :
185 : 20576 : void id128_hash_func(const sd_id128_t *p, struct siphash *state) {
186 : 20576 : siphash24_compress(p, sizeof(sd_id128_t), state);
187 : 20576 : }
188 : :
189 : 10350 : int id128_compare_func(const sd_id128_t *a, const sd_id128_t *b) {
190 : 10350 : return memcmp(a, b, 16);
191 : : }
192 : :
193 : : DEFINE_HASH_OPS(id128_hash_ops, sd_id128_t, id128_hash_func, id128_compare_func);
|