Initial import of binutils 2.22 on the new vendor branch
[dragonfly.git] / contrib / lvm2 / dist / lib / uuid / uuid.c
1 /*      $NetBSD: uuid.c,v 1.1.1.3 2009/12/02 00:26:49 haad Exp $        */
2
3 /*
4  * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5  * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
6  *
7  * This file is part of LVM2.
8  *
9  * This copyrighted material is made available to anyone wishing to use,
10  * modify, copy, or redistribute it subject to the terms and conditions
11  * of the GNU Lesser General Public License v.2.1.
12  *
13  * You should have received a copy of the GNU Lesser General Public License
14  * along with this program; if not, write to the Free Software Foundation,
15  * Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16  */
17
18 #include "lib.h"
19 #include "uuid.h"
20 #include "lvm-wrappers.h"
21
22 #include <assert.h>
23 #include <sys/stat.h>
24 #include <fcntl.h>
25 #include <unistd.h>
26 #include <ctype.h>
27
28 static const char _c[] =
29     "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#";
30
31 static int _built_inverse;
32 static char _inverse_c[256];
33
34 int lvid_create(union lvid *lvid, struct id *vgid)
35 {
36         memcpy(lvid->id, vgid, sizeof(*lvid->id));
37         return id_create(&lvid->id[1]);
38 }
39
40 void uuid_from_num(char *uuid, uint32_t num)
41 {
42         unsigned i;
43
44         for (i = ID_LEN; i; i--) {
45                 uuid[i - 1] = _c[num % (sizeof(_c) - 1)];
46                 num /= sizeof(_c) - 1;
47         }
48 }
49
50 int lvid_from_lvnum(union lvid *lvid, struct id *vgid, uint32_t lv_num)
51 {
52         int i;
53
54         memcpy(lvid->id, vgid, sizeof(*lvid->id));
55
56         for (i = ID_LEN; i; i--) {
57                 lvid->id[1].uuid[i - 1] = _c[lv_num % (sizeof(_c) - 1)];
58                 lv_num /= sizeof(_c) - 1;
59         }
60
61         lvid->s[sizeof(lvid->s) - 1] = '\0';
62
63         return 1;
64 }
65
66 int lvnum_from_lvid(union lvid *lvid)
67 {
68         int i, lv_num = 0;
69         char *c;
70
71         for (i = 0; i < ID_LEN; i++) {
72                 lv_num *= sizeof(_c) - 1;
73                 if ((c = strchr(_c, lvid->id[1].uuid[i])))
74                         lv_num += (int) (c - _c);
75                 if (lv_num < 0)
76                         lv_num = 0;
77         }
78
79         return lv_num;
80 }
81
82 int lvid_in_restricted_range(union lvid *lvid)
83 {
84         int i;
85
86         for (i = 0; i < ID_LEN - 3; i++)
87                 if (lvid->id[1].uuid[i] != '0')
88                         return 0;
89
90         for (i = ID_LEN - 3; i < ID_LEN; i++)
91                 if (!isdigit(lvid->id[1].uuid[i]))
92                         return 0;
93
94         return 1;
95 }
96
97
98 int id_create(struct id *id)
99 {
100         unsigned i;
101         size_t len = sizeof(id->uuid);
102
103         memset(id->uuid, 0, len);
104         if (!read_urandom(&id->uuid, len)) {
105                 return 0;
106         }
107
108         /*
109          * Skip out the last 2 chars in randomized creation for LVM1
110          * backwards compatibility.
111          */
112         for (i = 0; i < len; i++)
113                 id->uuid[i] = _c[id->uuid[i] % (sizeof(_c) - 3)];
114
115         return 1;
116 }
117
118 /*
119  * The only validity check we have is that
120  * the uuid just contains characters from
121  * '_c'.  A checksum would have been nice :(
122  */
123 static void _build_inverse(void)
124 {
125         const char *ptr;
126
127         if (_built_inverse)
128                 return;
129
130         memset(_inverse_c, 0, sizeof(_inverse_c));
131
132         for (ptr = _c; *ptr; ptr++)
133                 _inverse_c[(int) *ptr] = (char) 0x1;
134 }
135
136 int id_valid(struct id *id)
137 {
138         int i;
139
140         _build_inverse();
141
142         for (i = 0; i < ID_LEN; i++)
143                 if (!_inverse_c[id->uuid[i]]) {
144                         log_error("UUID contains invalid character");
145                         return 0;
146                 }
147
148         return 1;
149 }
150
151 int id_equal(const struct id *lhs, const struct id *rhs)
152 {
153         return !memcmp(lhs->uuid, rhs->uuid, sizeof(lhs->uuid));
154 }
155
156 #define GROUPS (ID_LEN / 4)
157
158 int id_write_format(const struct id *id, char *buffer, size_t size)
159 {
160         int i, tot;
161
162         static unsigned group_size[] = { 6, 4, 4, 4, 4, 4, 6 };
163
164         assert(ID_LEN == 32);
165
166         /* split into groups separated by dashes */
167         if (size < (32 + 6 + 1)) {
168                 log_error("Couldn't write uuid, buffer too small.");
169                 return 0;
170         }
171
172         for (i = 0, tot = 0; i < 7; i++) {
173                 memcpy(buffer, id->uuid + tot, group_size[i]);
174                 buffer += group_size[i];
175                 tot += group_size[i];
176                 *buffer++ = '-';
177         }
178
179         *--buffer = '\0';
180         return 1;
181 }
182
183 int id_read_format(struct id *id, const char *buffer)
184 {
185         int out = 0;
186
187         /* just strip out any dashes */
188         while (*buffer) {
189
190                 if (*buffer == '-') {
191                         buffer++;
192                         continue;
193                 }
194
195                 if (out >= ID_LEN) {
196                         log_error("Too many characters to be uuid.");
197                         return 0;
198                 }
199
200                 id->uuid[out++] = *buffer++;
201         }
202
203         if (out != ID_LEN) {
204                 log_error("Couldn't read uuid: incorrect number of "
205                           "characters.");
206                 return 0;
207         }
208
209         return id_valid(id);
210 }