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 <buildbot@rampaginggeek.com>
Reviewed-by: Derrick Brashear <shadow@dementix.org>
This commit is contained in:
Simon Wilkinson 2012-07-17 16:50:59 +01:00 committed by Derrick Brashear
parent b251b40572
commit 6f6bfb31ac
9 changed files with 287 additions and 5 deletions

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

163
src/opr/uuid.c Normal file
View File

@ -0,0 +1,163 @@
/*
* Copyright (c) 2012 Your File System Inc. All rights reserved.
*/
#include <afsconfig.h>
#include <afs/param.h>
#include <roken.h>
#ifdef HAVE_UUID_UUID_H
# include <uuid/uuid.h>
#endif
#ifdef AFS_NT40_ENV
# include <rpc.h>
#endif
#include <hcrypto/rand.h>
#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

38
src/opr/uuid.h Normal file
View File

@ -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

View File

@ -9,6 +9,7 @@ opr/jhash
opr/queues
opr/rbtree
opr/time
opr/uuid
ptserver/pt_util
ptserver/pts-man
rx/event

View File

@ -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

65
tests/opr/uuid-t.c Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (c) 2012 Your File System Inc. All rights reserved.
*/
#include <afsconfig.h>
#include <afs/param.h>
#include <roken.h>
#include <opr/uuid.h>
#include <tests/tap/basic.h>
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;
}