Print this page
4118 libuuid should provide uuid_unparse_{upper,lower} functions
Reviewed by: Serghei Samsi <sscdvp@gmail.com>
Reviewed by: Josef 'Jeff' Sipek <jeffpc@josefsipek.net>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/lib/libuuid/common/uuid.c
+++ new/usr/src/lib/libuuid/common/uuid.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
↓ open down ↓ |
15 lines elided |
↑ open up ↑ |
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 24 * Copyright 2012 Milan Jurik. All rights reserved.
25 25 * Copyright 2013 Joyent, Inc. All rights reserved.
26 + * Copyright 2014 Andrew Stormont.
26 27 */
27 28
28 29 /*
29 30 * The copyright in this file is taken from the original Leach & Salz
30 31 * UUID specification, from which this implementation is derived.
31 32 */
32 33
33 34 /*
34 35 * Copyright (c) 1990- 1993, 1996 Open Software Foundation, Inc.
35 36 * Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca. &
36 37 * Digital Equipment Corporation, Maynard, Mass. Copyright (c) 1998
37 38 * Microsoft. To anyone who acknowledges that this file is provided
38 39 * "AS IS" without any express or implied warranty: permission to use,
39 40 * copy, modify, and distribute this file for any purpose is hereby
40 41 * granted without fee, provided that the above copyright notices and
41 42 * this notice appears in all source code copies, and that none of the
42 43 * names of Open Software Foundation, Inc., Hewlett-Packard Company,
43 44 * or Digital Equipment Corporation be used in advertising or
44 45 * publicity pertaining to distribution of the software without
45 46 * specific, written prior permission. Neither Open Software
46 47 * Foundation, Inc., Hewlett-Packard Company, Microsoft, nor Digital
47 48 * Equipment Corporation makes any representations about the
48 49 * suitability of this software for any purpose.
49 50 */
50 51
51 52 /*
52 53 * This module is the workhorse for generating abstract
53 54 * UUIDs. It delegates system-specific tasks (such
54 55 * as obtaining the node identifier or system time)
55 56 * to the sysdep module.
56 57 */
57 58
58 59 #include <ctype.h>
59 60 #include <sys/param.h>
60 61 #include <sys/stat.h>
61 62 #include <errno.h>
62 63 #include <stdio.h>
63 64 #include <stdlib.h>
64 65 #include <strings.h>
65 66 #include <fcntl.h>
66 67 #include <unistd.h>
67 68 #include <synch.h>
68 69 #include <sys/mman.h>
69 70 #include "uuid_misc.h"
70 71
71 72 shared_buffer_t *data;
72 73
73 74 static uuid_node_t node_id_cache;
74 75 static int node_init;
75 76 static int file_type;
76 77 static int fd;
77 78
78 79 /*
79 80 * The urandmtx mutex prevents multiple opens of /dev/urandom and protects the
80 81 * cache.
81 82 */
82 83 #define RCACHE_SIZE 65535
83 84 static mutex_t urandmtx;
84 85 static int fd_urand = -1;
85 86 static char rcache[RCACHE_SIZE];
86 87 static char *rcachep = rcache;
87 88
88 89 /*
89 90 * misc routines
90 91 */
91 92 uint16_t get_random(void);
92 93 void get_current_time(uuid_time_t *);
93 94
94 95 void struct_to_string(uuid_t, struct uuid *);
95 96 void string_to_struct(struct uuid *, uuid_t);
96 97 int get_ethernet_address(uuid_node_t *);
97 98
98 99 /*
99 100 * local functions
100 101 */
101 102 static int map_state();
102 103 static void format_uuid(struct uuid *, uint16_t, uuid_time_t,
103 104 uuid_node_t);
104 105 static void fill_random_bytes(uchar_t *, int);
105 106 static int uuid_create(struct uuid *);
106 107 static void gen_ethernet_address(uuid_node_t *);
107 108 static void revalidate_data(uuid_node_t *);
108 109
109 110 /*
110 111 * Generates a uuid based on version 1 format.
111 112 * Returns 0 on success and -1 on failure.
112 113 */
113 114 static int
114 115 uuid_create(struct uuid *uuid)
115 116 {
116 117 uuid_time_t timestamp;
117 118 uuid_node_t system_node;
118 119 int ret, non_unique = 0;
119 120
120 121 /*
121 122 * Get the system MAC address and/or cache it
122 123 */
123 124 if (node_init) {
124 125 bcopy(&node_id_cache, &system_node, sizeof (uuid_node_t));
125 126 } else {
126 127 gen_ethernet_address(&system_node);
127 128 bcopy(&system_node, &node_id_cache, sizeof (uuid_node_t));
128 129 node_init = 1;
129 130 }
130 131
131 132 /*
132 133 * Access the state file, mmap it and initialize the shared lock.
133 134 * file_type tells us whether we had access to the state file or
134 135 * created a temporary one.
135 136 */
136 137 if (map_state() == -1)
137 138 return (-1);
138 139
139 140 /*
140 141 * Acquire the lock
141 142 */
142 143 for (;;) {
143 144 if ((ret = mutex_lock(&data->lock)) == 0)
144 145 break;
145 146 else
146 147 switch (ret) {
147 148 case EOWNERDEAD:
148 149 revalidate_data(&system_node);
149 150 (void) mutex_consistent(&data->lock);
150 151 (void) mutex_unlock(&data->lock);
151 152 break;
152 153 case ENOTRECOVERABLE:
153 154 return (ret);
154 155 }
155 156 }
156 157
157 158 /* State file is either new or is temporary, get a random clock seq */
158 159 if (data->state.clock == 0) {
159 160 data->state.clock = get_random();
160 161 non_unique++;
161 162 }
162 163
163 164 if (memcmp(&system_node, &data->state.node, sizeof (uuid_node_t)) != 0)
164 165 data->state.clock++;
165 166
166 167 get_current_time(×tamp);
167 168
168 169 /*
169 170 * If timestamp is not set or is not in the past, bump
170 171 * data->state.clock
171 172 */
172 173 if ((data->state.ts == 0) || (data->state.ts >= timestamp)) {
173 174 data->state.clock++;
174 175 data->state.ts = timestamp;
175 176 }
176 177
177 178 if (non_unique)
178 179 system_node.nodeID[0] |= 0x80;
179 180
180 181 /* Stuff fields into the UUID struct */
181 182 format_uuid(uuid, data->state.clock, timestamp, system_node);
182 183
183 184 (void) mutex_unlock(&data->lock);
184 185
185 186 return (0);
186 187 }
187 188
188 189 /*
189 190 * Fills system_node with Ethernet address if available,
190 191 * else fills random numbers
191 192 */
192 193 static void
193 194 gen_ethernet_address(uuid_node_t *system_node)
194 195 {
195 196 uchar_t node[6];
196 197
197 198 if (get_ethernet_address(system_node) != 0) {
198 199 fill_random_bytes(node, 6);
199 200 (void) memcpy(system_node->nodeID, node, 6);
200 201 /*
201 202 * use 8:0:20 with the multicast bit set
202 203 * to avoid namespace collisions.
203 204 */
204 205 system_node->nodeID[0] = 0x88;
205 206 system_node->nodeID[1] = 0x00;
206 207 system_node->nodeID[2] = 0x20;
207 208 }
208 209 }
209 210
210 211 /*
211 212 * Formats a UUID, given the clock_seq timestamp, and node address.
212 213 * Fills in passed-in pointer with the resulting uuid.
213 214 */
214 215 static void
215 216 format_uuid(struct uuid *uuid, uint16_t clock_seq,
216 217 uuid_time_t timestamp, uuid_node_t node)
217 218 {
218 219
219 220 /*
220 221 * First set up the first 60 bits from the timestamp
221 222 */
222 223 uuid->time_low = (uint32_t)(timestamp & 0xFFFFFFFF);
223 224 uuid->time_mid = (uint16_t)((timestamp >> 32) & 0xFFFF);
224 225 uuid->time_hi_and_version = (uint16_t)((timestamp >> 48) & 0x0FFF);
225 226
226 227 /*
227 228 * This is version 1, so say so in the UUID version field (4 bits)
228 229 */
229 230 uuid->time_hi_and_version |= (1 << 12);
230 231
231 232 /*
232 233 * Now do the clock sequence
233 234 */
234 235 uuid->clock_seq_low = clock_seq & 0xFF;
235 236
236 237 /*
237 238 * We must save the most-significant 2 bits for the reserved field
238 239 */
239 240 uuid->clock_seq_hi_and_reserved = (clock_seq & 0x3F00) >> 8;
240 241
241 242 /*
242 243 * The variant for this format is the 2 high bits set to 10,
243 244 * so here it is
244 245 */
245 246 uuid->clock_seq_hi_and_reserved |= 0x80;
246 247
247 248 /*
248 249 * write result to passed-in pointer
249 250 */
250 251 (void) memcpy(&uuid->node_addr, &node, sizeof (uuid->node_addr));
251 252 }
252 253
253 254 /*
254 255 * Opens/creates the state file, falling back to a tmp
255 256 */
256 257 static int
257 258 map_state()
258 259 {
259 260 FILE *tmp;
260 261
261 262 /* If file's mapped, return */
262 263 if (file_type != 0)
263 264 return (1);
264 265
265 266 if ((fd = open(STATE_LOCATION, O_RDWR)) < 0) {
266 267 file_type = TEMP_FILE;
267 268
268 269 if ((tmp = tmpfile()) == NULL)
269 270 return (-1);
270 271 else
271 272 fd = fileno(tmp);
272 273 } else {
273 274 file_type = STATE_FILE;
274 275 }
275 276
276 277 (void) ftruncate(fd, (off_t)sizeof (shared_buffer_t));
277 278
278 279 /* LINTED - alignment */
279 280 data = (shared_buffer_t *)mmap(NULL, sizeof (shared_buffer_t),
280 281 PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
281 282
282 283 if (data == MAP_FAILED)
283 284 return (-1);
284 285
285 286 (void) mutex_init(&data->lock, USYNC_PROCESS|LOCK_ROBUST, 0);
286 287
287 288 (void) close(fd);
288 289
289 290 return (1);
290 291 }
291 292
292 293 static void
293 294 revalidate_data(uuid_node_t *node)
294 295 {
295 296 int i;
296 297
297 298 data->state.ts = 0;
298 299
299 300 for (i = 0; i < sizeof (data->state.node.nodeID); i++)
300 301 data->state.node.nodeID[i] = 0;
301 302
302 303 data->state.clock = 0;
303 304
304 305 gen_ethernet_address(node);
305 306 bcopy(node, &node_id_cache, sizeof (uuid_node_t));
306 307 node_init = 1;
307 308 }
308 309
309 310 /*
310 311 * Prints a nicely-formatted uuid to stdout.
311 312 */
312 313 void
313 314 uuid_print(struct uuid u)
314 315 {
315 316 int i;
316 317
317 318 (void) printf("%8.8x-%4.4x-%4.4x-%2.2x%2.2x-", u.time_low, u.time_mid,
318 319 u.time_hi_and_version, u.clock_seq_hi_and_reserved,
319 320 u.clock_seq_low);
320 321 for (i = 0; i < 6; i++)
321 322 (void) printf("%2.2x", u.node_addr[i]);
322 323 (void) printf("\n");
323 324 }
324 325
325 326 /*
326 327 * Only called with urandmtx held.
327 328 * Fills/refills the cache of randomness. We know that our allocations of
328 329 * randomness are always much less than the total size of the cache.
329 330 * Tries to use /dev/urandom random number generator - if that fails for some
330 331 * reason, it retries MAX_RETRY times then sets rcachep to NULL so we no
331 332 * longer use the cache.
332 333 */
333 334 static void
334 335 load_cache()
335 336 {
336 337 int i, retries = 0;
337 338 int nbytes = RCACHE_SIZE;
338 339 char *buf = rcache;
339 340
340 341 while (nbytes > 0) {
341 342 i = read(fd_urand, buf, nbytes);
342 343 if ((i < 0) && (errno == EINTR)) {
343 344 continue;
344 345 }
345 346 if (i <= 0) {
346 347 if (retries++ == MAX_RETRY)
347 348 break;
348 349 continue;
349 350 }
350 351 nbytes -= i;
351 352 buf += i;
352 353 retries = 0;
353 354 }
354 355 if (nbytes == 0)
355 356 rcachep = rcache;
356 357 else
357 358 rcachep = NULL;
358 359 }
359 360
360 361 /*
361 362 * Fills buf with random numbers - nbytes is the number of bytes
362 363 * to fill-in. Tries to use cached data from the /dev/urandom random number
363 364 * generator - if that fails for some reason, it uses srand48(3C)
364 365 */
365 366 static void
366 367 fill_random_bytes(uchar_t *buf, int nbytes)
367 368 {
368 369 int i;
369 370
370 371 if (fd_urand == -1) {
371 372 (void) mutex_lock(&urandmtx);
372 373 /* check again now that we have the mutex */
373 374 if (fd_urand == -1) {
374 375 if ((fd_urand = open(URANDOM_PATH, O_RDONLY)) >= 0)
375 376 load_cache();
376 377 }
377 378 (void) mutex_unlock(&urandmtx);
378 379 }
379 380 if (fd_urand >= 0 && rcachep != NULL) {
380 381 int cnt;
381 382
382 383 (void) mutex_lock(&urandmtx);
383 384 if (rcachep != NULL &&
384 385 (rcachep + nbytes) >= (rcache + RCACHE_SIZE))
385 386 load_cache();
386 387
387 388 if (rcachep != NULL) {
388 389 for (cnt = 0; cnt < nbytes; cnt++)
389 390 *buf++ = *rcachep++;
390 391 (void) mutex_unlock(&urandmtx);
391 392 return;
392 393 }
393 394 (void) mutex_unlock(&urandmtx);
394 395 }
395 396 for (i = 0; i < nbytes; i++) {
396 397 *buf++ = get_random() & 0xFF;
397 398 }
398 399 }
399 400
400 401 /*
401 402 * Unpacks the structure members in "struct uuid" to a char string "uuid_t".
402 403 */
403 404 void
404 405 struct_to_string(uuid_t ptr, struct uuid *uu)
405 406 {
406 407 uint_t tmp;
407 408 uchar_t *out = ptr;
408 409
409 410 tmp = uu->time_low;
410 411 out[3] = (uchar_t)tmp;
411 412 tmp >>= 8;
412 413 out[2] = (uchar_t)tmp;
413 414 tmp >>= 8;
414 415 out[1] = (uchar_t)tmp;
415 416 tmp >>= 8;
416 417 out[0] = (uchar_t)tmp;
417 418
418 419 tmp = uu->time_mid;
419 420 out[5] = (uchar_t)tmp;
420 421 tmp >>= 8;
421 422 out[4] = (uchar_t)tmp;
422 423
423 424 tmp = uu->time_hi_and_version;
424 425 out[7] = (uchar_t)tmp;
425 426 tmp >>= 8;
426 427 out[6] = (uchar_t)tmp;
427 428
428 429 tmp = uu->clock_seq_hi_and_reserved;
429 430 out[8] = (uchar_t)tmp;
430 431 tmp = uu->clock_seq_low;
431 432 out[9] = (uchar_t)tmp;
432 433
433 434 (void) memcpy(out+10, uu->node_addr, 6);
434 435
435 436 }
436 437
437 438 /*
438 439 * Packs the values in the "uuid_t" string into "struct uuid".
439 440 */
440 441 void
441 442 string_to_struct(struct uuid *uuid, uuid_t in)
442 443 {
443 444 uchar_t *ptr;
444 445 uint_t tmp;
445 446
446 447 ptr = in;
447 448
448 449 tmp = *ptr++;
449 450 tmp = (tmp << 8) | *ptr++;
450 451 tmp = (tmp << 8) | *ptr++;
451 452 tmp = (tmp << 8) | *ptr++;
452 453 uuid->time_low = tmp;
453 454
454 455 tmp = *ptr++;
455 456 tmp = (tmp << 8) | *ptr++;
456 457 uuid->time_mid = tmp;
457 458
458 459 tmp = *ptr++;
459 460 tmp = (tmp << 8) | *ptr++;
460 461 uuid->time_hi_and_version = tmp;
461 462
462 463 tmp = *ptr++;
463 464 uuid->clock_seq_hi_and_reserved = tmp;
464 465
465 466 tmp = *ptr++;
466 467 uuid->clock_seq_low = tmp;
467 468
468 469 (void) memcpy(uuid->node_addr, ptr, 6);
469 470
470 471 }
471 472
472 473 /*
473 474 * Generates UUID based on DCE Version 4
474 475 */
475 476 void
476 477 uuid_generate_random(uuid_t uu)
477 478 {
478 479 struct uuid uuid;
479 480
480 481 if (uu == NULL)
481 482 return;
482 483
483 484 (void) memset(uu, 0, sizeof (uuid_t));
484 485 (void) memset(&uuid, 0, sizeof (struct uuid));
485 486
486 487 fill_random_bytes(uu, sizeof (uuid_t));
487 488 string_to_struct(&uuid, uu);
488 489 /*
489 490 * This is version 4, so say so in the UUID version field (4 bits)
490 491 */
491 492 uuid.time_hi_and_version |= (1 << 14);
492 493 /*
493 494 * we don't want the bit 1 to be set also which is for version 1
494 495 */
495 496 uuid.time_hi_and_version &= VER1_MASK;
496 497
497 498 /*
498 499 * The variant for this format is the 2 high bits set to 10,
499 500 * so here it is
500 501 */
501 502 uuid.clock_seq_hi_and_reserved |= 0x80;
502 503
503 504 /*
504 505 * Set MSB of Ethernet address to 1 to indicate that it was generated
505 506 * randomly
506 507 */
507 508 uuid.node_addr[0] |= 0x80;
508 509 struct_to_string(uu, &uuid);
509 510 }
510 511
511 512 /*
512 513 * Generates UUID based on DCE Version 1.
513 514 */
514 515 void
515 516 uuid_generate_time(uuid_t uu)
516 517 {
517 518 struct uuid uuid;
518 519
519 520 if (uu == NULL)
520 521 return;
521 522
522 523 if (uuid_create(&uuid) < 0) {
523 524 uuid_generate_random(uu);
524 525 return;
525 526 }
526 527
527 528 struct_to_string(uu, &uuid);
528 529 }
529 530
530 531 /*
531 532 * Creates a new UUID. The uuid will be generated based on high-quality
532 533 * randomness from /dev/urandom, if available by calling uuid_generate_random.
533 534 * If it failed to generate UUID then uuid_generate will call
534 535 * uuid_generate_time.
535 536 */
536 537 void
537 538 uuid_generate(uuid_t uu)
538 539 {
539 540 if (uu == NULL) {
540 541 return;
541 542 }
542 543 if (fd_urand == -1) {
543 544 (void) mutex_lock(&urandmtx);
544 545 /* check again now that we have the mutex */
545 546 if (fd_urand == -1) {
546 547 if ((fd_urand = open(URANDOM_PATH, O_RDONLY)) >= 0)
547 548 load_cache();
548 549 }
549 550 (void) mutex_unlock(&urandmtx);
550 551 }
551 552 if (fd_urand >= 0) {
552 553 uuid_generate_random(uu);
553 554 } else {
554 555 (void) uuid_generate_time(uu);
555 556 }
556 557 }
557 558
558 559 /*
559 560 * Copies the UUID variable src to dst.
560 561 */
561 562 void
562 563 uuid_copy(uuid_t dst, uuid_t src)
563 564 {
564 565 (void) memcpy(dst, src, UUID_LEN);
565 566 }
566 567
567 568 /*
568 569 * Sets the value of the supplied uuid variable uu, to the NULL value.
569 570 */
570 571 void
↓ open down ↓ |
535 lines elided |
↑ open up ↑ |
571 572 uuid_clear(uuid_t uu)
572 573 {
573 574 (void) memset(uu, 0, UUID_LEN);
574 575 }
575 576
576 577 /*
577 578 * This function converts the supplied UUID uu from the internal
578 579 * binary format into a 36-byte string (plus trailing null char)
579 580 * and stores this value in the character string pointed to by out.
580 581 */
581 -void
582 -uuid_unparse(uuid_t uu, char *out)
582 +static void
583 +uuid_unparse_common(uuid_t uu, char *out, boolean_t upper)
583 584 {
584 585 struct uuid uuid;
585 586 uint16_t clock_seq;
586 587 char etheraddr[13];
587 588 int index = 0, i;
588 589
589 590 /* basic sanity checking */
590 591 if (uu == NULL) {
591 592 return;
592 593 }
593 594
594 - /* XXX user should have allocated enough memory */
595 - /*
596 - * if (strlen(out) < UUID_PRINTABLE_STRING_LENGTH) {
597 - * return;
598 - * }
599 - */
600 595 string_to_struct(&uuid, uu);
601 596 clock_seq = uuid.clock_seq_hi_and_reserved;
602 597 clock_seq = (clock_seq << 8) | uuid.clock_seq_low;
603 598 for (i = 0; i < 6; i++) {
604 - (void) sprintf(ðeraddr[index++], "%.2x", uuid.node_addr[i]);
599 + (void) sprintf(ðeraddr[index++], upper ? "%.2X" : "%.2x",
600 + uuid.node_addr[i]);
605 601 index++;
606 602 }
607 603 etheraddr[index] = '\0';
608 604
609 - (void) snprintf(out, 25, "%08x-%04x-%04x-%04x-",
605 + (void) snprintf(out, 25,
606 + upper ? "%08X-%04X-%04X-%04X-" : "%08x-%04x-%04x-%04x-",
610 607 uuid.time_low, uuid.time_mid, uuid.time_hi_and_version, clock_seq);
611 608 (void) strlcat(out, etheraddr, UUID_PRINTABLE_STRING_LENGTH);
612 609 }
613 610
611 +void
612 +uuid_unparse_upper(uuid_t uu, char *out)
613 +{
614 + uuid_unparse_common(uu, out, B_TRUE);
615 +}
616 +
617 +void
618 +uuid_unparse_lower(uuid_t uu, char *out)
619 +{
620 + uuid_unparse_common(uu, out, B_FALSE);
621 +}
622 +
623 +void
624 +uuid_unparse(uuid_t uu, char *out)
625 +{
626 + /*
627 + * Historically uuid_unparse on Solaris returns lower case,
628 + * for compatibility we preserve this behaviour.
629 + */
630 + uuid_unparse_common(uu, out, B_FALSE);
631 +}
632 +
614 633 /*
615 634 * The uuid_is_null function compares the value of the supplied
616 635 * UUID variable uu to the NULL value. If the value is equal
617 636 * to the NULL UUID, 1 is returned, otherwise 0 is returned.
618 637 */
619 638 int
620 639 uuid_is_null(uuid_t uu)
621 640 {
622 641 int i;
623 642 uuid_t null_uu;
624 643
625 644 (void) memset(null_uu, 0, sizeof (uuid_t));
626 645 i = memcmp(uu, null_uu, sizeof (uuid_t));
627 646 if (i == 0) {
628 647 /* uu is NULL uuid */
629 648 return (1);
630 649 } else {
631 650 return (0);
632 651 }
633 652 }
634 653
635 654 /*
636 655 * uuid_parse converts the UUID string given by 'in' into the
637 656 * internal uuid_t format. The input UUID is a string of the form
638 657 * cefa7a9c-1dd2-11b2-8350-880020adbeef in printf(3C) format.
639 658 * Upon successfully parsing the input string, UUID is stored
640 659 * in the location pointed to by uu
641 660 */
642 661 int
643 662 uuid_parse(char *in, uuid_t uu)
644 663 {
645 664
646 665 char *ptr, buf[3];
647 666 int i;
648 667 struct uuid uuid;
649 668 uint16_t clock_seq;
650 669
651 670 /* do some sanity checking */
652 671 if ((strlen(in) != 36) || (uu == NULL) || (in[36] != '\0')) {
653 672 return (-1);
654 673 }
655 674
656 675 ptr = in;
657 676 for (i = 0; i < 36; i++, ptr++) {
658 677 if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) {
659 678 if (*ptr != '-') {
660 679 return (-1);
661 680 }
662 681 } else {
663 682 if (!isxdigit(*ptr)) {
664 683 return (-1);
665 684 }
666 685 }
667 686 }
668 687
669 688 uuid.time_low = strtoul(in, NULL, 16);
670 689 uuid.time_mid = strtoul(in+9, NULL, 16);
671 690 uuid.time_hi_and_version = strtoul(in+14, NULL, 16);
672 691 clock_seq = strtoul(in+19, NULL, 16);
673 692 uuid.clock_seq_hi_and_reserved = (clock_seq & 0xFF00) >> 8;
674 693 uuid.clock_seq_low = (clock_seq & 0xFF);
675 694
676 695 ptr = in+24;
677 696 buf[2] = '\0';
678 697 for (i = 0; i < 6; i++) {
679 698 buf[0] = *ptr++;
680 699 buf[1] = *ptr++;
681 700 uuid.node_addr[i] = strtoul(buf, NULL, 16);
682 701 }
683 702 struct_to_string(uu, &uuid);
684 703 return (0);
685 704 }
686 705
687 706 /*
688 707 * uuid_time extracts the time at which the supplied UUID uu
689 708 * was created. This function can only extract the creation
690 709 * time for UUIDs created with the uuid_generate_time function.
691 710 * The time at which the UUID was created, in seconds and
692 711 * microseconds since the epoch is stored in the location
693 712 * pointed to by ret_tv.
694 713 */
695 714 time_t
696 715 uuid_time(uuid_t uu, struct timeval *ret_tv)
697 716 {
698 717 struct uuid uuid;
699 718 uint_t high;
700 719 struct timeval tv;
701 720 u_longlong_t clock_reg;
702 721 uint_t tmp;
703 722 uint8_t clk;
704 723
705 724 string_to_struct(&uuid, uu);
706 725 tmp = (uuid.time_hi_and_version & 0xF000) >> 12;
707 726 clk = uuid.clock_seq_hi_and_reserved;
708 727
709 728 /* check if uu is NULL, Version = 1 of DCE and Variant = 0b10x */
710 729 if ((uu == NULL) || ((tmp & 0x01) != 0x01) || ((clk & 0x80) != 0x80)) {
711 730 return (-1);
712 731 }
713 732 high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16);
714 733 clock_reg = uuid.time_low | ((u_longlong_t)high << 32);
715 734
716 735 clock_reg -= (((u_longlong_t)0x01B21DD2) << 32) + 0x13814000;
717 736 tv.tv_sec = clock_reg / 10000000;
718 737 tv.tv_usec = (clock_reg % 10000000) / 10;
719 738
720 739 if (ret_tv) {
721 740 *ret_tv = tv;
722 741 }
723 742
724 743 return (tv.tv_sec);
725 744 }
↓ open down ↓ |
102 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX