From: Thomas Weißschuh Date: Mon, 12 Feb 2024 17:44:41 +0000 (+0100) Subject: libuuid: add support for RFC9562 UUIDs X-Git-Tag: v2.42-start~339^2~2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c8d5fbcf64c2a912d22ed9d405e8a0d3e35263af;p=thirdparty%2Futil-linux.git libuuid: add support for RFC9562 UUIDs Signed-off-by: Thomas Weißschuh --- diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c index 59e8c23f0..aa353e443 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 0f67ede0d..4c4b4eba2 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 2e3642cd6..2e0f70aa9 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 9b415b3ee..d52c2f307 100644 --- a/libuuid/src/uuid_time.c +++ b/libuuid/src/uuid_time.c @@ -53,30 +53,89 @@ #include #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)