diff options
| author | Larry Hastings <larry@hastings.org> | 2013-10-19 07:09:25 (GMT) |
|---|---|---|
| committer | Larry Hastings <larry@hastings.org> | 2013-10-19 07:09:25 (GMT) |
| commit | 3182680210fa0cf570233382bbaec8b64d57f4da (patch) | |
| tree | 93932cf52fd5cbbdeab62b2fc43851e3cb637e3d /Modules/posixmodule.c | |
| parent | 5ceae41083f3bec479fe8f135f442e6576c6e273 (diff) | |
| download | cpython-3182680210fa0cf570233382bbaec8b64d57f4da.zip cpython-3182680210fa0cf570233382bbaec8b64d57f4da.tar.gz cpython-3182680210fa0cf570233382bbaec8b64d57f4da.tar.bz2 | |
Issue #16612: Add "Argument Clinic", a compile-time preprocessor
for C files to generate argument parsing code. (See PEP 436.)
Diffstat (limited to 'Modules/posixmodule.c')
| -rw-r--r-- | Modules/posixmodule.c | 397 |
1 files changed, 301 insertions, 96 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index 2779852..1d02e73 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -8,6 +8,8 @@ of the compiler used. Different compilers define their own feature test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */ + + #ifdef __APPLE__ /* * Step 1 of support for weak-linking a number of symbols existing on @@ -712,7 +714,7 @@ dir_fd_converter(PyObject *o, void *p) * path.function_name * If non-NULL, path_converter will use that as the name * of the function in error messages. - * (If path.argument_name is NULL it omits the function name.) + * (If path.function_name is NULL it omits the function name.) * path.argument_name * If non-NULL, path_converter will use that as the name * of the parameter in error messages. @@ -776,6 +778,9 @@ typedef struct { PyObject *cleanup; } path_t; +#define PATH_T_INITIALIZE(function_name, nullable, allow_fd) \ + {function_name, NULL, nullable, allow_fd, NULL, NULL, 0, 0, NULL, NULL} + static void path_cleanup(path_t *path) { if (path->cleanup) { @@ -1313,6 +1318,7 @@ path_error(path_t *path) #endif } + /* POSIX generic methods */ static PyObject * @@ -2347,48 +2353,145 @@ posix_do_stat(char *function_name, path_t *path, return _pystat_fromstructstat(&st); } -PyDoc_STRVAR(posix_stat__doc__, -"stat(path, *, dir_fd=None, follow_symlinks=True) -> stat result\n\n\ -Perform a stat system call on the given path.\n\ -\n\ -path may be specified as either a string or as an open file descriptor.\n\ -\n\ -If dir_fd is not None, it should be a file descriptor open to a directory,\n\ - and path should be relative; path will then be relative to that directory.\n\ - dir_fd may not be supported on your platform; if it is unavailable, using\n\ - it will raise a NotImplementedError.\n\ -If follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, stat will examine the symbolic link itself instead of the file the\n\ - link points to.\n\ -It is an error to use dir_fd or follow_symlinks when specifying path as\n\ - an open file descriptor."); +#ifdef HAVE_FSTATAT + #define OS_STAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define OS_STAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + + +/*[python] + +class path_t_converter(CConverter): + + type = "path_t" + impl_by_reference = True + parse_by_reference = True + + converter = 'path_converter' + + def converter_init(self, *, allow_fd=False, nullable=False): + def strify(value): + return str(int(bool(value))) + + # right now path_t doesn't support default values. + # to support a default value, you'll need to override initialize(). + + assert self.default is unspecified + + self.nullable = nullable + self.allow_fd = allow_fd + + self.c_default = 'PATH_T_INITIALIZE("{}", {}, {})'.format( + self.function.name, + strify(nullable), + strify(allow_fd), + ) + + def cleanup(self): + return "path_cleanup(&" + self.name + ");\n" + + +class dir_fd_converter(CConverter): + type = 'int' + converter = 'OS_STAT_DIR_FD_CONVERTER' + + def converter_init(self): + if self.default in (unspecified, None): + self.c_default = 'DEFAULT_DIR_FD' + + +[python]*/ +/*[python checksum: da39a3ee5e6b4b0d3255bfef95601890afd80709]*/ + +/*[clinic] +module os + +os.stat -> object(doc_default='stat_result') + + path : path_t(allow_fd=True) + Path to be examined; can be string, bytes, or open-file-descriptor int. + + * + + dir_fd : dir_fd = None + If not None, it should be a file descriptor open to a directory, + and path should be a relative string; path will then be relative to + that directory. + + follow_symlinks: bool = True + If False, and the last element of the path is a symbolic link, + stat will examine the symbolic link itself instead of the file + the link points to. + +Perform a stat system call on the given path. + +dir_fd and follow_symlinks may not be implemented + on your platform. If they are unavailable, using them will raise a + NotImplementedError. + +It's an error to use dir_fd or follow_symlinks when specifying path as + an open file descriptor. + +[clinic]*/ + +PyDoc_STRVAR(os_stat__doc__, +"Perform a stat system call on the given path.\n" +"\n" +"os.stat(path, *, dir_fd=None, follow_symlinks=True) -> stat_result\n" +" path\n" +" Path to be examined; can be string, bytes, or open-file-descriptor int.\n" +" dir_fd\n" +" If not None, it should be a file descriptor open to a directory,\n" +" and path should be a relative string; path will then be relative to\n" +" that directory.\n" +" follow_symlinks\n" +" If False, and the last element of the path is a symbolic link,\n" +" stat will examine the symbolic link itself instead of the file\n" +" the link points to.\n" +"\n" +"dir_fd and follow_symlinks may not be implemented\n" +" on your platform. If they are unavailable, using them will raise a\n" +" NotImplementedError.\n" +"\n" +"It\'s an error to use dir_fd or follow_symlinks when specifying path as\n" +" an open file descriptor."); + +#define OS_STAT_METHODDEF \ + {"stat", (PyCFunction)os_stat, METH_VARARGS|METH_KEYWORDS, os_stat__doc__}, static PyObject * -posix_stat(PyObject *self, PyObject *args, PyObject *kwargs) +os_stat_impl(PyObject *self, path_t *path, int dir_fd, int follow_symlinks); + +static PyObject * +os_stat(PyObject *self, PyObject *args, PyObject *kwargs) { - static char *keywords[] = {"path", "dir_fd", "follow_symlinks", NULL}; - path_t path; + PyObject *return_value = NULL; + static char *_keywords[] = {"path", "dir_fd", "follow_symlinks", NULL}; + path_t path = PATH_T_INITIALIZE("stat", 0, 1); int dir_fd = DEFAULT_DIR_FD; int follow_symlinks = 1; - PyObject *return_value; - memset(&path, 0, sizeof(path)); - path.function_name = "stat"; - path.allow_fd = 1; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&p:stat", keywords, - path_converter, &path, -#ifdef HAVE_FSTATAT - dir_fd_converter, &dir_fd, -#else - dir_fd_unavailable, &dir_fd, -#endif - &follow_symlinks)) - return NULL; - return_value = posix_do_stat("stat", &path, dir_fd, follow_symlinks); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O&|$O&p:stat", _keywords, + path_converter, &path, OS_STAT_DIR_FD_CONVERTER, &dir_fd, &follow_symlinks)) + goto exit; + return_value = os_stat_impl(self, &path, dir_fd, follow_symlinks); + +exit: + /* Cleanup for path */ path_cleanup(&path); + return return_value; } +static PyObject * +os_stat_impl(PyObject *self, path_t *path, int dir_fd, int follow_symlinks) +/*[clinic checksum: 9d9af08e8cfafd12f94e73ea3065eb3056f99515]*/ +{ + return posix_do_stat("stat", path, dir_fd, follow_symlinks); +} + PyDoc_STRVAR(posix_lstat__doc__, "lstat(path, *, dir_fd=None) -> stat result\n\n\ Like stat(), but do not follow symbolic links.\n\ @@ -2414,44 +2517,120 @@ posix_lstat(PyObject *self, PyObject *args, PyObject *kwargs) #endif )) return NULL; - return_value = posix_do_stat("stat", &path, dir_fd, follow_symlinks); + return_value = posix_do_stat("lstat", &path, dir_fd, follow_symlinks); path_cleanup(&path); return return_value; } -PyDoc_STRVAR(posix_access__doc__, -"access(path, mode, *, dir_fd=None, effective_ids=False,\ - follow_symlinks=True)\n\n\ -Use the real uid/gid to test for access to a path. Returns True if granted,\n\ -False otherwise.\n\ -\n\ -If dir_fd is not None, it should be a file descriptor open to a directory,\n\ - and path should be relative; path will then be relative to that directory.\n\ -If effective_ids is True, access will use the effective uid/gid instead of\n\ - the real uid/gid.\n\ -If follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, access will examine the symbolic link itself instead of the file the\n\ - link points to.\n\ -dir_fd, effective_ids, and follow_symlinks may not be implemented\n\ - on your platform. If they are unavailable, using them will raise a\n\ - NotImplementedError.\n\ -\n\ -Note that most operations will use the effective uid/gid, therefore this\n\ - routine can be used in a suid/sgid environment to test if the invoking user\n\ - has the specified access to the path.\n\ -The mode argument can be F_OK to test existence, or the inclusive-OR\n\ - of R_OK, W_OK, and X_OK."); -static PyObject * -posix_access(PyObject *self, PyObject *args, PyObject *kwargs) +#ifdef HAVE_FACCESSAT + #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_converter +#else + #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_unavailable +#endif +/*[clinic] +os.access -> object(doc_default='True if granted, False otherwise') + + path: path_t(allow_fd=True) + Path to be tested; can be string, bytes, or open-file-descriptor int. + + mode: int + Operating-system mode bitfield. Can be F_OK to test existence, + or the inclusive-OR of R_OK, W_OK, and X_OK. + + * + + dir_fd : dir_fd = None + If not None, it should be a file descriptor open to a directory, + and path should be relative; path will then be relative to that + directory. + + effective_ids: bool = False + If True, access will use the effective uid/gid instead of + the real uid/gid. + + follow_symlinks: bool = True + If False, and the last element of the path is a symbolic link, + access will examine the symbolic link itself instead of the file + the link points to. + +Use the real uid/gid to test for access to a path. + +{parameters} +dir_fd, effective_ids, and follow_symlinks may not be implemented + on your platform. If they are unavailable, using them will raise a + NotImplementedError. + +Note that most operations will use the effective uid/gid, therefore this + routine can be used in a suid/sgid environment to test if the invoking user + has the specified access to the path. + +[clinic]*/ + +PyDoc_STRVAR(os_access__doc__, +"Use the real uid/gid to test for access to a path.\n" +"\n" +"os.access(path, mode, *, dir_fd=None, effective_ids=False, follow_symlinks=True) -> True if granted, False otherwise\n" +" path\n" +" Path to be tested; can be string, bytes, or open-file-descriptor int.\n" +" mode\n" +" Operating-system mode bitfield. Can be F_OK to test existence,\n" +" or the inclusive-OR of R_OK, W_OK, and X_OK.\n" +" dir_fd\n" +" If not None, it should be a file descriptor open to a directory,\n" +" and path should be relative; path will then be relative to that\n" +" directory.\n" +" effective_ids\n" +" If True, access will use the effective uid/gid instead of\n" +" the real uid/gid.\n" +" follow_symlinks\n" +" If False, and the last element of the path is a symbolic link,\n" +" access will examine the symbolic link itself instead of the file\n" +" the link points to.\n" +"\n" +"{parameters}\n" +"dir_fd, effective_ids, and follow_symlinks may not be implemented\n" +" on your platform. If they are unavailable, using them will raise a\n" +" NotImplementedError.\n" +"\n" +"Note that most operations will use the effective uid/gid, therefore this\n" +" routine can be used in a suid/sgid environment to test if the invoking user\n" +" has the specified access to the path."); + +#define OS_ACCESS_METHODDEF \ + {"access", (PyCFunction)os_access, METH_VARARGS|METH_KEYWORDS, os_access__doc__}, + +static PyObject * +os_access_impl(PyObject *self, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks); + +static PyObject * +os_access(PyObject *self, PyObject *args, PyObject *kwargs) { - static char *keywords[] = {"path", "mode", "dir_fd", "effective_ids", - "follow_symlinks", NULL}; - path_t path; + PyObject *return_value = NULL; + static char *_keywords[] = {"path", "mode", "dir_fd", "effective_ids", "follow_symlinks", NULL}; + path_t path = PATH_T_INITIALIZE("access", 0, 1); int mode; int dir_fd = DEFAULT_DIR_FD; int effective_ids = 0; int follow_symlinks = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O&i|$O&pp:access", _keywords, + path_converter, &path, &mode, OS_STAT_DIR_FD_CONVERTER, &dir_fd, &effective_ids, &follow_symlinks)) + goto exit; + return_value = os_access_impl(self, &path, mode, dir_fd, effective_ids, follow_symlinks); + +exit: + /* Cleanup for path */ + path_cleanup(&path); + + return return_value; +} + +static PyObject * +os_access_impl(PyObject *self, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks) +/*[clinic checksum: 0147557eb43243df57ba616cc7c35f232c69bc6a]*/ +{ PyObject *return_value = NULL; #ifdef MS_WINDOWS @@ -2460,17 +2639,6 @@ posix_access(PyObject *self, PyObject *args, PyObject *kwargs) int result; #endif - memset(&path, 0, sizeof(path)); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&i|$O&pp:access", keywords, - path_converter, &path, &mode, -#ifdef HAVE_FACCESSAT - dir_fd_converter, &dir_fd, -#else - dir_fd_unavailable, &dir_fd, -#endif - &effective_ids, &follow_symlinks)) - return NULL; - #ifndef HAVE_FACCESSAT if (follow_symlinks_specified("access", follow_symlinks)) goto exit; @@ -2514,11 +2682,11 @@ posix_access(PyObject *self, PyObject *args, PyObject *kwargs) flags |= AT_SYMLINK_NOFOLLOW; if (effective_ids) flags |= AT_EACCESS; - result = faccessat(dir_fd, path.narrow, mode, flags); + result = faccessat(dir_fd, path->narrow, mode, flags); } else #endif - result = access(path.narrow, mode); + result = access(path->narrow, mode); Py_END_ALLOW_THREADS return_value = PyBool_FromLong(!result); #endif @@ -2526,7 +2694,6 @@ posix_access(PyObject *self, PyObject *args, PyObject *kwargs) #ifndef HAVE_FACCESSAT exit: #endif - path_cleanup(&path); return return_value; } @@ -2543,35 +2710,76 @@ exit: #define X_OK 1 #endif + #ifdef HAVE_TTYNAME -PyDoc_STRVAR(posix_ttyname__doc__, -"ttyname(fd) -> string\n\n\ -Return the name of the terminal device connected to 'fd'."); + +/*[clinic] +os.ttyname -> DecodeFSDefault + + fd: int + Integer file descriptor handle. + + / + +Return the name of the terminal device connected to 'fd'. +[clinic]*/ + +PyDoc_STRVAR(os_ttyname__doc__, +"Return the name of the terminal device connected to \'fd\'.\n" +"\n" +"os.ttyname(fd)\n" +" fd\n" +" Integer file descriptor handle."); + +#define OS_TTYNAME_METHODDEF \ + {"ttyname", (PyCFunction)os_ttyname, METH_VARARGS, os_ttyname__doc__}, + +static char * +os_ttyname_impl(PyObject *self, int fd); static PyObject * -posix_ttyname(PyObject *self, PyObject *args) +os_ttyname(PyObject *self, PyObject *args) { - int id; - char *ret; + PyObject *return_value = NULL; + int fd; + char *_return_value; - if (!PyArg_ParseTuple(args, "i:ttyname", &id)) - return NULL; + if (!PyArg_ParseTuple(args, + "i:ttyname", + &fd)) + goto exit; + _return_value = os_ttyname_impl(self, fd); + if (_return_value == NULL) + goto exit; + return_value = PyUnicode_DecodeFSDefault(_return_value); + +exit: + return return_value; +} + +static char * +os_ttyname_impl(PyObject *self, int fd) +/*[clinic checksum: ea680155d87bb733f542d67653eca732dd0981a8]*/ +{ + char *ret; #if defined(__VMS) /* file descriptor 0 only, the default input device (stdin) */ - if (id == 0) { + if (fd == 0) { ret = ttyname(); } else { ret = NULL; } #else - ret = ttyname(id); + ret = ttyname(fd); #endif if (ret == NULL) - return posix_error(); - return PyUnicode_DecodeFSDefault(ret); + posix_error(); + return ret; } +#else +#define OS_TTYNAME_METHODDEF #endif #ifdef HAVE_CTERMID @@ -10912,13 +11120,13 @@ posix_set_handle_inheritable(PyObject *self, PyObject *args) #endif /* MS_WINDOWS */ + static PyMethodDef posix_methods[] = { - {"access", (PyCFunction)posix_access, - METH_VARARGS | METH_KEYWORDS, - posix_access__doc__}, -#ifdef HAVE_TTYNAME - {"ttyname", posix_ttyname, METH_VARARGS, posix_ttyname__doc__}, -#endif + + OS_STAT_METHODDEF + OS_ACCESS_METHODDEF + OS_TTYNAME_METHODDEF + {"chdir", (PyCFunction)posix_chdir, METH_VARARGS | METH_KEYWORDS, posix_chdir__doc__}, @@ -11002,9 +11210,6 @@ static PyMethodDef posix_methods[] = { {"rmdir", (PyCFunction)posix_rmdir, METH_VARARGS | METH_KEYWORDS, posix_rmdir__doc__}, - {"stat", (PyCFunction)posix_stat, - METH_VARARGS | METH_KEYWORDS, - posix_stat__doc__}, {"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__}, #if defined(HAVE_SYMLINK) {"symlink", (PyCFunction)posix_symlink, |
