1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright (C) 2018 Intel Corporation.
3 * All rights reserved.
4 */
5
6 #include "spdk/uuid.h"
7 #include "spdk/config.h"
8 #include "spdk/log.h"
9
10 #ifndef SPDK_CONFIG_HAVE_UUID_GENERATE_SHA1
11 #include <openssl/evp.h>
12 #endif /* SPDK_CONFIG_HAVE_UUID_GENERATE_SHA1 */
13
14 #ifndef __FreeBSD__
15
16 #include <uuid/uuid.h>
17
18 SPDK_STATIC_ASSERT(sizeof(struct spdk_uuid) == sizeof(uuid_t), "Size mismatch");
19
20 int
spdk_uuid_parse(struct spdk_uuid * uuid,const char * uuid_str)21 spdk_uuid_parse(struct spdk_uuid *uuid, const char *uuid_str)
22 {
23 return uuid_parse(uuid_str, (void *)uuid) == 0 ? 0 : -EINVAL;
24 }
25
26 int
spdk_uuid_fmt_lower(char * uuid_str,size_t uuid_str_size,const struct spdk_uuid * uuid)27 spdk_uuid_fmt_lower(char *uuid_str, size_t uuid_str_size, const struct spdk_uuid *uuid)
28 {
29 if (uuid_str_size < SPDK_UUID_STRING_LEN) {
30 return -EINVAL;
31 }
32
33 uuid_unparse_lower((void *)uuid, uuid_str);
34 return 0;
35 }
36
37 int
spdk_uuid_compare(const struct spdk_uuid * u1,const struct spdk_uuid * u2)38 spdk_uuid_compare(const struct spdk_uuid *u1, const struct spdk_uuid *u2)
39 {
40 return uuid_compare((void *)u1, (void *)u2);
41 }
42
43 void
spdk_uuid_generate(struct spdk_uuid * uuid)44 spdk_uuid_generate(struct spdk_uuid *uuid)
45 {
46 uuid_generate((void *)uuid);
47 }
48
49 void
spdk_uuid_copy(struct spdk_uuid * dst,const struct spdk_uuid * src)50 spdk_uuid_copy(struct spdk_uuid *dst, const struct spdk_uuid *src)
51 {
52 uuid_copy((void *)dst, (void *)src);
53 }
54
55 bool
spdk_uuid_is_null(const struct spdk_uuid * uuid)56 spdk_uuid_is_null(const struct spdk_uuid *uuid)
57 {
58 return uuid_is_null((void *)uuid);
59 }
60
61 void
spdk_uuid_set_null(struct spdk_uuid * uuid)62 spdk_uuid_set_null(struct spdk_uuid *uuid)
63 {
64 uuid_clear((void *)uuid);
65 }
66
67 #else
68
69 #include <uuid.h>
70
71 SPDK_STATIC_ASSERT(sizeof(struct spdk_uuid) == sizeof(uuid_t), "Size mismatch");
72
73 int
spdk_uuid_parse(struct spdk_uuid * uuid,const char * uuid_str)74 spdk_uuid_parse(struct spdk_uuid *uuid, const char *uuid_str)
75 {
76 uint32_t status;
77
78 /* uuid_from_string() differs from uuid_parse() in the way it handles empty strings: the
79 * former succeeds and returns a NULL UUID, while the latter treats is an error and returns
80 * non-zero exit code. So, to keep the behavior consistent between Linux and FreeBSD, we
81 * explicitly check for an empty string here.
82 */
83 if (strlen(uuid_str) == 0) {
84 return -EINVAL;
85 }
86
87 uuid_from_string(uuid_str, (uuid_t *)uuid, &status);
88
89 return status == 0 ? 0 : -EINVAL;
90 }
91
92 int
spdk_uuid_fmt_lower(char * uuid_str,size_t uuid_str_size,const struct spdk_uuid * uuid)93 spdk_uuid_fmt_lower(char *uuid_str, size_t uuid_str_size, const struct spdk_uuid *uuid)
94 {
95 uint32_t status;
96 char *str;
97
98 if (uuid_str_size < SPDK_UUID_STRING_LEN) {
99 return -EINVAL;
100 }
101
102 uuid_to_string((const uuid_t *)uuid, &str, &status);
103
104 if (status == uuid_s_no_memory) {
105 return -ENOMEM;
106 }
107
108 snprintf(uuid_str, uuid_str_size, "%s", str);
109 free(str);
110
111 return 0;
112 }
113
114 int
spdk_uuid_compare(const struct spdk_uuid * u1,const struct spdk_uuid * u2)115 spdk_uuid_compare(const struct spdk_uuid *u1, const struct spdk_uuid *u2)
116 {
117 return uuid_compare((const uuid_t *)u1, (const uuid_t *)u2, NULL);
118 }
119
120 void
spdk_uuid_generate(struct spdk_uuid * uuid)121 spdk_uuid_generate(struct spdk_uuid *uuid)
122 {
123 uuid_create((uuid_t *)uuid, NULL);
124 }
125
126 void
spdk_uuid_copy(struct spdk_uuid * dst,const struct spdk_uuid * src)127 spdk_uuid_copy(struct spdk_uuid *dst, const struct spdk_uuid *src)
128 {
129 memcpy(dst, src, sizeof(*dst));
130 }
131
132 bool
spdk_uuid_is_null(const struct spdk_uuid * uuid)133 spdk_uuid_is_null(const struct spdk_uuid *uuid)
134 {
135 return uuid_is_nil((const uuid_t *)uuid, NULL);
136 }
137
138 void
spdk_uuid_set_null(struct spdk_uuid * uuid)139 spdk_uuid_set_null(struct spdk_uuid *uuid)
140 {
141 uuid_create_nil((uuid_t *)uuid, NULL);
142 }
143
144 #endif
145
146 int
spdk_uuid_generate_sha1(struct spdk_uuid * uuid,struct spdk_uuid * ns_uuid,const char * name,size_t len)147 spdk_uuid_generate_sha1(struct spdk_uuid *uuid, struct spdk_uuid *ns_uuid, const char *name,
148 size_t len)
149 {
150 #ifdef SPDK_CONFIG_HAVE_UUID_GENERATE_SHA1
151 uuid_generate_sha1((void *)uuid, (void *)ns_uuid, name, len);
152 return 0;
153 #else
154 EVP_MD_CTX *mdctx;
155 const EVP_MD *md;
156 unsigned char md_value[EVP_MAX_MD_SIZE];
157 unsigned int md_len;
158
159 md = EVP_sha1();
160 assert(md != NULL);
161
162 mdctx = EVP_MD_CTX_new();
163 if (mdctx == NULL) {
164 return -ENOMEM;
165 }
166
167 if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) {
168 SPDK_ERRLOG("Could not initialize EVP digest!\n");
169 goto err;
170 }
171 if (EVP_DigestUpdate(mdctx, ns_uuid, sizeof(struct spdk_uuid)) != 1) {
172 SPDK_ERRLOG("Could update EVP digest with namespace UUID!\n");
173 goto err;
174 }
175 if (EVP_DigestUpdate(mdctx, name, len) != 1) {
176 SPDK_ERRLOG("Could update EVP digest with assigned name!\n");
177 goto err;
178 }
179 if (EVP_DigestFinal_ex(mdctx, md_value, &md_len) != 1) {
180 SPDK_ERRLOG("Could not generate EVP digest!\n");
181 goto err;
182 }
183 EVP_MD_CTX_free(mdctx);
184
185 memcpy(uuid, md_value, 16);
186 /* This part mimics original uuid_generate_sha1() from libuuid/src/gen_uuid.c.
187 * The original uuid structure included from uuid.h looks like this:
188 * struct uuid {
189 * uint32_t time_low;
190 * uint16_t time_mid;
191 * uint16_t time_hi_and_version;
192 * uint16_t clock_seq;
193 * uint8_t node[6];
194 * };
195 * so uuid->u.raw[6] and uuid->u.raw[8] are time_hi_and_version and clock_seq respectively.
196 */
197 uuid->u.raw[6] = (uuid->u.raw[6] & 0x0f) | 0x50;
198 uuid->u.raw[8] = (uuid->u.raw[8] & 0x3f) | 0x80;
199
200 return 0;
201
202 err:
203 EVP_MD_CTX_free(mdctx);
204 return -EINVAL;
205
206 #endif /* SPDK_CONFIG_HAVE_UUID_GENERATE_SHA1 */
207 }
208