summaryrefslogtreecommitdiffstats
path: root/lib/uuid/uuid.c
blob: 96b2a6756fa1c563fcff9fddd33276d05d366385 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
/*
 * Copyright (C) 2001 Sistina Software (UK) Limited.
 *
 * This file is released under the LGPL.
 */

#include "uuid.h"
#include "log.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

static unsigned char _c[] =
    "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";

static int _built_inverse;
static unsigned char _inverse_c[256];

int id_create(struct id *id)
{
	int random, i, len = sizeof(id->uuid);

	memset(id->uuid, 0, len);
	if ((random = open("/dev/urandom", O_RDONLY)) < 0) {
		log_sys_error("open", "id_create");
		return 0;
	}

	if (read(random, id->uuid, len) != len) {
		log_sys_error("read", "id_create");
		return 0;
	}
	close(random);

	for (i = 0; i < len; i++)
		id->uuid[i] = _c[id->uuid[i] % (sizeof(_c) - 1)];

	return 1;
}

/*
 * The only validity check we have is that
 * the uuid just contains characters from
 * '_c'.  A checksum would have been nice :(
 */
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_cmp(struct id *lhs, struct id *rhs)
{
	return memcmp(lhs->uuid, rhs->uuid, sizeof(lhs->uuid));
}

#define GROUPS (ID_LEN / 4)
int id_format(struct id *id, char *buffer, size_t size)
{
	int i;

	/* split into 8 groups of four, with dashes in between */
	if (size < (GROUPS * 5))
		return 0;

	for (i = 0; i < GROUPS; i++) {
		memcpy(buffer + (i * 5), id->uuid + (i * 4), 4);
		buffer[(i * 5) + 4] = '-';
	}

	buffer[GROUPS * 5] = '\0';
	return 1;
}

int id_read_format(struct id *id, char *buffer)
{
	int i;

	if (strlen(buffer) < (GROUPS * 5)) {
		log_err("Insufficient characters to be a proper uuid.");
		return 0;
	}

	for (i = 0; i < ID_LEN; i++)
		id->uuid[i] = buffer[((i / 4) * 5) + (i % 4)];

	return id_valid(id);
}