Add a small string formatting utility to opr
[openafs.git] / src / opr / uuid.c
1 /*
2  * Copyright (c) 2012 Your File System Inc. All rights reserved.
3  */
4
5 #include <afsconfig.h>
6 #include <afs/param.h>
7
8 #include <roken.h>
9
10 #ifdef HAVE_UUID_UUID_H
11 # include <uuid/uuid.h>
12 #endif
13
14 #ifdef AFS_NT40_ENV
15 # include <rpc.h>
16 #endif
17
18 #include <hcrypto/rand.h>
19
20 #include "uuid.h"
21 #include "jhash.h"
22
23 static const opr_uuid_t nilUid = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}};
24
25 void
26 opr_uuid_create(opr_uuid_t *uuid)
27 {
28 #if defined (AFS_NT40_ENV)
29     struct opr_uuid_unpacked raw;
30
31     UuidCreate((UUID *) &raw);
32     opr_uuid_pack(uuid, &raw);
33
34 #elif !defined(KERNEL) && defined(HAVE_UUID_GENERATE)
35
36     uuid_generate(uuid->data);
37
38 #else
39     RAND_bytes(uuid->data, 16);
40
41     uuid->data[6] = (uuid->data[6] & 0x0F) | 0x40; /* verison is 4 */
42     uuid->data[8] = (uuid->data[8] & 0x3F) | 0x80; /* variant is DCE */
43 #endif
44 }
45
46 int
47 opr_uuid_isNil(const opr_uuid_t *uuid)
48 {
49    return opr_uuid_equal(uuid, &nilUid);
50 }
51
52 int
53 opr_uuid_equal(const opr_uuid_t *uuid1, const opr_uuid_t *uuid2)
54 {
55    return memcmp(uuid1, uuid2, sizeof(opr_uuid_t)) == 0;
56 }
57
58 unsigned int
59 opr_uuid_hash(const opr_uuid_t *uuid)
60 {
61    /* uuid->data is a (unsigned char *), so there's every danger that this
62     * may cause an unaligned access on some platforms */
63    return opr_jhash((const afs_uint32 *)uuid->data, 4, 0);
64 }
65
66 #if !defined(KERNEL)
67 int
68 opr_uuid_toString(const opr_uuid_t *uuid, char **string)
69 {
70    unsigned const char *p;
71    int r;
72
73    p = uuid->data;
74    r = asprintf(string,
75                 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
76                 "%02x%02x%02x%02x%02x%02x",
77                 p[0], p[1], p[2],  p[3],  p[4],  p[5],  p[6],  p[7],
78                 p[8], p[9], p[10], p[11], p[12], p[13], p[14], p[15]);
79    if (r < 0) {
80        *string = NULL;
81        return ENOMEM;
82    }
83    return 0;
84 }
85
86 void
87 opr_uuid_freeString(char *string)
88 {
89     free(string);
90 }
91
92 int
93 opr_uuid_fromString(opr_uuid_t *uuid, const char *string)
94 {
95     unsigned int i[16];
96     int items, c;
97
98     /* XXX - Traditionally, AFS has printed UUIDs as
99      * 00000000-0000-00-00-00000000. We should perhaps also accept
100      * that format here
101      */
102     items = sscanf(string,
103                    "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
104                    "%02x%02x%02x%02x%02x%02x",
105                    &i[0],  &i[1],  &i[2],  &i[3], &i[4],  &i[5],
106                    &i[6],  &i[7],  &i[8],  &i[9], &i[10], &i[11],
107                    &i[12], &i[13], &i[14], &i[15]);
108     if (items !=16) {
109         /* Originally, AFS's printed UUIDs would take the form
110          * 00000000-0000-0000-00-00-00000000. Also handle this. */
111         items = sscanf(string,
112                    "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x-%02x-"
113                    "%02x%02x%02x%02x%02x%02x",
114                    &i[0],  &i[1],  &i[2],  &i[3], &i[4],  &i[5],
115                    &i[6],  &i[7],  &i[8],  &i[9], &i[10], &i[11],
116                    &i[12], &i[13], &i[14], &i[15]);
117     }
118     if (items !=16)
119         return EINVAL;
120
121     for (c=0; c<16; c++)
122         uuid->data[c] = i[c];
123
124     return 0;
125 }
126
127 #endif
128
129 void
130 opr_uuid_pack(opr_uuid_t *uuid, const struct opr_uuid_unpacked *raw)
131 {
132     afs_uint32 intval;
133     unsigned short shortval;
134
135     intval = htonl(raw->time_low);
136     memcpy(&uuid->data[0], &intval, sizeof(uint32_t));
137
138     shortval = htons(raw->time_mid);
139     memcpy(&uuid->data[4], &shortval, sizeof(uint16_t));
140
141     shortval = htons(raw->time_hi_and_version);
142     memcpy(&uuid->data[6], &shortval, sizeof(uint16_t));
143
144     uuid->data[8] = raw->clock_seq_hi_and_reserved;
145     uuid->data[9] = raw->clock_seq_low;
146
147     memcpy(&uuid->data[10], &raw->node, 6);
148 }
149
150 void
151 opr_uuid_unpack(const opr_uuid_t *uuid, struct opr_uuid_unpacked *raw)
152 {
153     afs_uint32 intval;
154     unsigned short shortval;
155
156     memcpy(&intval, &uuid->data[0], sizeof(uint32_t));
157     raw->time_low = ntohl(intval);
158
159     memcpy(&shortval, &uuid->data[4], sizeof(uint16_t));
160     raw->time_mid = ntohs(shortval);
161
162     memcpy(&shortval, &uuid->data[6], sizeof(uint16_t));
163     raw->time_hi_and_version = ntohs(shortval);
164
165     raw->clock_seq_hi_and_reserved = uuid->data[8];
166     raw->clock_seq_low = uuid->data[9];
167
168     memcpy(&raw->node, &uuid->data[10], 6);
169 }
170