src/uuid.c

00001 /*
00002  * Copyright (C) 2005 Jukka Zitting <jz@yukatan.fi>
00003  *
00004  * This program is free software; you can redistribute it and/or modify it
00005  * under the terms of the GNU Lesser General Public License as published
00006  * by the Free Software Foundation; either version 2 of the License, or
00007  * (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 #include <config.h>
00019 #include "midgard/uuid.h"
00020 #include "md5.h"
00021 #include <string.h>
00022 
00023 gboolean midgard_is_uuid(const gchar *uuid) {
00024         g_assert(uuid != NULL);
00025         static const char format[] = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx";
00026         int i;
00027         for (i = 0; i < sizeof(format); i++) {
00028                 if (format[i] == 'x') {
00029                         if (!g_ascii_isxdigit(uuid[i])) {
00030                                 return FALSE;
00031                         }
00032                 } else if (uuid[i] != format[i]) {
00033                         return FALSE;
00034                 }
00035         }
00036         return TRUE;
00037 }
00038 
00045 G_LOCK_DEFINE_STATIC(uuid);
00046 
00047 gchar *midgard_uuid_new(void) {
00048         static gboolean initialized = FALSE;
00049         static guint64 timestamp;
00050         static guint32 advance;
00051         static guint16 clockseq;
00052         static guint16 node_high;
00053         static guint32 node_low;
00054         guint64 time;
00055         guint16 nowseq;
00056         GTimeVal tv;
00057 
00058         G_LOCK(uuid);
00059         g_get_current_time(&tv);
00060         time = ((guint64) tv.tv_sec) * G_USEC_PER_SEC + ((guint64) tv.tv_usec);
00061         time = time * 10 + G_GINT64_CONSTANT(0x01B21DD213814000U);
00062         if (!initialized) {
00063                 timestamp = time;
00064                 advance = 0;
00065                 GRand *rand = g_rand_new();
00066                 guint32 r = g_rand_int(rand);
00067                 clockseq = r >> 16;
00068                 node_high = r | 0x0100;
00069                 node_low = g_rand_int(rand);
00070                 g_rand_free(rand);
00071                 initialized = TRUE;
00072         } else if (time < timestamp) {
00073                 timestamp = time;
00074                 advance = 0;
00075                 clockseq++;
00076         } else if (time == timestamp) {
00077                 advance++;
00078                 time += advance;
00079         } else {
00080                 timestamp = time;
00081                 advance = 0;
00082         }
00083         nowseq = clockseq;
00084         G_UNLOCK(uuid);
00085 
00086         return g_strdup_printf(
00087                 "%08lx-%04x-%04x-%04x-%04x%08lx",
00088                 (unsigned long) time,
00089                 (unsigned int) (time >> 32) & 0xffff,
00090                 (unsigned int) ((time >> 48) & 0x0ffff) | 0x1000,
00091                 (unsigned int) (nowseq & 0x3fff) | 0x8000,
00092                 (unsigned int) node_high,
00093                 (unsigned long) node_low);
00094 }
00095 
00102 static const unsigned char namespace_uuid[] = {
00103         0x00, 0xdc, 0x46, 0xa0, 0x0e, 0x0c, 0x10, 0x85,
00104         0x82, 0xbb, 0x00, 0x02, 0xa5, 0xd5, 0xfd, 0x2e
00105 };
00106 
00107 gchar *midgard_uuid_external(const gchar *external) {
00108         g_assert(external != NULL);
00109         unsigned char uuid[16];
00110 
00111         MD5_CTX md5;
00112         MD5Init(&md5);
00113         MD5Update(&md5, namespace_uuid, sizeof(namespace_uuid));
00114         MD5Update(&md5, (unsigned char *) external, strlen(external));
00115         MD5Final(uuid, &md5);
00116 
00117         return g_strdup_printf(
00118                 "%08lx-%04x-%04x-%04x-%04x%08lx",
00119                 (unsigned long) uuid[0] << 24 | uuid[1] << 16 | uuid[2] << 8 | uuid[3],
00120                 (unsigned int) uuid[4] << 8 | uuid[5],
00121                 (unsigned int) ((uuid[6] & 0x0f) | 0x30) << 8 | uuid[7],
00122                 (unsigned int) ((uuid[8] & 0x3f) | 0x80) << 8 | uuid[9],
00123                 (unsigned int) uuid[10] << 8 | uuid[11],
00124                 (unsigned long) uuid[12] << 24 | uuid[13] << 16 | uuid[14] << 8 | uuid[15]);
00125 }

Generated on Thu Feb 22 06:15:19 2007 for midgard-core by  doxygen 1.4.6