From 6f6bfb31acb0cfbe166d4df9f06a12bbdec0f496 Mon Sep 17 00:00:00 2001 From: Simon Wilkinson Date: Tue, 17 Jul 2012 16:50:59 +0100 Subject: [PATCH 1/1] opr: Add UUID handling functions Add a set of functions to the opr library to handle creating and manipulating UUIDs. The opr_uuid_t type is held as a 16 octet character string, which comprises the UUID encoded into network byte order. This is the primary form for manipulating UUIDs with this library, as it avoids any nbo/hbo problems. For applications which require raw access to the UUID components, the opr_uuid_unpacked structure is provided, and opr_uuid_pack/opr_uuid_unpack can be used to convert to and from this format. Finally, functions to print the UUID as a string, and parse a UUID from a string, are provided. When printing, we use the standard UUID format of 000000-0000-0000-0000-00000000. However, the afsUUID library used to print UUIDs as 000000-0000-0000-00-00-00000000, so we also accept this format. Change-Id: I78ef79b7ab8ae15fb955c6495118722875c94f8d Reviewed-on: http://gerrit.openafs.org/7977 Tested-by: BuildBot Reviewed-by: Derrick Brashear --- Makefile.in | 2 +- acinclude.m4 | 6 ++ src/opr/Makefile.in | 8 ++- src/opr/NTMakefile | 4 +- src/opr/uuid.c | 163 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/opr/uuid.h | 38 ++++++++++++ tests/TESTS | 1 + tests/opr/Makefile.in | 5 +- tests/opr/uuid-t.c | 65 ++++++++++++++++++++ 9 files changed, 287 insertions(+), 5 deletions(-) create mode 100644 src/opr/uuid.c create mode 100644 src/opr/uuid.h create mode 100644 tests/opr/uuid-t.c diff --git a/Makefile.in b/Makefile.in index 672e53d..22e3ca0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -149,7 +149,7 @@ config: prelude procmgmt: $(DIR_roken) config +${COMPILE_PART1} procmgmt ${COMPILE_PART2} -opr: config $(DIR_roken) +opr: config hcrypto $(DIR_roken) +${COMPILE_PART1} opr ${COMPILE_PART2} util: opr $(DIR_roken) procmgmt hcrypto lwp_depinstall rx_depinstall diff --git a/acinclude.m4 b/acinclude.m4 index 3855509..7e5c41f 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -1858,8 +1858,14 @@ LIB_hcrypto="-lafshcrypto" LDFLAGS_hcrypto="-L\$(TOP_LIBDIR)" AC_SUBST(LIB_hcrypto) AC_SUBST(LDFLAGS_hcrypto) + +dnl Check for UUID library +AC_CHECK_HEADERS([uuid/uuid.h]) +AC_CHECK_LIB(uuid, uuid_generate, LIBS_uuid="-luuid") +AC_CHECK_FUNCS([uuid_generate]) ]) + AC_DEFUN([SUMMARY], [ # Print a configuration summary echo diff --git a/src/opr/Makefile.in b/src/opr/Makefile.in index 6640779..11af649 100644 --- a/src/opr/Makefile.in +++ b/src/opr/Makefile.in @@ -2,14 +2,15 @@ srcdir=@srcdir@ include @TOP_OBJDIR@/src/config/Makefile.config include @TOP_OBJDIR@/src/config/Makefile.shared -objects = assert.o casestrcpy.o rbtree.o +objects = assert.o casestrcpy.o rbtree.o uuid.o HEADERS = $(TOP_INCDIR)/afs/opr.h \ $(TOP_INCDIR)/afs/opr_assert.h \ $(TOP_INCDIR)/opr/jhash.h \ $(TOP_INCDIR)/opr/queue.h \ $(TOP_INCDIR)/opr/rbtree.h \ - $(TOP_INCDIR)/opr/time.h + $(TOP_INCDIR)/opr/time.h \ + $(TOP_INCDIR)/opr/uuid.h all: $(HEADERS) $(TOP_LIBDIR)/libopr.a @@ -39,6 +40,9 @@ $(TOP_INCDIR)/opr/rbtree.h: ${srcdir}/rbtree.h $(TOP_INCDIR)/opr/time.h: ${srcdir}/opr_time.h $(INSTALL_DATA) $? $@ +$(TOP_INCDIR)/opr/uuid.h: ${srcdir}/uuid.h + $(INSTALL_DATA) $? $@ + clean: rm -f $(objects) libopr.a diff --git a/src/opr/NTMakefile b/src/opr/NTMakefile index 0eeefda..aec589a 100644 --- a/src/opr/NTMakefile +++ b/src/opr/NTMakefile @@ -16,7 +16,8 @@ INCFILES = \ $(DESTDIR)\include\opr\jhash.h \ $(DESTDIR)\include\opr\queue.h \ $(DESTDIR)\include\opr\rbtree.h \ - $(DESTDIR)\include\opr\time.h + $(DESTDIR)\include\opr\time.h \ + $(DESTDIR)\include\opr\uuid.h $(DESTDIR)\include\opr\time.h: opr_time.h $(COPY) $** $@ @@ -27,6 +28,7 @@ LIBOBJS = \ $(OUT)\assert.obj \ $(OUT)\casestrcpy.obj \ $(OUT)\rbtree.obj \ + $(OUT)\uuid.obj \ $(OUT)\AFS_component_version_number.obj $(LIBOBJS): $(INCFILES) diff --git a/src/opr/uuid.c b/src/opr/uuid.c new file mode 100644 index 0000000..451712d --- /dev/null +++ b/src/opr/uuid.c @@ -0,0 +1,163 @@ +/* + * Copyright (c) 2012 Your File System Inc. All rights reserved. + */ + +#include +#include + +#include + +#ifdef HAVE_UUID_UUID_H +# include +#endif + +#ifdef AFS_NT40_ENV +# include +#endif + +#include + +#include "uuid.h" +#include "jhash.h" + +static const opr_uuid_t nilUid = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + +void +opr_uuid_create(opr_uuid_t *uuid) +{ +#if defined (AFS_NT40_ENV) + struct opr_uuid_unpacked raw; + + UuidCreate((UUID *) &raw); + opr_uuid_pack(uuid, &raw); + +#elif !defined(KERNEL) && defined(HAVE_UUID_GENERATE) + + uuid_generate(uuid->data); + +#else + RAND_bytes(uuid->data, 16); + + uuid->data[6] = (uuid->data[6] & 0x0F) | 0x40; /* verison is 4 */ + uuid->data[8] = (uuid->data[8] & 0x3F) | 0x80; /* variant is DCE */ +#endif +} + +int +opr_uuid_isNil(const opr_uuid_t *uuid) +{ + return opr_uuid_equal(uuid, &nilUid); +} + +int +opr_uuid_equal(const opr_uuid_t *uuid1, const opr_uuid_t *uuid2) +{ + return memcmp(uuid1, uuid2, sizeof(opr_uuid_t)) == 0; +} + +int +opr_uuid_hash(const opr_uuid_t *uuid) +{ + /* uuid->data is a (unsigned char *), so there's every danger that this + * may cause an unaligned access on some platforms */ + return opr_jhash((const afs_uint32 *)uuid->data, 4, 0); +} + +#if !defined(KERNEL) +void +opr_uuid_toString(const opr_uuid_t *uuid, char **string) +{ + unsigned const char *p; + + p = uuid->data; + asprintf(string, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]); +} + +void +opr_uuid_freeString(char *string) +{ + free(string); +} + +int +opr_uuid_fromString(opr_uuid_t *uuid, const char *string) +{ + unsigned int i[16]; + int items, c; + + /* XXX - Traditionally, AFS has printed UUIDs as + * 00000000-0000-00-00-00000000. We should perhaps also accept + * that format here + */ + items = sscanf(string, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-" + "%02x%02x%02x%02x%02x%02x", + &i[0], &i[1], &i[2], &i[3], &i[4], &i[5], + &i[6], &i[7], &i[8], &i[9], &i[10], &i[11], + &i[12], &i[13], &i[14], &i[15]); + if (items !=16) { + /* Originally, AFS's printed UUIDs would take the form + * 00000000-0000-0000-00-00-00000000. Also handle this. */ + items = sscanf(string, + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x-%02x-" + "%02x%02x%02x%02x%02x%02x", + &i[0], &i[1], &i[2], &i[3], &i[4], &i[5], + &i[6], &i[7], &i[8], &i[9], &i[10], &i[11], + &i[12], &i[13], &i[14], &i[15]); + } + if (items !=16) + return EINVAL; + + for (c=0; c<16; c++) + uuid->data[c] = i[c]; + + return 0; +} + +void +opr_uuid_pack(opr_uuid_t *uuid, const struct opr_uuid_unpacked *raw) +{ + afs_uint32 intval; + unsigned short shortval; + + intval = htonl(raw->time_low); + memcpy(&uuid->data[0], &intval, sizeof(uint32_t)); + + shortval = htons(raw->time_mid); + memcpy(&uuid->data[4], &shortval, sizeof(uint16_t)); + + shortval = htons(raw->time_hi_and_version); + memcpy(&uuid->data[6], &shortval, sizeof(uint16_t)); + + uuid->data[8] = raw->clock_seq_hi_and_reserved; + uuid->data[9] = raw->clock_seq_low; + + memcpy(&uuid->data[10], &raw->node, 6); +} + +void +opr_uuid_unpack(const opr_uuid_t *uuid, struct opr_uuid_unpacked *raw) +{ + afs_uint32 intval; + unsigned short shortval; + + memcpy(&intval, &uuid->data[0], sizeof(uint32_t)); + raw->time_low = ntohl(intval); + + memcpy(&shortval, &uuid->data[4], sizeof(uint16_t)); + raw->time_mid = ntohs(shortval); + + memcpy(&shortval, &uuid->data[6], sizeof(uint16_t)); + raw->time_hi_and_version = ntohs(shortval); + + raw->clock_seq_hi_and_reserved = uuid->data[8]; + raw->clock_seq_low = uuid->data[9]; + + memcpy(&raw->node, &uuid->data[10], 6); +} + +#endif diff --git a/src/opr/uuid.h b/src/opr/uuid.h new file mode 100644 index 0000000..c69711b --- /dev/null +++ b/src/opr/uuid.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2012 Your File System Inc. All rights reserved. + */ + +#ifndef OPENAFS_OPR_UUID_H +#define OPENAFS_OPR_UUID_H 1 + +struct opr_uuid { + unsigned char data[16]; +}; + +struct opr_uuid_unpacked { + afs_uint32 time_low; + unsigned short time_mid; + unsigned short time_hi_and_version; + char clock_seq_hi_and_reserved; + char clock_seq_low; + char node[6]; +}; + +typedef struct opr_uuid opr_uuid_t; +typedef opr_uuid_t opr_uuid; /* For XDR */ + +extern void opr_uuid_create(opr_uuid_t *uuid); +extern int opr_uuid_isNil(const opr_uuid_t *uuid); +extern int opr_uuid_equal(const opr_uuid_t *uuid1, const opr_uuid_t *uuid2); +extern int opr_uuid_hash(const opr_uuid_t *uuid); + +#if !defined(KERNEL) +extern void opr_uuid_toString(const opr_uuid_t *uuid, char **string); +extern void opr_uuid_freeString(char *string); +extern int opr_uuid_fromString(opr_uuid_t *uuid, const char *string); +#endif + +extern void opr_uuid_pack(opr_uuid_t *uuid, const struct opr_uuid_unpacked *raw); +extern void opr_uuid_unpack(const opr_uuid_t *uuid, struct opr_uuid_unpacked *raw); + +#endif diff --git a/tests/TESTS b/tests/TESTS index 4ed9809..59c4fb3 100644 --- a/tests/TESTS +++ b/tests/TESTS @@ -9,6 +9,7 @@ opr/jhash opr/queues opr/rbtree opr/time +opr/uuid ptserver/pt_util ptserver/pts-man rx/event diff --git a/tests/opr/Makefile.in b/tests/opr/Makefile.in index dccdb58..e276dc4 100644 --- a/tests/opr/Makefile.in +++ b/tests/opr/Makefile.in @@ -7,7 +7,7 @@ MODULE_CFLAGS = -I$(srcdir)/../.. LIBS=../tap/libtap.a $(abs_top_builddir)/lib/libopr.a -tests = jhash-t queues-t rbtree-t time-t +tests = jhash-t queues-t rbtree-t time-t uuid-t all check test tests: $(tests) @@ -23,5 +23,8 @@ jhash-t: jhash-t.o time-t: time-t.o $(AFS_LDRULE) time-t.o ../tap/libtap.a $(XLIBS) +uuid-t: uuid-t.o + $(AFS_LDRULE) uuid-t.o ../tap/libtap.a $(LIBS) $(LIB_hcrypto) $(XLIBS) + clean distclean: $(RM) -f $(tests) *.o core diff --git a/tests/opr/uuid-t.c b/tests/opr/uuid-t.c new file mode 100644 index 0000000..e66721e --- /dev/null +++ b/tests/opr/uuid-t.c @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2012 Your File System Inc. All rights reserved. + */ + +#include +#include + +#include + +#include + +#include + +int +main(int argc, char **argv) +{ + opr_uuid_t uuidA = {{0x4F, 0x44, 0x94, 0x47, 0x76, 0xBA, 0x47, 0x2C, + 0x97, 0x1A, 0x86, 0x6B, 0xC0, 0x10, 0x1A, 0x4B}}; + opr_uuid_t uuidB = {{0x5D, 0x2A, 0x39, 0x36, 0x94, 0xB2, 0x48, 0x90, + 0xA8, 0xD2, 0x7F, 0xBC, 0x1B, 0x29, 0xDA, 0x9B}}; + opr_uuid_t uuidC; + char *str; + int version; + struct opr_uuid_unpacked raw; + + memset(&uuidC, 0, sizeof(opr_uuid_t)); + + ok(opr_uuid_isNil(&uuidC), "opr_uuid_isNil(nilUuid) works"); + ok(!opr_uuid_isNil(&uuidA), "opr_uuid_isNil(uuid) works"); + + ok(opr_uuid_equal(&uuidA, &uuidA), "opr_uuid_equal(A, A) works"); + ok(!opr_uuid_equal(&uuidA, &uuidB), "opr_uuid_equal(A, B) works"); + ok(!opr_uuid_equal(&uuidA, &uuidC), "opr_uuid_equal(A, nilUid) works"); + + is_int(1187447773, opr_uuid_hash(&uuidA), "opr_uuid_hash(A) works"); + is_int(1251907497, opr_uuid_hash(&uuidB), "opr_uuid_hash(B) works"); + + opr_uuid_toString(&uuidA, &str); + is_string("4f449447-76ba-472c-971a-866bc0101a4b", str, + "opr_uuid_toString(uuidA) works"); + opr_uuid_freeString(str); + + is_int(0, opr_uuid_fromString(&uuidC, "4F449447-76BA-472C-971A-866BC0101A4B"), + "opr_uuid_fromString works with conventional UUID"); + ok(opr_uuid_equal(&uuidA, &uuidC), " ... and UUID is correct"); + + memset(&uuidC, 0, sizeof(opr_uuid_t)); + is_int(0, opr_uuid_fromString(&uuidC, "4F449447-76BA-472C-97-1A-866BC0101A4B"), + "opr_uuid_fromString works with AFS style UUID"); + ok(opr_uuid_equal(&uuidA, &uuidC), " ... and UUID is correct"); + + memset(&uuidC, 0, sizeof(opr_uuid_t)); + opr_uuid_create(&uuidC); + ok(!opr_uuid_isNil(&uuidC), "opr_uuid_create makes non-nil UUID"); + is_int(0x80, uuidC.data[8] & 0xB0, "variant is DCE as expected"); + version = (uuidC.data[6] & 0xF0) >> 4; + ok(version >=1 && version <=5, "version %d is in expected range", version); + + opr_uuid_unpack(&uuidB, &raw); + opr_uuid_pack(&uuidC, &raw); + ok(opr_uuid_equal(&uuidB, &uuidC), + "opr_uuid_pack(opr_uuid_unpack()) works as expected"); + + return 0; +} -- 1.9.4