/* * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved. * Copyright (C) 2004 Red Hat, Inc. All rights reserved. * * This file is part of LVM2. * * This copyrighted material is made available to anyone wishing to use, * modify, copy, or redistribute it subject to the terms and conditions * of the GNU General Public License v.2. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include "lib.h" #include "uuid.h" #include #include #include static unsigned char _c[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!#"; static int _built_inverse; static unsigned char _inverse_c[256]; int lvid_create(union lvid *lvid, struct id *vgid) { memcpy(lvid->id, vgid, sizeof(*lvid->id)); id_create(&lvid->id[1]); return 1; } void uuid_from_num(char *uuid, uint32_t num) { unsigned i; for (i = ID_LEN; i; i--) { uuid[i - 1] = _c[num % (sizeof(_c) - 1)]; num /= sizeof(_c) - 1; } uuid[ID_LEN] = '\0'; } int lvid_from_lvnum(union lvid *lvid, struct id *vgid, uint32_t lv_num) { int i; memcpy(lvid->id, vgid, sizeof(*lvid->id)); for (i = ID_LEN; i; i--) { lvid->id[1].uuid[i - 1] = _c[lv_num % (sizeof(_c) - 1)]; lv_num /= sizeof(_c) - 1; } lvid->s[sizeof(lvid->s) - 1] = '\0'; return 1; } int lvnum_from_lvid(union lvid *lvid) { int i, lv_num = 0; unsigned char *c; for (i = 0; i < ID_LEN; i++) { lv_num *= sizeof(_c) - 1; if ((c = strchr(_c, lvid->id[1].uuid[i]))) lv_num += (int) (c - _c); } return lv_num; } int id_create(struct id *id) { int randomfile, i; size_t len = sizeof(id->uuid); memset(id->uuid, 0, len); if ((randomfile = open("/dev/urandom", O_RDONLY)) < 0) { log_sys_error("open", "id_create"); return 0; } if (read(randomfile, id->uuid, len) != len) { log_sys_error("read", "id_create"); close(randomfile); return 0; } close(randomfile); /* * Skip out the last 2 chars in randomized creation for LVM1 * backwards compatibility. */ for (i = 0; i < len; i++) id->uuid[i] = _c[id->uuid[i] % (sizeof(_c) - 3)]; return 1; } /* * The only validity check we have is that * the uuid just contains characters from * '_c'. A checksum would have been nice :( */ static void _build_inverse(void) { char *ptr; if (_built_inverse) return; memset(_inverse_c, 0, sizeof(_inverse_c)); for (ptr = _c; *ptr; ptr++) _inverse_c[(int) *ptr] = (char) 0x1; } int id_valid(struct id *id) { int i; _build_inverse(); for (i = 0; i < ID_LEN; i++) if (!_inverse_c[id->uuid[i]]) { log_err("UUID contains invalid character"); return 0; } return 1; } int id_equal(const struct id *lhs, const struct id *rhs) { return !memcmp(lhs->uuid, rhs->uuid, sizeof(lhs->uuid)); } #define GROUPS (ID_LEN / 4) int id_write_format(const struct id *id, char *buffer, size_t size) { int i, tot; static unsigned group_size[] = { 6, 4, 4, 4, 4, 4, 6 }; assert(ID_LEN == 32); /* split into groups separated by dashes */ if (size < (32 + 6 + 1)) { log_err("Couldn't write uuid, buffer too small."); return 0; } for (i = 0, tot = 0; i < 7; i++) { memcpy(buffer, id->uuid + tot, group_size[i]); buffer += group_size[i]; tot += group_size[i]; *buffer++ = '-'; } *--buffer = '\0'; return 1; } int id_read_format(struct id *id, const char *buffer) { int out = 0; /* just strip out any dashes */ while (*buffer) { if (*buffer == '-') { buffer++; continue; } if (out >= ID_LEN) { log_err("Too many characters to be uuid."); return 0; } id->uuid[out++] = *buffer++; } if (out != ID_LEN) { log_err("Couldn't read uuid, incorrect number of characters."); return 0; } return id_valid(id); }