xref: /spdk/lib/util/uuid.c (revision 8afdeef3becfe9409cc9e7372bd0bc10e8b7d46d)
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
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
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
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
44 spdk_uuid_generate(struct spdk_uuid *uuid)
45 {
46 	uuid_generate((void *)uuid);
47 }
48 
49 void
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
56 spdk_uuid_is_null(const struct spdk_uuid *uuid)
57 {
58 	return uuid_is_null((void *)uuid);
59 }
60 
61 void
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
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
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
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
121 spdk_uuid_generate(struct spdk_uuid *uuid)
122 {
123 	uuid_create((uuid_t *)uuid, NULL);
124 }
125 
126 void
127 spdk_uuid_copy(struct spdk_uuid *dst, const struct spdk_uuid *src)
128 {
129 	memcpy(dst, src, sizeof(*dst));
130 }
131 
132 bool
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
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
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