Factor out UUID handling into new uuid class
[xapian.git] / xapian-core / backends / uuids.cc
blob2bccb51806dd56f0ba6fc16fe61b7f552313002b
1 /** @file uuids.cc
2 * @brief Class for handling UUIDs
3 */
4 /* Copyright (C) 2008 Lemur Consulting Ltd
5 * Copyright (C) 2013,2015,2016,2017,2018 Olly Betts
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include <config.h>
24 #include "uuids.h"
26 #include "xapian/error.h"
28 #include <cstring>
29 #include "stringutils.h"
31 #include <sys/types.h>
32 #include "safeerrno.h"
33 #include "safefcntl.h"
34 #include "safeunistd.h"
36 #ifdef USE_PROC_FOR_UUID
37 # include "safesysstat.h"
38 #elif defined HAVE_UUID_UUID_H
39 # include <exception>
40 # include <uuid/uuid.h>
41 #elif defined HAVE_UUID_H
42 // UUID API on FreeBSD, NetBSD and AIX.
43 # include <exception>
44 # include <uuid.h>
45 #elif defined USE_WIN32_UUID_API
46 # include "safewindows.h"
47 # include <rpc.h>
48 # ifdef __WIN32__
49 # include "safewinsock2.h" // For htonl() and htons().
50 # else
51 // Cygwin:
52 # include <arpa/inet.h> // For htonl() and htons().
53 # endif
54 #endif
56 using namespace std;
58 /// Bit-mask to determine where to put hyphens in the string representation.
59 static constexpr unsigned UUID_GAP_MASK = 0x2a8;
61 void
62 Uuid::generate()
64 #ifdef USE_PROC_FOR_UUID
65 char buf[STRING_SIZE];
66 int fd = open("/proc/sys/kernel/random/uuid", O_RDONLY);
67 if (rare(fd == -1)) {
68 throw Xapian::DatabaseCreateError("Opening UUID generator failed", errno);
70 bool failed = (read(fd, buf, STRING_SIZE) != STRING_SIZE);
71 close(fd);
72 if (failed) {
73 throw Xapian::DatabaseCreateError("Generating UUID failed");
75 parse(buf);
76 #elif defined HAVE_UUID_UUID_H
77 uuid_t uu;
78 uuid_generate(uu);
79 memcpy(uuid_data, &uu, BINARY_SIZE);
80 #elif defined HAVE_UUID_H
81 uuid_t uu;
82 uint32_t status;
83 uuid_create(uu, &status);
84 if (status != uuid_s_ok) {
85 // Can only be uuid_s_no_memory it seems.
86 throw std::bad_alloc();
88 memcpy(uuid_data, &uu, BINARY_SIZE);
89 #elif defined USE_WIN32_UUID_API
90 UUID uuid;
91 if (rare(UuidCreate(&uuid) != RPC_S_OK)) {
92 // Throw a DatabaseCreateError, since we can't make a UUID. The
93 // windows API documentation is a bit unclear about the situations in
94 // which this can happen.
95 throw Xapian::DatabaseCreateError("Cannot create UUID");
97 uuid.Data1 = htonl(uuid.Data1);
98 uuid.Data2 = htons(uuid.Data2);
99 uuid.Data3 = htons(uuid.Data3);
100 memcpy(uuid_data, &uuid, BINARY_SIZE);
101 #else
102 # error Do not know how to generate UUIDs
103 #endif
106 void
107 Uuid::parse(const char* in)
109 for (unsigned i = 0; i != BINARY_SIZE; ++i) {
110 uuid_data[i] = hex_digit(in[0]) << 4 | hex_digit(in[1]);
111 in += ((UUID_GAP_MASK >> i) & 1) | 2;
115 string
116 Uuid::to_string() const
118 string result;
119 result.reserve(STRING_SIZE);
120 for (unsigned i = 0; i != BINARY_SIZE; ++i) {
121 unsigned char ch = uuid_data[i];
122 result += "0123456789abcdef"[ch >> 4];
123 result += "0123456789abcdef"[ch & 0x0f];
124 if ((UUID_GAP_MASK >> i) & 1)
125 result += '-';
127 return result;