diff options
| author | Karel Zak <kzak@redhat.com> | 2024-05-14 10:01:47 +0200 |
|---|---|---|
| committer | Karel Zak <kzak@redhat.com> | 2024-05-14 10:01:47 +0200 |
| commit | 6193777d7ba9e90a1999b1fecdd16f06a3e3cec1 (patch) | |
| tree | 56d99978bf7d9ac6be093850471efbf07269352b | |
| parent | 2d27e6e43f7946092c9cfc5d57b8d4bb58b34356 (diff) | |
| parent | a3d82ae138f4cd1534220773fcd8c29fa21ef540 (diff) | |
| download | util-linux-6193777d7ba9e90a1999b1fecdd16f06a3e3cec1.tar.gz | |
Merge branch 'uuidv7' of https://github.com/t-8ch/util-linux
* 'uuidv7' of https://github.com/t-8ch/util-linux:
uuidgen: add support for RFC9562 UUIDs
uuidparse: add support for RFC9562 UUIDs
libuuid: add support for RFC9562 UUIDs
| -rw-r--r-- | bash-completion/uuidgen | 2 | ||||
| -rw-r--r-- | libuuid/src/gen_uuid.c | 39 | ||||
| -rw-r--r-- | libuuid/src/libuuid.sym | 9 | ||||
| -rw-r--r-- | libuuid/src/uuid.h | 5 | ||||
| -rw-r--r-- | libuuid/src/uuid_time.c | 85 | ||||
| -rw-r--r-- | misc-utils/uuidgen.1.adoc | 7 | ||||
| -rw-r--r-- | misc-utils/uuidgen.c | 20 | ||||
| -rw-r--r-- | misc-utils/uuidparse.c | 15 | ||||
| -rw-r--r-- | tests/expected/uuid/uuidgen | 8 | ||||
| -rw-r--r-- | tests/expected/uuid/uuidparse | 5 | ||||
| -rwxr-xr-x | tests/ts/uuid/uuidgen | 4 | ||||
| -rwxr-xr-x | tests/ts/uuid/uuidparse | 3 |
12 files changed, 185 insertions, 17 deletions
diff --git a/bash-completion/uuidgen b/bash-completion/uuidgen index 45f690d45e..96b91cd624 100644 --- a/bash-completion/uuidgen +++ b/bash-completion/uuidgen @@ -31,6 +31,8 @@ _uuidgen_module() --md5 --count --sha1 + --time-v6 + --time-v7 --hex --help --version diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c index 59e8c23f01..aa353e4436 100644 --- a/libuuid/src/gen_uuid.c +++ b/libuuid/src/gen_uuid.c @@ -89,6 +89,7 @@ #include "c.h" #include "md5.h" #include "sha1.h" +#include "timeutils.h" #ifdef HAVE_TLS #define THREAD_LOCAL static __thread @@ -661,6 +662,44 @@ int uuid_generate_time_safe(uuid_t out) return uuid_generate_time_generic(out); } +void uuid_generate_time_v6(uuid_t out) +{ + struct uuid uu = {}; + uint64_t clock_reg; + + clock_reg = get_clock_counter(); + + uu.time_low = clock_reg >> 28; + uu.time_mid = clock_reg >> 12; + uu.time_hi_and_version = (clock_reg & 0x0FFF) | (6 << 12); + + ul_random_get_bytes(&uu.clock_seq, 8); + uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; + + uuid_pack(&uu, out); +} + +// FIXME variable additional information +void uuid_generate_time_v7(uuid_t out) +{ + struct timeval tv; + struct uuid uu; + uint64_t ms; + + gettimeofday(&tv, NULL); + + ms = tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC; + + uu.time_low = ms >> 16; + uu.time_mid = ms; + + ul_random_get_bytes(&uu.time_hi_and_version, 10); + uu.time_hi_and_version = (uu.time_hi_and_version & 0x0FFF) | (7 << 12); + uu.clock_seq = (uu.clock_seq & 0x3FFF) | 0x8000; + + uuid_pack(&uu, out); +} + int __uuid_generate_random(uuid_t out, int *num) { diff --git a/libuuid/src/libuuid.sym b/libuuid/src/libuuid.sym index 0f67ede0d5..4c4b4eba2e 100644 --- a/libuuid/src/libuuid.sym +++ b/libuuid/src/libuuid.sym @@ -60,6 +60,15 @@ global: uuid_time64; /* only on 32bit architectures with 64bit time_t */ } UUID_2.36; +/* + * version(s) since util-linux.2.41 + */ +UUID_2.41 { +global: + uuid_generate_time_v6; + uuid_generate_time_v7; +} UUID_2.40; + /* diff --git a/libuuid/src/uuid.h b/libuuid/src/uuid.h index 2e3642cd63..2e0f70aa9c 100644 --- a/libuuid/src/uuid.h +++ b/libuuid/src/uuid.h @@ -59,6 +59,9 @@ typedef unsigned char uuid_t[16]; #define UUID_TYPE_DCE_MD5 3 #define UUID_TYPE_DCE_RANDOM 4 #define UUID_TYPE_DCE_SHA1 5 +#define UUID_TYPE_DCE_TIME_V6 6 +#define UUID_TYPE_DCE_TIME_V7 7 +#define UUID_TYPE_DCE_VENDOR 8 #define UUID_TYPE_SHIFT 4 #define UUID_TYPE_MASK 0xf @@ -92,6 +95,8 @@ extern void uuid_generate(uuid_t out); extern void uuid_generate_random(uuid_t out); extern void uuid_generate_time(uuid_t out); extern int uuid_generate_time_safe(uuid_t out); +extern void uuid_generate_time_v6(uuid_t out); +extern void uuid_generate_time_v7(uuid_t out); extern void uuid_generate_md5(uuid_t out, const uuid_t ns, const char *name, size_t len); extern void uuid_generate_sha1(uuid_t out, const uuid_t ns, const char *name, size_t len); diff --git a/libuuid/src/uuid_time.c b/libuuid/src/uuid_time.c index 9b415b3ee7..d52c2f3070 100644 --- a/libuuid/src/uuid_time.c +++ b/libuuid/src/uuid_time.c @@ -53,30 +53,89 @@ #include <time.h> #include "uuidP.h" +#include "timeutils.h" #undef uuid_time /* prototype to make compiler happy */ time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv); +static uint64_t gregorian_to_unix(uint64_t ts) +{ + return ts - ((((uint64_t) 0x01B21DD2) << 32) + 0x13814000); +} + +static void uuid_time_v1(const struct uuid *uuid, struct timeval *tv) +{ + uint32_t high; + uint64_t clock_reg; + + high = uuid->time_mid | ((uuid->time_hi_and_version & 0xFFF) << 16); + clock_reg = uuid->time_low | ((uint64_t) high << 32); + + clock_reg = gregorian_to_unix(clock_reg); + tv->tv_sec = clock_reg / 10000000; + tv->tv_usec = (clock_reg % 10000000) / 10; +} + +static void uuid_time_v6(const struct uuid *uuid, struct timeval *tv) +{ + uint64_t clock_reg; + + clock_reg = uuid->time_low; + clock_reg <<= 16; + clock_reg |= uuid->time_mid; + clock_reg <<= 12; + clock_reg |= uuid->time_hi_and_version & 0xFFF; + + clock_reg = gregorian_to_unix(clock_reg); + tv->tv_sec = clock_reg / 10000000; + tv->tv_usec = (clock_reg % 10000000) / 10; +} + +static void uuid_time_v7(const struct uuid *uuid, struct timeval *tv) +{ + uint64_t clock_reg; + + clock_reg = uuid->time_low; + clock_reg <<= 16; + clock_reg |= uuid->time_mid; + + tv->tv_sec = clock_reg / MSEC_PER_SEC; + tv->tv_usec = (clock_reg % MSEC_PER_SEC) * USEC_PER_MSEC; +} + +static uint8_t __uuid_type(const struct uuid *uuid) +{ + return (uuid->time_hi_and_version >> 12) & 0xF; +} /* this function could be 32bit time_t and 32bit timeval or 64bit, depending on compiler flags and architecture. */ time_t __uuid_time(const uuid_t uu, struct timeval *ret_tv) { - struct timeval tv; - struct uuid uuid; - uint32_t high; - uint64_t clock_reg; + struct timeval tv; + struct uuid uuid; + uint8_t type; uuid_unpack(uu, &uuid); + type = __uuid_type(&uuid); - high = uuid.time_mid | ((uuid.time_hi_and_version & 0xFFF) << 16); - clock_reg = uuid.time_low | ((uint64_t) high << 32); - - clock_reg -= (((uint64_t) 0x01B21DD2) << 32) + 0x13814000; - tv.tv_sec = clock_reg / 10000000; - tv.tv_usec = (clock_reg % 10000000) / 10; + switch (type) { + case UUID_TYPE_DCE_TIME: + uuid_time_v1(&uuid, &tv); + break; + case UUID_TYPE_DCE_TIME_V6: + uuid_time_v6(&uuid, &tv); + break; + case UUID_TYPE_DCE_TIME_V7: + uuid_time_v7(&uuid, &tv); + break; + default: + tv.tv_sec = -1; + tv.tv_usec = -1; + break; + } if (ret_tv) *ret_tv = tv; @@ -88,7 +147,7 @@ extern time_t uuid_time64(const uuid_t uu, struct timeval *ret_tv) __attribute__ #else extern time_t uuid_time(const uuid_t uu, struct timeval *ret_tv) __attribute__((weak, alias("__uuid_time"))); #endif - + #if defined(__USE_TIME_BITS64) && defined(__GLIBC__) struct timeval32 { @@ -104,7 +163,7 @@ static inline int in_time32_t_range(time_t t) { int32_t s; - + s = t; return s == t; @@ -137,7 +196,7 @@ int uuid_type(const uuid_t uu) struct uuid uuid; uuid_unpack(uu, &uuid); - return ((uuid.time_hi_and_version >> 12) & 0xF); + return __uuid_type(&uuid); } int uuid_variant(const uuid_t uu) diff --git a/misc-utils/uuidgen.1.adoc b/misc-utils/uuidgen.1.adoc index 659a7804dc..1d89fe43d6 100644 --- a/misc-utils/uuidgen.1.adoc +++ b/misc-utils/uuidgen.1.adoc @@ -42,6 +42,12 @@ Use MD5 as the hash algorithm. *-s*, *--sha1*:: Use SHA1 as the hash algorithm. +*-6*, *--time-v6*:: +Generate a time-based UUID. This method creates a UUID based on the system clock plus and is lexicographically sortable according to the contained timestamp. + +*-7*, *--time-v7*:: +Generate a time-based UUID. This method creates a UUID based on the system clock plus and is lexicographically sortable according to the contained timestamp. + *-n*, *--namespace* _namespace_:: Generate the hash with the _namespace_ prefix. The _namespace_ is UUID, or '@ns' where "ns" is well-known predefined UUID addressed by namespace name (see above). @@ -71,6 +77,7 @@ uuidgen --sha1 --namespace @dns --name "www.example.com" *uuidparse*(1), *libuuid*(3), link:https://tools.ietf.org/html/rfc4122[RFC 4122] +link:https://tools.ietf.org/html/rfcXXXX[RFC XXXX] include::man-common/bugreports.adoc[] diff --git a/misc-utils/uuidgen.c b/misc-utils/uuidgen.c index 57769c1f40..56dea3c711 100644 --- a/misc-utils/uuidgen.c +++ b/misc-utils/uuidgen.c @@ -40,6 +40,8 @@ static void __attribute__((__noreturn__)) usage(void) fputs(_(" -m, --md5 generate md5 hash\n"), out); fputs(_(" -C, --count <num> generate more uuids in loop\n"), out); fputs(_(" -s, --sha1 generate sha1 hash\n"), out); + fputs(_(" -6, --time-v6 generate time-based v6 uuid\n"), out); + fputs(_(" -7, --time-v7 generate time-based v7 uuid\n"), out); fputs(_(" -x, --hex interpret name as hex string\n"), out); fputs(USAGE_SEPARATOR, out); fprintf(out, USAGE_HELP_OPTIONS(21)); @@ -104,14 +106,16 @@ main (int argc, char *argv[]) {"md5", no_argument, NULL, 'm'}, {"count", required_argument, NULL, 'C'}, {"sha1", no_argument, NULL, 's'}, + {"time-v6", no_argument, NULL, '6'}, + {"time-v7", no_argument, NULL, '7'}, {"hex", no_argument, NULL, 'x'}, {NULL, 0, NULL, 0} }; static const ul_excl_t excl[] = { + { '6', '7', 'm', 'r', 's', 't' }, { 'C', 'm', 's' }, { 'N', 'r', 't' }, - { 'm', 'r', 's', 't' }, { 'n', 'r', 't' }, { 0 } }; @@ -122,7 +126,7 @@ main (int argc, char *argv[]) textdomain(PACKAGE); close_stdout_atexit(); - while ((c = getopt_long(argc, argv, "C:rtVhn:N:msx", longopts, NULL)) != -1) { + while ((c = getopt_long(argc, argv, "C:rtVhn:N:msx67", longopts, NULL)) != -1) { err_exclusive_options(c, longopts, excl, excl_st); @@ -151,6 +155,12 @@ main (int argc, char *argv[]) case 'x': is_hex = 1; break; + case '6': + do_type = UUID_TYPE_DCE_TIME_V6; + break; + case '7': + do_type = UUID_TYPE_DCE_TIME_V7; + break; case 'h': usage(); @@ -192,6 +202,12 @@ main (int argc, char *argv[]) case UUID_TYPE_DCE_TIME: uuid_generate_time(uu); break; + case UUID_TYPE_DCE_TIME_V6: + uuid_generate_time_v6(uu); + break; + case UUID_TYPE_DCE_TIME_V7: + uuid_generate_time_v7(uu); + break; case UUID_TYPE_DCE_RANDOM: uuid_generate_random(uu); break; diff --git a/misc-utils/uuidparse.c b/misc-utils/uuidparse.c index 33d961c922..1336038118 100644 --- a/misc-utils/uuidparse.c +++ b/misc-utils/uuidparse.c @@ -203,6 +203,12 @@ static void fill_table_row(struct libscols_table *tb, char const *const uuid) case UUID_TYPE_DCE_TIME: str = xstrdup(_("time-based")); break; + case UUID_TYPE_DCE_TIME_V6: + str = xstrdup(_("time-v6")); + break; + case UUID_TYPE_DCE_TIME_V7: + str = xstrdup(_("time-v7")); + break; case UUID_TYPE_DCE_SECURITY: str = xstrdup("DCE"); break; @@ -215,6 +221,9 @@ static void fill_table_row(struct libscols_table *tb, char const *const uuid) case UUID_TYPE_DCE_SHA1: str = xstrdup(_("sha1-based")); break; + case UUID_TYPE_DCE_VENDOR: + str = xstrdup(_("vendor")); + break; default: str = xstrdup(_("unknown")); } @@ -224,7 +233,11 @@ static void fill_table_row(struct libscols_table *tb, char const *const uuid) str = xstrdup(_("invalid")); break; } - if (variant == UUID_VARIANT_DCE && type == UUID_TYPE_DCE_TIME) { + if (variant != UUID_VARIANT_DCE) + break; + if (type == UUID_TYPE_DCE_TIME || + type == UUID_TYPE_DCE_TIME_V6 || + type == UUID_TYPE_DCE_TIME_V7) { struct timeval tv; char date_buf[ISO_BUFSIZ]; diff --git a/tests/expected/uuid/uuidgen b/tests/expected/uuid/uuidgen index b0d1d98e74..7d517af8a3 100644 --- a/tests/expected/uuid/uuidgen +++ b/tests/expected/uuid/uuidgen @@ -2,7 +2,15 @@ option: -r return values: 0 and 0 option: -t return values: 0 and 0 +option: -6 +return values: 0 and 0 +option: -7 +return values: 0 and 0 option: --random return values: 0 and 0 option: --time return values: 0 and 0 +option: --time-v6 +return values: 0 and 0 +option: --time-v7 +return values: 0 and 0 diff --git a/tests/expected/uuid/uuidparse b/tests/expected/uuid/uuidparse index 5cac367559..9edb05e4e9 100644 --- a/tests/expected/uuid/uuidparse +++ b/tests/expected/uuid/uuidparse @@ -11,7 +11,7 @@ UUID VARIANT TYPE TIME 00000000-0000-3000-8000-000000000000 DCE name-based 00000000-0000-4000-8000-000000000000 DCE random 00000000-0000-5000-8000-000000000000 DCE sha1-based -00000000-0000-6000-8000-000000000000 DCE unknown +00000000-0000-6000-8000-000000000000 DCE time-v6 60038-03-11 05:36:10,955161+00:00 00000000-0000-0000-d000-000000000000 Microsoft 00000000-0000-1000-d000-000000000000 Microsoft 00000000-0000-2000-d000-000000000000 Microsoft @@ -27,5 +27,8 @@ UUID VARIANT TYPE TIME 00000000-0000-5000-f000-000000000000 other 00000000-0000-6000-f000-000000000000 other 9b274c46-544a-11e7-a972-00037f500001 DCE time-based 2017-06-18 17:21:46,544647+00:00 +1ec9414c-232a-6b00-b3c8-9f6bdeced846 DCE time-v6 2022-02-22 19:22:22,000000+00:00 +017f22e2-79b2-7cc3-98c4-dc0c0c07398f DCE time-v7 2022-02-22 19:22:22,002000+00:00 +5c146b14-3c52-8afd-938a-375d0df1fbf6 DCE vendor invalid-input invalid invalid invalid return value: 0 diff --git a/tests/ts/uuid/uuidgen b/tests/ts/uuid/uuidgen index cbaaefa7b3..48fab12f7b 100755 --- a/tests/ts/uuid/uuidgen +++ b/tests/ts/uuid/uuidgen @@ -37,8 +37,12 @@ test_flag() { test_flag -r test_flag -t +test_flag -6 +test_flag -7 test_flag --random test_flag --time +test_flag --time-v6 +test_flag --time-v7 rm -f "$OUTPUT_FILE" diff --git a/tests/ts/uuid/uuidparse b/tests/ts/uuid/uuidparse index 915886c8f7..2903ce56dc 100755 --- a/tests/ts/uuid/uuidparse +++ b/tests/ts/uuid/uuidparse @@ -54,6 +54,9 @@ echo '00000000-0000-0000-0000-000000000000 00000000-0000-6000-f000-000000000000 9b274c46-544a-11e7-a972-00037f500001 +1ec9414c-232a-6b00-b3c8-9f6bdeced846 +017f22e2-79b2-7cc3-98c4-dc0c0c07398f +5c146b14-3c52-8afd-938a-375d0df1fbf6 invalid-input' | $TS_CMD_UUIDPARSE >> $TS_OUTPUT 2>> $TS_ERRLOG echo "return value: $?" >> $TS_OUTPUT |
