1 | /* |
2 | * This Source Code Form is subject to the terms of the Mozilla Public |
3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. |
5 | * |
6 | * Copyright 1997 - July 2008 CWI, August 2008 - 2019 MonetDB B.V. |
7 | */ |
8 | |
9 | /* |
10 | * K.S. Mullender & A. de Rijke |
11 | * The UUID module |
12 | * The UUID module contains a wrapper for all function in |
13 | * libuuid. |
14 | */ |
15 | |
16 | #include "monetdb_config.h" |
17 | #include "mal.h" |
18 | #include "mal_exception.h" |
19 | #include "mal_atom.h" /* for malAtomSize */ |
20 | #ifdef HAVE_UUID_UUID_H |
21 | #include <uuid/uuid.h> |
22 | #endif |
23 | #ifndef HAVE_UUID |
24 | #ifdef HAVE_OPENSSL |
25 | # include <openssl/rand.h> |
26 | #else |
27 | #ifdef HAVE_COMMONCRYPTO |
28 | #include <CommonCrypto/CommonRandom.h> |
29 | #endif |
30 | #endif |
31 | #endif |
32 | |
33 | #ifdef HAVE_UUID |
34 | #define UUID_SIZE ((int) sizeof(uuid_t)) /* size of a UUID */ |
35 | #else |
36 | #define UUID_SIZE 16 /* size of a UUID */ |
37 | #endif |
38 | #define UUID_STRLEN 36 /* length of string representation */ |
39 | |
40 | typedef union { |
41 | #ifdef HAVE_HGE |
42 | hge h; /* force alignment, not otherwise used */ |
43 | #else |
44 | lng l[2]; /* force alignment, not otherwise used */ |
45 | #endif |
46 | #ifdef HAVE_UUID |
47 | uuid_t u; |
48 | #else |
49 | unsigned char u[UUID_SIZE]; |
50 | #endif |
51 | } uuid; |
52 | |
53 | mal_export str UUIDprelude(void *ret); |
54 | mal_export int UUIDcompare(const uuid *l, const uuid *r); |
55 | mal_export ssize_t UUIDfromString(const char *svalue, size_t *len, uuid **retval, bool external); |
56 | mal_export BUN UUIDhash(const void *u); |
57 | mal_export const uuid *UUIDnull(void); |
58 | mal_export uuid *UUIDread(uuid *u, stream *s, size_t cnt); |
59 | mal_export ssize_t UUIDtoString(str *retval, size_t *len, const uuid *value, bool external); |
60 | mal_export gdk_return UUIDwrite(const uuid *u, stream *s, size_t cnt); |
61 | |
62 | mal_export str UUIDgenerateUuid(uuid **retval); |
63 | mal_export str UUIDgenerateUuidInt(uuid **retval, int *d); |
64 | mal_export str UUIDstr2uuid(uuid **retval, str *s); |
65 | mal_export str UUIDuuid2str(str *retval, uuid **u); |
66 | mal_export str UUIDisaUUID(bit *retval, str *u); |
67 | mal_export str UUIDequal(bit *retval, uuid **l, uuid **r); |
68 | |
69 | static uuid uuid_nil; /* automatically initialized as zeros */ |
70 | |
71 | str |
72 | UUIDprelude(void *ret) |
73 | { |
74 | (void) ret; |
75 | assert(UUID_SIZE == 16); |
76 | (void) malAtomSize(sizeof(uuid), "uuid" ); |
77 | return MAL_SUCCEED; |
78 | } |
79 | |
80 | #define is_uuid_nil(x) (memcmp((x)->u, uuid_nil.u, UUID_SIZE) == 0) |
81 | |
82 | /** |
83 | * Returns the string representation of the given uuid value. |
84 | * Warning: GDK function |
85 | * Returns the length of the string |
86 | */ |
87 | ssize_t |
88 | UUIDtoString(str *retval, size_t *len, const uuid *value, bool external) |
89 | { |
90 | if (*len <= UUID_STRLEN || *retval == NULL) { |
91 | if (*retval) |
92 | GDKfree(*retval); |
93 | if ((*retval = GDKmalloc(UUID_STRLEN + 1)) == NULL) |
94 | return -1; |
95 | *len = UUID_STRLEN + 1; |
96 | } |
97 | if (is_uuid_nil(value)) { |
98 | if (external) { |
99 | snprintf(*retval, *len, "nil" ); |
100 | return 3; |
101 | } |
102 | strcpy(*retval, str_nil); |
103 | return 1; |
104 | } |
105 | snprintf(*retval, *len, |
106 | "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x" , |
107 | value->u[0], value->u[1], value->u[2], value->u[3], |
108 | value->u[4], value->u[5], value->u[6], value->u[7], |
109 | value->u[8], value->u[9], value->u[10], value->u[11], |
110 | value->u[12], value->u[13], value->u[14], value->u[15]); |
111 | assert(strlen(*retval) == UUID_STRLEN); |
112 | return UUID_STRLEN; |
113 | } |
114 | |
115 | ssize_t |
116 | UUIDfromString(const char *svalue, size_t *len, uuid **retval, bool external) |
117 | { |
118 | const char *s = svalue; |
119 | int i, j; |
120 | |
121 | if (*len < UUID_SIZE || *retval == NULL) { |
122 | GDKfree(*retval); |
123 | if ((*retval = GDKmalloc(UUID_SIZE)) == NULL) |
124 | return -1; |
125 | *len = UUID_SIZE; |
126 | } |
127 | if (external && strcmp(svalue, "nil" ) == 0) { |
128 | **retval = uuid_nil; |
129 | return 3; |
130 | } |
131 | if (GDK_STRNIL(svalue)) { |
132 | **retval = uuid_nil; |
133 | return 1; |
134 | } |
135 | for (i = 0, j = 0; i < UUID_SIZE; i++) { |
136 | /* on select locations we allow a '-' in the source string */ |
137 | if (j == 8 || j == 12 || j == 16 || j == 20) { |
138 | if (*s == '-') |
139 | s++; |
140 | } |
141 | if (isdigit((unsigned char) *s)) |
142 | (*retval)->u[i] = *s - '0'; |
143 | else if ('a' <= *s && *s <= 'f') |
144 | (*retval)->u[i] = *s - 'a' + 10; |
145 | else if ('A' <= *s && *s <= 'F') |
146 | (*retval)->u[i] = *s - 'A' + 10; |
147 | else |
148 | goto bailout; |
149 | s++; |
150 | j++; |
151 | (*retval)->u[i] <<= 4; |
152 | if (isdigit((unsigned char) *s)) |
153 | (*retval)->u[i] |= *s - '0'; |
154 | else if ('a' <= *s && *s <= 'f') |
155 | (*retval)->u[i] |= *s - 'a' + 10; |
156 | else if ('A' <= *s && *s <= 'F') |
157 | (*retval)->u[i] |= *s - 'A' + 10; |
158 | else |
159 | goto bailout; |
160 | s++; |
161 | j++; |
162 | } |
163 | return (ssize_t) (s - svalue); |
164 | |
165 | bailout: |
166 | **retval = uuid_nil; |
167 | return -1; |
168 | } |
169 | |
170 | int |
171 | UUIDcompare(const uuid *l, const uuid *r) |
172 | { |
173 | return memcmp(l->u, r->u, UUID_SIZE); |
174 | } |
175 | |
176 | str |
177 | UUIDgenerateUuid(uuid **retval) |
178 | { |
179 | uuid *u; |
180 | int i = 0, r = 0; |
181 | |
182 | if (*retval == NULL && (*retval = GDKmalloc(UUID_SIZE)) == NULL) |
183 | throw(MAL, "uuid.new" , SQLSTATE(HY001) MAL_MALLOC_FAIL); |
184 | u = *retval; |
185 | #ifdef HAVE_UUID |
186 | uuid_generate(u->u); |
187 | (void) i; |
188 | (void) r; |
189 | #else |
190 | #ifdef HAVE_OPENSSL |
191 | if (RAND_bytes(u->u, 16) < 0) |
192 | #else |
193 | #ifdef HAVE_COMMONCRYPTO |
194 | if (CCRandomGenerateBytes(u->u, 16) != kCCSuccess) |
195 | #endif |
196 | #endif |
197 | /* if it failed, use rand */ |
198 | for (i = 0; i < UUID_SIZE;) { |
199 | r = rand() % 65536; |
200 | u->u[i++] = (unsigned char) (r >> 8); |
201 | u->u[i++] = (unsigned char) r; |
202 | } |
203 | #endif |
204 | return MAL_SUCCEED; |
205 | } |
206 | |
207 | str |
208 | UUIDgenerateUuidInt(uuid **retval, int *d) |
209 | { |
210 | (void)d; |
211 | return UUIDgenerateUuid(retval); |
212 | } |
213 | |
214 | str |
215 | UUIDisaUUID(bit *retval, str *s) |
216 | { |
217 | uuid u; |
218 | uuid *pu = &u; |
219 | size_t l = UUID_SIZE; |
220 | *retval = UUIDfromString(*s, &l, &pu, false) == UUID_STRLEN; |
221 | return MAL_SUCCEED; |
222 | } |
223 | |
224 | str |
225 | UUIDstr2uuid(uuid **retval, str *s) |
226 | { |
227 | size_t l = *retval ? UUID_SIZE : 0; |
228 | |
229 | if (UUIDfromString(*s, &l, retval, false) == UUID_STRLEN) { |
230 | return MAL_SUCCEED; |
231 | } |
232 | throw(MAL, "uuid.uuid" , "Not a UUID" ); |
233 | } |
234 | |
235 | str |
236 | UUIDuuid2str(str *retval, uuid **u) |
237 | { |
238 | size_t l = 0; |
239 | *retval = NULL; |
240 | if (UUIDtoString(retval, &l, *u, false) < 0) |
241 | throw(MAL, "uuid.str" , GDK_EXCEPTION); |
242 | return MAL_SUCCEED; |
243 | } |
244 | |
245 | str |
246 | UUIDequal(bit *retval, uuid **l, uuid **r) |
247 | { |
248 | if (is_uuid_nil(*l) || is_uuid_nil(*r)) |
249 | *retval = bit_nil; |
250 | else |
251 | *retval = memcmp((*l)->u, (*r)->u, UUID_SIZE) == 0; |
252 | return MAL_SUCCEED; |
253 | } |
254 | |
255 | BUN |
256 | UUIDhash(const void *v) |
257 | { |
258 | const uuid *u = (const uuid *) v; |
259 | unsigned int u1, u2, u3, u4; |
260 | |
261 | u1 = (unsigned int) u->u[0] << 24 | (unsigned int) u->u[1] << 16 | |
262 | (unsigned int) u->u[2] << 8 | (unsigned int) u->u[3]; |
263 | u2 = (unsigned int) u->u[4] << 24 | (unsigned int) u->u[5] << 16 | |
264 | (unsigned int) u->u[6] << 8 | (unsigned int) u->u[7]; |
265 | u3 = (unsigned int) u->u[8] << 24 | (unsigned int) u->u[9] << 16 | |
266 | (unsigned int) u->u[10] << 8 | (unsigned int) u->u[11]; |
267 | u4 = (unsigned int) u->u[12] << 24 | (unsigned int) u->u[13] << 16 | |
268 | (unsigned int) u->u[14] << 8 | (unsigned int) u->u[15]; |
269 | return (BUN) mix_int(u1 ^ u2 ^ u3 ^ u4); |
270 | } |
271 | |
272 | const uuid * |
273 | UUIDnull(void) |
274 | { |
275 | return &uuid_nil; |
276 | } |
277 | |
278 | uuid * |
279 | UUIDread(uuid *U, stream *s, size_t cnt) |
280 | { |
281 | uuid *u = U; |
282 | if (u == NULL && (u = GDKmalloc(cnt * sizeof(uuid))) == NULL) |
283 | return NULL; |
284 | if (mnstr_read(s, u, UUID_SIZE, cnt) < (ssize_t) cnt) { |
285 | if (u != U) |
286 | GDKfree(u); |
287 | return NULL; |
288 | } |
289 | return u; |
290 | } |
291 | |
292 | gdk_return |
293 | UUIDwrite(const uuid *u, stream *s, size_t cnt) |
294 | { |
295 | return mnstr_write(s, u, UUID_SIZE, cnt) ? GDK_SUCCEED : GDK_FAIL; |
296 | } |
297 | |