1/*
2 * Python UUID module that wraps libuuid or Windows rpcrt4.dll.
3 * DCE compatible Universally Unique Identifier library.
4 */
5
6#define PY_SSIZE_T_CLEAN
7
8#include "Python.h"
9#ifdef HAVE_UUID_UUID_H
10#include <uuid/uuid.h>
11#elif defined(HAVE_UUID_H)
12#include <uuid.h>
13#endif
14
15#ifdef MS_WINDOWS
16#include <rpc.h>
17#endif
18
19#ifndef MS_WINDOWS
20
21static PyObject *
22py_uuid_generate_time_safe(PyObject *Py_UNUSED(context),
23 PyObject *Py_UNUSED(ignored))
24{
25 uuid_t uuid;
26#ifdef HAVE_UUID_GENERATE_TIME_SAFE
27 int res;
28
29 res = uuid_generate_time_safe(uuid);
30 return Py_BuildValue("y#i", (const char *) uuid, sizeof(uuid), res);
31#elif defined(HAVE_UUID_CREATE)
32 uint32_t status;
33 uuid_create(&uuid, &status);
34# if defined(HAVE_UUID_ENC_BE)
35 unsigned char buf[sizeof(uuid)];
36 uuid_enc_be(buf, &uuid);
37 return Py_BuildValue("y#i", buf, sizeof(uuid), (int) status);
38# else
39 return Py_BuildValue("y#i", (const char *) &uuid, sizeof(uuid), (int) status);
40# endif /* HAVE_UUID_CREATE */
41#else /* HAVE_UUID_GENERATE_TIME_SAFE */
42 uuid_generate_time(uuid);
43 return Py_BuildValue("y#O", (const char *) uuid, sizeof(uuid), Py_None);
44#endif /* HAVE_UUID_GENERATE_TIME_SAFE */
45}
46
47#else /* MS_WINDOWS */
48
49static PyObject *
50py_UuidCreate(PyObject *Py_UNUSED(context),
51 PyObject *Py_UNUSED(ignored))
52{
53 UUID uuid;
54 RPC_STATUS res;
55
56 Py_BEGIN_ALLOW_THREADS
57 res = UuidCreateSequential(&uuid);
58 Py_END_ALLOW_THREADS
59
60 switch (res) {
61 case RPC_S_OK:
62 case RPC_S_UUID_LOCAL_ONLY:
63 case RPC_S_UUID_NO_ADDRESS:
64 /*
65 All success codes, but the latter two indicate that the UUID is random
66 rather than based on the MAC address. If the OS can't figure this out,
67 neither can we, so we'll take it anyway.
68 */
69 return Py_BuildValue("y#", (const char *)&uuid, sizeof(uuid));
70 }
71 PyErr_SetFromWindowsErr(res);
72 return NULL;
73}
74
75#endif /* MS_WINDOWS */
76
77
78static int
79uuid_exec(PyObject *module) {
80 assert(sizeof(uuid_t) == 16);
81#if defined(MS_WINDOWS)
82 int has_uuid_generate_time_safe = 0;
83#elif defined(HAVE_UUID_GENERATE_TIME_SAFE)
84 int has_uuid_generate_time_safe = 1;
85#else
86 int has_uuid_generate_time_safe = 0;
87#endif
88 if (PyModule_AddIntConstant(module, "has_uuid_generate_time_safe",
89 has_uuid_generate_time_safe) < 0) {
90 return -1;
91 }
92 return 0;
93}
94
95static PyMethodDef uuid_methods[] = {
96#if defined(HAVE_UUID_UUID_H) || defined(HAVE_UUID_H)
97 {"generate_time_safe", py_uuid_generate_time_safe, METH_NOARGS, NULL},
98#endif
99#if defined(MS_WINDOWS)
100 {"UuidCreate", py_UuidCreate, METH_NOARGS, NULL},
101#endif
102 {NULL, NULL, 0, NULL} /* sentinel */
103};
104
105static PyModuleDef_Slot uuid_slots[] = {
106 {Py_mod_exec, uuid_exec},
107 {0, NULL}
108};
109
110static struct PyModuleDef uuidmodule = {
111 PyModuleDef_HEAD_INIT,
112 .m_name = "_uuid",
113 .m_size = 0,
114 .m_methods = uuid_methods,
115 .m_slots = uuid_slots,
116};
117
118PyMODINIT_FUNC
119PyInit__uuid(void)
120{
121 return PyModuleDef_Init(&uuidmodule);
122}
123