1 /* 2 * QEMU UUID functions 3 * 4 * Copyright 2016 Red Hat, Inc. 5 * 6 * Authors: 7 * Fam Zheng <famz@redhat.com> 8 * 9 * This program is free software; you can redistribute it and/or modify it 10 * under the terms of the GNU General Public License as published by the Free 11 * Software Foundation; either version 2 of the License, or (at your option) 12 * any later version. 13 * 14 */ 15 16 #include "qemu/osdep.h" 17 #include "qemu-common.h" 18 #include "qemu/uuid.h" 19 #include "qemu/bswap.h" 20 21 void qemu_uuid_generate(QemuUUID *uuid) 22 { 23 int i; 24 uint32_t tmp[4]; 25 26 QEMU_BUILD_BUG_ON(sizeof(QemuUUID) != 16); 27 28 for (i = 0; i < 4; ++i) { 29 tmp[i] = g_random_int(); 30 } 31 memcpy(uuid, tmp, sizeof(tmp)); 32 /* Set the two most significant bits (bits 6 and 7) of the 33 clock_seq_hi_and_reserved to zero and one, respectively. */ 34 uuid->data[8] = (uuid->data[8] & 0x3f) | 0x80; 35 /* Set the four most significant bits (bits 12 through 15) of the 36 time_hi_and_version field to the 4-bit version number. 37 */ 38 uuid->data[6] = (uuid->data[6] & 0xf) | 0x40; 39 } 40 41 int qemu_uuid_is_null(const QemuUUID *uu) 42 { 43 static QemuUUID null_uuid; 44 return qemu_uuid_is_equal(uu, &null_uuid); 45 } 46 47 int qemu_uuid_is_equal(const QemuUUID *lhv, const QemuUUID *rhv) 48 { 49 return memcmp(lhv, rhv, sizeof(QemuUUID)) == 0; 50 } 51 52 void qemu_uuid_unparse(const QemuUUID *uuid, char *out) 53 { 54 const unsigned char *uu = &uuid->data[0]; 55 snprintf(out, UUID_FMT_LEN + 1, UUID_FMT, 56 uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], uu[7], 57 uu[8], uu[9], uu[10], uu[11], uu[12], uu[13], uu[14], uu[15]); 58 } 59 60 char *qemu_uuid_unparse_strdup(const QemuUUID *uuid) 61 { 62 const unsigned char *uu = &uuid->data[0]; 63 return g_strdup_printf(UUID_FMT, 64 uu[0], uu[1], uu[2], uu[3], uu[4], uu[5], uu[6], 65 uu[7], uu[8], uu[9], uu[10], uu[11], uu[12], 66 uu[13], uu[14], uu[15]); 67 } 68 69 static bool qemu_uuid_is_valid(const char *str) 70 { 71 int i; 72 73 for (i = 0; i < strlen(str); i++) { 74 const char c = str[i]; 75 if (i == 8 || i == 13 || i == 18 || i == 23) { 76 if (str[i] != '-') { 77 return false; 78 } 79 } else { 80 if ((c >= '0' && c <= '9') || 81 (c >= 'A' && c <= 'F') || 82 (c >= 'a' && c <= 'f')) { 83 continue; 84 } 85 return false; 86 } 87 } 88 return i == 36; 89 } 90 91 int qemu_uuid_parse(const char *str, QemuUUID *uuid) 92 { 93 unsigned char *uu = &uuid->data[0]; 94 int ret; 95 96 if (!qemu_uuid_is_valid(str)) { 97 return -1; 98 } 99 100 ret = sscanf(str, UUID_FMT, &uu[0], &uu[1], &uu[2], &uu[3], 101 &uu[4], &uu[5], &uu[6], &uu[7], &uu[8], &uu[9], 102 &uu[10], &uu[11], &uu[12], &uu[13], &uu[14], 103 &uu[15]); 104 105 if (ret != 16) { 106 return -1; 107 } 108 return 0; 109 } 110 111 /* Swap from UUID format endian (BE) to the opposite or vice versa. 112 */ 113 void qemu_uuid_bswap(QemuUUID *uuid) 114 { 115 assert(QEMU_PTR_IS_ALIGNED(uuid, sizeof(uint32_t))); 116 bswap32s(&uuid->fields.time_low); 117 bswap16s(&uuid->fields.time_mid); 118 bswap16s(&uuid->fields.time_high_and_version); 119 } 120