cpython: 709850f1ec67 (original) (raw)
--- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -398,6 +398,268 @@ static int win32_can_symlink = 0; #endif #endif +/*
- */ +typedef struct argument_path_s {
- struct argument_path_s *next;
- PyObject *object;
- char *format;
- wchar_t **wide;
- char **narrow;
- Py_ssize_t *length;
+} argument_path_t; + +typedef struct {
- PyObject *args;
- PyObject *kwargs;
- char format[32];
- char *format_trace;
- char *keywords[8];
- int keyword_count;
- PyObject **varargs[16];
- int vararg_count;
- const char *function_name;
- argument_path_t *path_head;
+} argument_parser_table_t; + +#define APT_DECLARE(apt, fname) [](#l1.32)
- argument_parser_table_t apt; [](#l1.33)
- memset(&apt, 0, sizeof(apt)); [](#l1.34)
- apt.function_name = fname; [](#l1.35)
- apt.args = args; [](#l1.36)
- apt.kwargs = kwargs; [](#l1.37)
- apt.format_trace = apt.format
+ +#define _APT_ARGUMENT_OBJECT(apt, name, variable, format) [](#l1.40)
- *apt.format_trace++ = (format); [](#l1.41)
- apt.keywords[apt.keyword_count++] = (name); [](#l1.42)
- apt.varargs[apt.vararg_count++] = (PyObject **)(variable); [](#l1.43)
+ +#define APT_ARGUMENT_OBJECT(apt, name, variable) [](#l1.45)
+ +#define APT_ARGUMENT_OBJECT_WITH_CONVERTER(apt, name, variable, converter) [](#l1.48)
- apt.varargs[apt.vararg_count++] = (PyObject **)converter; [](#l1.49)
- APT_ARGUMENT_OBJECT(apt, name, variable); [](#l1.50)
- *apt.format_trace++ = '&'; [](#l1.51)
+ +#define APT_ARGUMENT_UNICODE(apt, name, variable) [](#l1.53)
+ +#define APT_ARGUMENT_BYTES(apt, name, variable) [](#l1.56)
+ +#define APT_ARGUMENT_INT(apt, name, variable) [](#l1.59)
+ +static int +bool_converter(PyObject *object, void *address) {
- int *output = (int *)address;
- int value = PyObject_IsTrue(object);
- if (value == -1)
return 0;[](#l1.67)
- *output = value;
- return 1;
+} + +#define APT_ARGUMENT_BOOL(apt, name, variable) [](#l1.72)
- #define _APT_DEFAULT_PATH_TYPE 'O'
- #define _APT_PATH_BEFORE apt.varargs[apt.vararg_count++] = (PyObject **)PyUnicode_FSConverter;
- #define _APT_PATH_AFTER *apt.format_trace++ = '&';
+#endif + +#define APT_ARGUMENT_PATH(apt, name, w, n, l) [](#l1.85)
- { [](#l1.86)
- argument_path_t *path = (argument_path_t *)alloca(sizeof(argument_path_t)); [](#l1.87)
- _APT_PATH_BEFORE; [](#l1.88)
- memset(path, 0, sizeof(*path)); [](#l1.89)
- path->wide = w; [](#l1.90)
- path->narrow = n; [](#l1.91)
- path->length = l; [](#l1.92)
- path->next = apt.path_head; [](#l1.93)
- apt.path_head = path; [](#l1.94)
- _APT_ARGUMENT_OBJECT(apt, name, &path->object, _APT_DEFAULT_PATH_TYPE); [](#l1.95)
- _APT_PATH_AFTER; [](#l1.96)
- } [](#l1.97)
+ +#define APT_OPTIONAL(apt) [](#l1.99)
- *apt.format_trace++ = '|' [](#l1.100)
+ +#define APT_KEYWORD_ONLY(apt) [](#l1.102)
- *apt.format_trace++ = '$' [](#l1.103)
+ + +static int apt_parse(argument_parser_table_t *apt) {
- *apt->format_trace++ = ':';
- strcpy(apt->format_trace, apt->function_name);
- apt->keywords[apt->keyword_count] = NULL;
switch (apt->vararg_count) {[](#l1.116)
case 0:[](#l1.117)
PyErr_SetString(PyExc_RuntimeError, "suspiciously too few arguments for apt_parse");[](#l1.118)
return 0;[](#l1.119)
#define APT_PREAMBLE \[](#l1.121)
result = PyArg_ParseTupleAndKeywords(apt->args, apt->kwargs, apt->format, apt->keywords, \[](#l1.122)
#define APT_POSTSCRIPT \[](#l1.124)
); \[](#l1.125)
break; \[](#l1.126)
case 1:[](#l1.128)
APT_PREAMBLE[](#l1.129)
apt->varargs[0][](#l1.130)
APT_POSTSCRIPT[](#l1.131)
case 2:[](#l1.132)
APT_PREAMBLE[](#l1.133)
apt->varargs[0],[](#l1.134)
apt->varargs[1][](#l1.135)
APT_POSTSCRIPT[](#l1.136)
case 3:[](#l1.137)
APT_PREAMBLE[](#l1.138)
apt->varargs[0],[](#l1.139)
apt->varargs[1],[](#l1.140)
apt->varargs[2][](#l1.141)
APT_POSTSCRIPT[](#l1.142)
case 4:[](#l1.143)
APT_PREAMBLE[](#l1.144)
apt->varargs[0],[](#l1.145)
apt->varargs[1],[](#l1.146)
apt->varargs[2],[](#l1.147)
apt->varargs[3][](#l1.148)
APT_POSTSCRIPT[](#l1.149)
case 5:[](#l1.150)
APT_PREAMBLE[](#l1.151)
apt->varargs[0],[](#l1.152)
apt->varargs[1],[](#l1.153)
apt->varargs[2],[](#l1.154)
apt->varargs[3],[](#l1.155)
apt->varargs[4][](#l1.156)
APT_POSTSCRIPT[](#l1.157)
case 6:[](#l1.158)
APT_PREAMBLE[](#l1.159)
apt->varargs[0],[](#l1.160)
apt->varargs[1],[](#l1.161)
apt->varargs[2],[](#l1.162)
apt->varargs[3],[](#l1.163)
apt->varargs[4],[](#l1.164)
apt->varargs[5][](#l1.165)
APT_POSTSCRIPT[](#l1.166)
case 7:[](#l1.167)
APT_PREAMBLE[](#l1.168)
apt->varargs[0],[](#l1.169)
apt->varargs[1],[](#l1.170)
apt->varargs[2],[](#l1.171)
apt->varargs[3],[](#l1.172)
apt->varargs[4],[](#l1.173)
apt->varargs[5],[](#l1.174)
apt->varargs[6][](#l1.175)
APT_POSTSCRIPT[](#l1.176)
case 8:[](#l1.177)
APT_PREAMBLE[](#l1.178)
apt->varargs[0],[](#l1.179)
apt->varargs[1],[](#l1.180)
apt->varargs[2],[](#l1.181)
apt->varargs[3],[](#l1.182)
apt->varargs[4],[](#l1.183)
apt->varargs[5],[](#l1.184)
apt->varargs[6],[](#l1.185)
apt->varargs[7][](#l1.186)
APT_POSTSCRIPT[](#l1.187)
default:[](#l1.188)
PyErr_SetString(PyExc_RuntimeError, "too many arguments for apt_parse");[](#l1.189)
return 0;[](#l1.190)
}[](#l1.191)
switch (*trace->format) {[](#l1.196)
case 'U':[](#l1.197)
*trace->wide = PyUnicode_AsUnicode(trace->object);[](#l1.198)
if (trace->length)[](#l1.199)
*trace->length = PyUnicode_GET_SIZE(trace->object);[](#l1.200)
break;[](#l1.201)
case 'y'[](#l1.202)
if (win32_warn_bytes_api())[](#l1.203)
return 0;[](#l1.204)
*trace->narrow = trace->object;[](#l1.205)
if (trace->length)[](#l1.206)
*trace->length = strlen((char *)trace->object);[](#l1.207)
break;[](#l1.208)
default:[](#l1.209)
PyErr_SetString(PyExc_RuntimeError, "unexpected format character in apt_parse");[](#l1.210)
return 0;[](#l1.211)
}[](#l1.212)
assert(*trace->format == 'O');[](#l1.214)
*trace->narrow = PyBytes_AsString(trace->object);[](#l1.215)
if (trace->length)[](#l1.216)
*trace->length = PyBytes_GET_SIZE(trace->object);[](#l1.217)
- for (trace = apt->path_head; trace != NULL; trace = trace->next) {
/*[](#l1.227)
* try flipping paths between wide and narrow.[](#l1.228)
*[](#l1.229)
* each element always started with wide.[](#l1.230)
* so:[](#l1.231)
* * if we see a wide, flip it to narrow and stop.[](#l1.232)
* * if we see a narrow, flip it to wide and move on to the next field.[](#l1.233)
* * if we run out of fields, we have exhausted all possibilities. fail.[](#l1.234)
*[](#l1.235)
* (conceptually it helps to think of the fields as a binary number[](#l1.236)
* with as many digits as there are entries in the path list.[](#l1.237)
* wide is 0, narrow is 1. we keep incrementing the number[](#l1.238)
* until we wrap around to 0 again.)[](#l1.239)
*/[](#l1.240)
if (*trace->format == 'U') {[](#l1.241)
*trace->format = 'y';[](#l1.242)
break;[](#l1.243)
}[](#l1.244)
if (*trace->format == 'y') {[](#l1.245)
*trace->format = 'U';[](#l1.246)
continue;[](#l1.247)
}[](#l1.248)
PyErr_SetString(PyExc_RuntimeError, "unexpected format character in apt_parse");[](#l1.249)
return 0;[](#l1.250)
}[](#l1.251)
- if (!trace)
break;[](#l1.253)
+} + +static void apt_cleanup(argument_parser_table_t *apt) { +#if !MS_WINDOWS
- argument_path_t *trace;
- for (trace = apt->path_head; trace != NULL; trace = trace->next) {
Py_XDECREF(trace->object);[](#l1.264)
- }
+#endif +} + /* A helper used by a number of POSIX-only functions */ #ifndef MS_WINDOWS static int @@ -1942,6 +2204,12 @@ posix_do_stat(PyObject *self, PyObject / POSIX methods */ +#ifdef AT_FDCWD +#define DEFAULT_DIR_FD AT_FDCWD +#else +#define DEFAULT_DIR_FD (-100) +#endif + PyDoc_STRVAR(posix_access__doc__, "access(path, mode) -> True if granted, False otherwise\n\n[](#l1.283) Use the real uid/gid to test for access to a path. Note that most\n[](#l1.284) @@ -1951,34 +2219,54 @@ specified access to the path. The mode existence, or the inclusive-OR of R_OK, W_OK, and X_OK."); static PyObject * -posix_access(PyObject *self, PyObject *args) -{
+posix_access(PyObject *self, PyObject *args, PyObject *kwargs) +{ int mode;
- int dir_fd = DEFAULT_DIR_FD;
- wchar_t *wide_path;
- char *path;
- int follow_symlinks = 1;
- int effective_ids = 0;
- PyObject *po;
- if (PyArg_ParseTuple(args, "Ui:access", &po, &mode)) {
wchar_t* wpath = PyUnicode_AsUnicode(po);[](#l1.305)
if (wpath == NULL)[](#l1.306)
return NULL;[](#l1.307)
Py_BEGIN_ALLOW_THREADS[](#l1.308)
attr = GetFileAttributesW(wpath);[](#l1.309)
Py_END_ALLOW_THREADS[](#l1.310)
goto finish;[](#l1.311)
- }
- /* Drop the argument parsing error as narrow strings
are also valid. */[](#l1.314)
- PyErr_Clear();
- if (!PyArg_ParseTuple(args, "yi:access", &path, &mode))
return NULL;[](#l1.317)
- if (win32_warn_bytes_api())
return NULL;[](#l1.319)
- Py_BEGIN_ALLOW_THREADS
- attr = GetFileAttributesA(path);
- Py_END_ALLOW_THREADS
- APT_DECLARE(apt, "access");
- APT_ARGUMENT_PATH(apt, "path", &wide_path, &path, NULL);
- APT_ARGUMENT_INT(apt, "mode", &mode);
- APT_OPTIONAL(apt);
- APT_KEYWORD_ONLY(apt);
- APT_ARGUMENT_INT(apt, "dir_fd", &dir_fd);
- APT_ARGUMENT_BOOL(apt, "follow_symlinks", &follow_symlinks);
- APT_ARGUMENT_BOOL(apt, "effective_ids", &effective_ids);
+ +#define ACCESS_FAIL_IF_KEYWORD_USED [](#l1.337)
- if (dir_fd != DEFAULT_DIR_FD) [](#l1.338)
PyErr_SetString(PyExc_NotImplementedError, "access: dir_fd unavailable on this platform"); \[](#l1.339)
- if (!follow_symlinks) [](#l1.340)
PyErr_SetString(PyExc_NotImplementedError, "access: follow_symlinks unavailable on this platform"); \[](#l1.341)
- if (effective_ids) [](#l1.342)
PyErr_SetString(PyExc_NotImplementedError, "access: effective_ids unavailable on this platform")[](#l1.343)
- Py_BEGIN_ALLOW_THREADS
- if (wide != NULL)
attr = GetFileAttributesW(wide_path);[](#l1.354)
- else
attr = GetFileAttributesA(path);[](#l1.356)
- Py_END_ALLOW_THREADS
+ if (attr == 0xFFFFFFFF) /* File does not exist, or cannot read attributes */ return PyBool_FromLong(0); @@ -1989,16 +2277,28 @@ finish: || !(attr & FILE_ATTRIBUTE_READONLY) || (attr & FILE_ATTRIBUTE_DIRECTORY)); #else
- PyObject *opath;
- int res;
- if (!PyArg_ParseTuple(args, "O&i:access",
PyUnicode_FSConverter, &opath, &mode))[](#l1.371)
return NULL;[](#l1.372)
- path = PyBytes_AsString(opath);
- Py_BEGIN_ALLOW_THREADS
- res = access(path, mode);
- Py_END_ALLOW_THREADS
- Py_DECREF(opath);
int flags = 0;[](#l1.382)
if (!follow_symlinks)[](#l1.383)
flags |= AT_SYMLINK_NOFOLLOW;[](#l1.384)
if (effective_ids)[](#l1.385)
flags |= AT_EACCESS;[](#l1.386)
Py_BEGIN_ALLOW_THREADS[](#l1.387)
res = faccessat(dir_fd, path, mode, flags);[](#l1.388)
Py_END_ALLOW_THREADS[](#l1.389)
ACCESS_FAIL_IF_KEYWORD_USED;[](#l1.391)
- } else {
Py_BEGIN_ALLOW_THREADS[](#l1.394)
res = access(path, mode);[](#l1.395)
Py_END_ALLOW_THREADS[](#l1.396)
- }
#endif } @@ -10596,7 +10896,9 @@ get_terminal_size(PyObject *self, PyObje static PyMethodDef posix_methods[] = {
- {"access", (PyCFunction)posix_access,
METH_VARARGS | METH_KEYWORDS,[](#l1.409)
posix_access__doc__},[](#l1.410)
#ifdef HAVE_TTYNAME {"ttyname", posix_ttyname, METH_VARARGS, posix_ttyname__doc__}, #endif