Index: ossp-pkg/uuid/ChangeLog RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/ChangeLog,v rcsdiff -q -kk '-r1.26' '-r1.27' -u '/v/ossp/cvs/ossp-pkg/uuid/Attic/ChangeLog,v' 2>/dev/null --- ChangeLog 2004/01/18 19:22:54 1.26 +++ ChangeLog 2004/01/18 19:59:12 1.27 @@ -13,6 +13,16 @@ Changes between 0.9.3 and 0.9.4 (16-Jan-2004 to xx-Jan-2004) + 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. + [Ralf S. Engelschall] + + o Document what DCE 1.1 UUID versions exist and what they are + intended for. + [Ralf S. Engelschall] + o Cleanup the C code to also pass warning-free a C++ compiler. [Ralf S. Engelschall] Index: ossp-pkg/uuid/TODO RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/TODO,v rcsdiff -q -kk '-r1.14' '-r1.15' -u '/v/ossp/cvs/ossp-pkg/uuid/Attic/TODO,v' 2>/dev/null --- TODO 2004/01/18 19:23:12 1.14 +++ TODO 2004/01/18 19:59:12 1.15 @@ -1,9 +1,6 @@ TODO - API versioning -- documentation of Vx and intentions - v1: one-time global unique identifier - v3: repeatable not-unique message digest - v4: one-time local unique identifier +- why are nanoseconds always "1"?! CANDO - getopt_long support - a more sophisticated test suite @@ -12,7 +9,3 @@ - persistent/non-volatile state writing? - additional Perl API for covering Perl language - additional C API for DCE 1.1 compatibility -- unify pack/unpack/parse/format/dump into: - typedef enum { UUID_FMT_BIN, UUID_FMT_STR, UUID_FMT_TXT, UUID_FMT_XML } uuid_fmt_t; - uuid_rc_t uuid_import(uuid_t *_uuid, uuid_fmt_t _fmt, const void *_buf, size_t _size); - uuid_rc_t uuid_export(uuid_t *_uuid, uuid_fmt_t _fmt, void **_buf, size_t _size); Index: ossp-pkg/uuid/uuid.c RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.c,v rcsdiff -q -kk '-r1.35' '-r1.36' -u '/v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.c,v' 2>/dev/null --- uuid.c 2004/01/18 19:22:54 1.35 +++ uuid.c 2004/01/18 19:59:12 1.36 @@ -51,8 +51,82 @@ #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 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. + + 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. + + 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 ;-) + + 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). + + 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. + + 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. */ + +/* 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 MAC_OCTETS 6 +#define IEEE_MAC_OCTETS 6 /* UUID binary representation according to UUID standards */ typedef struct { @@ -61,7 +135,7 @@ 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[MAC_OCTETS]; /* bits 0-47 of node MAC address */ + uuid_uint8_t node[IEEE_MAC_OCTETS]; /* bits 0-47 of node MAC address */ } uuid_obj_t; /* abstract data type (ADT) of API */ @@ -69,7 +143,7 @@ uuid_obj_t obj; /* inlined UUID object */ prng_t *prng; /* RPNG sub-object */ md5_t *md5; /* MD5 sub-object */ - uuid_uint8_t mac[MAC_OCTETS]; /* pre-determined MAC address */ + 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 */ }; @@ -125,19 +199,6 @@ return UUID_RC_OK; } -/* 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; -} - /* check whether UUID object represents "Nil UUID" */ uuid_rc_t uuid_isnil(uuid_t *uuid, int *result) { @@ -211,9 +272,9 @@ return UUID_RC_OK; } -/* unpack UUID binary presentation into UUID object +/* INTERNAL: unpack UUID binary presentation into UUID object (allows in-place operation for internal efficiency!) */ -uuid_rc_t uuid_unpack(uuid_t *uuid, const void *buf) +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; @@ -221,11 +282,11 @@ unsigned int i; /* sanity check argument(s) */ - if (uuid == NULL || buf == NULL) + if (uuid == NULL || data_ptr == NULL || data_len < UUID_LEN_BIN) return UUID_RC_ARG; - /* treat input buffer as octet stream */ - in = (const uuid_uint8_t *)buf; + /* treat input data_ptrfer as octet stream */ + in = (const uuid_uint8_t *)data_ptr; /* unpack "time_low" field */ tmp32 = *in++; @@ -257,9 +318,9 @@ return UUID_RC_OK; } -/* pack UUID object into binary representation +/* INTERNAL: pack UUID object into binary representation (allows in-place operation for internal efficiency!) */ -uuid_rc_t uuid_pack(uuid_t *uuid, void **buf) +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; @@ -267,16 +328,26 @@ unsigned int i; /* sanity check argument(s) */ - if (uuid == NULL || buf == NULL) + if (uuid == NULL || data_ptr == NULL) return UUID_RC_ARG; - /* optionally allocate octet buffer */ - if (*buf == NULL) - if ((*buf = malloc(sizeof(uuid_t))) == NULL) + /* optionally allocate octet data_ptrfer */ + 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 buffer as octet stream */ - out = (uuid_uint8_t *)(*buf); + /* treat output data_ptrfer as octet stream */ + out = (uuid_uint8_t *)(*data_ptr); /* pack "time_low" field */ tmp32 = uuid->obj.time_low; @@ -337,19 +408,21 @@ return UUID_TRUE; } -/* parse string representation into UUID object */ -uuid_rc_t uuid_parse(uuid_t *uuid, const char *str) +/* 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 || str == NULL) + 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; @@ -375,20 +448,30 @@ return UUID_RC_OK; } -/* format UUID object into string representation */ -uuid_rc_t uuid_format(uuid_t *uuid, char **str) +/* 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 || str == NULL) + if (uuid == NULL || data_ptr == NULL) return UUID_RC_ARG; - /* optionally allocate string buffer */ - if (*str == NULL) - if ((*str = (char *)malloc(UUID_LEN_STR+1)) == NULL) + /* 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(*str, UUID_LEN_STR+1, + 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, @@ -405,92 +488,247 @@ return UUID_RC_OK; } -/* INTERNAL: brand UUID with version and variant */ -static void uuid_brand(uuid_t *uuid, int version) +/* 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) { - /* 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); + 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; - /* 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; -} + /* sanity check argument(s) */ + if (uuid == NULL || data_ptr == NULL) + return UUID_RC_ARG; -/* 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 + /* initialize output buffer */ + out_ptr = NULL; + out = &out_ptr; -/* 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" + /* check for special case of "Nil UUID" */ + if ((rc = uuid_isnil(uuid, &isnil)) != UUID_RC_OK) + return rc; -/* IEEE 802 MAC address encoding/decoding bit fields + /* 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); - ATTENTION: + /* 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); - 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): + /* 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); - "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." + /* + * decode UUID content + */ - 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. + if (tmp8 == BM_OCTET(1,0,0,0,0,0,0,0) && tmp16 == 1) { + /* decode DCE 1.1 version 1 UUID */ - 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. + /* 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); - 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 ;-) + /* 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); - 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). + /* 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 */ - 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. + /* 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"; - 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. */ + /* pack UUID into binary representation */ + tmp_ptr = (void *)&tmp_bin; + tmp_len = sizeof(tmp_bin); + if ((rc = uuid_export_bin(uuid, &tmp_ptr, &tmp_len)) != UUID_RC_OK) + return rc; -/* 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) + /* mask out version and variant parts */ + tmp_bin[6] &= BM_MASK(3,0); + tmp_bin[8] &= BM_MASK(5,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) + /* 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_generate_v1(uuid_t *uuid, unsigned int mode, va_list ap) @@ -625,6 +863,19 @@ return UUID_RC_OK; } +/* 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) */ static struct { @@ -666,10 +917,10 @@ /* custom namespace via UUID string representation */ if ((rc = uuid_create(&uuid_object)) != UUID_RC_OK) return rc; - if ((rc = uuid_parse(uuid_object, ns)) != UUID_RC_OK) + if ((rc = uuid_import_str(uuid_object, ns, strlen(ns))) != UUID_RC_OK) return rc; uuid_octets = (void *)&(uuid_object->obj); - uuid_pack(uuid_object, &uuid_octets); + uuid_export_bin(uuid_object, &uuid_octets, NULL); md5_update(uuid->md5, uuid_octets, UUID_LEN_BIN); uuid_destroy(uuid_object); } @@ -697,9 +948,9 @@ md5_store(uuid->md5, &uuid_octets, NULL); /* fulfill requirement of standard and convert UUID data into - local/host byte order (this uses fact that uuid_unpack() is + local/host byte order (this uses fact that uuid_import_bin() is able to operate in-place!) */ - uuid_unpack(uuid, (void *)&(uuid->obj)); + uuid_import_bin(uuid, (void *)&(uuid->obj), UUID_LEN_BIN); /* brand UUID with version and variant */ uuid_brand(uuid, 3); @@ -744,172 +995,6 @@ return rc; } -/* 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; -} - /* translate UUID API error code into corresponding error string */ char *uuid_error(uuid_rc_t rc) { Index: ossp-pkg/uuid/uuid.h RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.h,v rcsdiff -q -kk '-r1.12' '-r1.13' -u '/v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.h,v' 2>/dev/null --- uuid.h 2004/01/18 19:22:54 1.12 +++ uuid.h 2004/01/18 19:59:12 1.13 @@ -51,7 +51,8 @@ UUID_RC_ARG = 1, UUID_RC_MEM = 2, UUID_RC_SYS = 3, - UUID_RC_INT = 4 + UUID_RC_INT = 4, + UUID_RC_IMP = 5 } uuid_rc_t; /* generation mode flags */ @@ -62,6 +63,13 @@ UUID_MCASTRND = (1 << 3) }; +/* import/export formats */ +typedef enum { + UUID_FMT_BIN = 0, /* import/export */ + UUID_FMT_STR = 1, /* import/export */ + UUID_FMT_TXT = 2 /* export only */ +} uuid_fmt_t; + /* abstract data type */ struct uuid_st; typedef struct uuid_st uuid_t; @@ -69,25 +77,20 @@ /* object handling */ extern uuid_rc_t uuid_create (uuid_t **_uuid); 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, ...); /* UUID comparison */ extern uuid_rc_t uuid_isnil (uuid_t *_uuid, int *_result); extern uuid_rc_t uuid_compare (uuid_t *_uuid, uuid_t *_uuid2, int *_result); -/* UUID binary representation handling */ -extern uuid_rc_t uuid_unpack (uuid_t *_uuid, const void *_buf); -extern uuid_rc_t uuid_pack (uuid_t *_uuid, void **_buf); - -/* UUID string representation handling */ -extern uuid_rc_t uuid_parse (uuid_t *_uuid, const char *_str); -extern uuid_rc_t uuid_format (uuid_t *_uuid, char **_str); - -/* UUID generation and dumping */ -extern uuid_rc_t uuid_generate (uuid_t *_uuid, unsigned int _mode, ...); -extern uuid_rc_t uuid_dump (uuid_t *_uuid, char **_str); +/* UUID import/export */ +extern uuid_rc_t uuid_import (uuid_t *_uuid, uuid_fmt_t _fmt, const void *_data_ptr, size_t _data_len); +extern uuid_rc_t uuid_export (uuid_t *_uuid, uuid_fmt_t _fmt, void **_data_ptr, size_t *_data_len); -/* error handling */ +/* library error handling */ extern char *uuid_error (uuid_rc_t _rc); DECLARATION_END Index: ossp-pkg/uuid/uuid.pod RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.pod,v co -q -kk -p'1.11' '/v/ossp/cvs/ossp-pkg/uuid/Attic/uuid.pod,v' | diff -u /dev/null - -L'ossp-pkg/uuid/uuid.pod' 2>/dev/null --- ossp-pkg/uuid/uuid.pod +++ - 2024-05-17 00:41:03.646209271 +0200 @@ -0,0 +1,398 @@ +## +## 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.pod: manual page +## + +=pod + +=head1 NAME + +B - B + +=head1 VERSION + +OSSP uuid UUID_VERSION_STR + +=head1 DESCRIPTION + +B is a ISO-C application programming interface (API) and +corresponding command line interface (CLI) for the generation of DCE +1.1 and ISO/IEC 11578:1996 compliant I +(UUID). It supports DCE 1.1 variant UUIDs of version 1 (time and node +based), version 3 (name based) and version 4 (random number based). + +UUIDs are 128 bit numbers which are intended to have a high likelihood +of uniqueness over space and time and are computationally difficult +to guess. They are globally unique identifiers which can be locally +generated without contacting a global registration authority. UUIDs +are intended as unique identifiers for both mass tagging objects +with an extremely short lifetime and to reliably identifying very +persistent objects across a network. + +This is the ISO-C application programming interface (API) of B. + +=head2 UUID Binary Representation + +According to the DCE 1.1 and ISO/IEC 11578:1996 standards, a DCE 1.1 +variant UUID is a 128 bit number defined out of 7 fields, each field a +multiple of an octet in size and stored in network byte order: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 0| time_low | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 1| time_mid | time_hi_and_version | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 2|clk_seq_hi_res | clk_seq_low | node (0-1) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + 3| node (2-5) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +An example of a UUID binary representation is the octet stream "C<0xEC +0xB9 0xF3 0x5F 0x44 0x2A 0x11 0xD8 0x8A 0x24 0x00 0x90 0x27 0x2F 0xF7 +0x25>". The binary representation format is exactly what the B +API functions B() and B() deal with. + +=head2 UUID ASCII String Representation + +According to the DCE 1.1 and ISO/IEC 11578:1996 standards, a DCE +1.1 variant UUID is represented as an ASCII string consisting +of 8 hexadecimal digits followed by a hyphen, then three groups +of 4 hexadecimal digits each followed by a hyphen, then 12 +hexadecimal digits. Formally, the string representation is defined by +the following grammar: + + uuid = "-" "-" + "-" + + "-" + time_low = 4* + time_mid = 2* + time_high_and_version = 2* + clock_seq_and_reserved = + clock_seq_low = + node = 6* + hex_octet = + hex_digit = "0"|"1"|"2"|"3"|"4"|"5"|"6"|"7"|"8"|"9" + |"a"|"b"|"c"|"d"|"e"|"f" + |"A"|"B"|"C"|"D"|"E"|"F" + +An example of a UUID string representation is the ASCII string +"C<54531d28-402b-11d8-af12-0002a5094c23>". The string representation +format is exactly what the B API functions B() and +B() deal with. + +=head2 UUID Variants and Versions + +A UUID has a variant and version. The variant defines the layout of the +UUID. The version defines the content of the UUID. The UUID variant +supported in B is the DCE 1.1 variant only. The DCE 1.1 UUID +variant versions supported in B are: + +=over 4 + +=item B (time and node based) + +These are the classical UUIDs, created out of a 60-bit system time, +a 14-bit local clock sequence and 48-bit system MAC address. The MAC +address can be either the real one of a physical network interface card +(NIC) or a random multi-cast MAC address. Version 1 UUIDs are usually +used as one-time global unique identifiers. + +=item B (name based) + +These are UUIDs which are based on the 128-bit MD5 message digest of the +concatenation of a 128-bit namespace UUID and a name string of arbitrary +length. Version 3 UUIDs are usually used for non-unique but repeatable +message digest identifiers. + +=item B (random data based) + +These are UUIDs which are based on just 128-bit of random data. Version +4 UUIDs are usually used as one-time local unique identifiers. + +=back + +=head2 UUID Uniqueness + +Version 1 UUIDs are guaranteed to be unique through combinations of +hardware addresses, time stamps and random seeds. There is a reference +in the UUID to the hardware (MAC) address of the first network interface +card (NIC) on the host which generated the UUID -- this reference +is intended to ensure the UUID will be unique in space as the MAC +address of every network card is assigned by a single global authority +(IEEE) and is guaranteed to be unique. The next component in a UUID +is a timestamp which, as clock always (should) move forward, will +be unique in time. Just in case some part of the above goes wrong +(the hardware address cannot be determined or the clock moved steps +backward), there is a random clock sequence component placed into the +UUID as a "catch-all" for uniqueness. + +Version 3 UUIDs are guaranteed to be inherently globally unique if the +combination of namespace and name used to generate them is unique. + +Version 4 UUIDs are not guaranteed to be globally unique, because they +are generated out of locally gathered pseudo-random numbers only. +Nevertheless there is still a high likelihood of uniqueness over space +and time and that they are computationally difficult to guess. + +=head2 Nil UUID + +There is a special I UUID consisting of all octets set to zero in +the binary representation. It can be used as a special UUID value which does +not conflict with real UUIDs. + +=head1 APPLICATION PROGRAMMING INTERFACE + +The ISO-C Application Programming Interface (API) of B +consists of the following components. + +=head2 CONSTANTS + +The following constants are provided: + +=over 4 + +=item B, B + +The number of octets of the UUID binary and string representations. +Notice that the lengths of the string representation does I include +the necessary C termination character. + +=item B, B, B, B + +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. + +=item B, B, B, B, B + +The possible numerical return-codes of API functions. +Use B() to translate them into string versions. + +=item B, B, B + +The I formats for use with B() and B(). +The B indicates the UUID binary representation (of +length B), the B indicates the UUID string +representation (of length B) and the B +indicates the textual description (of arbitrary length) of a UUID. + +=back + +=head2 FUNCTIONS + +The following functions are provided: + +=over 4 + +=item uuid_rc_t B(uuid_t **I); + +Create a new UUID object and store a pointer to it in C<*>I. +A UUID object consists of an internal representation of a UUID, the +internal PRNG and MD5 generator contexts, and cached MAC address and +timestamp information. The initial UUID is the I UUID. + +=item uuid_rc_t B(uuid_t *I); + +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. +If this is the case, it returns I in C<*>I. +Else it returns I in C<*>I. + +=item uuid_rc_t B(uuid_t *I, uuid_t *I, int *I); + +Compares the order of the two UUIDs in I and I +and returns the result in C<*>I: C<-1> if I is +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. +The data is read from the buffer at I which contains at least +I bytes. + +The format of the external representation is specified by I and the +minimum expected length in I depends on it. Valid values for +I are B and B. + +=item uuid_rc_t B(uuid_t *I, uuid_fmt_t I, void **I, size_t *I); + +Exports a UUID I into an external representation of format I. +The data is written to the buffer at C<*>I which has room +for at least C<*>I bytes. If C<*>I is C, +a new buffer is allocated (and I ignored as input). If +I is not C, the number of written bytes are stored into +C<*>I. + +The format of the external representation is specified by I and the +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, ...); + +Generates a new UUID in I according to I and optional +arguments (dependent on I). + +If I contains the C bit, a DCE 1.1 variant UUID of +version 1 is generated. Then optionally the bit C forces +the use of random multi-cast MAC address instead of the real physical +MAC address (the default). The UUID is generated out of the 60-bit current +system time, a 12-bit clock sequence and the 48-bit MAC address. + +If I contains the C bit, a DCE 1.1 variant UUID +of version 3 is generated and two additional C-terminated string +arguments of type "C" are expected: first a namespace, +given as an internally pre-defined id (currently known are ids "C", +"C", "C", and "C") or a UUID in string representation. +Second, a name string of arbitrary length. The UUID is generated out of +the 128-bit MD5 from the concatenated octet stream of namespace UUID and name +string. + +If I contains the C bit, a DCE 1.1 variant UUID +of version 4 is generated. The UUID is generated out of 128-bit random +data. + +=item char *B(uuid_rc_t I); + +Returns a constant string representation corresponding to the +return-code I for use in displaying B errors. + +=back + +=head1 EXAMPLE + +The following shows an example usage of the API. Error handling is +omitted for code simplification and has to be re-added for production +code. + + /* generate a DCE 1.1 v1 UUID from system environment */ + 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_destroy(uuid); + return str; + } + + /* generate a DCE 1.1 v3 UUID from an URL */ + char *uuid_v3(const char *url) + { + uuid_t *uuid; + char *str = NULL; + + uuid_create(&uuid); + uuid_generate(uuid, UUID_VERSION3, "URL", url); + uuid_export(uuid, UUID_FMT_STR, &str, NULL); + uuid_destroy(uuid); + return str; + } + +=head1 SEE ALSO + +See the following are references to more B documentation and specifications: + +=over 4 + +=item + +B, +IETF Internet Draft (expired), +Paul J. Leach, Rich Salz, +February 1998, 27 pages, +http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt + +=item + +B, +appendix B, +Open Group Technical Standard +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 + +=item + +B, +ISO/IEC 11578:1996, +August 2001, 570 pages, (CHF 340,00), +http://www.iso.ch/cate/d2229.html + +=item + +B, +section B<6.4.1 Node Field Generation Without the IEEE 802 Address>, +IETF RFC 2518, +February 1999, 94 pages, +http://www.ietf.org/rfc/rfc2518.txt + +=item + +B, +P. Leach, M. Mealling, R. Salz, +IETF Internet Draft draft-mealling-uuid-urn-01, +October 2003, 31 pages, +http://www.ietf.org/internet-drafts/draft-mealling-uuid-urn-01.txt + +=item + +B, +FreeBSD manual pages uuid(3) and uuidgen(2), +http://www.freebsd.org/cgi/man.cgi?query=uuid&manpath=FreeBSD+5.2-RELEASE + +=back + +=head1 HISTORY + +B was implemented in January 2004 by Ralf S. Engelschall +Erse@engelschall.comE. It was prompted by the use of UUIDs +in the B and B projects. It is a clean room +implementation intended to be strictly standards compliant and maximum +portable. + +=head1 SEE ALSO + +uuid(1), uuid-config(1). + +=cut + Index: ossp-pkg/uuid/uuid_cli.c RCS File: /v/ossp/cvs/ossp-pkg/uuid/Attic/uuid_cli.c,v co -q -kk -p'1.11' '/v/ossp/cvs/ossp-pkg/uuid/Attic/uuid_cli.c,v' | diff -u /dev/null - -L'ossp-pkg/uuid/uuid_cli.c' 2>/dev/null --- ossp-pkg/uuid/uuid_cli.c +++ - 2024-05-17 00:41:03.649393956 +0200 @@ -0,0 +1,213 @@ +/* +** 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_cli.c: command line tool +*/ + +#include +#include +#include +#include +#include +#include + +#include "uuid.h" + +/* error handler */ +static void +error(int ec, const char *str, ...) +{ + va_list ap; + + va_start(ap, str); + fprintf(stderr, "uuid:ERROR: "); + vfprintf(stderr, str, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(ec); +} + +/* usage handler */ +static void +usage(const char *str, ...) +{ + va_list ap; + + va_start(ap, str); + if (str != NULL) { + fprintf(stderr, "uuid:ERROR: "); + vfprintf(stderr, str, ap); + fprintf(stderr, "\n"); + } + fprintf(stderr, "usage: uuid [-1] [-n count] [-a] [-d] [-o filename] [UUID]\n"); + va_end(ap); + exit(1); +} + +/* main procedure */ +int main(int argc, char *argv[]) +{ + uuid_t *uuid; + uuid_rc_t rc; + FILE *fp; + char *p; + int ch; + int count; + int i; + int iterate; + int raw; + int decode; + char *cp; + void *vp; + size_t n; + unsigned int version; + + /* command line parsing */ + count = -1; /* no count yet */ + fp = stdout; /* default output file */ + iterate = 0; /* not one at a time */ + raw = 0; /* default is ASCII output */ + decode = 0; /* default is to encode */ + version = UUID_VERSION1; + while ((ch = getopt(argc, argv, "1n:rdmo:v:")) != -1) { + switch (ch) { + case '1': + iterate = 1; + break; + case 'n': + if (count > 0) + usage("option 'n' specified multiple times"); + count = strtol(optarg, &p, 10); + if (*p != '\0' || count < 1) + usage("invalid argument to option 'n'"); + break; + case 'r': + raw = 1; + break; + case 'd': + decode = 1; + break; + case 'o': + if (fp != stdout) + error(1, "multiple output files are not allowed"); + if ((fp = fopen(optarg, "w")) == NULL) + error(1, "fopen: %s", strerror(errno)); + break; + case 'm': + version |= UUID_MCASTRND; + break; + case 'v': + i = strtol(optarg, &p, 10); + if (*p != '\0') + usage("invalid argument to option 'v'"); + switch (i) { + case 1: version = UUID_VERSION1; break;; + case 3: version = UUID_VERSION3; break;; + case 4: version = UUID_VERSION4; break;; + default: + usage("invalid version on option 'v'"); + break; + } + break; + default: + usage("invalid option '%c'", optopt); + } + } + argv += optind; + argc -= optind; + if (count == -1) + count = 1; + + if (decode) { + /* decoding */ + if (argc != 1) + usage("invalid number of arguments"); + if ((rc = uuid_create(&uuid)) != UUID_RC_OK) + error(1, "uuid_create: %s", uuid_error(rc)); + 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)); + cp = NULL; + if ((rc = uuid_export(uuid, UUID_FMT_TXT, (void **)&cp, NULL)) != UUID_RC_OK) + error(1, "uuid_dump: %s", uuid_error(rc)); + fprintf(stdout, "%s", cp); + free(cp); + if ((rc = uuid_destroy(uuid)) != UUID_RC_OK) + error(1, "uuid_destroy: %s", uuid_error(rc)); + } + else { + /* encoding */ + if ( (version == UUID_VERSION1 && argc != 0) + || (version == UUID_VERSION3 && argc != 2) + || (version == UUID_VERSION4 && argc != 0)) + usage("invalid number of arguments"); + if ((rc = uuid_create(&uuid)) != UUID_RC_OK) + error(1, "uuid_create: %s", uuid_error(rc)); + if (argc == 1) { + /* load initial UUID for setting old generator state */ + 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)); + } + 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 (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) + error(1, "uuid_export: %s", uuid_error(rc)); + fwrite(vp, n, 1, fp); + free(vp); + } + else { + cp = NULL; + if ((rc = uuid_export(uuid, UUID_FMT_STR, (void **)&cp, &n)) != UUID_RC_OK) + error(1, "uuid_format: %s", uuid_error(rc)); + fprintf(fp, "%s\n", cp); + free(cp); + } + } + if ((rc = uuid_destroy(uuid)) != UUID_RC_OK) + error(1, "uuid_destroy: %s", uuid_error(rc)); + } + + /* close output channel */ + if (fp != stdout) + fclose(fp); + + return 0; +} +