Index: ossp-pkg/uuid/ChangeLog RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/ChangeLog,v rcsdiff -q -kk '-r1.28' '-r1.29' -u '/v/ossp/cvs/ossp-pkg/uuid/Attic/ChangeLog,v' 2>/dev/null --- ChangeLog 2004/01/18 20:19:23 1.28 +++ ChangeLog 2004/01/19 12:15:04 1.29 @@ -13,14 +13,28 @@ Changes between 0.9.3 and 0.9.4 (16-Jan-2004 to xx-Jan-2004) + o Include in uuid.h because of size_t usage. + [Ralf S. Engelschall] + + 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. + [Ralf S. Engelschall] + o Add version support to API via UUID_VERSION (compile-time) and uuid_version() (link-time). [Ralf S. Engelschall] - o 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. + o INCOMPATIBILITY: 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. [Ralf S. Engelschall] o Document what DCE 1.1 UUID versions exist and what they are Index: ossp-pkg/uuid/uuid.c RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.c,v co -q -kk -p'1.41' '/v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.c,v' | diff -u /dev/null - -L'ossp-pkg/uuid/uuid.c' 2>/dev/null --- ossp-pkg/uuid/uuid.c +++ - 2024-05-17 15:28:10.683446360 +0200 @@ -0,0 +1,1015 @@ +/* +** OSSP uuid - Universally Unique Identifier +** Copyright (c) 2004 Ralf S. Engelschall +** Copyright (c) 2004 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 +*/ + +/* system headers */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* own headers */ +#include "config.h" +#include "uuid.h" +#include "uuid_vers.h" +#include "uuid_md5.h" +#include "uuid_prng.h" +#include "uuid_mac.h" +#include "uuid_ui64.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 + + 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 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). + + 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) + +/* 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 */ + 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) +{ + /* argument sanity check */ + if (uuid == NULL) + return UUID_RC_ARG; + + /* allocate UUID object */ + if ((*uuid = (uuid_t *)malloc(sizeof(uuid_t))) == NULL) + return UUID_RC_MEM; + + /* 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) + return UUID_RC_INT; + if (md5_create(&(*uuid)->md5) != MD5_RC_OK) + return UUID_RC_INT; + + /* resolve MAC address for insertion into node field of UUIDs */ + 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); + } + + /* initialize time attributes */ + (*uuid)->time_last.tv_sec = 0; + (*uuid)->time_last.tv_usec = 0; + (*uuid)->time_seq = 0; + + 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 and MD5 sub-objects */ + prng_destroy(uuid->prng); + md5_destroy(uuid->md5); + + /* free UUID object */ + free(uuid); + + 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 = UUID_TRUE; + for (i = 0, ucp = (unsigned char *)&(uuid->obj); i < UUID_LEN_BIN; i++) { + if (*ucp++ != '\0') { + *result = UUID_FALSE; + break; + } + } + + return UUID_RC_OK; +} + +/* compare UUID objects */ +uuid_rc_t uuid_compare(uuid_t *uuid1, uuid_t *uuid2, int *result) +{ + int r; + + /* argument sanity check */ + if (result == NULL) + return UUID_RC_ARG; + + /* convinience macro for setting result */ +# define RESULT(r) \ + do { \ + *result = (r); \ + goto result_exit; \ + } while (0) + + /* 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), r) ? 0 : -1); + if (uuid2 == NULL) + RESULT((uuid_isnil(uuid1, &r), r) ? 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 = *in++; + tmp32 = (tmp32 << 8) | *in++; + tmp32 = (tmp32 << 8) | *in++; + tmp32 = (tmp32 << 8) | *in++; + uuid->obj.time_low = tmp32; + + /* unpack "time_mid" field */ + tmp16 = *in++; + tmp16 = (tmp16 << 8) | *in++; + uuid->obj.time_mid = tmp16; + + /* unpack "time_hi_and_version" field */ + tmp16 = *in++; + tmp16 = (tmp16 << 8) | *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 < 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(uuid_t *uuid, void **data_ptr, size_t *data_len) +{ + uuid_uint8_t *out; + uuid_uint32_t tmp32; + uuid_uint16_t tmp16; + unsigned int i; + + /* 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 = 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 = (uuid_uint8_t *)(*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 < 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 < sizeof(uuid->obj.node); i++) { + hexbuf[0] = *cp++; + hexbuf[1] = *cp++; + uuid->obj.node[i] = strtoul(hexbuf, NULL, 16); + } + + return UUID_RC_OK; +} + +/* INTERNAL: export UUID object to string representation */ +static uuid_rc_t uuid_export_str(uuid_t *uuid, void **data_ptr, size_t *data_len) +{ + /* sanity check argument(s) */ + if (uuid == NULL || data_ptr == NULL) + return UUID_RC_ARG; + + /* allocate output buffer */ + if (*data_ptr == NULL) { + if ((*data_ptr = (void *)malloc(UUID_LEN_STR+1)) == NULL) + return UUID_RC_MEM; + if (data_len != NULL) + *data_len = UUID_LEN_STR+1; + } + else { + 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 */ + str_snprintf((char *)(*data_ptr), 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]); + + return UUID_RC_OK; +} + +/* 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" } +}; + +/* INTERNAL: dump UUID object as descriptive text */ +static uuid_rc_t uuid_export_txt(uuid_t *uuid, void **data_ptr, size_t *data_len) +{ + 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]; + 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; + unsigned int i; + + /* 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 string representation */ + 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; + str_rsprintf(out, "UUID: %s\n", tmp_str); + + /* 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(out, "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(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); + 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); + + /* decode clock sequence */ + tmp32 = ((uuid->obj.clock_seq_hi_and_reserved & BM_MASK(5,0)) << 8) + + uuid->obj.clock_seq_low; + str_rsprintf(out, " clock: %ld (usually random)\n", (long)tmp32); + + /* decode node MAC address */ + 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_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 = (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 */ + 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_TXT: rc = UUID_RC_IMP; /* not implemented */ break; + default: rc = UUID_RC_ARG; + } + + return rc; +} + +/* UUID exporting */ +uuid_rc_t uuid_export(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_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, int version) +{ + /* 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); + + /* 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; +#ifdef HAVE_NANOSLEEP + struct timespec ts; +#else + struct timeval tv; +#endif + ui64_t t; + ui64_t offset; + ui64_t ov; + uuid_uint16_t clck; + + /* + * GENERATE TIME + */ + + /* determine current system time and sequence counter */ + while (1) { + /* determine current system time */ + if (gettimeofday(&time_now, NULL) == -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 */ + uuid->time_seq = 0; + + /* 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 */ +#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 + } + + /* convert from timeval (sec,usec) to OSSP ui64 (100*nsec) format */ + t = ui64_n2i(time_now.tv_sec); + t = ui64_muln(t, 1000000, NULL); + t = ui64_addn(t, 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, 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))) + prng_data(uuid->prng, (void *)&clck, sizeof(clck)); + 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_MCASTRND) || (uuid->mac[0] & BM_OCTET(1,0,0,0,0,0,0,0))) { + /* generate random IEEE 802 local multicast MAC address */ + prng_data(uuid->prng, (void *)&(uuid->obj.node), sizeof(uuid->obj.node)); + uuid->obj.node[0] |= IEEE_MAC_MCBIT_ENC; + uuid->obj.node[0] |= IEEE_MAC_LOBIT_ENC; + } + 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) */ +static struct { + char *name; + uuid_uint8_t uuid[UUID_LEN_BIN]; +} uuid_value_table[] = { + { "nil", /* 00000000-0000-0000-0000-000000000000 ("Nil UUID") */ + { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 } }, + { "ns:DNS", /* 6ba7b810-9dad-11d1-80b4-00c04fd430c8 (see draft-leach-uuids-guids-01.txt) */ + { 0x6b,0xa7,0xb8,0x10,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8 } }, + { "ns:URL", /* 6ba7b811-9dad-11d1-80b4-00c04fd430c8 (see draft-leach-uuids-guids-01.txt) */ + { 0x6b,0xa7,0xb8,0x11,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8 } }, + { "ns:OID", /* 6ba7b812-9dad-11d1-80b4-00c04fd430c8 (see draft-leach-uuids-guids-01.txt) */ + { 0x6b,0xa7,0xb8,0x12,0x9d,0xad,0x11,0xd1,0x80,0xb4,0x00,0xc0,0x4f,0xd4,0x30,0xc8 } }, + { "ns:X500", /* 6ba7b814-9dad-11d1-80b4-00c04fd430c8 (see draft-leach-uuids-guids-01.txt) */ + { 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 < 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 */ +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; + + /* 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); + uuid_export(uuid_ns, UUID_FMT_BIN, &uuid_ptr, &uuid_len); + md5_update(uuid->md5, uuid_buf, uuid_len); + + /* load the argument name string into MD5 context */ + md5_update(uuid->md5, str, strlen(str)); + + /* 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); + md5_store(uuid->md5, &uuid_ptr, NULL); + + /* 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!) */ + uuid_import(uuid, UUID_FMT_BIN, (void *)&(uuid->obj), UUID_LEN_BIN); + + /* 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 */ + prng_data(uuid->prng, (void *)&(uuid->obj), sizeof(uuid->obj)); + + /* brand UUID with version and variant */ + uuid_brand(uuid, 4); + + 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_VERSION1) + rc = uuid_make_v1(uuid, mode, ap); + else if (mode & UUID_VERSION3) + rc = uuid_make_v3(uuid, mode, ap); + else if (mode & UUID_VERSION4) + rc = uuid_make_v4(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; + default: str = NULL; break; + } + return str; +} + +/* OSSP uuid version (link-time information) */ +unsigned long uuid_version(void) +{ + return (unsigned long)(_UUID_VERSION); +} + Index: ossp-pkg/uuid/uuid.h RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.h,v rcsdiff -q -kk '-r1.14' '-r1.15' -u '/v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.h,v' 2>/dev/null --- uuid.h 2004/01/18 20:19:23 1.14 +++ uuid.h 2004/01/19 12:15:05 1.15 @@ -30,6 +30,9 @@ #ifndef __UUID_H__ #define __UUID_H__ +/* required system headers */ +#include + /* OSSP uuid version (compile-time information) */ #define UUID_VERSION 0x009204 @@ -82,8 +85,8 @@ extern uuid_rc_t uuid_destroy (uuid_t *_uuid); /* UUID generation */ -extern uuid_rc_t uuid_nil (uuid_t *_uuid); -extern uuid_rc_t uuid_generate (uuid_t *_uuid, unsigned int _mode, ...); +extern uuid_rc_t uuid_load (uuid_t *_uuid, const char *_name); +extern uuid_rc_t uuid_make (uuid_t *_uuid, unsigned int _mode, ...); /* UUID comparison */ extern uuid_rc_t uuid_isnil (uuid_t *_uuid, int *_result); Index: ossp-pkg/uuid/uuid.pod RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.pod,v rcsdiff -q -kk '-r1.11' '-r1.12' -u '/v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.pod,v' 2>/dev/null --- uuid.pod 2004/01/18 19:59:12 1.11 +++ uuid.pod 2004/01/19 12:15:05 1.12 @@ -186,7 +186,7 @@ =item B, B, B, B -The I bits for use with B(). The +The I bits for use with B(). The BI specify which UUID version to generate. The B forces the use of a random multi-cast MAC address instead of the real physical MAC address in version 1 UUIDs. @@ -223,10 +223,6 @@ Destroy UUID object I. -=item uuid_rc_t B(uuid_t *I); - -Sets or resets the UUID in I to the I UUID. - =item uuid_rc_t B(uuid_t *I, int *I); Checks whether the UUID in I is the I UUID. @@ -240,7 +236,6 @@ smaller than I, C<0> if I is equal to I and C<+1> if I is greater than I. - =item uuid_rc_t B(uuid_t *I, uuid_fmt_t I, const void *I, size_t I); Imports a UUID I from an external representation of format I. @@ -264,7 +259,31 @@ minimum required length in C<*>I depends on it. Valid values for I are B, B and B. -=item uuid_rc_t B(uuid_t *I, unsigned int I, ...); +=item uuid_rc_t B(uuid_t *I, const char *I); + +Loads a pre-defined UUID value into the UUID object I. The +following I arguments are currently known: + +=over 4 + +=item I I + +=item nil 00000000-0000-0000-0000-000000000000 + +=item ns:DNS 6ba7b810-9dad-11d1-80b4-00c04fd430c8 + +=item ns:URL 6ba7b811-9dad-11d1-80b4-00c04fd430c8 + +=item ns:OID 6ba7b812-9dad-11d1-80b4-00c04fd430c8 + +=item ns:X500 6ba7b814-9dad-11d1-80b4-00c04fd430c8 + +=back + +The "CI" are names of pre-defined name-space UUIDs for use in +the generation of DCE 1.1 version 3 UUIDs. + +=item uuid_rc_t B(uuid_t *I, unsigned int I, ...); Generates a new UUID in I according to I and optional arguments (dependent on I). @@ -302,27 +321,31 @@ code. /* generate a DCE 1.1 v1 UUID from system environment */ - char *uuid_v1(void) + char *uuid_v1(void) { uuid_t *uuid; char *str = NULL; uuid_create(&uuid); - uuid_generate(uuid, UUID_VERSION1); - uuid_export(uuid, UUID_FMT_STR, &str, NULL); + uuid_make(uuid, UUID_VERSION1); + uuid_export(uuid, UUID_FMT_STR, (void **)&str, NULL); uuid_destroy(uuid); return str; } /* generate a DCE 1.1 v3 UUID from an URL */ - char *uuid_v3(const char *url) + char *uuid_v3(const char *url) { uuid_t *uuid; + uuid_t *uuid_ns; char *str = NULL; uuid_create(&uuid); - uuid_generate(uuid, UUID_VERSION3, "URL", url); - uuid_export(uuid, UUID_FMT_STR, &str, NULL); + uuid_create(&uuid_ns); + uuid_load(uuid_ns, "ns:URL"); + uuid_make(uuid, UUID_VERSION3, uuid_ns, url); + uuid_export(uuid, UUID_FMT_STR, (void **)&str, NULL); + uuid_destroy(uuid_ns); uuid_destroy(uuid); return str; } @@ -333,7 +356,7 @@ =over 4 -=item +=item B, IETF Internet Draft (expired), @@ -341,7 +364,7 @@ February 1998, 27 pages, http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt -=item +=item B, appendix B, @@ -349,16 +372,16 @@ Document Number C706, August 1997, 737 pages, (supersedes C309 DCE: Remote Procedure Call 8/1994, which was basis for ISO/IEC 11578:1996 specification), -http://www.opengroup.org/publications/catalog/c706.htm +http://www.opengroup.org/publications/catalog/c706.htm -=item +=item B, ISO/IEC 11578:1996, August 2001, 570 pages, (CHF 340,00), http://www.iso.ch/cate/d2229.html -=item +=item B, section B<6.4.1 Node Field Generation Without the IEEE 802 Address>, Index: ossp-pkg/uuid/uuid_cli.c RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/uuid_cli.c,v rcsdiff -q -kk '-r1.12' '-r1.13' -u '/v/ossp/cvs/ossp-pkg/uuid/Attic/uuid_cli.c,v' 2>/dev/null --- uuid_cli.c 2004/01/19 09:11:00 1.12 +++ uuid_cli.c 2004/01/19 12:15:05 1.13 @@ -71,6 +71,7 @@ int main(int argc, char *argv[]) { uuid_t *uuid; + uuid_t *uuid_ns; uuid_rc_t rc; FILE *fp; char *p; @@ -149,10 +150,10 @@ if (strlen(argv[0]) != UUID_LEN_STR) error(1, "invalid length of UUID string representation"); if ((rc = uuid_import(uuid, UUID_FMT_STR, argv[0], strlen(argv[0]))) != UUID_RC_OK) - error(1, "uuid_parse: %s", uuid_error(rc)); + error(1, "uuid_import: %s", uuid_error(rc)); vp = NULL; if ((rc = uuid_export(uuid, UUID_FMT_TXT, &vp, NULL)) != UUID_RC_OK) - error(1, "uuid_dump: %s", uuid_error(rc)); + error(1, "uuid_export: %s", uuid_error(rc)); fprintf(stdout, "%s", (char *)vp); free(vp); if ((rc = uuid_destroy(uuid)) != UUID_RC_OK) @@ -171,19 +172,29 @@ if (strlen(argv[0]) != UUID_LEN_STR) error(1, "invalid length of UUID string representation"); if ((rc = uuid_import(uuid, UUID_FMT_STR, argv[0], strlen(argv[0]))) != UUID_RC_OK) - error(1, "uuid_parse: %s", uuid_error(rc)); + error(1, "uuid_import: %s", uuid_error(rc)); } for (i = 0; i < count; i++) { if (iterate) { - if ((rc = uuid_nil(uuid)) != UUID_RC_OK) - error(1, "uuid_nil: %s", uuid_error(rc)); + if ((rc = uuid_load(uuid, "nil")) != UUID_RC_OK) + error(1, "uuid_load: %s", uuid_error(rc)); + } + if (version == UUID_VERSION3) { + if ((rc = uuid_create(&uuid_ns)) != UUID_RC_OK) + error(1, "uuid_create: %s", uuid_error(rc)); + if ((rc = uuid_load(uuid_ns, argv[0])) != UUID_RC_OK) { + if ((rc = uuid_import(uuid_ns, UUID_FMT_STR, argv[0], strlen(argv[0]))) != UUID_RC_OK) + error(1, "uuid_import: %s", uuid_error(rc)); + } + if ((rc = uuid_make(uuid, version, uuid_ns, argv[1])) != UUID_RC_OK) + error(1, "uuid_make: %s", uuid_error(rc)); + if ((rc = uuid_destroy(uuid_ns)) != UUID_RC_OK) + error(1, "uuid_destroy: %s", uuid_error(rc)); + } + else { + if ((rc = uuid_make(uuid, version)) != UUID_RC_OK) + error(1, "uuid_make: %s", uuid_error(rc)); } - if (version == UUID_VERSION3) - rc = uuid_generate(uuid, version, argv[0], argv[1]); - else - rc = uuid_generate(uuid, version); - if (rc != UUID_RC_OK) - error(1, "uuid_generate: %s", uuid_error(rc)); if (raw) { vp = NULL; if ((rc = uuid_export(uuid, UUID_FMT_BIN, &vp, &n)) != UUID_RC_OK) @@ -194,7 +205,7 @@ else { vp = NULL; if ((rc = uuid_export(uuid, UUID_FMT_STR, &vp, &n)) != UUID_RC_OK) - error(1, "uuid_format: %s", uuid_error(rc)); + error(1, "uuid_export: %s", uuid_error(rc)); fprintf(fp, "%s\n", (char *)vp); free(vp); }