1 /* @file win32_uuid.cc
2  * @brief Provide UUID functions compatible with libuuid from util-linux-ng.
3  */
4 /* Copyright (C) 2008 Lemur Consulting Ltd
5  * Copyright (C) 2013,2015 Olly Betts
6  *
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.
11  *
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.
16  *
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
20  */
21 
22 #include <config.h>
23 
24 #include "win32_uuid.h"
25 
26 #include "xapian/error.h"
27 
28 #include <cstring>
29 
30 #ifdef __WIN32__
31 # include "safewinsock2.h" // For htonl() and htons().
32 #else
33 // Cygwin:
34 # include <arpa/inet.h> // For htonl() and htons().
35 #endif
36 
37 using namespace std;
38 
39 /// The size of a UUID in bytes.
40 const size_t UUID_SIZE = 16;
41 
42 /// The size of a UUID string in bytes (not including trailing '\0').
43 const size_t UUID_STRING_SIZE = 36;
44 
45 void
uuid_generate(uuid_t uu)46 uuid_generate(uuid_t uu)
47 {
48     UUID uuid;
49     if (rare(UuidCreate(&uuid) != RPC_S_OK)) {
50 	// Throw a DatabaseCreateError, since we can't make a UUID.  The
51 	// windows API documentation is a bit unclear about the situations in
52 	// which this can happen, but if this behaviour causes a problem, an
53 	// alternative would be to create a UUID ourselves somehow in this
54 	// situation.
55 	throw Xapian::DatabaseCreateError("Cannot create UUID");
56     }
57     uuid.Data1 = htonl(uuid.Data1);
58     uuid.Data2 = htons(uuid.Data2);
59     uuid.Data3 = htons(uuid.Data3);
60     memcpy(uu, &uuid, UUID_SIZE);
61 }
62 
63 int
uuid_parse(const char * in,uuid_t uu)64 uuid_parse(const char * in, uuid_t uu)
65 {
66     UUID uuid;
67     // UuidFromString() requires a non-const unsigned char * pointer, though it
68     // doesn't modify the passed string.
69     unsigned char * in_ = (unsigned char *)const_cast<char *>(in);
70     if (UuidFromString(in_, &uuid) != RPC_S_OK)
71 	return -1;
72     uuid.Data1 = htonl(uuid.Data1);
73     uuid.Data2 = htons(uuid.Data2);
74     uuid.Data3 = htons(uuid.Data3);
75     memcpy(uu, &uuid, UUID_SIZE);
76     return 0;
77 }
78 
uuid_unparse_lower(const uuid_t uu,char * out)79 void uuid_unparse_lower(const uuid_t uu, char * out)
80 {
81     UUID uuid;
82     char *uuidstr;
83     memcpy(&uuid, uu, UUID_SIZE);
84     uuid.Data1 = htonl(uuid.Data1);
85     uuid.Data2 = htons(uuid.Data2);
86     uuid.Data3 = htons(uuid.Data3);
87     if (rare(UuidToString(&uuid, (unsigned char **)(&uuidstr)) != RPC_S_OK)) {
88 	// The only documented (or really conceivable) error code is
89 	// RPC_S_OUT_OF_MEMORY.
90 	throw std::bad_alloc();
91     }
92     memcpy(out, strlwr(uuidstr), UUID_STRING_SIZE);
93     out[UUID_STRING_SIZE] = '\0';
94     RpcStringFree((unsigned char**)(&uuidstr));
95 }
96 
uuid_clear(uuid_t uu)97 void uuid_clear(uuid_t uu)
98 {
99     memset(uu, 0, UUID_SIZE);
100 }
101 
uuid_is_null(const uuid_t uu)102 int uuid_is_null(const uuid_t uu)
103 {
104     unsigned i = 0;
105     while (i < UUID_SIZE) {
106 	if (uu[i++])
107 	    return 0;
108     }
109     return 1;
110 }
111