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