aboutsummaryrefslogtreecommitdiff
path: root/libbutl/uuid-windows.cxx
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2018-08-22 17:26:08 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2018-08-22 17:36:23 +0200
commitfebb9c275b5247df596876e4eea7fa17b7ec45e7 (patch)
tree214a192cc6b019fb25a659cfdb84601da74438bf /libbutl/uuid-windows.cxx
parentf8fc81a5c9fcd986473797df9286c6c9fef683bf (diff)
Add support for UUID generation
Diffstat (limited to 'libbutl/uuid-windows.cxx')
-rw-r--r--libbutl/uuid-windows.cxx131
1 files changed, 131 insertions, 0 deletions
diff --git a/libbutl/uuid-windows.cxx b/libbutl/uuid-windows.cxx
new file mode 100644
index 0000000..825505b
--- /dev/null
+++ b/libbutl/uuid-windows.cxx
@@ -0,0 +1,131 @@
+// file : libbutl/uuid-windows.cxx -*- C++ -*-
+// copyright : Copyright (c) 2014-2018 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUILD2_BOOTSTRAP
+
+#include <libbutl/uuid.hxx>
+
+#include <rpc.h> // UuidCreate*()
+#include <errno.h>
+
+#include <cassert>
+#include <system_error>
+
+using namespace std;
+
+namespace butl
+{
+ void uuid::
+ assign (const _GUID& g)
+ {
+ time_low = g.Data1;
+ time_mid = g.Data2;
+ time_hiv = g.Data3;
+ clock_seq_hir = g.Data4[0];
+ clock_seq_low = g.Data4[1];
+ memcpy (node, &g.Data4[2], 6);
+ }
+
+ template<>
+ LIBBUTL_SYMEXPORT _GUID uuid::
+ guid<_GUID> () const
+ {
+ _GUID r;
+ r.Data1 = time_low;
+ r.Data2 = time_mid;
+ r.Data3 = time_hiv;
+ r.Data4[0] = clock_seq_hir;
+ r.Data4[1] = clock_seq_low;
+ memcpy (&r.Data4[2], node, 6);
+ return r;
+ }
+
+ void
+ uuid_throw_weak (); // uuid.cxx
+
+ uuid uuid_system_generator::
+ generate (bool strong)
+ {
+ // The common way to generate a UUID on Windows is with the CoCreateGuid()
+ // function which, according to the documentation, calls UuidCreate().
+ // There is some talk of it somehow generating stronger UUIDs but it is
+ // probably bogus (it most likely simply returns an error if UuidCreate()
+ // returns a "weak" UUID).
+ //
+ // UuidCreate(), on the other hand, has various interesting return codes
+ // as well as the UuidCreateSequential() variant which always generates a
+ // MAC/time-based UUID (according to the documentation, since Windows 2000
+ // UuidCreate() always generates a random UUID). So let's use that.
+ //
+ // While the documentation doesn't explicitly state this, presumably
+ // UuidCreate() uses a "decent" source of randomness. See this post for
+ // some background:
+ //
+ // https://stackoverflow.com/questions/35366368/does-uuidcreate-use-a-csprng
+ //
+ // So we assume a random UUID returned by UuidCreate() is strong. What to
+ // do if it's not is a tricky question (is it even possible?): we can call
+ // UuidCreateSequential() to generate a MAC/time-based UUID but it's
+ // possible the time was not obtained in a collision-safe manner (see the
+ // Linux implementation for background). However, the documentation
+ // suggests that it is safe ("... guaranteed to be unique among all UUIDs
+ // generated on the computer"). And so we assume it is.
+ //
+ auto rpcfail = [strong] (RPC_STATUS s)
+ {
+ if (s != RPC_S_UUID_LOCAL_ONLY)
+ {
+ char m [DCE_C_ERROR_STRING_LEN];
+
+ throw system_error (
+ ENOSYS,
+ system_category (),
+ (DceErrorInqTextA (s, reinterpret_cast<RPC_CSTR> (m)) == RPC_S_OK
+ ? m
+ : "unknown RPC error"));
+ }
+ else if (strong)
+ uuid_throw_weak ();
+ };
+
+ UUID d;
+ RPC_STATUS s (UuidCreate (&d));
+
+ if (s != RPC_S_OK)
+ rpcfail (s);
+
+ uuid r (d);
+ assert (r.variant () == uuid_variant::dce); // Sanity check.
+
+ if (strong && r.version () != uuid_version::random)
+ {
+ s = UuidCreateSequential (&d);
+
+ if (s != RPC_S_OK)
+ rpcfail (s);
+
+ r.assign (d);
+
+ // UuidCreateSequential() on Wine returns the Microsoft variant.
+ //
+ if (r.variant () != uuid_variant::dce ||
+ r.version () != uuid_version::time)
+ rpcfail (RPC_S_UUID_LOCAL_ONLY);
+ }
+
+ return r;
+ }
+
+ void uuid_system_generator::
+ initialize ()
+ {
+ }
+
+ void uuid_system_generator::
+ terminate ()
+ {
+ }
+}
+
+#endif // BUILD2_BOOTSTRAP