head 1.68; access; symbols UUID_1_6_2:1.67 UUID_1_6_1:1.66 UUID_1_6_0:1.64 UUID_1_5_1:1.61 UUID_1_5_0:1.61 UUID_1_4_2:1.58 UUID_1_4_1:1.58 UUID_1_4_0:1.57 UUID_1_3_2:1.56 UUID_1_3_1:1.56 UUID_1_3_0:1.55 UUID_1_2_1:1.51 UUID_1_2_0:1.50 UUID_1_1_2:1.49 UUID_1_1_1:1.48 UUID_1_1_0:1.48 UUID_1_0_4:1.48 UUID_1_0_3:1.48 UUID_1_0_2:1.48 UUID_1_0_1:1.48 UUID_1_0_0:1.46 UUID_0_9_7:1.45 UUID_0_9_6:1.44 UUID_0_9_5:1.44 UUID_0_9_4:1.44 UUID_0_9_3:1.32 UUID_0_9_2:1.31 UUID_0_9_1:1.23 UUID_0_9_0:1.21; locks; strict; comment @ * @; 1.68 date 2008.07.05.12.58.15; author rse; state dead; branches; next 1.67; commitid XLXN7vUmABwPcC9t; 1.67 date 2008.03.06.12.14.49; author rse; state Exp; branches; next 1.66; commitid DMtu1kD8JmZZQ3Us; 1.66 date 2008.02.21.08.58.45; author rse; state Exp; branches; next 1.65; commitid 49UAeQtix4DIdfSs; 1.65 date 2008.01.10.14.18.46; author rse; state Exp; branches; next 1.64; commitid LqMgFGBgTR7clSMs; 1.64 date 2007.01.01.18.14.54; author rse; state Exp; branches; next 1.63; commitid jOXiIO8S8v7xFP0s; 1.63 date 2006.10.06.08.32.40; author rse; state Exp; branches; next 1.62; commitid UUM6UebO1uCWeBPr; 1.62 date 2006.08.02.13.11.09; author rse; state Exp; branches; next 1.61; commitid fwUmuuaIDS3gSgHr; 1.61 date 2006.07.28.19.04.32; author rse; state Exp; branches; next 1.60; commitid 6qZlcn3KsEQtZEGr; 1.60 date 2006.07.28.18.22.43; author rse; state Exp; branches; next 1.59; commitid vxSuPdVUv6L7LEGr; 1.59 date 2006.05.11.09.37.28; author rse; state Exp; branches; next 1.58; commitid u4EPMISJDipjmAwr; 1.58 date 2006.02.07.08.19.15; author rse; state Exp; branches; next 1.57; commitid ysd3ZoQahbomUCkr; 1.57 date 2006.01.13.06.44.30; author rse; state Exp; branches; next 1.56; commitid hYfQc9JIMh4bcphr; 1.56 date 2005.09.24.10.28.32; author rse; state Exp; branches; next 1.55; 1.55 date 2005.09.01.20.50.18; author rse; state Exp; branches; next 1.54; 1.54 date 2005.08.31.19.21.13; author rse; state Exp; branches; next 1.53; 1.53 date 2005.08.31.14.28.28; author rse; state Exp; branches; next 1.52; 1.52 date 2005.08.30.20.34.35; author rse; state Exp; branches; next 1.51; 1.51 date 2005.03.29.19.01.41; author rse; state Exp; branches; next 1.50; 1.50 date 2005.01.23.11.28.51; author rse; state Exp; branches; next 1.49; 1.49 date 2004.12.31.19.20.34; author rse; state Exp; branches; next 1.48; 1.48 date 2004.06.09.19.17.39; author rse; state Exp; branches; next 1.47; 1.47 date 2004.02.17.09.23.06; author thl; state Exp; branches; next 1.46; 1.46 date 2004.02.16.09.13.58; author rse; state Exp; branches; next 1.45; 1.45 date 2004.02.13.21.01.41; author rse; state Exp; branches; next 1.44; 1.44 date 2004.01.19.14.56.35; author rse; state Exp; branches; next 1.43; 1.43 date 2004.01.19.14.11.49; author rse; state Exp; branches; next 1.42; 1.42 date 2004.01.19.13.55.18; author rse; state Exp; branches; next 1.41; 1.41 date 2004.01.19.12.15.05; author rse; state Exp; branches; next 1.40; 1.40 date 2004.01.19.12.08.28; author ms; state Exp; branches; next 1.39; 1.39 date 2004.01.19.09.26.55; author rse; state Exp; branches; next 1.38; 1.38 date 2004.01.19.09.17.27; author rse; state Exp; branches; next 1.37; 1.37 date 2004.01.18.20.19.23; author rse; state Exp; branches; next 1.36; 1.36 date 2004.01.18.19.59.12; author rse; state Exp; branches; next 1.35; 1.35 date 2004.01.18.19.22.54; author rse; state Exp; branches; next 1.34; 1.34 date 2004.01.18.11.31.10; author rse; state Exp; branches; next 1.33; 1.33 date 2004.01.17.14.21.57; author rse; state Exp; branches; next 1.32; 1.32 date 2004.01.16.12.20.45; author rse; state Exp; branches; next 1.31; 1.31 date 2004.01.15.19.19.49; author rse; state Exp; branches; next 1.30; 1.30 date 2004.01.15.17.39.40; author ms; state Exp; branches; next 1.29; 1.29 date 2004.01.15.17.24.56; author ms; state Exp; branches; next 1.28; 1.28 date 2004.01.15.16.22.09; author rse; state Exp; branches; next 1.27; 1.27 date 2004.01.15.15.29.36; author rse; state Exp; branches; next 1.26; 1.26 date 2004.01.15.13.45.18; author rse; state Exp; branches; next 1.25; 1.25 date 2004.01.15.12.38.32; author rse; state Exp; branches; next 1.24; 1.24 date 2004.01.15.12.32.26; author rse; state Exp; branches; next 1.23; 1.23 date 2004.01.13.19.43.14; author rse; state Exp; branches; next 1.22; 1.22 date 2004.01.11.12.14.19; author rse; state Exp; branches; next 1.21; 1.21 date 2004.01.10.22.43.40; author rse; state Exp; branches; next 1.20; 1.20 date 2004.01.10.22.18.48; author rse; state Exp; branches; next 1.19; 1.19 date 2004.01.10.21.54.52; author rse; state Exp; branches; next 1.18; 1.18 date 2004.01.10.21.47.45; author rse; state Exp; branches; next 1.17; 1.17 date 2004.01.10.19.17.39; author rse; state Exp; branches; next 1.16; 1.16 date 2004.01.10.17.01.22; author rse; state Exp; branches; next 1.15; 1.15 date 2004.01.10.15.19.21; author rse; state Exp; branches; next 1.14; 1.14 date 2004.01.10.12.16.03; author rse; state Exp; branches; next 1.13; 1.13 date 2004.01.10.11.54.05; author rse; state Exp; branches; next 1.12; 1.12 date 2004.01.10.11.14.18; author rse; state Exp; branches; next 1.11; 1.11 date 2004.01.10.11.07.26; author rse; state Exp; branches; next 1.10; 1.10 date 2004.01.10.10.49.00; author rse; state Exp; branches; next 1.9; 1.9 date 2004.01.09.21.59.57; author rse; state Exp; branches; next 1.8; 1.8 date 2004.01.09.21.01.04; author rse; state Exp; branches; next 1.7; 1.7 date 2004.01.09.16.11.40; author rse; state Exp; branches; next 1.6; 1.6 date 2004.01.09.11.32.06; author rse; state Exp; branches; next 1.5; 1.5 date 2004.01.09.11.28.56; author rse; state Exp; branches; next 1.4; 1.4 date 2004.01.09.09.06.25; author rse; state Exp; branches; next 1.3; 1.3 date 2004.01.08.21.31.47; author rse; state Exp; branches; next 1.2; 1.2 date 2004.01.06.20.43.34; author rse; state Exp; branches; next 1.1; 1.1 date 2004.01.06.20.14.28; author rse; state Exp; branches; next ; desc @@ 1.68 log @remove OSSP uuid from CVS -- it is now versioned controlled in a Monotone repository @ text @/* ** OSSP uuid - Universally Unique Identifier ** Copyright (c) 2004-2008 Ralf S. Engelschall ** Copyright (c) 2004-2008 The OSSP Project ** ** This file is part of OSSP uuid, a library for the generation ** of UUIDs which can found at http://www.ossp.org/pkg/lib/uuid/ ** ** Permission to use, copy, modify, and distribute this software for ** any purpose with or without fee is hereby granted, provided that ** the above copyright notice and this permission notice appear in all ** copies. ** ** THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ** SUCH DAMAGE. ** ** uuid.c: library API implementation */ /* own headers (part 1/2) */ #include "uuid.h" #include "uuid_ac.h" /* system headers */ #include #include #include #include #include #include #include #include #include #include /* own headers (part 2/2) */ #include "uuid_vers.h" #include "uuid_md5.h" #include "uuid_sha1.h" #include "uuid_prng.h" #include "uuid_mac.h" #include "uuid_time.h" #include "uuid_ui64.h" #include "uuid_ui128.h" #include "uuid_str.h" #include "uuid_bm.h" #include "uuid_ac.h" /* maximum number of 100ns ticks of the actual resolution of system clock (which in our case is 1us (= 1000ns) because we use gettimeofday(2) */ #define UUIDS_PER_TICK 10 /* time offset between UUID and Unix Epoch time according to standards. (UUID UTC base time is October 15, 1582 Unix UTC base time is January 1, 1970) */ #define UUID_TIMEOFFSET "01B21DD213814000" /* IEEE 802 MAC address encoding/decoding bit fields */ #define IEEE_MAC_MCBIT BM_OCTET(0,0,0,0,0,0,0,1) #define IEEE_MAC_LOBIT BM_OCTET(0,0,0,0,0,0,1,0) /* IEEE 802 MAC address octet length */ #define IEEE_MAC_OCTETS 6 /* UUID binary representation according to UUID standards */ typedef struct { uuid_uint32_t time_low; /* bits 0-31 of time field */ uuid_uint16_t time_mid; /* bits 32-47 of time field */ uuid_uint16_t time_hi_and_version; /* bits 48-59 of time field plus 4 bit version */ uuid_uint8_t clock_seq_hi_and_reserved; /* bits 8-13 of clock sequence field plus 2 bit variant */ uuid_uint8_t clock_seq_low; /* bits 0-7 of clock sequence field */ uuid_uint8_t node[IEEE_MAC_OCTETS]; /* bits 0-47 of node MAC address */ } uuid_obj_t; /* abstract data type (ADT) of API */ struct uuid_st { uuid_obj_t obj; /* inlined UUID object */ prng_t *prng; /* RPNG sub-object */ md5_t *md5; /* MD5 sub-object */ sha1_t *sha1; /* SHA-1 sub-object */ uuid_uint8_t mac[IEEE_MAC_OCTETS]; /* pre-determined MAC address */ struct timeval time_last; /* last retrieved timestamp */ unsigned long time_seq; /* last timestamp sequence counter */ }; /* create UUID object */ uuid_rc_t uuid_create(uuid_t **uuid) { uuid_t *obj; /* argument sanity check */ if (uuid == NULL) return UUID_RC_ARG; /* allocate UUID object */ if ((obj = (uuid_t *)malloc(sizeof(uuid_t))) == NULL) return UUID_RC_MEM; /* create PRNG, MD5 and SHA1 sub-objects */ if (prng_create(&obj->prng) != PRNG_RC_OK) { free(obj); return UUID_RC_INT; } if (md5_create(&obj->md5) != MD5_RC_OK) { (void)prng_destroy(obj->prng); free(obj); return UUID_RC_INT; } if (sha1_create(&obj->sha1) != SHA1_RC_OK) { (void)md5_destroy(obj->md5); (void)prng_destroy(obj->prng); free(obj); return UUID_RC_INT; } /* set UUID object initially to "Nil UUID" */ if (uuid_load(obj, "nil") != UUID_RC_OK) { (void)sha1_destroy(obj->sha1); (void)md5_destroy(obj->md5); (void)prng_destroy(obj->prng); free(obj); return UUID_RC_INT; } /* resolve MAC address for insertion into node field of UUIDs */ if (!mac_address((unsigned char *)(obj->mac), sizeof(obj->mac))) { memset(obj->mac, 0, sizeof(obj->mac)); obj->mac[0] = BM_OCTET(1,0,0,0,0,0,0,0); } /* initialize time attributes */ obj->time_last.tv_sec = 0; obj->time_last.tv_usec = 0; obj->time_seq = 0; /* store result object */ *uuid = obj; return UUID_RC_OK; } /* destroy UUID object */ uuid_rc_t uuid_destroy(uuid_t *uuid) { /* argument sanity check */ if (uuid == NULL) return UUID_RC_ARG; /* destroy PRNG, MD5 and SHA-1 sub-objects */ (void)prng_destroy(uuid->prng); (void)md5_destroy(uuid->md5); (void)sha1_destroy(uuid->sha1); /* free UUID object */ free(uuid); return UUID_RC_OK; } /* clone UUID object */ uuid_rc_t uuid_clone(const uuid_t *uuid, uuid_t **clone) { uuid_t *obj; /* argument sanity check */ if (uuid == NULL || uuid_clone == NULL) return UUID_RC_ARG; /* allocate UUID object */ if ((obj = (uuid_t *)malloc(sizeof(uuid_t))) == NULL) return UUID_RC_MEM; /* clone entire internal state */ memcpy(obj, uuid, sizeof(uuid_t)); /* re-initialize with new PRNG, MD5 and SHA1 sub-objects */ if (prng_create(&obj->prng) != PRNG_RC_OK) { free(obj); return UUID_RC_INT; } if (md5_create(&obj->md5) != MD5_RC_OK) { (void)prng_destroy(obj->prng); free(obj); return UUID_RC_INT; } if (sha1_create(&obj->sha1) != SHA1_RC_OK) { (void)md5_destroy(obj->md5); (void)prng_destroy(obj->prng); free(obj); return UUID_RC_INT; } /* store result object */ *clone = obj; return UUID_RC_OK; } /* check whether UUID object represents "Nil UUID" */ uuid_rc_t uuid_isnil(const uuid_t *uuid, int *result) { const unsigned char *ucp; int i; /* sanity check argument(s) */ if (uuid == NULL || result == NULL) return UUID_RC_ARG; /* a "Nil UUID" is defined as all octets zero, so check for this case */ *result = UUID_TRUE; for (i = 0, ucp = (unsigned char *)&(uuid->obj); i < UUID_LEN_BIN; i++) { if (*ucp++ != (unsigned char)'\0') { *result = UUID_FALSE; break; } } return UUID_RC_OK; } /* compare UUID objects */ uuid_rc_t uuid_compare(const uuid_t *uuid1, const uuid_t *uuid2, int *result) { int r; /* argument sanity check */ if (result == NULL) return UUID_RC_ARG; /* convenience macro for setting result */ #define RESULT(r) \ /*lint -save -e801 -e717*/ \ do { \ *result = (r); \ goto result_exit; \ } while (0) \ /*lint -restore*/ /* special cases: NULL or equal UUIDs */ if (uuid1 == uuid2) RESULT(0); if (uuid1 == NULL && uuid2 == NULL) RESULT(0); if (uuid1 == NULL) RESULT((uuid_isnil(uuid2, &r) == UUID_RC_OK ? r : 0) ? 0 : -1); if (uuid2 == NULL) RESULT((uuid_isnil(uuid1, &r) == UUID_RC_OK ? r : 0) ? 0 : 1); /* standard cases: regular different UUIDs */ if (uuid1->obj.time_low != uuid2->obj.time_low) RESULT((uuid1->obj.time_low < uuid2->obj.time_low) ? -1 : 1); if ((r = (int)uuid1->obj.time_mid - (int)uuid2->obj.time_mid) != 0) RESULT((r < 0) ? -1 : 1); if ((r = (int)uuid1->obj.time_hi_and_version - (int)uuid2->obj.time_hi_and_version) != 0) RESULT((r < 0) ? -1 : 1); if ((r = (int)uuid1->obj.clock_seq_hi_and_reserved - (int)uuid2->obj.clock_seq_hi_and_reserved) != 0) RESULT((r < 0) ? -1 : 1); if ((r = (int)uuid1->obj.clock_seq_low - (int)uuid2->obj.clock_seq_low) != 0) RESULT((r < 0) ? -1 : 1); if ((r = memcmp(uuid1->obj.node, uuid2->obj.node, sizeof(uuid1->obj.node))) != 0) RESULT((r < 0) ? -1 : 1); /* default case: the keys are equal */ *result = 0; result_exit: return UUID_RC_OK; } /* INTERNAL: unpack UUID binary presentation into UUID object (allows in-place operation for internal efficiency!) */ static uuid_rc_t uuid_import_bin(uuid_t *uuid, const void *data_ptr, size_t data_len) { const uuid_uint8_t *in; uuid_uint32_t tmp32; uuid_uint16_t tmp16; unsigned int i; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_BIN) return UUID_RC_ARG; /* treat input data buffer as octet stream */ in = (const uuid_uint8_t *)data_ptr; /* unpack "time_low" field */ tmp32 = (uuid_uint32_t)(*in++); tmp32 = (tmp32 << 8) | (uuid_uint32_t)(*in++); tmp32 = (tmp32 << 8) | (uuid_uint32_t)(*in++); tmp32 = (tmp32 << 8) | (uuid_uint32_t)(*in++); uuid->obj.time_low = tmp32; /* unpack "time_mid" field */ tmp16 = (uuid_uint16_t)(*in++); tmp16 = (uuid_uint16_t)(tmp16 << 8) | (uuid_uint16_t)(*in++); uuid->obj.time_mid = tmp16; /* unpack "time_hi_and_version" field */ tmp16 = (uuid_uint16_t)*in++; tmp16 = (uuid_uint16_t)(tmp16 << 8) | (uuid_uint16_t)(*in++); uuid->obj.time_hi_and_version = tmp16; /* unpack "clock_seq_hi_and_reserved" field */ uuid->obj.clock_seq_hi_and_reserved = *in++; /* unpack "clock_seq_low" field */ uuid->obj.clock_seq_low = *in++; /* unpack "node" field */ for (i = 0; i < (unsigned int)sizeof(uuid->obj.node); i++) uuid->obj.node[i] = *in++; return UUID_RC_OK; } /* INTERNAL: pack UUID object into binary representation (allows in-place operation for internal efficiency!) */ static uuid_rc_t uuid_export_bin(const uuid_t *uuid, void *_data_ptr, size_t *data_len) { uuid_uint8_t **data_ptr; uuid_uint8_t *out; uuid_uint32_t tmp32; uuid_uint16_t tmp16; unsigned int i; /* cast generic data pointer to particular pointer to pointer type */ data_ptr = (uuid_uint8_t **)_data_ptr; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL) return UUID_RC_ARG; /* optionally allocate octet data buffer */ if (*data_ptr == NULL) { if ((*data_ptr = (uuid_uint8_t *)malloc(sizeof(uuid_t))) == NULL) return UUID_RC_MEM; if (data_len != NULL) *data_len = UUID_LEN_BIN; } else { if (data_len == NULL) return UUID_RC_ARG; if (*data_len < UUID_LEN_BIN) return UUID_RC_MEM; *data_len = UUID_LEN_BIN; } /* treat output data buffer as octet stream */ out = *data_ptr; /* pack "time_low" field */ tmp32 = uuid->obj.time_low; out[3] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8; out[2] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8; out[1] = (uuid_uint8_t)(tmp32 & 0xff); tmp32 >>= 8; out[0] = (uuid_uint8_t)(tmp32 & 0xff); /* pack "time_mid" field */ tmp16 = uuid->obj.time_mid; out[5] = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8; out[4] = (uuid_uint8_t)(tmp16 & 0xff); /* pack "time_hi_and_version" field */ tmp16 = uuid->obj.time_hi_and_version; out[7] = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8; out[6] = (uuid_uint8_t)(tmp16 & 0xff); /* pack "clock_seq_hi_and_reserved" field */ out[8] = uuid->obj.clock_seq_hi_and_reserved; /* pack "clock_seq_low" field */ out[9] = uuid->obj.clock_seq_low; /* pack "node" field */ for (i = 0; i < (unsigned int)sizeof(uuid->obj.node); i++) out[10+i] = uuid->obj.node[i]; return UUID_RC_OK; } /* INTERNAL: check for valid UUID string representation syntax */ static int uuid_isstr(const char *str, size_t str_len) { int i; const char *cp; /* example reference: f81d4fae-7dec-11d0-a765-00a0c91e6bf6 012345678901234567890123456789012345 0 1 2 3 */ if (str == NULL) return UUID_FALSE; if (str_len == 0) str_len = strlen(str); if (str_len < UUID_LEN_STR) return UUID_FALSE; for (i = 0, cp = str; i < UUID_LEN_STR; i++, cp++) { if ((i == 8) || (i == 13) || (i == 18) || (i == 23)) { if (*cp == '-') continue; else return UUID_FALSE; } if (!isxdigit((int)(*cp))) return UUID_FALSE; } return UUID_TRUE; } /* INTERNAL: import UUID object from string representation */ static uuid_rc_t uuid_import_str(uuid_t *uuid, const void *data_ptr, size_t data_len) { uuid_uint16_t tmp16; const char *cp; char hexbuf[3]; const char *str; unsigned int i; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_STR) return UUID_RC_ARG; /* check for correct UUID string representation syntax */ str = (const char *)data_ptr; if (!uuid_isstr(str, 0)) return UUID_RC_ARG; /* parse hex values of "time" parts */ uuid->obj.time_low = (uuid_uint32_t)strtoul(str, NULL, 16); uuid->obj.time_mid = (uuid_uint16_t)strtoul(str+9, NULL, 16); uuid->obj.time_hi_and_version = (uuid_uint16_t)strtoul(str+14, NULL, 16); /* parse hex values of "clock" parts */ tmp16 = (uuid_uint16_t)strtoul(str+19, NULL, 16); uuid->obj.clock_seq_low = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8; uuid->obj.clock_seq_hi_and_reserved = (uuid_uint8_t)(tmp16 & 0xff); /* parse hex values of "node" part */ cp = str+24; hexbuf[2] = '\0'; for (i = 0; i < (unsigned int)sizeof(uuid->obj.node); i++) { hexbuf[0] = *cp++; hexbuf[1] = *cp++; uuid->obj.node[i] = (uuid_uint8_t)strtoul(hexbuf, NULL, 16); } return UUID_RC_OK; } /* INTERNAL: import UUID object from single integer value representation */ static uuid_rc_t uuid_import_siv(uuid_t *uuid, const void *data_ptr, size_t data_len) { const char *str; uuid_uint8_t tmp_bin[UUID_LEN_BIN]; ui128_t ui, ui2; uuid_rc_t rc; int i; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL || data_len < 1) return UUID_RC_ARG; /* check for correct UUID single integer value syntax */ str = (const char *)data_ptr; for (i = 0; i < (int)data_len; i++) if (!isdigit((int)str[i])) return UUID_RC_ARG; /* parse single integer value representation (SIV) */ ui = ui128_s2i(str, NULL, 10); /* import octets into UUID binary representation */ for (i = 0; i < UUID_LEN_BIN; i++) { ui = ui128_rol(ui, 8, &ui2); tmp_bin[i] = (uuid_uint8_t)(ui128_i2n(ui2) & 0xff); } /* import into internal UUID representation */ if ((rc = uuid_import(uuid, UUID_FMT_BIN, (void *)&tmp_bin, UUID_LEN_BIN)) != UUID_RC_OK) return rc; return UUID_RC_OK; } /* INTERNAL: export UUID object to string representation */ static uuid_rc_t uuid_export_str(const uuid_t *uuid, void *_data_ptr, size_t *data_len) { char **data_ptr; char *data_buf; /* cast generic data pointer to particular pointer to pointer type */ data_ptr = (char **)_data_ptr; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL) return UUID_RC_ARG; /* determine output buffer */ if (*data_ptr == NULL) { if ((data_buf = (char *)malloc(UUID_LEN_STR+1)) == NULL) return UUID_RC_MEM; if (data_len != NULL) *data_len = UUID_LEN_STR+1; } else { data_buf = (char *)(*data_ptr); if (data_len == NULL) return UUID_RC_ARG; if (*data_len < UUID_LEN_STR+1) return UUID_RC_MEM; *data_len = UUID_LEN_STR+1; } /* format UUID into string representation */ if (str_snprintf(data_buf, UUID_LEN_STR+1, "%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", (unsigned long)uuid->obj.time_low, (unsigned int)uuid->obj.time_mid, (unsigned int)uuid->obj.time_hi_and_version, (unsigned int)uuid->obj.clock_seq_hi_and_reserved, (unsigned int)uuid->obj.clock_seq_low, (unsigned int)uuid->obj.node[0], (unsigned int)uuid->obj.node[1], (unsigned int)uuid->obj.node[2], (unsigned int)uuid->obj.node[3], (unsigned int)uuid->obj.node[4], (unsigned int)uuid->obj.node[5]) != UUID_LEN_STR) { if (*data_ptr == NULL) free(data_buf); return UUID_RC_INT; } /* pass back new buffer if locally allocated */ if (*data_ptr == NULL) *data_ptr = data_buf; return UUID_RC_OK; } /* INTERNAL: export UUID object to single integer value representation */ static uuid_rc_t uuid_export_siv(const uuid_t *uuid, void *_data_ptr, size_t *data_len) { char **data_ptr; char *data_buf; void *tmp_ptr; size_t tmp_len; uuid_uint8_t tmp_bin[UUID_LEN_BIN]; ui128_t ui, ui2; uuid_rc_t rc; int i; /* cast generic data pointer to particular pointer to pointer type */ data_ptr = (char **)_data_ptr; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL) return UUID_RC_ARG; /* determine output buffer */ if (*data_ptr == NULL) { if ((data_buf = (char *)malloc(UUID_LEN_SIV+1)) == NULL) return UUID_RC_MEM; if (data_len != NULL) *data_len = UUID_LEN_SIV+1; } else { data_buf = (char *)(*data_ptr); if (data_len == NULL) return UUID_RC_ARG; if (*data_len < UUID_LEN_SIV+1) return UUID_RC_MEM; *data_len = UUID_LEN_SIV+1; } /* export into UUID binary representation */ tmp_ptr = (void *)&tmp_bin; tmp_len = sizeof(tmp_bin); if ((rc = uuid_export(uuid, UUID_FMT_BIN, &tmp_ptr, &tmp_len)) != UUID_RC_OK) { if (*data_ptr == NULL) free(data_buf); return rc; } /* import from UUID binary representation */ ui = ui128_zero(); for (i = 0; i < UUID_LEN_BIN; i++) { ui2 = ui128_n2i((unsigned long)tmp_bin[i]); ui = ui128_rol(ui, 8, NULL); ui = ui128_or(ui, ui2); } /* format into single integer value representation */ (void)ui128_i2s(ui, data_buf, UUID_LEN_SIV+1, 10); /* pass back new buffer if locally allocated */ if (*data_ptr == NULL) *data_ptr = data_buf; return UUID_RC_OK; } /* decoding tables */ static struct { uuid_uint8_t num; const char *desc; } uuid_dectab_variant[] = { { (uuid_uint8_t)BM_OCTET(0,0,0,0,0,0,0,0), "reserved (NCS backward compatible)" }, { (uuid_uint8_t)BM_OCTET(1,0,0,0,0,0,0,0), "DCE 1.1, ISO/IEC 11578:1996" }, { (uuid_uint8_t)BM_OCTET(1,1,0,0,0,0,0,0), "reserved (Microsoft GUID)" }, { (uuid_uint8_t)BM_OCTET(1,1,1,0,0,0,0,0), "reserved (future use)" } }; static struct { int num; const char *desc; } uuid_dectab_version[] = { { 1, "time and node based" }, { 3, "name based, MD5" }, { 4, "random data based" }, { 5, "name based, SHA-1" } }; /* INTERNAL: dump UUID object as descriptive text */ static uuid_rc_t uuid_export_txt(const uuid_t *uuid, void *_data_ptr, size_t *data_len) { char **data_ptr; uuid_rc_t rc; char **out; char *out_ptr; size_t out_len; const char *version; const char *variant; char *content; int isnil; uuid_uint8_t tmp8; uuid_uint16_t tmp16; uuid_uint32_t tmp32; uuid_uint8_t tmp_bin[UUID_LEN_BIN]; char tmp_str[UUID_LEN_STR+1]; char tmp_siv[UUID_LEN_SIV+1]; void *tmp_ptr; size_t tmp_len; ui64_t t; ui64_t t_offset; int t_nsec; int t_usec; time_t t_sec; char t_buf[19+1]; /* YYYY-MM-DD HH:MM:SS */ struct tm *tm; int i; /* cast generic data pointer to particular pointer to pointer type */ data_ptr = (char **)_data_ptr; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL) return UUID_RC_ARG; /* initialize output buffer */ out_ptr = NULL; out = &out_ptr; /* check for special case of "Nil UUID" */ if ((rc = uuid_isnil(uuid, &isnil)) != UUID_RC_OK) return rc; /* decode into various representations */ tmp_ptr = (void *)&tmp_str; tmp_len = sizeof(tmp_str); if ((rc = uuid_export(uuid, UUID_FMT_STR, &tmp_ptr, &tmp_len)) != UUID_RC_OK) return rc; tmp_ptr = (void *)&tmp_siv; tmp_len = sizeof(tmp_siv); if ((rc = uuid_export(uuid, UUID_FMT_SIV, &tmp_ptr, &tmp_len)) != UUID_RC_OK) return rc; (void)str_rsprintf(out, "encode: STR: %s\n", tmp_str); (void)str_rsprintf(out, " SIV: %s\n", tmp_siv); /* decode UUID variant */ tmp8 = uuid->obj.clock_seq_hi_and_reserved; if (isnil) variant = "n.a."; else { variant = "unknown"; for (i = 7; i >= 0; i--) { if ((tmp8 & (uuid_uint8_t)BM_BIT(i,1)) == 0) { tmp8 &= ~(uuid_uint8_t)BM_MASK(i,0); break; } } for (i = 0; i < (int)(sizeof(uuid_dectab_variant)/sizeof(uuid_dectab_variant[0])); i++) { if (uuid_dectab_variant[i].num == tmp8) { variant = uuid_dectab_variant[i].desc; break; } } } (void)str_rsprintf(out, "decode: variant: %s\n", variant); /* decode UUID version */ tmp16 = (BM_SHR(uuid->obj.time_hi_and_version, 12) & (uuid_uint16_t)BM_MASK(3,0)); if (isnil) version = "n.a."; else { version = "unknown"; for (i = 0; i < (int)(sizeof(uuid_dectab_version)/sizeof(uuid_dectab_version[0])); i++) { if (uuid_dectab_version[i].num == (int)tmp16) { version = uuid_dectab_version[i].desc; break; } } } str_rsprintf(out, " version: %d (%s)\n", (int)tmp16, version); /* * decode UUID content */ if (tmp8 == BM_OCTET(1,0,0,0,0,0,0,0) && tmp16 == 1) { /* decode DCE 1.1 version 1 UUID */ /* decode system time */ t = ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_hi_and_version & BM_MASK(11,0))), 48, NULL), t = ui64_or(t, ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_mid)), 32, NULL)); t = ui64_or(t, ui64_n2i((unsigned long)(uuid->obj.time_low))); t_offset = ui64_s2i(UUID_TIMEOFFSET, NULL, 16); t = ui64_sub(t, t_offset, NULL); t = ui64_divn(t, 10, &t_nsec); t = ui64_divn(t, 1000000, &t_usec); t_sec = (time_t)ui64_i2n(t); tm = gmtime(&t_sec); (void)strftime(t_buf, sizeof(t_buf), "%Y-%m-%d %H:%M:%S", tm); (void)str_rsprintf(out, " content: time: %s.%06d.%d UTC\n", t_buf, t_usec, t_nsec); /* decode clock sequence */ tmp32 = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5,0)) << 8) + uuid->obj.clock_seq_low; (void)str_rsprintf(out, " clock: %ld (usually random)\n", (long)tmp32); /* decode node MAC address */ (void)str_rsprintf(out, " node: %02x:%02x:%02x:%02x:%02x:%02x (%s %s)\n", (unsigned int)uuid->obj.node[0], (unsigned int)uuid->obj.node[1], (unsigned int)uuid->obj.node[2], (unsigned int)uuid->obj.node[3], (unsigned int)uuid->obj.node[4], (unsigned int)uuid->obj.node[5], (uuid->obj.node[0] & IEEE_MAC_LOBIT ? "local" : "global"), (uuid->obj.node[0] & IEEE_MAC_MCBIT ? "multicast" : "unicast")); } else { /* decode anything else as hexadecimal byte-string only */ /* determine annotational hint */ content = "not decipherable: unknown UUID version"; if (isnil) content = "special case: DCE 1.1 Nil UUID"; else if (tmp16 == 3) content = "not decipherable: MD5 message digest only"; else if (tmp16 == 4) content = "no semantics: random data only"; else if (tmp16 == 5) content = "not decipherable: truncated SHA-1 message digest only"; /* pack UUID into binary representation */ tmp_ptr = (void *)&tmp_bin; tmp_len = sizeof(tmp_bin); if ((rc = uuid_export(uuid, UUID_FMT_BIN, &tmp_ptr, &tmp_len)) != UUID_RC_OK) return rc; /* mask out version and variant parts */ tmp_bin[6] &= BM_MASK(3,0); tmp_bin[8] &= BM_MASK(5,0); /* dump as colon-seperated hexadecimal byte-string */ (void)str_rsprintf(out, " content: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n" " (%s)\n", (unsigned int)tmp_bin[0], (unsigned int)tmp_bin[1], (unsigned int)tmp_bin[2], (unsigned int)tmp_bin[3], (unsigned int)tmp_bin[4], (unsigned int)tmp_bin[5], (unsigned int)tmp_bin[6], (unsigned int)tmp_bin[7], (unsigned int)tmp_bin[8], (unsigned int)tmp_bin[9], (unsigned int)tmp_bin[10], (unsigned int)tmp_bin[11], (unsigned int)tmp_bin[12], (unsigned int)tmp_bin[13], (unsigned int)tmp_bin[14], (unsigned int)tmp_bin[15], content); } /* provide result */ out_len = strlen(out_ptr)+1; if (*data_ptr == NULL) { *data_ptr = (void *)out_ptr; if (data_len != NULL) *data_len = out_len; } else { if (data_len == NULL) return UUID_RC_ARG; if (*data_len < out_len) return UUID_RC_MEM; memcpy(*data_ptr, out_ptr, out_len); } return UUID_RC_OK; } /* UUID importing */ uuid_rc_t uuid_import(uuid_t *uuid, uuid_fmt_t fmt, const void *data_ptr, size_t data_len) { uuid_rc_t rc; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL) return UUID_RC_ARG; /* dispatch into format-specific functions */ switch (fmt) { case UUID_FMT_BIN: rc = uuid_import_bin(uuid, data_ptr, data_len); break; case UUID_FMT_STR: rc = uuid_import_str(uuid, data_ptr, data_len); break; case UUID_FMT_SIV: rc = uuid_import_siv(uuid, data_ptr, data_len); break; case UUID_FMT_TXT: rc = UUID_RC_IMP; /* not implemented */ break; default: rc = UUID_RC_ARG; } return rc; } /* UUID exporting */ uuid_rc_t uuid_export(const uuid_t *uuid, uuid_fmt_t fmt, void *data_ptr, size_t *data_len) { uuid_rc_t rc; /* sanity check argument(s) */ if (uuid == NULL || data_ptr == NULL) return UUID_RC_ARG; /* dispatch into format-specific functions */ switch (fmt) { case UUID_FMT_BIN: rc = uuid_export_bin(uuid, data_ptr, data_len); break; case UUID_FMT_STR: rc = uuid_export_str(uuid, data_ptr, data_len); break; case UUID_FMT_SIV: rc = uuid_export_siv(uuid, data_ptr, data_len); break; case UUID_FMT_TXT: rc = uuid_export_txt(uuid, data_ptr, data_len); break; default: rc = UUID_RC_ARG; } return rc; } /* INTERNAL: brand UUID with version and variant */ static void uuid_brand(uuid_t *uuid, unsigned int version) { /* set version (as given) */ uuid->obj.time_hi_and_version &= BM_MASK(11,0); uuid->obj.time_hi_and_version |= (uuid_uint16_t)BM_SHL(version, 12); /* set variant (always DCE 1.1 only) */ uuid->obj.clock_seq_hi_and_reserved &= BM_MASK(5,0); uuid->obj.clock_seq_hi_and_reserved |= BM_SHL(0x02, 6); return; } /* INTERNAL: generate UUID version 1: time, clock and node based */ static uuid_rc_t uuid_make_v1(uuid_t *uuid, unsigned int mode, va_list ap) { struct timeval time_now; ui64_t t; ui64_t offset; ui64_t ov; uuid_uint16_t clck; /* * GENERATE TIME */ /* determine current system time and sequence counter */ for (;;) { /* determine current system time */ if (time_gettimeofday(&time_now) == -1) return UUID_RC_SYS; /* check whether system time changed since last retrieve */ if (!( time_now.tv_sec == uuid->time_last.tv_sec && time_now.tv_usec == uuid->time_last.tv_usec)) { /* reset time sequence counter and continue */ uuid->time_seq = 0; break; } /* until we are out of UUIDs per tick, increment the time/tick sequence counter and continue */ if (uuid->time_seq < UUIDS_PER_TICK) { uuid->time_seq++; break; } /* stall the UUID generation until the system clock (which has a gettimeofday(2) resolution of 1us) catches up */ time_usleep(1); } /* convert from timeval (sec,usec) to OSSP ui64 (100*nsec) format */ t = ui64_n2i((unsigned long)time_now.tv_sec); t = ui64_muln(t, 1000000, NULL); t = ui64_addn(t, (int)time_now.tv_usec, NULL); t = ui64_muln(t, 10, NULL); /* adjust for offset between UUID and Unix Epoch time */ offset = ui64_s2i(UUID_TIMEOFFSET, NULL, 16); t = ui64_add(t, offset, NULL); /* compensate for low resolution system clock by adding the time/tick sequence counter */ if (uuid->time_seq > 0) t = ui64_addn(t, (int)uuid->time_seq, NULL); /* store the 60 LSB of the time in the UUID */ t = ui64_rol(t, 16, &ov); uuid->obj.time_hi_and_version = (uuid_uint16_t)(ui64_i2n(ov) & 0x00000fff); /* 12 of 16 bit only! */ t = ui64_rol(t, 16, &ov); uuid->obj.time_mid = (uuid_uint16_t)(ui64_i2n(ov) & 0x0000ffff); /* all 16 bit */ t = ui64_rol(t, 32, &ov); uuid->obj.time_low = (uuid_uint32_t)(ui64_i2n(ov) & 0xffffffff); /* all 32 bit */ /* * GENERATE CLOCK */ /* retrieve current clock sequence */ clck = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5,0)) << 8) + uuid->obj.clock_seq_low; /* generate new random clock sequence (initially or if the time has stepped backwards) or else just increase it */ if ( clck == 0 || ( time_now.tv_sec < uuid->time_last.tv_sec || ( time_now.tv_sec == uuid->time_last.tv_sec && time_now.tv_usec < uuid->time_last.tv_usec))) { if (prng_data(uuid->prng, (void *)&clck, sizeof(clck)) != PRNG_RC_OK) return UUID_RC_INT; } else clck++; clck %= BM_POW2(14); /* store back new clock sequence */ uuid->obj.clock_seq_hi_and_reserved = (uuid->obj.clock_seq_hi_and_reserved & BM_MASK(7,6)) | (uuid_uint8_t)((clck >> 8) & 0xff); uuid->obj.clock_seq_low = (uuid_uint8_t)(clck & 0xff); /* * GENERATE NODE */ if ((mode & UUID_MAKE_MC) || (uuid->mac[0] & BM_OCTET(1,0,0,0,0,0,0,0))) { /* generate random IEEE 802 local multicast MAC address */ if (prng_data(uuid->prng, (void *)&(uuid->obj.node), sizeof(uuid->obj.node)) != PRNG_RC_OK) return UUID_RC_INT; uuid->obj.node[0] |= IEEE_MAC_MCBIT; uuid->obj.node[0] |= IEEE_MAC_LOBIT; } else { /* use real regular MAC address */ memcpy(uuid->obj.node, uuid->mac, sizeof(uuid->mac)); } /* * FINISH */ /* remember current system time for next iteration */ uuid->time_last.tv_sec = time_now.tv_sec; uuid->time_last.tv_usec = time_now.tv_usec; /* brand with version and variant */ uuid_brand(uuid, 1); return UUID_RC_OK; } /* INTERNAL: pre-defined UUID values. (defined as network byte ordered octet stream) */ #define UUID_MAKE(a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16) \ { (uuid_uint8_t)(a1), (uuid_uint8_t)(a2), (uuid_uint8_t)(a3), (uuid_uint8_t)(a4), \ (uuid_uint8_t)(a5), (uuid_uint8_t)(a6), (uuid_uint8_t)(a7), (uuid_uint8_t)(a8), \ (uuid_uint8_t)(a9), (uuid_uint8_t)(a10), (uuid_uint8_t)(a11), (uuid_uint8_t)(a12), \ (uuid_uint8_t)(a13), (uuid_uint8_t)(a14), (uuid_uint8_t)(a15), (uuid_uint8_t)(a16) } static struct { char *name; uuid_uint8_t uuid[UUID_LEN_BIN]; } uuid_value_table[] = { { "nil", /* 00000000-0000-0000-0000-000000000000 ("Nil UUID") */ UUID_MAKE(0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00) }, { "ns:DNS", /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */ UUID_MAKE(0x6b,0xa7,0xb8,0x10,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8) }, { "ns:URL", /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */ UUID_MAKE(0x6b,0xa7,0xb8,0x11,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8) }, { "ns:OID", /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */ UUID_MAKE(0x6b,0xa7,0xb8,0x12,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8) }, { "ns:X500", /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 (see RFC 4122) */ UUID_MAKE(0x6b,0xa7,0xb8,0x14,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8) } }; /* load UUID object with pre-defined value */ uuid_rc_t uuid_load(uuid_t *uuid, const char *name) { uuid_uint8_t *uuid_octets; uuid_rc_t rc; unsigned int i; /* sanity check argument(s) */ if (uuid == NULL || name == NULL) return UUID_RC_ARG; /* search for UUID in table */ uuid_octets = NULL; for (i = 0; i < (unsigned int)sizeof(uuid_value_table)/sizeof(uuid_value_table[0]); i++) { if (strcmp(uuid_value_table[i].name, name) == 0) { uuid_octets = uuid_value_table[i].uuid; break; } } if (uuid_octets == NULL) return UUID_RC_ARG; /* import value into UUID object */ if ((rc = uuid_import(uuid, UUID_FMT_BIN, uuid_octets, UUID_LEN_BIN)) != UUID_RC_OK) return rc; return UUID_RC_OK; } /* INTERNAL: generate UUID version 3: name based with MD5 */ static uuid_rc_t uuid_make_v3(uuid_t *uuid, unsigned int mode, va_list ap) { char *str; uuid_t *uuid_ns; uuid_uint8_t uuid_buf[UUID_LEN_BIN]; void *uuid_ptr; size_t uuid_len; uuid_rc_t rc; /* determine namespace UUID and name string arguments */ if ((uuid_ns = (uuid_t *)va_arg(ap, void *)) == NULL) return UUID_RC_ARG; if ((str = (char *)va_arg(ap, char *)) == NULL) return UUID_RC_ARG; /* initialize MD5 context */ if (md5_init(uuid->md5) != MD5_RC_OK) return UUID_RC_MEM; /* load the namespace UUID into MD5 context */ uuid_ptr = (void *)&uuid_buf; uuid_len = sizeof(uuid_buf); if ((rc = uuid_export(uuid_ns, UUID_FMT_BIN, &uuid_ptr, &uuid_len)) != UUID_RC_OK) return rc; if (md5_update(uuid->md5, uuid_buf, uuid_len) != MD5_RC_OK) return UUID_RC_INT; /* load the argument name string into MD5 context */ if (md5_update(uuid->md5, str, strlen(str)) != MD5_RC_OK) return UUID_RC_INT; /* store MD5 result into UUID (requires MD5_LEN_BIN space, UUID_LEN_BIN space is available, and both are equal in size, so we are safe!) */ uuid_ptr = (void *)&(uuid->obj); if (md5_store(uuid->md5, &uuid_ptr, NULL) != MD5_RC_OK) return UUID_RC_INT; /* fulfill requirement of standard and convert UUID data into local/host byte order (this uses fact that uuid_import_bin() is able to operate in-place!) */ if ((rc = uuid_import(uuid, UUID_FMT_BIN, (void *)&(uuid->obj), UUID_LEN_BIN)) != UUID_RC_OK) return rc; /* brand UUID with version and variant */ uuid_brand(uuid, 3); return UUID_RC_OK; } /* INTERNAL: generate UUID version 4: random number based */ static uuid_rc_t uuid_make_v4(uuid_t *uuid, unsigned int mode, va_list ap) { /* fill UUID with random data */ if (prng_data(uuid->prng, (void *)&(uuid->obj), sizeof(uuid->obj)) != PRNG_RC_OK) return UUID_RC_INT; /* brand UUID with version and variant */ uuid_brand(uuid, 4); return UUID_RC_OK; } /* INTERNAL: generate UUID version 5: name based with SHA-1 */ static uuid_rc_t uuid_make_v5(uuid_t *uuid, unsigned int mode, va_list ap) { char *str; uuid_t *uuid_ns; uuid_uint8_t uuid_buf[UUID_LEN_BIN]; void *uuid_ptr; size_t uuid_len; uuid_uint8_t sha1_buf[SHA1_LEN_BIN]; void *sha1_ptr; uuid_rc_t rc; /* determine namespace UUID and name string arguments */ if ((uuid_ns = (uuid_t *)va_arg(ap, void *)) == NULL) return UUID_RC_ARG; if ((str = (char *)va_arg(ap, char *)) == NULL) return UUID_RC_ARG; /* initialize SHA-1 context */ if (sha1_init(uuid->sha1) != SHA1_RC_OK) return UUID_RC_INT; /* load the namespace UUID into SHA-1 context */ uuid_ptr = (void *)&uuid_buf; uuid_len = sizeof(uuid_buf); if ((rc = uuid_export(uuid_ns, UUID_FMT_BIN, &uuid_ptr, &uuid_len)) != UUID_RC_OK) return rc; if (sha1_update(uuid->sha1, uuid_buf, uuid_len) != SHA1_RC_OK) return UUID_RC_INT; /* load the argument name string into SHA-1 context */ if (sha1_update(uuid->sha1, str, strlen(str)) != SHA1_RC_OK) return UUID_RC_INT; /* store SHA-1 result into UUID (requires SHA1_LEN_BIN space, but UUID_LEN_BIN space is available only, so use a temporary buffer to store SHA-1 results and then use lower part only according to standard */ sha1_ptr = (void *)sha1_buf; if (sha1_store(uuid->sha1, &sha1_ptr, NULL) != SHA1_RC_OK) return UUID_RC_INT; uuid_ptr = (void *)&(uuid->obj); memcpy(uuid_ptr, sha1_ptr, UUID_LEN_BIN); /* fulfill requirement of standard and convert UUID data into local/host byte order (this uses fact that uuid_import_bin() is able to operate in-place!) */ if ((rc = uuid_import(uuid, UUID_FMT_BIN, (void *)&(uuid->obj), UUID_LEN_BIN)) != UUID_RC_OK) return rc; /* brand UUID with version and variant */ uuid_brand(uuid, 5); return UUID_RC_OK; } /* generate UUID */ uuid_rc_t uuid_make(uuid_t *uuid, unsigned int mode, ...) { va_list ap; uuid_rc_t rc; /* sanity check argument(s) */ if (uuid == NULL) return UUID_RC_ARG; /* dispatch into version dependent generation functions */ va_start(ap, mode); if (mode & UUID_MAKE_V1) rc = uuid_make_v1(uuid, mode, ap); else if (mode & UUID_MAKE_V3) rc = uuid_make_v3(uuid, mode, ap); else if (mode & UUID_MAKE_V4) rc = uuid_make_v4(uuid, mode, ap); else if (mode & UUID_MAKE_V5) rc = uuid_make_v5(uuid, mode, ap); else rc = UUID_RC_ARG; va_end(ap); return rc; } /* translate UUID API error code into corresponding error string */ char *uuid_error(uuid_rc_t rc) { char *str; switch (rc) { case UUID_RC_OK: str = "everything ok"; break; case UUID_RC_ARG: str = "invalid argument"; break; case UUID_RC_MEM: str = "out of memory"; break; case UUID_RC_SYS: str = "system error"; break; case UUID_RC_INT: str = "internal error"; break; case UUID_RC_IMP: str = "not implemented"; break; default: str = NULL; break; } return str; } /* OSSP uuid version (link-time information) */ unsigned long uuid_version(void) { return (unsigned long)(_UUID_VERSION); } @ 1.67 log @1. Remove unused "struct timezone" from time_gettimeofday() in order to simplify portability. 2. Add support for POSIX clock_gettime(3) in case the Unix/POSIX gettimeofday(3) is not available. @ text @@ 1.66 log @Port to Win32 API @ text @d889 1 a889 1 if (time_gettimeofday(&time_now, NULL) == -1) @ 1.65 log @adjust copyright messages for 2008 and bump version in advance @ text @d52 1 a876 5 #ifdef HAVE_NANOSLEEP struct timespec ts; #else struct timeval tv; #endif d889 1 a889 1 if (gettimeofday(&time_now, NULL) == -1) d909 1 a909 11 #ifdef HAVE_NANOSLEEP /* sleep for 500ns (1/2us) */ ts.tv_sec = 0; ts.tv_nsec = 500; nanosleep(&ts, NULL); #else /* sleep for 1000ns (1us) */ tv.tv_sec = 0; tv.tv_usec = 1; select(0, NULL, NULL, NULL, &tv); #endif @ 1.64 log @Adjust copyright messages for new year 2007. @ text @d3 2 a4 2 ** Copyright (c) 2004-2007 Ralf S. Engelschall ** Copyright (c) 2004-2007 The OSSP Project @ 1.63 log @Change type of "data_ptr" argument in uuid_export() API signature from "void **" to "void *" as there is unfortunately no "generic pointer to pointer type" in ISO C (see also http://c-faq.com/ptrs/genericpp.html) and "void **" is just a "pointer to a 'void *'". The "void **" especially had the nasty side-effect that it breaks strict pointer aliasing rules of ISO C and hence would require fiddling with temporary variables on all uuid_export() calls if one would be 100% correct and avoid aliasing related compiler warnings. Instead, as uuid_export() internally has to cast the "data_ptr" to the particular expected type anyway, it is better to have "data_ptr" just be a really generic "void *" in the API signature. Keep in mind that although this is an API change, it doesn't cause any incompatibilities as the function still expects the same "pointer to a pointer of a particular type". This expected pointer is just now passed the more correct although less intuitive way. Submitted by: Hrvoje Niksic @ text @d3 2 a4 2 ** Copyright (c) 2004-2006 Ralf S. Engelschall ** Copyright (c) 2004-2006 The OSSP Project @ 1.62 log @Optional DMALLOC based memory debugging support. @ text @d331 1 a331 1 static uuid_rc_t uuid_export_bin(const uuid_t *uuid, void **data_ptr, size_t *data_len) d333 1 d339 3 d348 1 a348 1 if ((*data_ptr = malloc(sizeof(uuid_t))) == NULL) d362 1 a362 1 out = (uuid_uint8_t *)(*data_ptr); d499 1 a499 1 static uuid_rc_t uuid_export_str(const uuid_t *uuid, void **data_ptr, size_t *data_len) d501 1 d504 3 d554 1 a554 1 static uuid_rc_t uuid_export_siv(const uuid_t *uuid, void **data_ptr, size_t *data_len) d556 1 d565 3 d636 1 a636 1 static uuid_rc_t uuid_export_txt(const uuid_t *uuid, void **data_ptr, size_t *data_len) d638 1 d664 3 d839 1 a839 1 uuid_rc_t uuid_export(const uuid_t *uuid, uuid_fmt_t fmt, void **data_ptr, size_t *data_len) @ 1.61 log @Even more pendantic code cleanups according to complains by SPLINT @ text @a30 1 #include "config.h" d32 1 @ 1.60 log @Fixed potential memory leak in uuid_create() as spotted by SPLINT. @ text @d108 1 a108 1 /* create PRNG sub-object */ a112 2 /* create MD5 sub-object */ d114 1 a114 1 prng_destroy(obj->prng); a117 2 /* create SHA1 sub-object */ d119 2 a120 2 md5_destroy(obj->md5); prng_destroy(obj->prng); d126 7 a132 1 uuid_load(obj, "nil"); d136 1 a136 1 memset(obj->mac, '\0', sizeof(obj->mac)); d159 3 a161 3 prng_destroy(uuid->prng); md5_destroy(uuid->md5); sha1_destroy(uuid->sha1); d186 2 a187 1 if (prng_create(&obj->prng) != PRNG_RC_OK) d189 4 a192 1 if (md5_create(&obj->md5) != MD5_RC_OK) d194 5 a198 1 if (sha1_create(&obj->sha1) != SHA1_RC_OK) d200 1 d221 1 a221 1 if (*ucp++ != '\0') { d300 4 a303 4 tmp32 = *in++; tmp32 = (tmp32 << 8) | *in++; tmp32 = (tmp32 << 8) | *in++; tmp32 = (tmp32 << 8) | *in++; d307 2 a308 2 tmp16 = *in++; tmp16 = (uuid_uint16_t)(tmp16 << 8) | *in++; d312 2 a313 2 tmp16 = *in++; tmp16 = (uuid_uint16_t)(tmp16 << 8) | *in++; d323 1 a323 1 for (i = 0; i < sizeof(uuid->obj.node); i++) d384 1 a384 1 for (i = 0; i < sizeof(uuid->obj.node); i++) d450 1 a450 1 for (i = 0; i < sizeof(uuid->obj.node); i++) { d465 1 d474 1 a474 1 for (i = 0; i < data_len; i++) d488 2 a489 1 uuid_import(uuid, UUID_FMT_BIN, (void *)&tmp_bin, UUID_LEN_BIN); d579 3 a581 1 if ((rc = uuid_export(uuid, UUID_FMT_BIN, &tmp_ptr, &tmp_len)) != UUID_RC_OK) d583 1 d594 1 a594 1 ui128_i2s(ui, data_buf, UUID_LEN_SIV+1, 10); d608 4 a611 4 { BM_OCTET(0,0,0,0,0,0,0,0), "reserved (NCS backward compatible)" }, { BM_OCTET(1,0,0,0,0,0,0,0), "DCE 1.1, ISO/IEC 11578:1996" }, { BM_OCTET(1,1,0,0,0,0,0,0), "reserved (Microsoft GUID)" }, { BM_OCTET(1,1,1,0,0,0,0,0), "reserved (future use)" } d672 2 a673 2 str_rsprintf(out, "encode: STR: %s\n", tmp_str); str_rsprintf(out, " SIV: %s\n", tmp_siv); d682 2 a683 2 if ((tmp8 & BM_BIT(i,1)) == 0) { tmp8 &= ~BM_MASK(i,0); d694 1 a694 1 str_rsprintf(out, "decode: variant: %s\n", variant); d697 1 a697 1 tmp16 = (BM_SHR(uuid->obj.time_hi_and_version, 12) & BM_MASK(3,0)); d728 2 a729 2 strftime(t_buf, sizeof(t_buf), "%Y-%m-%d %H:%M:%S", tm); str_rsprintf(out, " content: time: %s.%06d.%d UTC\n", t_buf, t_usec, t_nsec); d734 1 a734 1 str_rsprintf(out, " clock: %ld (usually random)\n", (long)tmp32); d737 1 a737 1 str_rsprintf(out, " node: %02x:%02x:%02x:%02x:%02x:%02x (%s %s)\n", d772 1 a772 1 str_rsprintf(out, d949 4 a952 2 && time_now.tv_usec < uuid->time_last.tv_usec))) prng_data(uuid->prng, (void *)&clck, sizeof(clck)); d996 5 d1006 1 a1006 1 { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, d1008 1 a1008 1 { 0x6b,0xa7,0xb8,0x10,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8 } }, d1010 1 a1010 1 { 0x6b,0xa7,0xb8,0x11,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8 } }, d1012 1 a1012 1 { 0x6b,0xa7,0xb8,0x12,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8 } }, d1014 1 a1014 1 { 0x6b,0xa7,0xb8,0x14,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8 } } d1030 1 a1030 1 for (i = 0; i < sizeof(uuid_value_table)/sizeof(uuid_value_table[0]); i++) { d1054 1 d1069 4 a1072 2 uuid_export(uuid_ns, UUID_FMT_BIN, &uuid_ptr, &uuid_len); md5_update(uuid->md5, uuid_buf, uuid_len); d1075 2 a1076 1 md5_update(uuid->md5, str, strlen(str)); d1082 2 a1083 1 md5_store(uuid->md5, &uuid_ptr, NULL); d1088 2 a1089 1 uuid_import(uuid, UUID_FMT_BIN, (void *)&(uuid->obj), UUID_LEN_BIN); d1101 2 a1102 1 prng_data(uuid->prng, (void *)&(uuid->obj), sizeof(uuid->obj)); d1120 1 d1130 1 a1130 1 return UUID_RC_MEM; d1135 4 a1138 2 uuid_export(uuid_ns, UUID_FMT_BIN, &uuid_ptr, &uuid_len); sha1_update(uuid->sha1, uuid_buf, uuid_len); d1141 2 a1142 1 sha1_update(uuid->sha1, str, strlen(str)); d1149 2 a1150 1 sha1_store(uuid->sha1, &sha1_ptr, NULL); d1157 2 a1158 1 uuid_import(uuid, UUID_FMT_BIN, (void *)&(uuid->obj), UUID_LEN_BIN); @ 1.59 log @Add full support for Single Integer Value (SIV) UUID representation for both importing and exporting in C/C++/Perl/PHP APIs. @ text @d108 3 a110 2 /* create PRNG, MD5 and SHA1 sub-objects */ if (prng_create(&obj->prng) != PRNG_RC_OK) d112 6 a117 1 if (md5_create(&obj->md5) != MD5_RC_OK) d119 7 a125 1 if (sha1_create(&obj->sha1) != SHA1_RC_OK) d127 1 @ 1.58 log @Apply workaround to uuid.h to avoid conflicts with vendor UUID implementations where uuid_t (Darwin / MacOS X) or uuid_create/uuid_compare (POSIX) might exist. Supported by: SpaceNet (MacOS X platform) @ text @d53 1 d435 33 d519 55 d610 1 d634 1 a634 1 /* decode into string representation */ d639 6 a644 1 str_rsprintf(out, "UUID: %s\n", tmp_str); d665 1 a665 1 str_rsprintf(out, "variant: %s\n", variant); d680 1 a680 1 str_rsprintf(out, "version: %d (%s)\n", (int)tmp16, version); d700 1 a700 1 str_rsprintf(out, "content: time: %s.%06d.%d UTC\n", t_buf, t_usec, t_nsec); d705 1 a705 1 str_rsprintf(out, " clock: %ld (usually random)\n", (long)tmp32); d708 1 a708 1 str_rsprintf(out, " node: %02x:%02x:%02x:%02x:%02x:%02x (%s %s)\n", d744 2 a745 2 "content: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n" " (%s)\n", d785 1 d806 1 @ 1.57 log @Adjust copyright messages for new year 2006. @ text @d30 4 d46 1 a46 3 /* own headers */ #include "config.h" #include "uuid.h" @ 1.56 log @Fix two incorrect casts, detected by compiling the C code under C++ constraints. @ text @d3 2 a4 2 ** Copyright (c) 2004-2005 Ralf S. Engelschall ** Copyright (c) 2004-2005 The OSSP Project @ 1.55 log @fix uuid_clone() function @ text @d443 1 a443 1 if ((data_buf = (void *)malloc(UUID_LEN_STR+1)) == NULL) @ 1.54 log @constifiy uuid_clone() @ text @d165 1 a165 1 memcpy(obj, uuid, sizeof(uuid)); @ 1.53 log @Cleanup the internals of the uuid_create() function and add a new corresponding uuid_clone() API function. @ text @d152 1 a152 1 uuid_rc_t uuid_clone(uuid_t *uuid, uuid_t **clone) @ 1.52 log @Reference the new officially published RFC 4122 @ text @d95 2 d102 1 a102 1 if ((*uuid = (uuid_t *)malloc(sizeof(uuid_t))) == NULL) d105 2 a106 5 /* set UUID object initially to "Nil UUID" */ uuid_load(*uuid, "nil"); /* create PRNG and MD5 sub-objects */ if (prng_create(&(*uuid)->prng) != PRNG_RC_OK) d108 1 a108 1 if (md5_create(&(*uuid)->md5) != MD5_RC_OK) d110 1 a110 1 if (sha1_create(&(*uuid)->sha1) != SHA1_RC_OK) d113 3 d117 3 a119 3 if (!mac_address((unsigned char *)((*uuid)->mac), sizeof((*uuid)->mac))) { memset((*uuid)->mac, '\0', sizeof((*uuid)->mac)); (*uuid)->mac[0] = BM_OCTET(1,0,0,0,0,0,0,0); d123 6 a128 3 (*uuid)->time_last.tv_sec = 0; (*uuid)->time_last.tv_usec = 0; (*uuid)->time_seq = 0; d151 30 @ 1.51 log @Cleanup the source code even more by following a large set of FlexeLint's suggestions. @ text @d837 1 a837 1 { "ns:DNS", /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 (see draft-leach-uuids-guids-01.txt) */ d839 1 a839 1 { "ns:URL", /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 (see draft-leach-uuids-guids-01.txt) */ d841 1 a841 1 { "ns:OID", /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 (see draft-leach-uuids-guids-01.txt) */ d843 1 a843 1 { "ns:X500", /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 (see draft-leach-uuids-guids-01.txt) */ @ 1.50 log @Added support for new version 5 UUIDs (name-based, SHA-1) according to latest draft-mealling-uuid-urn-05.txt. @ text @a36 1 #include d147 1 a147 1 uuid_rc_t uuid_isnil(uuid_t *uuid, int *result) d169 1 a169 1 uuid_rc_t uuid_compare(uuid_t *uuid1, uuid_t *uuid2, int *result) d178 2 a179 1 # define RESULT(r) \ d183 2 a184 1 } while (0) d192 1 a192 1 RESULT((uuid_isnil(uuid2, &r), r) ? 0 : -1); d194 1 a194 1 RESULT((uuid_isnil(uuid1, &r), r) ? 0 : 1); d246 1 a246 1 tmp16 = (tmp16 << 8) | *in++; d251 1 a251 1 tmp16 = (tmp16 << 8) | *in++; d269 1 a269 1 static uuid_rc_t uuid_export_bin(uuid_t *uuid, void **data_ptr, size_t *data_len) d391 1 a391 1 uuid->obj.node[i] = strtoul(hexbuf, NULL, 16); d398 1 a398 1 static uuid_rc_t uuid_export_str(uuid_t *uuid, void **data_ptr, size_t *data_len) d400 2 d406 1 a406 1 /* allocate output buffer */ d408 1 a408 1 if ((*data_ptr = (void *)malloc(UUID_LEN_STR+1)) == NULL) d414 1 d423 1 a423 1 str_snprintf((char *)(*data_ptr), UUID_LEN_STR+1, d435 9 a443 1 (unsigned int)uuid->obj.node[5]); d469 1 a469 1 static uuid_rc_t uuid_export_txt(uuid_t *uuid, void **data_ptr, size_t *data_len) d661 1 a661 1 uuid_rc_t uuid_export(uuid_t *uuid, uuid_fmt_t fmt, void **data_ptr, size_t *data_len) d681 1 a681 1 static void uuid_brand(uuid_t *uuid, int version) d685 1 a685 1 uuid->obj.time_hi_and_version |= BM_SHL((uuid_uint16_t)version, 12); d712 1 a712 1 while (1) { d748 1 a748 1 t = ui64_n2i(time_now.tv_sec); d750 1 a750 1 t = ui64_addn(t, time_now.tv_usec, NULL); d760 1 a760 1 t = ui64_addn(t, uuid->time_seq, NULL); d805 2 a806 1 prng_data(uuid->prng, (void *)&(uuid->obj.node), sizeof(uuid->obj.node)); d951 1 a951 1 if (sha1_init(uuid->sha1) != MD5_RC_OK) @ 1.49 log @Adjust copyright messages for new year 2005. @ text @d48 1 d87 1 d112 2 d136 1 a136 1 /* destroy PRNG and MD5 sub-objects */ d139 1 d451 3 a453 2 { 3, "name based" }, { 4, "random data based" } d578 1 a578 1 content = "not decipherable, because unknown UUID version"; d580 1 a580 1 content = "special case of DCE 1.1 Nil UUID"; d582 1 a582 1 content = "not decipherable, because message digest only"; d584 3 a586 1 content = "no semantics, because random data only"; d863 1 a863 1 /* INTERNAL: generate UUID version 3: name based */ d920 50 d988 2 @ 1.48 log @Remove some warnings occurring under GCC 3.5 @ text @d3 2 a4 2 ** Copyright (c) 2004 Ralf S. Engelschall ** Copyright (c) 2004 The OSSP Project @ 1.47 log @correct spelling: privileges, convenient; @ text @d475 1 a475 1 unsigned int i; d508 1 a508 1 for (i = 0; i < sizeof(uuid_dectab_variant)/sizeof(uuid_dectab_variant[0]); i++) { d523 1 a523 1 for (i = 0; i < sizeof(uuid_dectab_version)/sizeof(uuid_dectab_version[0]); i++) { @ 1.46 log @- Resolve namespace conflicts with GCC 3.4 internal pow10() and round() functions within uuid_str.c. - Fix buffer handling in "uuid_export(..., UUID_FMT_TXT, vp, ...)" in case "vp" is not NULL. Partly submitted by: Fuyuki @ text @d173 1 a173 1 /* convinience macro for setting result */ @ 1.45 log @remove --with-rfc2518 option and functionality because even the IETF/IESG has finally approved our report about the broken random multicast MAC address generation in the standard (and will fix it in new versions of the draft-mealling-uuid-urn). So, finally get rid of this broken-by-design backward compatibility @ text @d614 1 a614 1 memcpy(*data_ptr, &out_ptr, out_len); @ 1.44 log @nanosecond calculations are correct. Nevertheless start counting from 0 because it looks better ;-) @ text @d64 3 a66 63 /* IEEE 802 MAC address encoding/decoding bit fields ATTENTION: In case no real/physical IEEE 802 address is available, both "draft-leach-uuids-guids-01" (section "4. Node IDs when no IEEE 802 network card is available") and RFC 2518 (section "6.4.1 Node Field Generation Without the IEEE 802 Address") recommend (quoted from RFC 2518): "The ideal solution is to obtain a 47 bit cryptographic quality random number, and use it as the low 47 bits of the node ID, with the most significant bit of the first octet of the node ID set to 1. This bit is the unicast/multicast bit, which will never be set in IEEE 802 addresses obtained from network cards; hence, there can never be a conflict between UUIDs generated by machines with and without network cards." This passage clearly explains the intention to use IEEE 802 multicast addresses. Unfortunately, it incorrectly explains how to implement this! It should instead specify the "*LEAST* significant bit of the first octet of the node ID" as the multicast bit in a memory and hexadecimal string representation of a 48-bit IEEE 802 MAC address. Unfortunately, even the reference implementation included in the expired IETF "draft-leach-uuids-guids-01" incorrectly set the multicast bit with an OR bit operation and an incorrect mask of 0x80. Hence, several other UUID implementations found on the Internet have inherited this bug. Luckily, neither DCE 1.1 nor ISO/IEC 11578:1996 are affected by this problem. They disregard the topic of missing IEEE 802 addresses entirely, and thus avoid adopting this bug from the original draft and code ;-) It seems that this standards bug arises from a false interpretation, as the multicast bit is actually the *MOST* significant bit in IEEE 802.3 (Ethernet) _transmission order_ of an IEEE 802 MAC address. The authors were likely not aware that the bitwise order of an octet from a MAC address memory and hexadecimal string representation is still always from left (MSB, bit 7) to right (LSB, bit 0). For more information, see "Understanding Physical Addresses" in "Ethernet -- The Definitive Guide", p.43, and the section "ETHERNET MULTICAST ADDRESSES" in http://www.iana.org/assignments/ethernet-numbers. At OSSP, we do it the intended/correct way and generate a real IEEE 802 multicast address. Those wanting to encode broken IEEE 802 MAC addresses (as specified) can nevertheless use a brain dead compile-time option to switch off the correct behavior. When decoding we always use the correct behavior of course. */ /* encoding */ #ifdef WITH_RFC2518 #define IEEE_MAC_MCBIT_ENC BM_OCTET(1,0,0,0,0,0,0,0) #else #define IEEE_MAC_MCBIT_ENC BM_OCTET(0,0,0,0,0,0,0,1) #endif #define IEEE_MAC_LOBIT_ENC BM_OCTET(0,0,0,0,0,0,1,0) /* decoding */ #define IEEE_MAC_MCBIT_DEC BM_OCTET(0,0,0,0,0,0,0,1) #define IEEE_MAC_LOBIT_DEC BM_OCTET(0,0,0,0,0,0,1,0) d565 2 a566 2 (uuid->obj.node[0] & IEEE_MAC_LOBIT_DEC ? "local" : "global"), (uuid->obj.node[0] & IEEE_MAC_MCBIT_DEC ? "multicast" : "unicast")); d786 2 a787 2 uuid->obj.node[0] |= IEEE_MAC_MCBIT_ENC; uuid->obj.node[0] |= IEEE_MAC_LOBIT_ENC; @ 1.43 log @flush more pending cleanups @ text @d759 2 a760 2 && time_now.tv_usec == uuid->time_last.tv_usec)) /* reset time sequence counter */ d762 2 @ 1.42 log @remove doubled 'is' and reformat with par(1) @ text @d841 1 a841 1 if ((mode & UUID_MCASTRND) || (uuid->mac[0] & BM_OCTET(1,0,0,0,0,0,0,0))) { d982 1 a982 1 if (mode & UUID_VERSION1) d984 1 a984 1 else if (mode & UUID_VERSION3) d986 1 a986 1 else if (mode & UUID_VERSION4) d1005 2 @ 1.41 log @o Include in uuid.h because of size_t usage. o INCOMPATIBILITY: Refactor the API and rename uuid_generate() to uuid_make() and use a "uuid_t" pointer for the namespace on UUID_VERSION3 generation. To allow access to the internal pre-defined namespace UUIDs, provide a new uuid_load() function. Because uuid_load() now also allows the loading of the "nil" UUID, remove uuid_nil() from the API. After this second refactoring the API is now the one we originally wished for the forthcoming version 1.0 of OSSP uuid. @ text @d100 5 a104 5 as the multicast bit is actually is the *MOST* significant bit in IEEE 802.3 (Ethernet) _transmission order_ of an IEEE 802 MAC address. The authors were likely not aware that the bitwise order of an octet from a MAC address memory and hexadecimal string representation is still always from left (MSB, bit 7) to right (LSB, bit 0). d110 5 a114 5 At OSSP, we do it the intended/correct way and generate a real IEEE 802 multicast address. Those wanting to encode broken IEEE 802 MAC addresses (as specified) can nevertheless use a brain dead compile-time option to switch off the correct behavior. When decoding we always use the correct behavior of course. */ @ 1.40 log @edited comments for grammar and usage corrections, and formatted text as well @ text @d163 1 a163 1 uuid_nil(*uuid); d734 1 a734 1 static uuid_rc_t uuid_generate_v1(uuid_t *uuid, unsigned int mode, va_list ap) d866 2 a867 15 /* set UUID object to represents "Nil UUID" */ uuid_rc_t uuid_nil(uuid_t *uuid) { /* argument sanity check */ if (uuid == NULL) return UUID_RC_ARG; /* clear all octets to create "Nil UUID" */ memset((void *)&(uuid->obj), '\0', sizeof(uuid->obj)); return UUID_RC_OK; } /* INTERNAL: UUID Namespace Ids as pre-defined by draft-leach-uuids-guids-01.txt (defined here as network byte ordered octet stream for direct MD5 feeding) */ d871 4 a874 2 } uuid_ns_table[] = { { "DNS", /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 */ d876 1 a876 1 { "URL", /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 */ d878 1 a878 1 { "OID", /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 */ d880 1 a880 1 { "X500", /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 */ d884 29 d914 1 a914 1 static uuid_rc_t uuid_generate_v3(uuid_t *uuid, unsigned int mode, va_list ap) d917 4 a920 5 char *ns; void *uuid_octets; uuid_t *uuid_object; uuid_rc_t rc; unsigned int i; d922 2 a923 2 /* determine namespace UUID name and argument name string */ if ((ns = (char *)va_arg(ap, char *)) == NULL) d933 4 a936 24 if (uuid_isstr(ns, 0)) { /* custom namespace via UUID string representation */ if ((rc = uuid_create(&uuid_object)) != UUID_RC_OK) return rc; if ((rc = uuid_import(uuid_object, UUID_FMT_STR, ns, strlen(ns))) != UUID_RC_OK) return rc; uuid_octets = (void *)&(uuid_object->obj); uuid_export(uuid_object, UUID_FMT_BIN, &uuid_octets, NULL); md5_update(uuid->md5, uuid_octets, UUID_LEN_BIN); uuid_destroy(uuid_object); } else { /* standard namespace via UUID namespace id */ uuid_octets = NULL; for (i = 0; i < sizeof(uuid_ns_table)/sizeof(uuid_ns_table[0]); i++) { if (strcmp(uuid_ns_table[i].name, ns) == 0) { uuid_octets = uuid_ns_table[i].uuid; break; } } if (uuid_octets == NULL) return UUID_RC_ARG; md5_update(uuid->md5, uuid_octets, UUID_LEN_BIN); } d944 2 a945 2 uuid_octets = (void *)&(uuid->obj); md5_store(uuid->md5, &uuid_octets, NULL); d959 1 a959 1 static uuid_rc_t uuid_generate_v4(uuid_t *uuid, unsigned int mode, va_list ap) d971 1 a971 1 uuid_rc_t uuid_generate(uuid_t *uuid, unsigned int mode, ...) d983 1 a983 1 rc = uuid_generate_v1(uuid, mode, ap); d985 1 a985 1 rc = uuid_generate_v3(uuid, mode, ap); d987 1 a987 1 rc = uuid_generate_v4(uuid, mode, ap); @ 1.39 log @use meta-API also internally to be consistent @ text @d82 1 a82 1 This clearly explains that the intention is to use IEEE 802 multicast d84 3 a86 3 this! It actually is the "*LEAST* significant bit of the first octet of the node ID" in a memory and hexadecimal string representation of a 48-bit IEEE 802 MAC address. d91 2 a92 2 0x80. Hence, multiple other UUID implementations can be found on the Internet which inherited this bug. d99 6 a104 7 The reason for the bug in the standards seems to be that the multicast bit actually is the *MOST* significant bit in IEEE 802.3 (Ethernet) _transmission order_ of an IEEE 802 MAC address. The authors seem to be confused by this and especially were not aware that the bitwise order of an octet from a MAC address memory and hexadecimal string representation is still always from left (MSB, bit 7) to right (LSB, bit 0). d106 3 a108 4 For more information on this, see especially "Understanding Physical Addresses" in "Ethernet -- The Definitive Guide", p.43, and section "ETHERNET MULTICAST ADDRESSES" in http://www.iana.org/assignments/ethernet-numbers. d110 5 a114 4 Hence, we do it the intended/correct way and generate a real IEEE 802 multicast address, but with a brain-dead compile-time option one can nevertheless enforce the broken generation of IEEE 802 MAC addresses. For the decoding we always use the correct way, of course. */ @ 1.38 log @fix typos @ text @d644 1 a644 1 if ((rc = uuid_export_bin(uuid, &tmp_ptr, &tmp_len)) != UUID_RC_OK) d921 1 a921 1 if ((rc = uuid_import_str(uuid_object, ns, strlen(ns))) != UUID_RC_OK) d924 1 a924 1 uuid_export_bin(uuid_object, &uuid_octets, NULL); d954 1 a954 1 uuid_import_bin(uuid, (void *)&(uuid->obj), UUID_LEN_BIN); @ 1.37 log @Add version support to API via UUID_VERSION (compile-time) and uuid_version() (link-time). @ text @d289 1 a289 1 /* treat input data_ptrfer as octet stream */ d335 1 a335 1 /* optionally allocate octet data_ptrfer */ d350 1 a350 1 /* treat output data_ptrfer as octet stream */ @ 1.36 log @- Refactor the API by merging uuid_{unpack,pack,parse,format,dump}() functions into unified uuid_{import,export}() functions. This allows us to easily add support for other formats (e.g. XML) in the future without having the change the API in principle. - Document what DCE 1.1 UUID versions exist and what they are intended for. @ text @d46 1 d1012 6 @ 1.35 log @- Cleanup the C code to also pass warning-free a C++ compiler. - Support C++ by enclosing the C API declarations in 'extern "C" {...}' within uuid.h. Submitted by: Guerry Semones @ text @d54 74 d129 1 a129 1 #define MAC_OCTETS 6 d138 1 a138 1 uuid_uint8_t node[MAC_OCTETS]; /* bits 0-47 of node MAC address */ d146 1 a146 1 uuid_uint8_t mac[MAC_OCTETS]; /* pre-determined MAC address */ a201 13 /* set UUID object to represents "Nil UUID" */ uuid_rc_t uuid_nil(uuid_t *uuid) { /* argument sanity check */ if (uuid == NULL) return UUID_RC_ARG; /* clear all octets to create "Nil UUID" */ memset((void *)&(uuid->obj), '\0', sizeof(uuid->obj)); return UUID_RC_OK; } d275 1 a275 1 /* unpack UUID binary presentation into UUID object d277 1 a277 1 uuid_rc_t uuid_unpack(uuid_t *uuid, const void *buf) d285 1 a285 1 if (uuid == NULL || buf == NULL) d288 2 a289 2 /* treat input buffer as octet stream */ in = (const uuid_uint8_t *)buf; d321 1 a321 1 /* pack UUID object into binary representation d323 1 a323 1 uuid_rc_t uuid_pack(uuid_t *uuid, void **buf) d331 1 a331 1 if (uuid == NULL || buf == NULL) d334 11 a344 3 /* optionally allocate octet buffer */ if (*buf == NULL) if ((*buf = malloc(sizeof(uuid_t))) == NULL) d346 2 d349 2 a350 2 /* treat output buffer as octet stream */ out = (uuid_uint8_t *)(*buf); d411 2 a412 2 /* parse string representation into UUID object */ uuid_rc_t uuid_parse(uuid_t *uuid, const char *str) d417 1 d421 1 a421 1 if (uuid == NULL || str == NULL) d425 1 d451 2 a452 2 /* format UUID object into string representation */ uuid_rc_t uuid_format(uuid_t *uuid, char **str) d455 1 a455 1 if (uuid == NULL || str == NULL) d458 11 a468 3 /* optionally allocate string buffer */ if (*str == NULL) if ((*str = (char *)malloc(UUID_LEN_STR+1)) == NULL) d470 2 d474 1 a474 1 str_snprintf(*str, UUID_LEN_STR+1, d491 21 a511 2 /* INTERNAL: brand UUID with version and variant */ static void uuid_brand(uuid_t *uuid, int version) d513 126 a638 3 /* set version (as given) */ uuid->obj.time_hi_and_version &= BM_MASK(11,0); uuid->obj.time_hi_and_version |= BM_SHL((uuid_uint16_t)version, 12); d640 5 a644 5 /* set variant (always DCE 1.1 only) */ uuid->obj.clock_seq_hi_and_reserved &= BM_MASK(5,0); uuid->obj.clock_seq_hi_and_reserved |= BM_SHL(0x02, 6); return; } d646 3 a648 3 /* maximum number of 100ns ticks of the actual resolution of system clock (which in our case is 1us (= 1000ns) because we use gettimeofday(2) */ #define UUIDS_PER_TICK 10 d650 11 a660 4 /* time offset between UUID and Unix Epoch time according to standards. (UUID UTC base time is October 15, 1582 Unix UTC base time is January 1, 1970) */ #define UUID_TIMEOFFSET "01B21DD213814000" d662 14 a675 1 /* IEEE 802 MAC address encoding/decoding bit fields d677 2 a678 1 ATTENTION: d680 4 a683 5 In case no real/physical IEEE 802 address is available, both "draft-leach-uuids-guids-01" (section "4. Node IDs when no IEEE 802 network card is available") and RFC 2518 (section "6.4.1 Node Field Generation Without the IEEE 802 Address") recommend (quoted from RFC 2518): d685 3 a687 7 "The ideal solution is to obtain a 47 bit cryptographic quality random number, and use it as the low 47 bits of the node ID, with the most significant bit of the first octet of the node ID set to 1. This bit is the unicast/multicast bit, which will never be set in IEEE 802 addresses obtained from network cards; hence, there can never be a conflict between UUIDs generated by machines with and without network cards." d689 7 a695 5 This clearly explains that the intention is to use IEEE 802 multicast addresses. Unfortunately, it incorrectly explains how to implement this! It actually is the "*LEAST* significant bit of the first octet of the node ID" in a memory and hexadecimal string representation of a 48-bit IEEE 802 MAC address. d697 2 a698 5 Unfortunately, even the reference implementation included in the expired IETF "draft-leach-uuids-guids-01" incorrectly set the multicast bit with an OR bit operation and an incorrect mask of 0x80. Hence, multiple other UUID implementations can be found on the Internet which inherited this bug. d700 4 a703 4 Luckily, neither DCE 1.1 nor ISO/IEC 11578:1996 are affected by this problem. They disregard the topic of missing IEEE 802 addresses entirely, and thus avoid adopting this bug from the original draft and code ;-) d705 3 a707 7 The reason for the bug in the standards seems to be that the multicast bit actually is the *MOST* significant bit in IEEE 802.3 (Ethernet) _transmission order_ of an IEEE 802 MAC address. The authors seem to be confused by this and especially were not aware that the bitwise order of an octet from a MAC address memory and hexadecimal string representation is still always from left (MSB, bit 7) to right (LSB, bit 0). d709 7 a715 4 For more information on this, see especially "Understanding Physical Addresses" in "Ethernet -- The Definitive Guide", p.43, and section "ETHERNET MULTICAST ADDRESSES" in http://www.iana.org/assignments/ethernet-numbers. d717 2 a718 4 Hence, we do it the intended/correct way and generate a real IEEE 802 multicast address, but with a brain-dead compile-time option one can nevertheless enforce the broken generation of IEEE 802 MAC addresses. For the decoding we always use the correct way, of course. */ d720 6 a725 7 /* encoding */ #ifdef WITH_RFC2518 #define IEEE_MAC_MCBIT_ENC BM_OCTET(1,0,0,0,0,0,0,0) #else #define IEEE_MAC_MCBIT_ENC BM_OCTET(0,0,0,0,0,0,0,1) #endif #define IEEE_MAC_LOBIT_ENC BM_OCTET(0,0,0,0,0,0,1,0) d727 5 a731 3 /* decoding */ #define IEEE_MAC_MCBIT_DEC BM_OCTET(0,0,0,0,0,0,0,1) #define IEEE_MAC_LOBIT_DEC BM_OCTET(0,0,0,0,0,0,1,0) d866 13 d920 1 a920 1 if ((rc = uuid_parse(uuid_object, ns)) != UUID_RC_OK) d923 1 a923 1 uuid_pack(uuid_object, &uuid_octets); d951 1 a951 1 local/host byte order (this uses fact that uuid_unpack() is d953 1 a953 1 uuid_unpack(uuid, (void *)&(uuid->obj)); a995 166 } /* decoding tables */ static struct { uuid_uint8_t num; const char *desc; } uuid_dectab_variant[] = { { BM_OCTET(0,0,0,0,0,0,0,0), "reserved (NCS backward compatible)" }, { BM_OCTET(1,0,0,0,0,0,0,0), "DCE 1.1, ISO/IEC 11578:1996" }, { BM_OCTET(1,1,0,0,0,0,0,0), "reserved (Microsoft GUID)" }, { BM_OCTET(1,1,1,0,0,0,0,0), "reserved (future use)" } }; static struct { int num; const char *desc; } uuid_dectab_version[] = { { 1, "time and node based" }, { 3, "name based" }, { 4, "random data based" } }; /* dump UUID object as descriptive text */ uuid_rc_t uuid_dump(uuid_t *uuid, char **str) { const char *version; const char *variant; uuid_rc_t rc; uuid_uint8_t tmp8; uuid_uint16_t tmp16; uuid_uint32_t tmp32; char string[UUID_LEN_STR+1]; char *s; unsigned int i; ui64_t t; ui64_t offset; int t_nsec; int t_usec; time_t t_sec; char buf[19+1]; /* YYYY-MM-DD HH:MM:SS */ char *content; struct tm *tm; int isnil; uuid_uint8_t tmp[UUID_LEN_BIN]; void *tmp_ptr; /* sanity check argument(s) */ if (uuid == NULL || str == NULL) return UUID_RC_ARG; /* initialize output buffer */ *str = NULL; /* decode into string representation */ s = string; uuid_format(uuid, &s); str_rsprintf(str, "UUID: %s\n", s); /* check for special case of "Nil UUID" */ if ((rc = uuid_isnil(uuid, &isnil)) != UUID_RC_OK) return rc; /* decode UUID variant */ tmp8 = uuid->obj.clock_seq_hi_and_reserved; if (isnil) variant = "n.a."; else { variant = "unknown"; for (i = 7; i >= 0; i--) { if ((tmp8 & BM_BIT(i,1)) == 0) { tmp8 &= ~BM_MASK(i,0); break; } } for (i = 0; i < sizeof(uuid_dectab_variant)/sizeof(uuid_dectab_variant[0]); i++) { if (uuid_dectab_variant[i].num == tmp8) { variant = uuid_dectab_variant[i].desc; break; } } } str_rsprintf(str, "variant: %s\n", variant); /* decode UUID version */ tmp16 = (BM_SHR(uuid->obj.time_hi_and_version, 12) & BM_MASK(3,0)); if (isnil) version = "n.a."; else { version = "unknown"; for (i = 0; i < sizeof(uuid_dectab_version)/sizeof(uuid_dectab_version[0]); i++) { if (uuid_dectab_version[i].num == (int)tmp16) { version = uuid_dectab_version[i].desc; break; } } } str_rsprintf(str, "version: %d (%s)\n", (int)tmp16, version); /* * decode UUID content */ if (tmp8 == BM_OCTET(1,0,0,0,0,0,0,0) && tmp16 == 1) { /* decode DCE 1.1 version 1 UUID */ /* decode system time */ t = ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_hi_and_version & BM_MASK(11,0))), 48, NULL), t = ui64_or(t, ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_mid)), 32, NULL)); t = ui64_or(t, ui64_n2i((unsigned long)(uuid->obj.time_low))); offset = ui64_s2i(UUID_TIMEOFFSET, NULL, 16); t = ui64_sub(t, offset, NULL); t = ui64_divn(t, 10, &t_nsec); t = ui64_divn(t, 1000000, &t_usec); t_sec = (time_t)ui64_i2n(t); tm = gmtime(&t_sec); strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm); str_rsprintf(str, "content: time: %s.%06d.%d UTC\n", buf, t_usec, t_nsec); /* decode clock sequence */ tmp32 = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5,0)) << 8) + uuid->obj.clock_seq_low; str_rsprintf(str, " clock: %ld (usually random)\n", (long)tmp32); /* decode node MAC address */ str_rsprintf(str, " node: %02x:%02x:%02x:%02x:%02x:%02x (%s %s)\n", (unsigned int)uuid->obj.node[0], (unsigned int)uuid->obj.node[1], (unsigned int)uuid->obj.node[2], (unsigned int)uuid->obj.node[3], (unsigned int)uuid->obj.node[4], (unsigned int)uuid->obj.node[5], (uuid->obj.node[0] & IEEE_MAC_LOBIT_DEC ? "local" : "global"), (uuid->obj.node[0] & IEEE_MAC_MCBIT_DEC ? "multicast" : "unicast")); } else { /* decode anything else as hexadecimal byte-string only */ /* determine annotational hint */ content = "not decipherable, because unknown UUID version"; if (isnil) content = "special case of DCE 1.1 Nil UUID"; else if (tmp16 == 3) content = "not decipherable, because message digest only"; else if (tmp16 == 4) content = "no semantics, because random data only"; /* pack UUID into binary representation */ tmp_ptr = tmp; if ((rc = uuid_pack(uuid, &tmp_ptr)) != UUID_RC_OK) return rc; /* mask out version and variant parts */ tmp[6] &= BM_MASK(3,0); tmp[8] &= BM_MASK(5,0); /* dump as colon-seperated hexadecimal byte-string */ str_rsprintf(str, "content: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n" " (%s)\n", (unsigned int)tmp[0], (unsigned int)tmp[1], (unsigned int)tmp[2], (unsigned int)tmp[3], (unsigned int)tmp[4], (unsigned int)tmp[5], (unsigned int)tmp[6], (unsigned int)tmp[7], (unsigned int)tmp[8], (unsigned int)tmp[9], (unsigned int)tmp[10], (unsigned int)tmp[11], (unsigned int)tmp[12], (unsigned int)tmp[13], (unsigned int)tmp[14], (unsigned int)tmp[15], content); } return UUID_RC_OK; @ 1.34 log @Improvide decoding in uuid_dump() by at least hex-dumping the binary representation in case of v3, v4 and Nil UUIDs. Also, annotate with better hints. @ text @d221 1 a221 1 int i; d267 1 a267 1 int i; d346 1 a346 1 int i; d652 1 a652 1 int i; d777 1 a777 1 int i; @ 1.33 log @Recognize special "Nil UUID" on decoding in uuid_dump(). @ text @d88 1 a88 1 /* set UUID object initially to "nil UUID" */ d128 1 a128 1 /* set UUID object to represents 'nil UUID' */ d135 1 a135 1 /* clear all octets to create "nil UUID" */ d141 1 a141 1 /* check whether UUID object represents 'nil UUID' */ d151 1 a151 1 /* a "nil UUID" is defined as all octets zero, so check for this case */ d771 1 d784 1 d786 3 a788 1 int r; d802 3 a804 7 /* short-circuit special case of 'nil UUID' */ if (uuid_isnil(uuid, &r), r) { str_rsprintf(str, "variant: [none]\n" "version: [none]\n" "content: Nil UUID\n"); return UUID_RC_OK; } a806 1 variant = "unknown"; d808 9 a816 4 for (i = 7; i >= 0; i--) { if ((tmp8 & BM_BIT(i,1)) == 0) { tmp8 &= ~BM_MASK(i,0); break; d818 5 a822 5 } for (i = 0; i < sizeof(uuid_dectab_variant)/sizeof(uuid_dectab_variant[0]); i++) { if (uuid_dectab_variant[i].num == tmp8) { variant = uuid_dectab_variant[i].desc; break; a827 1 version = "unknown"; d829 9 a837 4 for (i = 0; i < sizeof(uuid_dectab_version)/sizeof(uuid_dectab_version[0]); i++) { if (uuid_dectab_version[i].num == (int)tmp16) { version = uuid_dectab_version[i].desc; break; d842 6 a847 8 /* we currently support DCE 1.1 variants of version 1/3/4 only */ if (!( tmp8 == BM_OCTET(1,0,0,0,0,0,0,0) && (tmp16 == 1 || tmp16 == 3 || tmp16 == 4))) return UUID_RC_OK; /* decode more */ if (tmp16 == 1) { /* decode version 1 */ d878 30 a907 7 else if (tmp16 == 3) { /* decode version 3 */ str_rsprintf(str, "content: [not decipherable]\n"); } else if (tmp16 == 4) { /* decode version 4 */ str_rsprintf(str, "content: [no semantics]\n"); @ 1.32 log @be correct and pass signed long @ text @d784 1 d797 8 @ 1.31 log @after solving the conflicts with Michael's fixes, this is my cleaned up version. Feel free to fix the grammar again if I introduced new problems. But I wanted to refactor the text a little bit now. @ text @d850 1 a850 1 str_rsprintf(str, " clock: %ld (usually random)\n", (unsigned long)tmp32); @ 1.30 log @Correct grammar and improve clarity. @ text @d430 52 a481 45 /* * ATTENTION: * * In case no real/physical IEEE 802 address is available, both * "draft-leach-uuids-guids-01" (section "4. Node IDs when no IEEE 802 * network card is available") and RFC 2518 (section "6.4.1 Node Field * Generation Without the IEEE 802 Address") recommend (quoted from RFC * 2518): * * "The ideal solution is to obtain a 47 bit cryptographic quality * random number, and use it as the low 47 bits of the node ID, with the * most significant bit of the first octet of the node ID set to 1. This * bit is the unicast/multicast bit, which will never be set in IEEE 802 * addresses obtained from network cards; hence, there can never be a * conflict between UUIDs generated by machines with and without network * cards." * * This clearly explains the intention. Unfortunately, it incorrectly * explains how to achieve it. Both http://www.iana.org/assignments/ethernet-numbers and "Understanding * Physical Addresses" in "Ethernet -- The Definitive Guide", p.43 state that the unicast/multicast bit * is the "LEAST significant bit of the first octet of the node ID" in a * memory representation of a 48-bit MAC address. However, this unicast/multicast bit * is the MOST significant bit in the IEEE 802.3 _transmission order_ * of a MAC address. The bitwise memory order of a MAC address octet is * always from left/MSB/bit-7 to right/LSB/bit-0! * * Unfortunately, even the reference code in * "draft-leach-uuids-guids-01" incorrectly sets the multicast bit with * an "OR 0x80" bit operation. This could be considered "standards * compliant" (because the exact wording above is "with the most * significant bit"). However, from the remaining explanation it becomes 100% * clear that the intention was different and the wording and code was * incorrect. The authors were likely unaware of this difference in bit * ordering between memory and wire transmission. * * By default, OSSP uuid works the intended/correct way and generates a real * IEEE 802 multicast address. Nevertheless, a compile-time option exists * for the generation of incorrect addresses according * to the standards. For the decoding we always use the correct way of * course. * * Luckily, neither DCE 1.1 nor ISO/IEC 11578:1996 are affected by this problem. * They disregard the topic of missing IEEE 802 addresses entirely, and thus * avoid adopting this bug from the original draft and code ;-) */ @ 1.29 log @Fix grammar and improve usage. @ text @d448 2 a449 3 * explains how to achieve it. Because (see also * http://www.iana.org/assignments/ethernet-numbers and "Understanding * Physical Addresses" in "Ethernet -- The Definitive Guide", p.43) it d451 2 a452 2 * memory representation of a 48-bit MAC address. The reason is that it * is the MOST significant bit only in IEEE 802.3 _transmission order_ @ 1.28 log @Provide both incorrect RFC2518-based and correct IEEE 802 multicast address generation. The default now is the correct IEEE 802 multicast address generation but compile-time option --with-rfc2518 selects the broken variant. @ text @d447 2 a448 2 * This clearly explains what the intention is. Unfortunately, it * explains it incorrectly how to achieve this. Because (see also d454 2 a455 2 * of a MAC address. The memory order of an octet from a MAC address is * always with the bits from left/MSB/bit-7 to right/LSB/bit-0! d461 1 a461 1 * significant bit"), but from the remaining explanation it becomes 100% d463 1 a463 1 * incorrect because the authors were unaware of this difference in bit d466 4 a469 4 * So, OSSP uuid does it the intended/correct way and generates a real * IEEE 802 multicast address, but with a compile-time option one can * nevertheless enforce the generation of incorrect addresses according * to the standards. For the decoding we always use the correct way, of d472 3 a474 3 * Luckily, both DCE 1.1 and ISO/IEC 11578:1996 do not deal with the * situation of not available IEEE 802 addresses at all and so have * avoided to adopt this bug from the original draft and code ;-) @ 1.27 log @fix clock calculation @ text @d430 59 d598 1 a598 1 /* use random multi-cast MAC address */ d600 2 a601 1 uuid->obj.node[0] |= BM_OCTET(1,0,0,0,0,0,0,0); d847 1 a847 1 str_rsprintf(str, " node: %02x:%02x:%02x:%02x:%02x:%02x (%s)\n", d854 2 a855 1 (uuid->obj.node[0] & 0x80 ? "random multicast" : "real unicast")); @ 1.26 log @Use BM_XXX() and str_xxx() APIs throughout internal implementation. @ text @d525 1 a525 1 clck &= BM_MASK(5,0); @ 1.25 log @Moved uuid_[u]int{8,16,32}_t auto-configuration into own internal header uuid_ac.h. @ text @d54 3 d59 6 a64 6 uuid_uint32_t time_low; uuid_uint16_t time_mid; uuid_uint16_t time_hi_and_version; uuid_uint8_t clock_seq_hi_and_reserved; uuid_uint8_t clock_seq_low; uuid_uint8_t node[6]; d69 6 a74 6 uuid_obj_t obj; /* inlined UUID object */ prng_t *prng; /* RPNG sub-object */ md5_t *md5; /* MD5 sub-object */ uuid_uint8_t mac[6]; /* pre-determined MAC address */ struct timeval time_last; /* last retrieved timestamp */ unsigned long time_seq; /* last timestamp sequence counter */ d100 1 a100 1 (*uuid)->mac[0] = 0x80; d312 1 a312 1 static int uuid_isstr(const char *str) d323 3 a325 1 if (strlen(str) != UUID_LEN_STR) d327 1 a327 1 for (i = 0, cp = str; i <= UUID_LEN_STR; i++, cp++) { a333 3 if (i == UUID_LEN_STR) if (*cp == '\0') continue; d353 1 a353 1 if (!uuid_isstr(str)) d391 1 a391 1 sprintf(*str, d412 2 a413 2 uuid->obj.time_hi_and_version &= 0x0fff; uuid->obj.time_hi_and_version |= (((uuid_uint16_t)version & 0x0fff) << 12); d416 2 a417 2 uuid->obj.clock_seq_hi_and_reserved &= ~((0x03) << 6); uuid->obj.clock_seq_hi_and_reserved |= (0x02 << 6); d513 1 a513 1 clck = ((uuid->obj.clock_seq_hi_and_reserved & ~((0x03) << 6)) << 8) d525 1 a525 1 clck &= ~((0x03) << 6); d529 1 a529 1 (uuid->obj.clock_seq_hi_and_reserved & ((0x03) << 6)) d538 1 a538 1 if ((mode & UUID_MCASTRND) || (uuid->mac[0] & 0x80)) { d541 1 a541 1 uuid->obj.node[0] |= 0x80; d599 1 a599 1 if (uuid_isstr(ns)) { d750 1 a750 1 tmp16 = (BM_SHR(uuid->obj.time_hi_and_version, 12) & 0x000f); d769 1 a769 1 t = ui64_rol(ui64_n2i((unsigned long)(uuid->obj.time_hi_and_version & 0x0fff)), 48, NULL), d782 1 a782 1 tmp32 = ((uuid->obj.clock_seq_hi_and_reserved & ~((0x03) << 6)) << 8) @ 1.24 log @Fixed portability by replacing accidentally introduced uint{8,16,32}_t with the portable uuid_uint{8,16,32}_t. Prefix all variable symbols in uuid.h with underscores to avoid namespace conflicts. Submitted by: Guerry Semones @ text @d30 1 d43 1 d52 1 a52 63 /* determine types of 8-bit size */ #if SIZEOF_CHAR == 1 typedef char uuid_int8_t; #else #error uexpected: sizeof(char) != 1 !? #endif #if SIZEOF_UNSIGNED_CHAR == 1 typedef unsigned char uuid_uint8_t; #else #error uexpected: sizeof(unsigned char) != 1 !? #endif /* determine types of 16-bit size */ #if SIZEOF_SHORT == 2 typedef short uuid_int16_t; #elif SIZEOF_INT == 2 typedef int uuid_int16_t; #elif SIZEOF_LONG == 2 typedef long uuid_int16_t; #else #error unexpected: no type found for uuid_int16_t #endif #if SIZEOF_UNSIGNED_SHORT == 2 typedef unsigned short uuid_uint16_t; #elif SIZEOF_UNSIGNED_INT == 2 typedef unsigned int uuid_uint16_t; #elif SIZEOF_UNSIGNED_LONG == 2 typedef unsigned long uuid_uint16_t; #else #error unexpected: no type found for uuid_uint16_t #endif /* determine types of 32-bit size */ #if SIZEOF_SHORT == 4 typedef short uuid_int32_t; #elif SIZEOF_INT == 4 typedef int uuid_int32_t; #elif SIZEOF_LONG == 4 typedef long uuid_int32_t; #elif SIZEOF_LONG_LONG == 4 typedef long long uuid_int32_t; #else #error unexpected: no type found for uuid_int32_t #endif #if SIZEOF_UNSIGNED_SHORT == 4 typedef unsigned short uuid_uint32_t; #elif SIZEOF_UNSIGNED_INT == 4 typedef unsigned int uuid_uint32_t; #elif SIZEOF_UNSIGNED_LONG == 4 typedef unsigned long uuid_uint32_t; #elif SIZEOF_UNSIGNED_LONG_LONG == 4 typedef unsigned long long uuid_uint32_t; #else #error unexpected: no type found for uuid_uint32_t #endif #ifndef FALSE #define FALSE 0 #endif #ifndef TRUE #define TRUE !FALSE #endif d149 1 a149 1 *result = TRUE; d152 1 a152 1 *result = FALSE; d319 1 a319 1 return FALSE; d321 1 a321 1 return FALSE; d327 1 a327 1 return FALSE; d333 1 a333 1 return FALSE; d335 1 a335 1 return TRUE; @ 1.23 log @Implement uuid_dump() and corresponding uuid CLI "-d" option for dumping a given UUID into clear text. For convinience reasons add uuid_bm.h (bit mask API) and uuid_str (string formatting API) sub-modules. @ text @d763 3 a765 3 uint8_t tmp8; uint16_t tmp16; uint32_t tmp32; @ 1.22 log @more documentation @ text @d48 2 d483 5 d546 2 a547 5 /* adjust for offset between UUID and Unix Epoch time through adding the magic offset 01B21DD213814000 from draft-leach-uuids-guids-01. (UUID UTC base time is October 15, 1582 Unix UTC base time is January 1, 1970) */ offset = ui64_s2i("01B21DD213814000", NULL, 16); d739 19 d761 16 d780 83 a862 1 /* FIXME */ @ 1.21 log @fix building @ text @d196 22 a265 22 return UUID_RC_OK; } /* check whether UUID object represents 'nil UUID' */ uuid_rc_t uuid_isnil(uuid_t *uuid, int *result) { const unsigned char *ucp; int i; /* sanity check argument(s) */ if (uuid == NULL || result == NULL) return UUID_RC_ARG; /* a "nil UUID" is defined as all octets zero, so check for this case */ *result = TRUE; for (i = 0, ucp = (unsigned char *)&(uuid->obj); i < UUID_LEN_BIN; i++) { if (*ucp++ != '\0') { *result = FALSE; break; } } @ 1.20 log @implement last component of v1 UUID generation: clock sequence @ text @d485 3 d489 1 @ 1.19 log @better wording @ text @d481 2 a482 2 /* INTERNAL: generate UUID version 1, time part */ static uuid_rc_t uuid_generate_v1_time(uuid_t *uuid, unsigned int mode, va_list ap) d489 5 d503 1 a503 1 && time_now.tv_usec == uuid->time_last.tv_usec)) { a506 5 /* remember system time for next iteration */ uuid->time_last.tv_sec = time_now.tv_sec; uuid->time_last.tv_usec = time_now.tv_usec; } d558 29 a586 9 return UUID_RC_OK; } /* INTERNAL: generate UUID version 1, clock part */ static uuid_rc_t uuid_generate_v1_clock(uuid_t *uuid, unsigned int mode, va_list ap) { /* FIXME */ return UUID_RC_OK; } a587 3 /* INTERNAL: generate UUID version 1, node part */ static uuid_rc_t uuid_generate_v1_node(uuid_t *uuid, unsigned int mode, va_list ap) { a596 7 return UUID_RC_OK; } /* INTERNAL: generate UUID version 1: time, clock and node based */ static uuid_rc_t uuid_generate_v1(uuid_t *uuid, unsigned int mode, va_list ap) { uuid_rc_t rc; d598 7 a604 7 /* generate individual parts of v1 UUID */ if ((rc = uuid_generate_v1_time (uuid, mode, ap)) != UUID_RC_OK) return rc; if ((rc = uuid_generate_v1_clock(uuid, mode, ap)) != UUID_RC_OK) return rc; if ((rc = uuid_generate_v1_node (uuid, mode, ap)) != UUID_RC_OK) return rc; @ 1.18 log @add system clock resolution compensation according to the UUID standard(s) @ text @d514 2 a515 2 /* else sleep a little bit until the system clock (which has a gettimeofday(2) resolution of 1us) has changed. */ @ 1.17 log @apply fixed after run-time testing under Linux and Solaris @ text @d124 6 a129 4 uuid_obj_t obj; /* inlined UUID object */ prng_t *prng; /* RPNG sub-object */ md5_t *md5; /* MD5 sub-object */ uuid_uint8_t mac[6]; /* pre-determined MAC address */ d158 5 d477 4 d484 1 d490 38 a527 3 /* determine current system time */ if (gettimeofday(&tv, NULL) == -1) return UUID_RC_SYS; d530 1 a530 1 t = ui64_n2i(tv.tv_sec); d532 1 a532 1 t = ui64_addn(t, tv.tv_usec, NULL); d541 5 @ 1.16 log @add MAC address framework part of UUID v1 generation and implement the MAC address resolving for BSD style platforms with getifaddrs(3) @ text @d383 1 a383 1 if (!isxdigit(*cp)) @ 1.15 log @add time part of UUID v1 generation @ text @d36 2 d40 1 a40 2 #include #include d46 1 d124 4 a127 3 uuid_obj_t obj; /* inlined UUID object */ prng_t *prng; /* RPNG sub-object */ md5_t *md5; /* MD5 sub-object */ d150 6 d519 9 a527 1 /* FIXME */ @ 1.14 log @move out PRNG into own object and attach a PRNG and MD5 object for reuse into the UUID object @ text @d461 53 d517 10 a528 2 /* FIXME */ @ 1.13 log @move internal binary representation into sub-object of API abstract data type in order to have room for adding internal PRNG and MD5 states to the abstract data type @ text @d44 1 d122 3 a124 1 uuid_obj_t obj; d134 1 a134 1 /* allocate UUID binary representation buffer */ d138 1 a138 1 /* set initially to "nil UUID" */ d141 6 d157 5 a161 1 /* free UUID binary representation buffer */ a447 62 /* INTERNAL: pseudo-random number generator (PRNG) */ static void uuid_prng_getdata(uuid_uint8_t *data_ptr, size_t data_len) { static int initialized = FALSE; static int fd = -1; struct timeval tv; pid_t pid; size_t n; size_t i; uuid_uint8_t *p; int cnt; if (!initialized) { /* try to open the system PRNG device */ if ((fd = open("/dev/urandom", O_RDONLY)) == -1) fd = open("/dev/random", O_RDONLY|O_NONBLOCK); if (fd != -1) fcntl(fd, F_SETFD, FD_CLOEXEC); /* seed the PRNG once */ gettimeofday(&tv, NULL); pid = getpid(); srand((unsigned int)( ((uuid_uint32_t)pid << 16) ^ (uuid_uint32_t)pid ^ (uuid_uint32_t)tv.tv_sec ^ (uuid_uint32_t)tv.tv_usec)); /* crank the PRNG a few times */ gettimeofday(&tv, NULL); for (i = (unsigned int)(tv.tv_sec ^ tv.tv_usec) & 0x1F; i > 0; i--) (void)rand(); initialized = TRUE; } /* try to gather data from the system PRNG device */ if (fd != -1) { p = data_ptr; n = data_len; cnt = 0; while (n > 0) { i = read(fd, (void *)p, n); if (i <= 0) { if (cnt++ > 16) break; continue; } n -= i; p += i; cnt = 0; } } /* always also apply the weaker PRNG. In case the stronger PRNG device based source failed, this is the only remaining randomness, of course */ for (p = data_ptr, n = 0; n < data_len; n++) *p++ ^= (uuid_uint8_t)(((uuid_uint32_t)rand() >> 7) & 0xFF); return; } a495 1 md5_t *md5; d504 2 a505 2 /* create MD5 context */ if (md5_create(&md5) != MD5_RC_OK) d517 1 a517 1 md5_update(md5, uuid_octets, UUID_LEN_BIN); d531 1 a531 1 md5_update(md5, uuid_octets, UUID_LEN_BIN); d535 1 a535 1 md5_update(md5, str, strlen(str)); d541 1 a541 4 md5_store(md5, &uuid_octets, NULL); /* destroy MD5 context */ md5_destroy(md5); d558 1 a558 1 uuid_prng_getdata((void *)&(uuid->obj), sizeof(uuid->obj)); @ 1.12 log @cleanups and more code documentation @ text @d110 1 a110 1 struct uuid_st { d117 5 d162 1 a162 1 memset(uuid, '\0', sizeof(uuid_t)); d168 1 a168 1 uuid_rc_t uuid_compare(uuid_t *a, uuid_t *b, int *result) d184 1 a184 1 if (a == b) d186 1 a186 1 if (a == NULL && b == NULL) d188 4 a191 4 if (a == NULL) RESULT((uuid_isnil(b, &r), r) ? 0 : -1); if (b == NULL) RESULT((uuid_isnil(a, &r), r) ? 0 : 1); d194 4 a197 4 if (a->time_low != b->time_low) RESULT((a->time_low < b->time_low) ? -1 : 1); if ((r = (int)a->time_mid - (int)b->time_mid) != 0) d199 2 a200 2 if ((r = (int)a->time_hi_and_version - (int)b->time_hi_and_version) != 0) d202 2 a203 2 if ((r = (int)a->clock_seq_hi_and_reserved - (int)b->clock_seq_hi_and_reserved) != 0) d205 2 a206 2 if ((r = (int)a->clock_seq_low - (int)b->clock_seq_low) != 0) d208 1 a208 1 if ((r = memcmp(a->node, b->node, sizeof(a->node))) != 0) d230 1 a230 1 for (i = 0, ucp = (unsigned char *)uuid; i < UUID_LEN_BIN; i++) { d240 2 a241 1 /* unpack UUID binary presentation into UUID object (allows in-place operation!) */ d261 1 a261 1 uuid->time_low = tmp32; d266 1 a266 1 uuid->time_mid = tmp16; d271 1 a271 1 uuid->time_hi_and_version = tmp16; d274 1 a274 1 uuid->clock_seq_hi_and_reserved = *in++; d277 1 a277 1 uuid->clock_seq_low = *in++; d280 2 a281 2 for (i = 0; i < sizeof(uuid->node); i++) uuid->node[i] = *in++; d286 2 a287 1 /* pack UUID object into binary representation (allows in-place operation!) */ d308 1 a308 1 tmp32 = uuid->time_low; d315 1 a315 1 tmp16 = uuid->time_mid; d320 1 a320 1 tmp16 = uuid->time_hi_and_version; d325 1 a325 1 out[8] = uuid->clock_seq_hi_and_reserved; d328 1 a328 1 out[9] = uuid->clock_seq_low; d331 2 a332 2 for (i = 0; i < sizeof(uuid->node); i++) out[10+i] = uuid->node[i]; d384 3 a386 3 uuid->time_low = (uuid_uint32_t)strtoul(str, NULL, 16); uuid->time_mid = (uuid_uint16_t)strtoul(str+9, NULL, 16); uuid->time_hi_and_version = (uuid_uint16_t)strtoul(str+14, NULL, 16); d390 2 a391 2 uuid->clock_seq_low = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8; uuid->clock_seq_hi_and_reserved = (uuid_uint8_t)(tmp16 & 0xff); d396 1 a396 1 for (i = 0; i < sizeof(uuid->node); i++) { d399 1 a399 1 uuid->node[i] = strtoul(hexbuf, NULL, 16); d420 11 a430 11 (unsigned long)uuid->time_low, (unsigned int)uuid->time_mid, (unsigned int)uuid->time_hi_and_version, (unsigned int)uuid->clock_seq_hi_and_reserved, (unsigned int)uuid->clock_seq_low, (unsigned int)uuid->node[0], (unsigned int)uuid->node[1], (unsigned int)uuid->node[2], (unsigned int)uuid->node[3], (unsigned int)uuid->node[4], (unsigned int)uuid->node[5]); d501 2 a502 2 uuid->time_hi_and_version &= 0x0fff; uuid->time_hi_and_version |= (((uuid_uint16_t)version & 0x0fff) << 12); d505 2 a506 2 uuid->clock_seq_hi_and_reserved &= ~((0x03) << 6); uuid->clock_seq_hi_and_reserved |= (0x02 << 6); d565 3 a567 2 uuid_pack(uuid_object, (void **)&uuid_object); md5_update(md5, (void *)uuid_object, UUID_LEN_BIN); d590 2 a591 1 md5_store(md5, (void *)&uuid, NULL); d599 1 a599 1 uuid_unpack(uuid, (void *)uuid); d611 1 a611 1 uuid_prng_getdata((void *)uuid, sizeof(uuid_t)); @ 1.11 log @be more flexible and allow custom namespace UUIDs @ text @d119 1 d136 1 d149 1 d162 1 d213 1 d235 1 d280 1 d330 1 a330 1 /* check for correct UUID string representation syntax */ d336 4 a339 6 /* * example reference: * f81d4fae-7dec-11d0-a765-00a0c91e6bf6 * 012345678901234567890123456789012345 * 0 1 2 3 */ d360 1 d398 1 d428 1 a428 1 /* pseudo-random number generator (PRNG) */ d490 1 a490 1 /* brand UUID with version and variant */ d503 1 a503 1 /* generate UUID version 1: time, clock and node based */ d514 3 a516 5 /* * UUID Namespace Ids as pre-defined by draft-leach-uuids-guids-01.txt * (defined here as network byte ordered octet stream for direct MD5 feeding) */ struct { d530 1 a530 1 /* generate UUID version 3: name based */ d534 3 a536 3 char *ns_name; void *ns_uuid; uuid_t *uuid_tmp; d542 1 a542 1 if ((ns_name = (char *)va_arg(ap, char *)) == NULL) d552 1 a552 1 if (uuid_isstr(ns_name)) { d554 1 a554 1 if ((rc = uuid_create(&uuid_tmp)) != UUID_RC_OK) d556 1 a556 1 if ((rc = uuid_parse(uuid_tmp, ns_name)) != UUID_RC_OK) d558 3 a560 3 uuid_pack(uuid_tmp, (void **)&uuid_tmp); md5_update(md5, (void *)uuid_tmp, UUID_LEN_BIN); uuid_destroy(uuid_tmp); d564 1 a564 1 ns_uuid = NULL; d566 2 a567 2 if (strcmp(uuid_ns_table[i].name, ns_name) == 0) { ns_uuid = uuid_ns_table[i].uuid; d571 1 a571 1 if (ns_uuid == NULL) d573 1 a573 1 md5_update(md5, ns_uuid, UUID_LEN_BIN); d598 1 a598 1 /* generate UUID version 4: random number based */ d610 1 d635 1 d645 1 @ 1.10 log @add UUID version 3 (name based) generation support (verified to be correct against Data::UUID, the only name supporting UUID implementation available for comparison) @ text @d323 2 a324 1 uuid_rc_t uuid_parse(uuid_t *uuid, const char *str) d326 1 a326 1 uuid_uint16_t tmp16; a327 6 char hexbuf[3]; int i; /* sanity check argument(s) */ if (uuid == NULL || str == NULL) return UUID_RC_ARG; a329 1 * pass 1: check UUID string representation syntax d335 2 d338 1 a338 1 return UUID_RC_ARG; d344 1 a344 1 return -1; d350 1 a350 1 return UUID_RC_ARG; d352 2 d355 16 a370 3 /* * pass 2: parse hex values of string representation syntax */ d374 2 d379 2 d531 2 d547 22 a568 6 ns_uuid = NULL; for (i = 0; i < sizeof(uuid_ns_table)/sizeof(uuid_ns_table[0]); i++) { if (strcmp(uuid_ns_table[i].name, ns_name) == 0) { ns_uuid = uuid_ns_table[i].uuid; break; } a569 3 if (ns_uuid == NULL) return UUID_RC_ARG; md5_update(md5, ns_uuid, UUID_LEN_BIN); @ 1.9 log @add generator framework and implement version 4 UUIDs (random number only) @ text @d43 1 d492 18 d513 45 a557 1 /* brand with version and variant */ a559 2 /* FIXME */ d566 1 a566 1 /* fill with random data */ d569 1 a569 1 /* brand with version and variant */ @ 1.8 log @fix framework and print ASCII output by default @ text @d36 4 d405 109 d517 1 d522 2 d525 8 a532 1 /* FIXME */ d534 2 a535 1 return UUID_RC_OK; @ 1.7 log @use format instead of unparse and fix pack/unpack usage @ text @a319 1 uuid_t uuid_tmp; d355 3 a357 3 uuid_tmp.time_low = (uuid_uint32_t)strtoul(str, NULL, 16); uuid_tmp.time_mid = (uuid_uint16_t)strtoul(str+9, NULL, 16); uuid_tmp.time_hi_and_version = (uuid_uint16_t)strtoul(str+14, NULL, 16); d359 2 a360 2 uuid_tmp.clock_seq_low = (uuid_uint8_t)(tmp16 & 0xff); tmp16 >>= 8; uuid_tmp.clock_seq_hi_and_reserved = (uuid_uint8_t)(tmp16 & 0xff); d363 1 a363 1 for (i = 0; i < sizeof(uuid_tmp.node); i++) { d366 1 a366 1 uuid_tmp.node[i] = strtoul(hexbuf, NULL, 16); a373 2 uuid_t uuid_tmp; d386 11 a396 11 (unsigned long)uuid_tmp.time_low, (unsigned int)uuid_tmp.time_mid, (unsigned int)uuid_tmp.time_hi_and_version, (unsigned int)uuid_tmp.clock_seq_hi_and_reserved, (unsigned int)uuid_tmp.clock_seq_low, (unsigned int)uuid_tmp.node[0], (unsigned int)uuid_tmp.node[1], (unsigned int)uuid_tmp.node[2], (unsigned int)uuid_tmp.node[3], (unsigned int)uuid_tmp.node[4], (unsigned int)uuid_tmp.node[5]); @ 1.6 log @add copy of OSSP ui64 for 64-bit arithmetics @ text @d373 1 a373 1 uuid_rc_t uuid_unparse(uuid_t *uuid, char **str) @ 1.5 log @flush work of this forenoon @ text @d39 1 @ 1.4 log @use 'nil' instead of 'null' because the standards name the special zeroed UUID 'nil' @ text @d35 1 d96 8 a103 1 /* private data type declaration */ d115 1 d118 2 d122 4 a125 1 uuid_null(*uuid); d131 1 d134 2 d137 1 d141 1 a141 1 uuid_rc_t uuid_null(uuid_t *uuid) d143 1 d146 2 d149 1 d153 1 a153 1 uuid_rc_t uuid_generate(uuid_t *uuid, unsigned int mode, ...) d155 1 a155 1 va_list ap; d157 2 a158 1 if (uuid == NULL) d160 40 a199 3 va_start(ap, mode); /* FIXME */ va_end(ap); d203 1 a203 1 uuid_rc_t uuid_compare(uuid_t *a, uuid_t *b, int *result) d205 2 a206 1 int r; d208 2 a209 1 if (result == NULL) d212 7 a218 42 /* deal with NULL or equal pointers. */ if (a == b) { *result = 0; return UUID_RC_OK; } if (a == NULL && b == NULL) { *result = 0; return UUID_RC_OK; } if (a == NULL) { *result = ((uuid_isnil(b, &r), r) ? 0 : -1); return UUID_RC_OK; } if (b == NULL) { *result = ((uuid_isnil(a, &r), r) ? 0 : 1); return UUID_RC_OK; } /* we have to compare the hard way. */ if (a->time_low != b->time_low) { *result = ((a->time_low < b->time_low) ? -1 : 1); return UUID_RC_OK; } if ((r = (int)a->time_mid - (int)b->time_mid) != 0) { *result = ((r < 0) ? -1 : 1); return UUID_RC_OK; } if ((r = (int)a->time_hi_and_version - (int)b->time_hi_and_version) != 0) { *result = ((r < 0) ? -1 : 1); return UUID_RC_OK; } if ((r = (int)a->clock_seq_hi_and_reserved - (int)b->clock_seq_hi_and_reserved) != 0) { *result = ((r < 0) ? -1 : 1); return UUID_RC_OK; } if ((r = (int)a->clock_seq_low - (int)b->clock_seq_low) != 0) { *result = ((r < 0) ? -1 : 1); return UUID_RC_OK; } if ((r = memcmp(a->node, b->node, sizeof(a->node))) != 0) { *result = ((r < 0) ? -1 : 1); return UUID_RC_OK; a220 2 /* else the keys are equal */ *result = 0; d224 1 a224 1 uuid_rc_t uuid_isnil(uuid_t *uuid, int *result) d226 7 a232 1 if (uuid == NULL || result == NULL) d234 31 a264 13 *result = 0; if ( uuid->time_low == 0 && uuid->time_mid == 0 && uuid->time_hi_and_version == 0 && uuid->clock_seq_hi_and_reserved == 0 && uuid->clock_seq_low == 0 && uuid->node[0] == 0 && uuid->node[1] == 0 && uuid->node[2] == 0 && uuid->node[3] == 0 && uuid->node[4] == 0 && uuid->node[5] == 0) *result = 1; d268 1 a268 1 uuid_rc_t uuid_parse(uuid_t *uuid, const char *str) d270 7 a276 1 if (uuid == NULL) d278 36 a313 1 /* FIXME */ d317 1 a317 1 uuid_rc_t uuid_format(uuid_t *uuid, char **str) d319 7 d328 41 a368 1 /* FIXME */ d372 1 a372 1 uuid_rc_t uuid_read(uuid_t *uuid, const void *buf) d374 4 a377 1 if (uuid == NULL) d379 21 a399 1 /* FIXME */ d403 1 a403 1 uuid_rc_t uuid_write(uuid_t *uuid, void **buf) d405 4 a408 1 if (uuid == NULL || buf == NULL) d410 1 d412 1 d418 1 @ 1.3 log @introduce UUID versioning into API @ text @d160 1 a160 1 *result = ((uuid_isnull(b, &r), r) ? 0 : -1); d164 1 a164 1 *result = ((uuid_isnull(a, &r), r) ? 0 : 1); d199 1 a199 1 uuid_rc_t uuid_isnull(uuid_t *uuid, int *result) @ 1.2 log @implement uuid_compare function @ text @d32 1 d131 1 a131 1 uuid_rc_t uuid_generate(uuid_t *uuid) d133 2 d137 1 d139 1 d246 8 @ 1.1 log @import the first cut for our forthcoming OSSP uuid library @ text @d138 1 a138 1 uuid_rc_t uuid_compare(uuid_t *uuid, uuid_t *uuid2, int *result) d140 3 a142 1 if (uuid == NULL || uuid2 == NULL || result == NULL) d144 47 a190 1 /* FIXME */ @