diff options
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r-- | Modules/posixmodule.c | 8017 |
1 files changed, 4323 insertions, 3694 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index d45f59e..7da1ab0 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -6,7 +6,7 @@ functions are either unimplemented or implemented differently. The source assumes that for Windows NT, the macro 'MS_WINDOWS' is defined independent of the compiler used. Different compilers define their own feature - test macro, e.g. '__BORLANDC__' or '_MSC_VER'. */ + test macro, e.g. '_MSC_VER'. */ @@ -25,8 +25,11 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" +#include "structmember.h" #ifndef MS_WINDOWS #include "posixmodule.h" +#else +#include "winreparse.h" #endif #ifdef __cplusplus @@ -141,13 +144,6 @@ corresponding Unix manual entries for more information on calls."); #define HAVE_SYSTEM 1 #include <process.h> #else -#ifdef __BORLANDC__ /* Borland compiler */ -#define HAVE_EXECV 1 -#define HAVE_OPENDIR 1 -#define HAVE_PIPE 1 -#define HAVE_SYSTEM 1 -#define HAVE_WAIT 1 -#else #ifdef _MSC_VER /* Microsoft compiler */ #define HAVE_GETPPID 1 #define HAVE_GETLOGIN 1 @@ -177,14 +173,14 @@ corresponding Unix manual entries for more information on calls."); #define HAVE_WAIT 1 #define HAVE_TTYNAME 1 #endif /* _MSC_VER */ -#endif /* __BORLANDC__ */ #endif /* ! __WATCOMC__ || __QNX__ */ /*[clinic input] +# one of the few times we lie about this name! module os [clinic start generated code]*/ -/*[clinic end generated code: output=da39a3ee5e6b4b0d input=8cff096d1133288f]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=94a0f0f978acae17]*/ #ifndef _MSC_VER @@ -211,11 +207,7 @@ extern int rmdir(char *); extern int chdir(const char *); extern int rmdir(const char *); #endif -#ifdef __BORLANDC__ -extern int chmod(const char *, int); -#else extern int chmod(const char *, mode_t); -#endif /*#ifdef HAVE_FCHMOD extern int fchmod(int, mode_t); #endif*/ @@ -301,6 +293,9 @@ extern int lstat(const char *, struct stat *); #ifndef IO_REPARSE_TAG_SYMLINK #define IO_REPARSE_TAG_SYMLINK (0xA000000CL) #endif +#ifndef IO_REPARSE_TAG_MOUNT_POINT +#define IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L) +#endif #include "osdefs.h" #include <malloc.h> #include <windows.h> @@ -356,8 +351,8 @@ static int win32_can_symlink = 0; #ifdef MS_WINDOWS # define STAT win32_stat # define LSTAT win32_lstat -# define FSTAT win32_fstat -# define STRUCT_STAT struct win32_stat +# define FSTAT _Py_fstat_noraise +# define STRUCT_STAT struct _Py_stat_struct #else # define STAT stat # define LSTAT lstat @@ -378,6 +373,20 @@ static int win32_can_symlink = 0; #define DWORD_MAX 4294967295U +#ifdef MS_WINDOWS +#define INITFUNC PyInit_nt +#define MODNAME "nt" +#else +#define INITFUNC PyInit_posix +#define MODNAME "posix" +#endif + +#ifdef MS_WINDOWS +/* defined in fileutils.c */ +PyAPI_FUNC(void) _Py_time_t_to_FILE_TIME(time_t, int, FILETIME *); +PyAPI_FUNC(void) _Py_attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *, + ULONG, struct _Py_stat_struct *); +#endif #ifdef MS_WINDOWS static int @@ -701,7 +710,6 @@ dir_fd_converter(PyObject *o, void *p) } - /* * A PyArg_ParseTuple "converter" function * that handles filesystem paths in the manner @@ -797,8 +805,8 @@ 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} +#define PATH_T_INITIALIZE(function_name, argument_name, nullable, allow_fd) \ + {function_name, argument_name, nullable, allow_fd, NULL, NULL, -1, 0, NULL, NULL} static void path_cleanup(path_t *path) { @@ -920,8 +928,8 @@ path_converter(PyObject *o, void *p) { #endif narrow = PyBytes_AS_STRING(bytes); - if (length != strlen(narrow)) { - FORMAT_EXCEPTION(PyExc_ValueError, "embedded NUL character in %s"); + if ((size_t)length != strlen(narrow)) { + FORMAT_EXCEPTION(PyExc_ValueError, "embedded null character in %s"); Py_DECREF(bytes); return 0; } @@ -1022,97 +1030,46 @@ dir_fd_and_follow_symlinks_invalid(char *function_name, int dir_fd, return 0; } -/* A helper used by a number of POSIX-only functions */ -#ifndef MS_WINDOWS +#ifdef MS_WINDOWS + typedef PY_LONG_LONG Py_off_t; +#else + typedef off_t Py_off_t; +#endif + static int -_parse_off_t(PyObject* arg, void* addr) +Py_off_t_converter(PyObject *arg, void *addr) { -#if !defined(HAVE_LARGEFILE_SUPPORT) - *((off_t*)addr) = PyLong_AsLong(arg); +#ifdef HAVE_LARGEFILE_SUPPORT + *((Py_off_t *)addr) = PyLong_AsLongLong(arg); #else - *((off_t*)addr) = PyLong_AsLongLong(arg); + *((Py_off_t *)addr) = PyLong_AsLong(arg); #endif if (PyErr_Occurred()) return 0; return 1; } + +static PyObject * +PyLong_FromPy_off_t(Py_off_t offset) +{ +#ifdef HAVE_LARGEFILE_SUPPORT + return PyLong_FromLongLong(offset); +#else + return PyLong_FromLong(offset); #endif +} -#if defined _MSC_VER && _MSC_VER >= 1400 -/* Microsoft CRT in VS2005 and higher will verify that a filehandle is - * valid and raise an assertion if it isn't. - * Normally, an invalid fd is likely to be a C program error and therefore - * an assertion can be useful, but it does contradict the POSIX standard - * which for write(2) states: - * "Otherwise, -1 shall be returned and errno set to indicate the error." - * "[EBADF] The fildes argument is not a valid file descriptor open for - * writing." - * Furthermore, python allows the user to enter any old integer - * as a fd and should merely raise a python exception on error. - * The Microsoft CRT doesn't provide an official way to check for the - * validity of a file descriptor, but we can emulate its internal behaviour - * by using the exported __pinfo data member and knowledge of the - * internal structures involved. - * The structures below must be updated for each version of visual studio - * according to the file internal.h in the CRT source, until MS comes - * up with a less hacky way to do this. - * (all of this is to avoid globally modifying the CRT behaviour using - * _set_invalid_parameter_handler() and _CrtSetReportMode()) - */ -/* The actual size of the structure is determined at runtime. - * Only the first items must be present. - */ -typedef struct { - intptr_t osfhnd; - char osfile; -} my_ioinfo; -extern __declspec(dllimport) char * __pioinfo[]; +#if defined _MSC_VER && _MSC_VER >= 1400 && _MSC_VER < 1900 +/* Legacy implementation of _PyVerify_fd_dup2 while transitioning to + * MSVC 14.0. This should eventually be removed. (issue23524) + */ #define IOINFO_L2E 5 -#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) #define IOINFO_ARRAYS 64 +#define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E) #define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS) -#define FOPEN 0x01 #define _NO_CONSOLE_FILENO (intptr_t)-2 -/* This function emulates what the windows CRT does to validate file handles */ -int -_PyVerify_fd(int fd) -{ - const int i1 = fd >> IOINFO_L2E; - const int i2 = fd & ((1 << IOINFO_L2E) - 1); - - static size_t sizeof_ioinfo = 0; - - /* Determine the actual size of the ioinfo structure, - * as used by the CRT loaded in memory - */ - if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) { - sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS; - } - if (sizeof_ioinfo == 0) { - /* This should not happen... */ - goto fail; - } - - /* See that it isn't a special CLEAR fileno */ - if (fd != _NO_CONSOLE_FILENO) { - /* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that. Instead - * we check pointer validity and other info - */ - if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) { - /* finally, check that the file is open */ - my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo); - if (info->osfile & FOPEN) { - return 1; - } - } - } - fail: - errno = EBADF; - return 0; -} - /* the special case of checking dup2. The target fd must be in a sensible range */ static int _PyVerify_fd_dup2(int fd1, int fd2) @@ -1127,46 +1084,10 @@ _PyVerify_fd_dup2(int fd1, int fd2) return 0; } #else -/* dummy version. _PyVerify_fd() is already defined in fileobject.h */ -#define _PyVerify_fd_dup2(A, B) (1) +#define _PyVerify_fd_dup2(fd1, fd2) (_PyVerify_fd(fd1) && (fd2) >= 0) #endif #ifdef MS_WINDOWS -/* The following structure was copied from - http://msdn.microsoft.com/en-us/library/ms791514.aspx as the required - include doesn't seem to be present in the Windows SDK (at least as included - with Visual Studio Express). */ -typedef struct _REPARSE_DATA_BUFFER { - ULONG ReparseTag; - USHORT ReparseDataLength; - USHORT Reserved; - union { - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - ULONG Flags; - WCHAR PathBuffer[1]; - } SymbolicLinkReparseBuffer; - - struct { - USHORT SubstituteNameOffset; - USHORT SubstituteNameLength; - USHORT PrintNameOffset; - USHORT PrintNameLength; - WCHAR PathBuffer[1]; - } MountPointReparseBuffer; - - struct { - UCHAR DataBuffer[1]; - } GenericReparseBuffer; - }; -} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER; - -#define REPARSE_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_DATA_BUFFER,\ - GenericReparseBuffer) -#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 ) static int win32_get_reparse_tag(HANDLE reparse_point_handle, ULONG *reparse_tag) @@ -1351,47 +1272,36 @@ path_error2(path_t *path, path_t *path2) /* POSIX generic methods */ -static PyObject * -posix_fildes(PyObject *fdobj, int (*func)(int)) +static int +fildes_converter(PyObject *o, void *p) { int fd; - int res; - fd = PyObject_AsFileDescriptor(fdobj); + int *pointer = (int *)p; + fd = PyObject_AsFileDescriptor(o); if (fd < 0) - return NULL; - if (!_PyVerify_fd(fd)) - return posix_error(); - Py_BEGIN_ALLOW_THREADS - res = (*func)(fd); - Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); - Py_INCREF(Py_None); - return Py_None; + return 0; + if (!_PyVerify_fd(fd)) { + posix_error(); + return 0; + } + *pointer = fd; + return 1; } static PyObject * -posix_1str(const char *func_name, PyObject *args, char *format, - int (*func)(const char*)) +posix_fildes_fd(int fd, int (*func)(int)) { - path_t path; int res; - memset(&path, 0, sizeof(path)); - path.function_name = func_name; - if (!PyArg_ParseTuple(args, format, - path_converter, &path)) - return NULL; - Py_BEGIN_ALLOW_THREADS - res = (*func)(path.narrow); - Py_END_ALLOW_THREADS - if (res < 0) { - path_error(&path); - path_cleanup(&path); - return NULL; - } - path_cleanup(&path); - Py_INCREF(Py_None); - return Py_None; + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = (*func)(fd); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res != 0) + return (!async_err) ? posix_error() : NULL; + Py_RETURN_NONE; } @@ -1470,89 +1380,7 @@ win32_wchdir(LPCWSTR path) Therefore, we implement our own stat, based on the Win32 API directly. */ #define HAVE_STAT_NSEC 1 - -struct win32_stat{ - unsigned long st_dev; - __int64 st_ino; - unsigned short st_mode; - int st_nlink; - int st_uid; - int st_gid; - unsigned long st_rdev; - __int64 st_size; - time_t st_atime; - int st_atime_nsec; - time_t st_mtime; - int st_mtime_nsec; - time_t st_ctime; - int st_ctime_nsec; -}; - -static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 and 1.1.1970 */ - -static void -FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out) -{ - /* XXX endianness. Shouldn't matter, as all Windows implementations are little-endian */ - /* Cannot simply cast and dereference in_ptr, - since it might not be aligned properly */ - __int64 in; - memcpy(&in, in_ptr, sizeof(in)); - *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100 nsec. */ - *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, time_t); -} - -static void -time_t_to_FILE_TIME(time_t time_in, int nsec_in, FILETIME *out_ptr) -{ - /* XXX endianness */ - __int64 out; - out = time_in + secs_between_epochs; - out = out * 10000000 + nsec_in / 100; - memcpy(out_ptr, &out, sizeof(out)); -} - -/* Below, we *know* that ugo+r is 0444 */ -#if _S_IREAD != 0400 -#error Unsupported C library -#endif -static int -attributes_to_mode(DWORD attr) -{ - int m = 0; - if (attr & FILE_ATTRIBUTE_DIRECTORY) - m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */ - else - m |= _S_IFREG; - if (attr & FILE_ATTRIBUTE_READONLY) - m |= 0444; - else - m |= 0666; - return m; -} - -static int -attribute_data_to_stat(BY_HANDLE_FILE_INFORMATION *info, ULONG reparse_tag, struct win32_stat *result) -{ - memset(result, 0, sizeof(*result)); - result->st_mode = attributes_to_mode(info->dwFileAttributes); - result->st_size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow; - result->st_dev = info->dwVolumeSerialNumber; - result->st_rdev = result->st_dev; - FILE_TIME_to_time_t_nsec(&info->ftCreationTime, &result->st_ctime, &result->st_ctime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime, &result->st_mtime, &result->st_mtime_nsec); - FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime, &result->st_atime, &result->st_atime_nsec); - result->st_nlink = info->nNumberOfLinks; - result->st_ino = (((__int64)info->nFileIndexHigh)<<32) + info->nFileIndexLow; - if (reparse_tag == IO_REPARSE_TAG_SYMLINK) { - /* first clear the S_IFMT bits */ - result->st_mode ^= (result->st_mode & S_IFMT); - /* now set the bits that make this a symlink */ - result->st_mode |= S_IFLNK; - } - - return 0; -} +#define HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES 1 static BOOL attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag) @@ -1577,6 +1405,25 @@ attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *rep return TRUE; } +static void +find_data_to_file_info_w(WIN32_FIND_DATAW *pFileData, + BY_HANDLE_FILE_INFORMATION *info, + ULONG *reparse_tag) +{ + memset(info, 0, sizeof(*info)); + info->dwFileAttributes = pFileData->dwFileAttributes; + info->ftCreationTime = pFileData->ftCreationTime; + info->ftLastAccessTime = pFileData->ftLastAccessTime; + info->ftLastWriteTime = pFileData->ftLastWriteTime; + info->nFileSizeHigh = pFileData->nFileSizeHigh; + info->nFileSizeLow = pFileData->nFileSizeLow; +/* info->nNumberOfLinks = 1; */ + if (pFileData->dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) + *reparse_tag = pFileData->dwReserved0; + else + *reparse_tag = 0; +} + static BOOL attributes_from_dir_w(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag) { @@ -1586,45 +1433,10 @@ attributes_from_dir_w(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG * if (hFindFile == INVALID_HANDLE_VALUE) return FALSE; FindClose(hFindFile); - memset(info, 0, sizeof(*info)); - *reparse_tag = 0; - info->dwFileAttributes = FileData.dwFileAttributes; - info->ftCreationTime = FileData.ftCreationTime; - info->ftLastAccessTime = FileData.ftLastAccessTime; - info->ftLastWriteTime = FileData.ftLastWriteTime; - info->nFileSizeHigh = FileData.nFileSizeHigh; - info->nFileSizeLow = FileData.nFileSizeLow; -/* info->nNumberOfLinks = 1; */ - if (FileData.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) - *reparse_tag = FileData.dwReserved0; + find_data_to_file_info_w(&FileData, info, reparse_tag); return TRUE; } -/* Grab GetFinalPathNameByHandle dynamically from kernel32 */ -static int has_GetFinalPathNameByHandle = -1; -static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD, - DWORD); -static int -check_GetFinalPathNameByHandle() -{ - HINSTANCE hKernel32; - DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD, - DWORD); - - /* only recheck */ - if (-1 == has_GetFinalPathNameByHandle) - { - hKernel32 = GetModuleHandleW(L"KERNEL32"); - *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32, - "GetFinalPathNameByHandleA"); - *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32, - "GetFinalPathNameByHandleW"); - has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA && - Py_GetFinalPathNameByHandleW; - } - return has_GetFinalPathNameByHandle; -} - static BOOL get_target_path(HANDLE hdl, wchar_t **target_path) { @@ -1633,8 +1445,8 @@ get_target_path(HANDLE hdl, wchar_t **target_path) /* We have a good handle to the target, use it to determine the target path name (then we'll call lstat on it). */ - buf_size = Py_GetFinalPathNameByHandleW(hdl, 0, 0, - VOLUME_NAME_DOS); + buf_size = GetFinalPathNameByHandleW(hdl, 0, 0, + VOLUME_NAME_DOS); if(!buf_size) return FALSE; @@ -1644,7 +1456,7 @@ get_target_path(HANDLE hdl, wchar_t **target_path) return FALSE; } - result_length = Py_GetFinalPathNameByHandleW(hdl, + result_length = GetFinalPathNameByHandleW(hdl, buf, buf_size, VOLUME_NAME_DOS); if(!result_length) { @@ -1664,10 +1476,10 @@ get_target_path(HANDLE hdl, wchar_t **target_path) } static int -win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, +win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse); static int -win32_xstat_impl(const char *path, struct win32_stat *result, +win32_xstat_impl(const char *path, struct _Py_stat_struct *result, BOOL traverse) { int code; @@ -1677,12 +1489,6 @@ win32_xstat_impl(const char *path, struct win32_stat *result, wchar_t *target_path; const char *dot; - if(!check_GetFinalPathNameByHandle()) { - /* If the OS doesn't have GetFinalPathNameByHandle, don't - traverse reparse point. */ - traverse = FALSE; - } - hFile = CreateFileA( path, FILE_READ_ATTRIBUTES, /* desired access */ @@ -1750,7 +1556,7 @@ win32_xstat_impl(const char *path, struct win32_stat *result, } else CloseHandle(hFile); } - attribute_data_to_stat(&info, reparse_tag, result); + _Py_attribute_data_to_stat(&info, reparse_tag, result); /* Set S_IEXEC if it is an .exe, .bat, ... */ dot = strrchr(path, '.'); @@ -1763,7 +1569,7 @@ win32_xstat_impl(const char *path, struct win32_stat *result, } static int -win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, +win32_xstat_impl_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) { int code; @@ -1773,12 +1579,6 @@ win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, wchar_t *target_path; const wchar_t *dot; - if(!check_GetFinalPathNameByHandle()) { - /* If the OS doesn't have GetFinalPathNameByHandle, don't - traverse reparse point. */ - traverse = FALSE; - } - hFile = CreateFileW( path, FILE_READ_ATTRIBUTES, /* desired access */ @@ -1846,7 +1646,7 @@ win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, } else CloseHandle(hFile); } - attribute_data_to_stat(&info, reparse_tag, result); + _Py_attribute_data_to_stat(&info, reparse_tag, result); /* Set S_IEXEC if it is an .exe, .bat, ... */ dot = wcsrchr(path, '.'); @@ -1859,7 +1659,7 @@ win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, } static int -win32_xstat(const char *path, struct win32_stat *result, BOOL traverse) +win32_xstat(const char *path, struct _Py_stat_struct *result, BOOL traverse) { /* Protocol violation: we explicitly clear errno, instead of setting it to a POSIX error. Callers should use GetLastError. */ @@ -1869,7 +1669,7 @@ win32_xstat(const char *path, struct win32_stat *result, BOOL traverse) } static int -win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse) +win32_xstat_w(const wchar_t *path, struct _Py_stat_struct *result, BOOL traverse) { /* Protocol violation: we explicitly clear errno, instead of setting it to a POSIX error. Callers should use GetLastError. */ @@ -1891,80 +1691,29 @@ win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse) The _w represent Unicode equivalents of the aforementioned ANSI functions. */ static int -win32_lstat(const char* path, struct win32_stat *result) +win32_lstat(const char* path, struct _Py_stat_struct *result) { return win32_xstat(path, result, FALSE); } static int -win32_lstat_w(const wchar_t* path, struct win32_stat *result) +win32_lstat_w(const wchar_t* path, struct _Py_stat_struct *result) { return win32_xstat_w(path, result, FALSE); } static int -win32_stat(const char* path, struct win32_stat *result) +win32_stat(const char* path, struct _Py_stat_struct *result) { return win32_xstat(path, result, TRUE); } static int -win32_stat_w(const wchar_t* path, struct win32_stat *result) +win32_stat_w(const wchar_t* path, struct _Py_stat_struct *result) { return win32_xstat_w(path, result, TRUE); } -static int -win32_fstat(int file_number, struct win32_stat *result) -{ - BY_HANDLE_FILE_INFORMATION info; - HANDLE h; - int type; - - if (!_PyVerify_fd(file_number)) - h = INVALID_HANDLE_VALUE; - else - h = (HANDLE)_get_osfhandle(file_number); - - /* Protocol violation: we explicitly clear errno, instead of - setting it to a POSIX error. Callers should use GetLastError. */ - errno = 0; - - if (h == INVALID_HANDLE_VALUE) { - /* This is really a C library error (invalid file handle). - We set the Win32 error to the closes one matching. */ - SetLastError(ERROR_INVALID_HANDLE); - return -1; - } - memset(result, 0, sizeof(*result)); - - type = GetFileType(h); - if (type == FILE_TYPE_UNKNOWN) { - DWORD error = GetLastError(); - if (error != 0) { - return -1; - } - /* else: valid but unknown file */ - } - - if (type != FILE_TYPE_DISK) { - if (type == FILE_TYPE_CHAR) - result->st_mode = _S_IFCHR; - else if (type == FILE_TYPE_PIPE) - result->st_mode = _S_IFIFO; - return 0; - } - - if (!GetFileInformationByHandle(h, &info)) { - return -1; - } - - attribute_data_to_stat(&info, 0, result); - /* specific to fstat() */ - result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow; - return 0; -} - #endif /* MS_WINDOWS */ PyDoc_STRVAR(stat_result__doc__, @@ -2014,6 +1763,9 @@ static PyStructSequence_Field stat_result_fields[] = { #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME {"st_birthtime", "time of creation"}, #endif +#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES + {"st_file_attributes", "Windows file attribute bits"}, +#endif {0} }; @@ -2053,6 +1805,12 @@ static PyStructSequence_Field stat_result_fields[] = { #define ST_BIRTHTIME_IDX ST_GEN_IDX #endif +#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES +#define ST_FILE_ATTRIBUTES_IDX (ST_BIRTHTIME_IDX+1) +#else +#define ST_FILE_ATTRIBUTES_IDX ST_BIRTHTIME_IDX +#endif + static PyStructSequence_Desc stat_result_desc = { "stat_result", /* name */ stat_result__doc__, /* doc */ @@ -2154,10 +1912,12 @@ static int _stat_float_times = 1; PyDoc_STRVAR(stat_float_times__doc__, "stat_float_times([newval]) -> oldval\n\n\ Determine whether os.[lf]stat represents time stamps as float objects.\n\ -If newval is True, future calls to stat() return floats, if it is False,\n\ -future calls return ints. \n\ -If newval is omitted, return the current setting.\n"); +\n\ +If value is True, future calls to stat() return floats; if it is False,\n\ +future calls return ints.\n\ +If value is omitted, return the current setting.\n"); +/* AC 3.5: the public default value should be None, not ready for that yet */ static PyObject* stat_float_times(PyObject* self, PyObject *args) { @@ -2317,6 +2077,10 @@ _pystat_fromstructstat(STRUCT_STAT *st) PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX, PyLong_FromLong((long)st->st_flags)); #endif +#ifdef HAVE_STRUCT_STAT_ST_FILE_ATTRIBUTES + PyStructSequence_SET_ITEM(v, ST_FILE_ATTRIBUTES_IDX, + PyLong_FromUnsignedLong(st->st_file_attributes)); +#endif if (PyErr_Occurred()) { Py_DECREF(v); @@ -2380,12 +2144,177 @@ posix_do_stat(char *function_name, path_t *path, return _pystat_fromstructstat(&st); } +/*[python input] + +for s in """ + +FACCESSAT +FCHMODAT +FCHOWNAT +FSTATAT +LINKAT +MKDIRAT +MKFIFOAT +MKNODAT +OPENAT +READLINKAT +SYMLINKAT +UNLINKAT + +""".strip().split(): + s = s.strip() + print(""" +#ifdef HAVE_{s} + #define {s}_DIR_FD_CONVERTER dir_fd_converter +#else + #define {s}_DIR_FD_CONVERTER dir_fd_unavailable +#endif +""".rstrip().format(s=s)) + +for s in """ + +FCHDIR +FCHMOD +FCHOWN +FDOPENDIR +FEXECVE +FPATHCONF +FSTATVFS +FTRUNCATE + +""".strip().split(): + s = s.strip() + print(""" +#ifdef HAVE_{s} + #define PATH_HAVE_{s} 1 +#else + #define PATH_HAVE_{s} 0 +#endif + +""".rstrip().format(s=s)) +[python start generated code]*/ + +#ifdef HAVE_FACCESSAT + #define FACCESSAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define FACCESSAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_FCHMODAT + #define FCHMODAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define FCHMODAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_FCHOWNAT + #define FCHOWNAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define FCHOWNAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + #ifdef HAVE_FSTATAT - #define OS_STAT_DIR_FD_CONVERTER dir_fd_converter + #define FSTATAT_DIR_FD_CONVERTER dir_fd_converter #else - #define OS_STAT_DIR_FD_CONVERTER dir_fd_unavailable + #define FSTATAT_DIR_FD_CONVERTER dir_fd_unavailable #endif +#ifdef HAVE_LINKAT + #define LINKAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define LINKAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_MKDIRAT + #define MKDIRAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define MKDIRAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_MKFIFOAT + #define MKFIFOAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define MKFIFOAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_MKNODAT + #define MKNODAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define MKNODAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_OPENAT + #define OPENAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define OPENAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_READLINKAT + #define READLINKAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define READLINKAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_SYMLINKAT + #define SYMLINKAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define SYMLINKAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_UNLINKAT + #define UNLINKAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define UNLINKAT_DIR_FD_CONVERTER dir_fd_unavailable +#endif + +#ifdef HAVE_FCHDIR + #define PATH_HAVE_FCHDIR 1 +#else + #define PATH_HAVE_FCHDIR 0 +#endif + +#ifdef HAVE_FCHMOD + #define PATH_HAVE_FCHMOD 1 +#else + #define PATH_HAVE_FCHMOD 0 +#endif + +#ifdef HAVE_FCHOWN + #define PATH_HAVE_FCHOWN 1 +#else + #define PATH_HAVE_FCHOWN 0 +#endif + +#ifdef HAVE_FDOPENDIR + #define PATH_HAVE_FDOPENDIR 1 +#else + #define PATH_HAVE_FDOPENDIR 0 +#endif + +#ifdef HAVE_FEXECVE + #define PATH_HAVE_FEXECVE 1 +#else + #define PATH_HAVE_FEXECVE 0 +#endif + +#ifdef HAVE_FPATHCONF + #define PATH_HAVE_FPATHCONF 1 +#else + #define PATH_HAVE_FPATHCONF 0 +#endif + +#ifdef HAVE_FSTATVFS + #define PATH_HAVE_FSTATVFS 1 +#else + #define PATH_HAVE_FSTATVFS 0 +#endif + +#ifdef HAVE_FTRUNCATE + #define PATH_HAVE_FTRUNCATE 1 +#else + #define PATH_HAVE_FTRUNCATE 0 +#endif +/*[python end generated code: output=4bd4f6f7d41267f1 input=80b4c890b6774ea5]*/ + /*[python input] @@ -2400,22 +2329,25 @@ class path_t_converter(CConverter): def converter_init(self, *, allow_fd=False, nullable=False): # right now path_t doesn't support default values. # to support a default value, you'll need to override initialize(). - if self.default is not unspecified: + if self.default not in (unspecified, None): fail("Can't specify a default to the path_t converter!") - if self.c_default is not None: - fail("Can't specify a c_default to the path_t converter!") + if self.c_default not in (None, 'Py_None'): + raise RuntimeError("Can't specify a c_default to the path_t converter!") self.nullable = nullable self.allow_fd = allow_fd def pre_render(self): def strify(value): + if isinstance(value, str): + return value return str(int(bool(value))) # add self.py_name here when merging with posixmodule conversion - self.c_default = 'PATH_T_INITIALIZE("{}", {}, {})'.format( + self.c_default = 'PATH_T_INITIALIZE("{}", "{}", {}, {})'.format( self.function.name, + self.name, strify(self.nullable), strify(self.allow_fd), ) @@ -2426,15 +2358,87 @@ class path_t_converter(CConverter): class dir_fd_converter(CConverter): type = 'int' - converter = 'OS_STAT_DIR_FD_CONVERTER' - def converter_init(self): + def converter_init(self, requires=None): if self.default in (unspecified, None): self.c_default = 'DEFAULT_DIR_FD' + if isinstance(requires, str): + self.converter = requires.upper() + '_DIR_FD_CONVERTER' + else: + self.converter = 'dir_fd_converter' + +class fildes_converter(CConverter): + type = 'int' + converter = 'fildes_converter' + +class uid_t_converter(CConverter): + type = "uid_t" + converter = '_Py_Uid_Converter' + +class gid_t_converter(CConverter): + type = "gid_t" + converter = '_Py_Gid_Converter' + +class dev_t_converter(CConverter): + type = 'dev_t' + converter = '_Py_Dev_Converter' + +class dev_t_return_converter(unsigned_long_return_converter): + type = 'dev_t' + conversion_fn = '_PyLong_FromDev' + unsigned_cast = '(dev_t)' + +class FSConverter_converter(CConverter): + type = 'PyObject *' + converter = 'PyUnicode_FSConverter' + def converter_init(self): + if self.default is not unspecified: + fail("FSConverter_converter does not support default values") + self.c_default = 'NULL' + + def cleanup(self): + return "Py_XDECREF(" + self.name + ");\n" + +class pid_t_converter(CConverter): + type = 'pid_t' + format_unit = '" _Py_PARSE_PID "' +class idtype_t_converter(int_converter): + type = 'idtype_t' + +class id_t_converter(CConverter): + type = 'id_t' + format_unit = '" _Py_PARSE_PID "' + +class Py_intptr_t_converter(CConverter): + type = 'Py_intptr_t' + format_unit = '" _Py_PARSE_INTPTR "' + +class Py_off_t_converter(CConverter): + type = 'Py_off_t' + converter = 'Py_off_t_converter' + +class Py_off_t_return_converter(long_return_converter): + type = 'Py_off_t' + conversion_fn = 'PyLong_FromPy_off_t' + +class path_confname_converter(CConverter): + type="int" + converter="conv_path_confname" + +class confstr_confname_converter(path_confname_converter): + converter='conv_confstr_confname' + +class sysconf_confname_converter(path_confname_converter): + converter="conv_sysconf_confname" + +class sched_param_converter(CConverter): + type = 'struct sched_param' + converter = 'convert_sched_param' + impl_by_reference = True; [python start generated code]*/ -/*[python end generated code: output=da39a3ee5e6b4b0d input=5c9f456f53244fc3]*/ +/*[python end generated code: output=da39a3ee5e6b4b0d input=affe68316f160401]*/ /*[clinic input] @@ -2445,7 +2449,7 @@ os.stat * - dir_fd : dir_fd = None + dir_fd : dir_fd(requires='fstatat') = 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. @@ -2466,103 +2470,40 @@ It's an error to use dir_fd or follow_symlinks when specifying path as [clinic start generated code]*/ -PyDoc_STRVAR(os_stat__doc__, -"stat($module, /, path, *, dir_fd=None, follow_symlinks=True)\n" -"--\n" -"\n" -"Perform a stat system call on the given path.\n" -"\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 * -os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks); - -static PyObject * -os_stat(PyModuleDef *module, PyObject *args, PyObject *kwargs) +os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks) +/*[clinic end generated code: output=708c225f94fcfc8e input=099d356c306fa24a]*/ { - 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; + return 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(module, &path, dir_fd, follow_symlinks); -exit: - /* Cleanup for path */ - path_cleanup(&path); +/*[clinic input] +os.lstat - return return_value; -} + path : path_t -static PyObject * -os_stat_impl(PyModuleDef *module, path_t *path, int dir_fd, int follow_symlinks) -/*[clinic end generated code: output=f1dcaa5e24db9882 input=5ae155bd475fd20a]*/ -{ - 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\ -Equivalent to stat(path, follow_symlinks=False)."); + dir_fd : dir_fd(requires='fstatat') = None + +Perform a stat system call on the given path, without following symbolic links. + +Like stat(), but do not follow symbolic links. +Equivalent to stat(path, follow_symlinks=False). +[clinic start generated code]*/ static PyObject * -posix_lstat(PyObject *self, PyObject *args, PyObject *kwargs) +os_lstat_impl(PyModuleDef *module, path_t *path, int dir_fd) +/*[clinic end generated code: output=7a748e333fcb39bd input=0b7474765927b925]*/ { - static char *keywords[] = {"path", "dir_fd", NULL}; - path_t path; - int dir_fd = DEFAULT_DIR_FD; int follow_symlinks = 0; - PyObject *return_value; - - memset(&path, 0, sizeof(path)); - path.function_name = "lstat"; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:lstat", keywords, - path_converter, &path, -#ifdef HAVE_FSTATAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd -#endif - )) - return NULL; - return_value = posix_do_stat("lstat", &path, dir_fd, follow_symlinks); - path_cleanup(&path); - return return_value; + return posix_do_stat("lstat", path, dir_fd, follow_symlinks); } -#ifdef HAVE_FACCESSAT - #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_converter -#else - #define OS_ACCESS_DIR_FD_CONVERTER dir_fd_unavailable -#endif /*[clinic input] -os.access +os.access -> bool path: path_t(allow_fd=True) Path to be tested; can be string, bytes, or open-file-descriptor int. @@ -2573,7 +2514,7 @@ os.access * - dir_fd : dir_fd = None + dir_fd : dir_fd(requires='faccessat') = 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. @@ -2600,73 +2541,11 @@ Note that most operations will use the effective uid/gid, therefore this [clinic start generated code]*/ -PyDoc_STRVAR(os_access__doc__, -"access($module, /, path, mode, *, dir_fd=None, effective_ids=False,\n" -" follow_symlinks=True)\n" -"--\n" -"\n" -"Use the real uid/gid to test for access to a path.\n" -"\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" -"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(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks); - -static PyObject * -os_access(PyModuleDef *module, PyObject *args, PyObject *kwargs) -{ - 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(module, &path, mode, dir_fd, effective_ids, follow_symlinks); - -exit: - /* Cleanup for path */ - path_cleanup(&path); - - return return_value; -} - -static PyObject * +static int os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effective_ids, int follow_symlinks) -/*[clinic end generated code: output=a6ed4f151be9df0f input=2e2e7594371f5b7e]*/ +/*[clinic end generated code: output=f9e734db3d88b767 input=b75a756797af45ec]*/ { - PyObject *return_value = NULL; + int return_value; #ifdef MS_WINDOWS DWORD attr; @@ -2676,11 +2555,11 @@ os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effe #ifndef HAVE_FACCESSAT if (follow_symlinks_specified("access", follow_symlinks)) - goto exit; + return -1; if (effective_ids) { argument_unavailable_error("access", "effective_ids"); - goto exit; + return -1; } #endif @@ -2700,11 +2579,10 @@ os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effe * * or it's a directory. * (Directories cannot be read-only on Windows.) */ - return_value = PyBool_FromLong( - (attr != INVALID_FILE_ATTRIBUTES) && + return_value = (attr != INVALID_FILE_ATTRIBUTES) && (!(mode & 2) || !(attr & FILE_ATTRIBUTE_READONLY) || - (attr & FILE_ATTRIBUTE_DIRECTORY))); + (attr & FILE_ATTRIBUTE_DIRECTORY)); #else Py_BEGIN_ALLOW_THREADS @@ -2723,12 +2601,9 @@ os_access_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int effe #endif result = access(path->narrow, mode); Py_END_ALLOW_THREADS - return_value = PyBool_FromLong(!result); + return_value = !result; #endif -#ifndef HAVE_FACCESSAT -exit: -#endif return return_value; } @@ -2747,7 +2622,6 @@ exit: #ifdef HAVE_TTYNAME - /*[clinic input] os.ttyname -> DecodeFSDefault @@ -2759,44 +2633,9 @@ os.ttyname -> DecodeFSDefault Return the name of the terminal device connected to 'fd'. [clinic start generated code]*/ -PyDoc_STRVAR(os_ttyname__doc__, -"ttyname($module, fd, /)\n" -"--\n" -"\n" -"Return the name of the terminal device connected to \'fd\'.\n" -"\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(PyModuleDef *module, int fd); - -static PyObject * -os_ttyname(PyModuleDef *module, PyObject *args) -{ - PyObject *return_value = NULL; - int fd; - char *_return_value; - - if (!PyArg_ParseTuple(args, - "i:ttyname", - &fd)) - goto exit; - _return_value = os_ttyname_impl(module, fd); - if (_return_value == NULL) - goto exit; - return_value = PyUnicode_DecodeFSDefault(_return_value); - -exit: - return return_value; -} - static char * os_ttyname_impl(PyModuleDef *module, int fd) -/*[clinic end generated code: output=cee7bc4cffec01a2 input=5f72ca83e76b3b45]*/ +/*[clinic end generated code: output=03ad3d5ccaef75c3 input=5f72ca83e76b3b45]*/ { char *ret; @@ -2805,17 +2644,18 @@ os_ttyname_impl(PyModuleDef *module, int fd) posix_error(); return ret; } -#else -#define OS_TTYNAME_METHODDEF #endif #ifdef HAVE_CTERMID -PyDoc_STRVAR(posix_ctermid__doc__, -"ctermid() -> string\n\n\ -Return the name of the controlling terminal for this process."); +/*[clinic input] +os.ctermid + +Return the name of the controlling terminal for this process. +[clinic start generated code]*/ static PyObject * -posix_ctermid(PyObject *self, PyObject *noargs) +os_ctermid_impl(PyModuleDef *module) +/*[clinic end generated code: output=1b73788201e0aebd input=3b87fdd52556382d]*/ { char *ret; char buffer[L_ctermid]; @@ -2829,106 +2669,111 @@ posix_ctermid(PyObject *self, PyObject *noargs) return posix_error(); return PyUnicode_DecodeFSDefault(buffer); } -#endif +#endif /* HAVE_CTERMID */ -PyDoc_STRVAR(posix_chdir__doc__, -"chdir(path)\n\n\ -Change the current working directory to the specified path.\n\ -\n\ -path may always be specified as a string.\n\ -On some platforms, path may also be specified as an open file descriptor.\n\ - If this functionality is unavailable, using it raises an exception."); + +/*[clinic input] +os.chdir + + path: path_t(allow_fd='PATH_HAVE_FCHDIR') + +Change the current working directory to the specified path. + +path may always be specified as a string. +On some platforms, path may also be specified as an open file descriptor. + If this functionality is unavailable, using it raises an exception. +[clinic start generated code]*/ static PyObject * -posix_chdir(PyObject *self, PyObject *args, PyObject *kwargs) +os_chdir_impl(PyModuleDef *module, path_t *path) +/*[clinic end generated code: output=7358e3a20fb5aa93 input=1a4a15b4d12cb15d]*/ { - path_t path; int result; - PyObject *return_value = NULL; - static char *keywords[] = {"path", NULL}; - - memset(&path, 0, sizeof(path)); - path.function_name = "chdir"; -#ifdef HAVE_FCHDIR - path.allow_fd = 1; -#endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:chdir", keywords, - path_converter, &path - )) - return NULL; Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS - if (path.wide) - result = win32_wchdir(path.wide); + if (path->wide) + result = win32_wchdir(path->wide); else - result = win32_chdir(path.narrow); + result = win32_chdir(path->narrow); result = !result; /* on unix, success = 0, on windows, success = !0 */ #else #ifdef HAVE_FCHDIR - if (path.fd != -1) - result = fchdir(path.fd); + if (path->fd != -1) + result = fchdir(path->fd); else #endif - result = chdir(path.narrow); + result = chdir(path->narrow); #endif Py_END_ALLOW_THREADS if (result) { - return_value = path_error(&path); - goto exit; + return path_error(path); } - return_value = Py_None; - Py_INCREF(Py_None); - -exit: - path_cleanup(&path); - return return_value; + Py_RETURN_NONE; } + #ifdef HAVE_FCHDIR -PyDoc_STRVAR(posix_fchdir__doc__, -"fchdir(fd)\n\n\ -Change to the directory of the given file descriptor. fd must be\n\ -opened on a directory, not a file. Equivalent to os.chdir(fd)."); +/*[clinic input] +os.fchdir + + fd: fildes + +Change to the directory of the given file descriptor. + +fd must be opened on a directory, not a file. +Equivalent to os.chdir(fd). + +[clinic start generated code]*/ static PyObject * -posix_fchdir(PyObject *self, PyObject *fdobj) +os_fchdir_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=361d30df6b2d3418 input=18e816479a2fa985]*/ { - return posix_fildes(fdobj, fchdir); + return posix_fildes_fd(fd, fchdir); } #endif /* HAVE_FCHDIR */ -PyDoc_STRVAR(posix_chmod__doc__, -"chmod(path, mode, *, dir_fd=None, follow_symlinks=True)\n\n\ -Change the access permissions of a file.\n\ -\n\ -path may always be specified as a string.\n\ -On some platforms, path may also be specified as an open file descriptor.\n\ - If this functionality is unavailable, using it raises an exception.\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 follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, chmod will modify 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.\n\ -dir_fd and follow_symlinks may not be implemented on your platform.\n\ - If they are unavailable, using them will raise a NotImplementedError."); +/*[clinic input] +os.chmod + + path: path_t(allow_fd='PATH_HAVE_FCHMOD') + Path to be modified. May always be specified as a str or bytes. + On some platforms, path may also be specified as an open file descriptor. + If this functionality is unavailable, using it raises an exception. + + mode: int + Operating-system mode bitfield. + + * + + dir_fd : dir_fd(requires='fchmodat') = 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. + + follow_symlinks: bool = True + If False, and the last element of the path is a symbolic link, + chmod will modify the symbolic link itself instead of the file + the link points to. + +Change the access permissions of a file. + +It is an error to use dir_fd or follow_symlinks when specifying path as + an open file descriptor. +dir_fd and follow_symlinks may not be implemented on your platform. + If they are unavailable, using them will raise a NotImplementedError. + +[clinic start generated code]*/ static PyObject * -posix_chmod(PyObject *self, PyObject *args, PyObject *kwargs) +os_chmod_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd, int follow_symlinks) +/*[clinic end generated code: output=96063c976f23106a input=7f1618e5e15cc196]*/ { - path_t path; - int mode; - int dir_fd = DEFAULT_DIR_FD; - int follow_symlinks = 1; int result; - PyObject *return_value = NULL; - static char *keywords[] = {"path", "mode", "dir_fd", - "follow_symlinks", NULL}; #ifdef MS_WINDOWS DWORD attr; @@ -2938,33 +2783,17 @@ posix_chmod(PyObject *self, PyObject *args, PyObject *kwargs) int fchmodat_nofollow_unsupported = 0; #endif - memset(&path, 0, sizeof(path)); - path.function_name = "chmod"; -#ifdef HAVE_FCHMOD - path.allow_fd = 1; -#endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&i|$O&p:chmod", keywords, - path_converter, &path, - &mode, -#ifdef HAVE_FCHMODAT - dir_fd_converter, &dir_fd, -#else - dir_fd_unavailable, &dir_fd, -#endif - &follow_symlinks)) - return NULL; - #if !(defined(HAVE_FCHMODAT) || defined(HAVE_LCHMOD)) if (follow_symlinks_specified("chmod", follow_symlinks)) - goto exit; + return NULL; #endif #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS - if (path.wide) - attr = GetFileAttributesW(path.wide); + if (path->wide) + attr = GetFileAttributesW(path->wide); else - attr = GetFileAttributesA(path.narrow); + attr = GetFileAttributesA(path->narrow); if (attr == INVALID_FILE_ATTRIBUTES) result = 0; else { @@ -2972,27 +2801,26 @@ posix_chmod(PyObject *self, PyObject *args, PyObject *kwargs) attr &= ~FILE_ATTRIBUTE_READONLY; else attr |= FILE_ATTRIBUTE_READONLY; - if (path.wide) - result = SetFileAttributesW(path.wide, attr); + if (path->wide) + result = SetFileAttributesW(path->wide, attr); else - result = SetFileAttributesA(path.narrow, attr); + result = SetFileAttributesA(path->narrow, attr); } Py_END_ALLOW_THREADS if (!result) { - return_value = path_error(&path); - goto exit; + return path_error(path); } #else /* MS_WINDOWS */ Py_BEGIN_ALLOW_THREADS #ifdef HAVE_FCHMOD - if (path.fd != -1) - result = fchmod(path.fd, mode); + if (path->fd != -1) + result = fchmod(path->fd, mode); else #endif #ifdef HAVE_LCHMOD if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD)) - result = lchmod(path.narrow, mode); + result = lchmod(path->narrow, mode); else #endif #ifdef HAVE_FCHMODAT @@ -3007,7 +2835,7 @@ posix_chmod(PyObject *self, PyObject *args, PyObject *kwargs) * support dir_fd and follow_symlinks=False. (Hopefully.) * Until then, we need to be careful what exception we raise. */ - result = fchmodat(dir_fd, path.narrow, mode, + result = fchmodat(dir_fd, path->narrow, mode, follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); /* * But wait! We can't throw the exception without allowing threads, @@ -3020,7 +2848,7 @@ posix_chmod(PyObject *self, PyObject *args, PyObject *kwargs) } else #endif - result = chmod(path.narrow, mode); + result = chmod(path->narrow, mode); Py_END_ALLOW_THREADS if (result) { @@ -3034,272 +2862,287 @@ posix_chmod(PyObject *self, PyObject *args, PyObject *kwargs) } else #endif - return_value = path_error(&path); - goto exit; + return path_error(path); } #endif - Py_INCREF(Py_None); - return_value = Py_None; -exit: - path_cleanup(&path); - return return_value; + Py_RETURN_NONE; } #ifdef HAVE_FCHMOD -PyDoc_STRVAR(posix_fchmod__doc__, -"fchmod(fd, mode)\n\n\ -Change the access permissions of the file given by file\n\ -descriptor fd. Equivalent to os.chmod(fd, mode)."); +/*[clinic input] +os.fchmod + + fd: int + mode: int + +Change the access permissions of the file given by file descriptor fd. + +Equivalent to os.chmod(fd, mode). +[clinic start generated code]*/ static PyObject * -posix_fchmod(PyObject *self, PyObject *args) +os_fchmod_impl(PyModuleDef *module, int fd, int mode) +/*[clinic end generated code: output=2ee31ca226d1ed33 input=8ab11975ca01ee5b]*/ { - int fd, mode, res; - if (!PyArg_ParseTuple(args, "ii:fchmod", &fd, &mode)) - return NULL; - Py_BEGIN_ALLOW_THREADS - res = fchmod(fd, mode); - Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); + int res; + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = fchmod(fd, mode); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res != 0) + return (!async_err) ? posix_error() : NULL; + Py_RETURN_NONE; } #endif /* HAVE_FCHMOD */ + #ifdef HAVE_LCHMOD -PyDoc_STRVAR(posix_lchmod__doc__, -"lchmod(path, mode)\n\n\ -Change the access permissions of a file. If path is a symlink, this\n\ -affects the link itself rather than the target.\n\ -Equivalent to chmod(path, mode, follow_symlinks=False)."); +/*[clinic input] +os.lchmod + + path: path_t + mode: int + +Change the access permissions of a file, without following symbolic links. + +If path is a symlink, this affects the link itself rather than the target. +Equivalent to chmod(path, mode, follow_symlinks=False)." +[clinic start generated code]*/ static PyObject * -posix_lchmod(PyObject *self, PyObject *args) +os_lchmod_impl(PyModuleDef *module, path_t *path, int mode) +/*[clinic end generated code: output=7c0cc46588d89e46 input=90c5663c7465d24f]*/ { - path_t path; - int i; int res; - memset(&path, 0, sizeof(path)); - path.function_name = "lchmod"; - if (!PyArg_ParseTuple(args, "O&i:lchmod", - path_converter, &path, &i)) - return NULL; Py_BEGIN_ALLOW_THREADS - res = lchmod(path.narrow, i); + res = lchmod(path->narrow, mode); Py_END_ALLOW_THREADS if (res < 0) { - path_error(&path); - path_cleanup(&path); + path_error(path); return NULL; } - path_cleanup(&path); Py_RETURN_NONE; } #endif /* HAVE_LCHMOD */ #ifdef HAVE_CHFLAGS -PyDoc_STRVAR(posix_chflags__doc__, -"chflags(path, flags, *, follow_symlinks=True)\n\n\ -Set file flags.\n\ -\n\ -If follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, chflags will change flags on the symbolic link itself instead of the\n\ - file the link points to.\n\ -follow_symlinks may not be implemented on your platform. If it is\n\ -unavailable, using it will raise a NotImplementedError."); +/*[clinic input] +os.chflags + + path: path_t + flags: unsigned_long(bitwise=True) + follow_symlinks: bool=True + +Set file flags. + +If follow_symlinks is False, and the last element of the path is a symbolic + link, chflags will change flags on the symbolic link itself instead of the + file the link points to. +follow_symlinks may not be implemented on your platform. If it is +unavailable, using it will raise a NotImplementedError. + +[clinic start generated code]*/ static PyObject * -posix_chflags(PyObject *self, PyObject *args, PyObject *kwargs) +os_chflags_impl(PyModuleDef *module, path_t *path, unsigned long flags, int follow_symlinks) +/*[clinic end generated code: output=9e5f9417afc20c4b input=0327e29feb876236]*/ { - path_t path; - unsigned long flags; - int follow_symlinks = 1; int result; - PyObject *return_value = NULL; - static char *keywords[] = {"path", "flags", "follow_symlinks", NULL}; - - memset(&path, 0, sizeof(path)); - path.function_name = "chflags"; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&k|$i:chflags", keywords, - path_converter, &path, - &flags, &follow_symlinks)) - return NULL; #ifndef HAVE_LCHFLAGS if (follow_symlinks_specified("chflags", follow_symlinks)) - goto exit; + return NULL; #endif Py_BEGIN_ALLOW_THREADS #ifdef HAVE_LCHFLAGS if (!follow_symlinks) - result = lchflags(path.narrow, flags); + result = lchflags(path->narrow, flags); else #endif - result = chflags(path.narrow, flags); + result = chflags(path->narrow, flags); Py_END_ALLOW_THREADS - if (result) { - return_value = path_error(&path); - goto exit; - } - - return_value = Py_None; - Py_INCREF(Py_None); + if (result) + return path_error(path); -exit: - path_cleanup(&path); - return return_value; + Py_RETURN_NONE; } #endif /* HAVE_CHFLAGS */ + #ifdef HAVE_LCHFLAGS -PyDoc_STRVAR(posix_lchflags__doc__, -"lchflags(path, flags)\n\n\ -Set file flags.\n\ -This function will not follow symbolic links.\n\ -Equivalent to chflags(path, flags, follow_symlinks=False)."); +/*[clinic input] +os.lchflags + + path: path_t + flags: unsigned_long(bitwise=True) + +Set file flags. + +This function will not follow symbolic links. +Equivalent to chflags(path, flags, follow_symlinks=False). +[clinic start generated code]*/ static PyObject * -posix_lchflags(PyObject *self, PyObject *args) +os_lchflags_impl(PyModuleDef *module, path_t *path, unsigned long flags) +/*[clinic end generated code: output=6741322fb949661b input=f9f82ea8b585ca9d]*/ { - path_t path; - unsigned long flags; int res; - memset(&path, 0, sizeof(path)); - path.function_name = "lchflags"; - if (!PyArg_ParseTuple(args, "O&k:lchflags", - path_converter, &path, &flags)) - return NULL; Py_BEGIN_ALLOW_THREADS - res = lchflags(path.narrow, flags); + res = lchflags(path->narrow, flags); Py_END_ALLOW_THREADS if (res < 0) { - path_error(&path); - path_cleanup(&path); - return NULL; + return path_error(path); } - path_cleanup(&path); Py_RETURN_NONE; } #endif /* HAVE_LCHFLAGS */ + #ifdef HAVE_CHROOT -PyDoc_STRVAR(posix_chroot__doc__, -"chroot(path)\n\n\ -Change root directory to path."); +/*[clinic input] +os.chroot + path: path_t + +Change root directory to path. + +[clinic start generated code]*/ static PyObject * -posix_chroot(PyObject *self, PyObject *args) +os_chroot_impl(PyModuleDef *module, path_t *path) +/*[clinic end generated code: output=b6dbfabe74ecaa9d input=14822965652c3dc3]*/ { - return posix_1str("chroot", args, "O&:chroot", chroot); + int res; + Py_BEGIN_ALLOW_THREADS + res = chroot(path->narrow); + Py_END_ALLOW_THREADS + if (res < 0) + return path_error(path); + Py_RETURN_NONE; } -#endif +#endif /* HAVE_CHROOT */ + #ifdef HAVE_FSYNC -PyDoc_STRVAR(posix_fsync__doc__, -"fsync(fildes)\n\n\ -force write of file with filedescriptor to disk."); +/*[clinic input] +os.fsync + + fd: fildes + +Force write of fd to disk. +[clinic start generated code]*/ static PyObject * -posix_fsync(PyObject *self, PyObject *fdobj) +os_fsync_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=83a350851064aea7 input=21c3645c056967f2]*/ { - return posix_fildes(fdobj, fsync); + return posix_fildes_fd(fd, fsync); } #endif /* HAVE_FSYNC */ + #ifdef HAVE_SYNC -PyDoc_STRVAR(posix_sync__doc__, -"sync()\n\n\ -Force write of everything to disk."); +/*[clinic input] +os.sync + +Force write of everything to disk. +[clinic start generated code]*/ static PyObject * -posix_sync(PyObject *self, PyObject *noargs) +os_sync_impl(PyModuleDef *module) +/*[clinic end generated code: output=ba524f656c201c40 input=84749fe5e9b404ff]*/ { Py_BEGIN_ALLOW_THREADS sync(); Py_END_ALLOW_THREADS Py_RETURN_NONE; } -#endif +#endif /* HAVE_SYNC */ -#ifdef HAVE_FDATASYNC +#ifdef HAVE_FDATASYNC #ifdef __hpux extern int fdatasync(int); /* On HP-UX, in libc but not in unistd.h */ #endif -PyDoc_STRVAR(posix_fdatasync__doc__, -"fdatasync(fildes)\n\n\ -force write of file with filedescriptor to disk.\n\ - does not force update of metadata."); +/*[clinic input] +os.fdatasync + + fd: fildes + +Force write of fd to disk without forcing update of metadata. +[clinic start generated code]*/ static PyObject * -posix_fdatasync(PyObject *self, PyObject *fdobj) +os_fdatasync_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=e0f04a3aff515b75 input=bc74791ee54dd291]*/ { - return posix_fildes(fdobj, fdatasync); + return posix_fildes_fd(fd, fdatasync); } #endif /* HAVE_FDATASYNC */ #ifdef HAVE_CHOWN -PyDoc_STRVAR(posix_chown__doc__, -"chown(path, uid, gid, *, dir_fd=None, follow_symlinks=True)\n\n\ -Change the owner and group id of path to the numeric uid and gid.\n\ -\n\ -path may always be specified as a string.\n\ -On some platforms, path may also be specified as an open file descriptor.\n\ - If this functionality is unavailable, using it raises an exception.\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 follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, chown will modify 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.\n\ -dir_fd and follow_symlinks may not be implemented on your platform.\n\ - If they are unavailable, using them will raise a NotImplementedError."); +/*[clinic input] +os.chown + + path : path_t(allow_fd='PATH_HAVE_FCHOWN') + Path to be examined; can be string, bytes, or open-file-descriptor int. + + uid: uid_t + + gid: gid_t + + * + + dir_fd : dir_fd(requires='fchownat') = 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. + + 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. + +Change the owner and group id of path to the numeric uid and gid.\ + +path may always be specified as a string. +On some platforms, path may also be specified as an open file descriptor. + If this functionality is unavailable, using it raises an exception. +If dir_fd is 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. +If follow_symlinks is False, and the last element of the path is a symbolic + link, chown will modify the symbolic link itself instead of the file the + link points to. +It is an error to use dir_fd or follow_symlinks when specifying path as + an open file descriptor. +dir_fd and follow_symlinks may not be implemented on your platform. + If they are unavailable, using them will raise a NotImplementedError. + +[clinic start generated code]*/ static PyObject * -posix_chown(PyObject *self, PyObject *args, PyObject *kwargs) +os_chown_impl(PyModuleDef *module, path_t *path, uid_t uid, gid_t gid, int dir_fd, int follow_symlinks) +/*[clinic end generated code: output=59a8db91897fb46c input=a61cc35574814d5d]*/ { - path_t path; - uid_t uid; - gid_t gid; - int dir_fd = DEFAULT_DIR_FD; - int follow_symlinks = 1; int result; - PyObject *return_value = NULL; - static char *keywords[] = {"path", "uid", "gid", "dir_fd", - "follow_symlinks", NULL}; - - memset(&path, 0, sizeof(path)); - path.function_name = "chown"; -#ifdef HAVE_FCHOWN - path.allow_fd = 1; -#endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&O&|$O&p:chown", keywords, - path_converter, &path, - _Py_Uid_Converter, &uid, - _Py_Gid_Converter, &gid, -#ifdef HAVE_FCHOWNAT - dir_fd_converter, &dir_fd, -#else - dir_fd_unavailable, &dir_fd, -#endif - &follow_symlinks)) - return NULL; #if !(defined(HAVE_LCHOWN) || defined(HAVE_FCHOWNAT)) if (follow_symlinks_specified("chown", follow_symlinks)) - goto exit; + return NULL; #endif - if (dir_fd_and_fd_invalid("chown", dir_fd, path.fd) || - fd_and_follow_symlinks_invalid("chown", path.fd, follow_symlinks)) - goto exit; + if (dir_fd_and_fd_invalid("chown", dir_fd, path->fd) || + fd_and_follow_symlinks_invalid("chown", path->fd, follow_symlinks)) + return NULL; #ifdef __APPLE__ /* @@ -3310,102 +3153,98 @@ posix_chown(PyObject *self, PyObject *args, PyObject *kwargs) */ if ((!follow_symlinks) && (lchown == NULL)) { follow_symlinks_specified("chown", follow_symlinks); - goto exit; + return NULL; } #endif Py_BEGIN_ALLOW_THREADS #ifdef HAVE_FCHOWN - if (path.fd != -1) - result = fchown(path.fd, uid, gid); + if (path->fd != -1) + result = fchown(path->fd, uid, gid); else #endif #ifdef HAVE_LCHOWN if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD)) - result = lchown(path.narrow, uid, gid); + result = lchown(path->narrow, uid, gid); else #endif #ifdef HAVE_FCHOWNAT if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) - result = fchownat(dir_fd, path.narrow, uid, gid, + result = fchownat(dir_fd, path->narrow, uid, gid, follow_symlinks ? 0 : AT_SYMLINK_NOFOLLOW); else #endif - result = chown(path.narrow, uid, gid); + result = chown(path->narrow, uid, gid); Py_END_ALLOW_THREADS - if (result) { - return_value = path_error(&path); - goto exit; - } - - return_value = Py_None; - Py_INCREF(Py_None); + if (result) + return path_error(path); -exit: - path_cleanup(&path); - return return_value; + Py_RETURN_NONE; } #endif /* HAVE_CHOWN */ + #ifdef HAVE_FCHOWN -PyDoc_STRVAR(posix_fchown__doc__, -"fchown(fd, uid, gid)\n\n\ -Change the owner and group id of the file given by file descriptor\n\ -fd to the numeric uid and gid. Equivalent to os.chown(fd, uid, gid)."); +/*[clinic input] +os.fchown + + fd: int + uid: uid_t + gid: gid_t + +Change the owner and group id of the file specified by file descriptor. + +Equivalent to os.chown(fd, uid, gid). + +[clinic start generated code]*/ static PyObject * -posix_fchown(PyObject *self, PyObject *args) +os_fchown_impl(PyModuleDef *module, int fd, uid_t uid, gid_t gid) +/*[clinic end generated code: output=7545abf8f6086d76 input=3af544ba1b13a0d7]*/ { - int fd; - uid_t uid; - gid_t gid; int res; - if (!PyArg_ParseTuple(args, "iO&O&:fchown", &fd, - _Py_Uid_Converter, &uid, - _Py_Gid_Converter, &gid)) - return NULL; - Py_BEGIN_ALLOW_THREADS - res = fchown(fd, uid, gid); - Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = fchown(fd, uid, gid); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res != 0) + return (!async_err) ? posix_error() : NULL; + Py_RETURN_NONE; } #endif /* HAVE_FCHOWN */ + #ifdef HAVE_LCHOWN -PyDoc_STRVAR(posix_lchown__doc__, -"lchown(path, uid, gid)\n\n\ -Change the owner and group id of path to the numeric uid and gid.\n\ -This function will not follow symbolic links.\n\ -Equivalent to os.chown(path, uid, gid, follow_symlinks=False)."); +/*[clinic input] +os.lchown + + path : path_t + uid: uid_t + gid: gid_t + +Change the owner and group id of path to the numeric uid and gid. + +This function will not follow symbolic links. +Equivalent to os.chown(path, uid, gid, follow_symlinks=False). +[clinic start generated code]*/ static PyObject * -posix_lchown(PyObject *self, PyObject *args) +os_lchown_impl(PyModuleDef *module, path_t *path, uid_t uid, gid_t gid) +/*[clinic end generated code: output=bb0d2da1579ac275 input=b1c6014d563a7161]*/ { - path_t path; - uid_t uid; - gid_t gid; int res; - memset(&path, 0, sizeof(path)); - path.function_name = "lchown"; - if (!PyArg_ParseTuple(args, "O&O&O&:lchown", - path_converter, &path, - _Py_Uid_Converter, &uid, - _Py_Gid_Converter, &gid)) - return NULL; Py_BEGIN_ALLOW_THREADS - res = lchown(path.narrow, uid, gid); + res = lchown(path->narrow, uid, gid); Py_END_ALLOW_THREADS if (res < 0) { - path_error(&path); - path_cleanup(&path); - return NULL; + return path_error(path); } - path_cleanup(&path); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #endif /* HAVE_LCHOWN */ @@ -3462,148 +3301,124 @@ posix_getcwd(int use_bytes) return PyUnicode_DecodeFSDefault(buf); } -PyDoc_STRVAR(posix_getcwd__doc__, -"getcwd() -> path\n\n\ -Return a unicode string representing the current working directory."); + +/*[clinic input] +os.getcwd + +Return a unicode string representing the current working directory. +[clinic start generated code]*/ static PyObject * -posix_getcwd_unicode(PyObject *self) +os_getcwd_impl(PyModuleDef *module) +/*[clinic end generated code: output=efe3a8c0121525ea input=f069211bb70e3d39]*/ { return posix_getcwd(0); } -PyDoc_STRVAR(posix_getcwdb__doc__, -"getcwdb() -> path\n\n\ -Return a bytes string representing the current working directory."); + +/*[clinic input] +os.getcwdb + +Return a bytes string representing the current working directory. +[clinic start generated code]*/ static PyObject * -posix_getcwd_bytes(PyObject *self) +os_getcwdb_impl(PyModuleDef *module) +/*[clinic end generated code: output=7fce42ee4b2a296a input=f6f6a378dad3d9cb]*/ { return posix_getcwd(1); } + #if ((!defined(HAVE_LINK)) && defined(MS_WINDOWS)) #define HAVE_LINK 1 #endif #ifdef HAVE_LINK -PyDoc_STRVAR(posix_link__doc__, -"link(src, dst, *, src_dir_fd=None, dst_dir_fd=None, follow_symlinks=True)\n\n\ -Create a hard link to a file.\n\ -\n\ -If either src_dir_fd or dst_dir_fd is not None, it should be a file\n\ - descriptor open to a directory, and the respective path string (src or dst)\n\ - should be relative; the path will then be relative to that directory.\n\ -If follow_symlinks is False, and the last element of src is a symbolic\n\ - link, link will create a link to the symbolic link itself instead of the\n\ - file the link points to.\n\ -src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your\n\ - platform. If they are unavailable, using them will raise a\n\ - NotImplementedError."); - -static PyObject * -posix_link(PyObject *self, PyObject *args, PyObject *kwargs) -{ - path_t src, dst; - int src_dir_fd = DEFAULT_DIR_FD; - int dst_dir_fd = DEFAULT_DIR_FD; - int follow_symlinks = 1; - PyObject *return_value = NULL; - static char *keywords[] = {"src", "dst", "src_dir_fd", "dst_dir_fd", - "follow_symlinks", NULL}; +/*[clinic input] + +os.link + + src : path_t + dst : path_t + * + src_dir_fd : dir_fd = None + dst_dir_fd : dir_fd = None + follow_symlinks: bool = True + +Create a hard link to a file. + +If either src_dir_fd or dst_dir_fd is not None, it should be a file + descriptor open to a directory, and the respective path string (src or dst) + should be relative; the path will then be relative to that directory. +If follow_symlinks is False, and the last element of src is a symbolic + link, link will create a link to the symbolic link itself instead of the + file the link points to. +src_dir_fd, dst_dir_fd, and follow_symlinks may not be implemented on your + platform. If they are unavailable, using them will raise a + NotImplementedError. +[clinic start generated code]*/ + +static PyObject * +os_link_impl(PyModuleDef *module, path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int follow_symlinks) +/*[clinic end generated code: output=c0a9ded8111d2a79 input=b0095ebbcbaa7e04]*/ +{ #ifdef MS_WINDOWS BOOL result; #else int result; #endif - memset(&src, 0, sizeof(src)); - memset(&dst, 0, sizeof(dst)); - src.function_name = "link"; - dst.function_name = "link"; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|O&O&p:link", keywords, - path_converter, &src, - path_converter, &dst, - dir_fd_converter, &src_dir_fd, - dir_fd_converter, &dst_dir_fd, - &follow_symlinks)) - return NULL; - #ifndef HAVE_LINKAT if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD)) { argument_unavailable_error("link", "src_dir_fd and dst_dir_fd"); - goto exit; + return NULL; } #endif - if ((src.narrow && dst.wide) || (src.wide && dst.narrow)) { + if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) { PyErr_SetString(PyExc_NotImplementedError, "link: src and dst must be the same type"); - goto exit; + return NULL; } #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS - if (src.wide) - result = CreateHardLinkW(dst.wide, src.wide, NULL); + if (src->wide) + result = CreateHardLinkW(dst->wide, src->wide, NULL); else - result = CreateHardLinkA(dst.narrow, src.narrow, NULL); + result = CreateHardLinkA(dst->narrow, src->narrow, NULL); Py_END_ALLOW_THREADS - if (!result) { - return_value = path_error2(&src, &dst); - goto exit; - } + if (!result) + return path_error2(src, dst); #else Py_BEGIN_ALLOW_THREADS #ifdef HAVE_LINKAT if ((src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) - result = linkat(src_dir_fd, src.narrow, - dst_dir_fd, dst.narrow, + result = linkat(src_dir_fd, src->narrow, + dst_dir_fd, dst->narrow, follow_symlinks ? AT_SYMLINK_FOLLOW : 0); else #endif - result = link(src.narrow, dst.narrow); + result = link(src->narrow, dst->narrow); Py_END_ALLOW_THREADS - if (result) { - return_value = path_error2(&src, &dst); - goto exit; - } + if (result) + return path_error2(src, dst); #endif - return_value = Py_None; - Py_INCREF(Py_None); - -exit: - path_cleanup(&src); - path_cleanup(&dst); - return return_value; + Py_RETURN_NONE; } #endif - -PyDoc_STRVAR(posix_listdir__doc__, -"listdir(path='.') -> list_of_filenames\n\n\ -Return a list containing the names of the files in the directory.\n\ -The list is in arbitrary order. It does not include the special\n\ -entries '.' and '..' even if they are present in the directory.\n\ -\n\ -path can be specified as either str or bytes. If path is bytes,\n\ - the filenames returned will also be bytes; in all other circumstances\n\ - the filenames returned will be str.\n\ -On some platforms, path may also be specified as an open file descriptor;\n\ - the file descriptor must refer to a directory.\n\ - If this functionality is unavailable, using it raises NotImplementedError."); - #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR) static PyObject * _listdir_windows_no_opendir(path_t *path, PyObject *list) { - static char *keywords[] = {"path", NULL}; PyObject *v; HANDLE hFindFile = INVALID_HANDLE_VALUE; BOOL result; @@ -3862,38 +3677,42 @@ exit: } /* end of _posix_listdir */ #endif /* which OS */ -static PyObject * -posix_listdir(PyObject *self, PyObject *args, PyObject *kwargs) -{ - path_t path; - PyObject *list = NULL; - static char *keywords[] = {"path", NULL}; - PyObject *return_value; - memset(&path, 0, sizeof(path)); - path.function_name = "listdir"; - path.nullable = 1; -#ifdef HAVE_FDOPENDIR - path.allow_fd = 1; - path.fd = -1; -#endif +/*[clinic input] +os.listdir - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:listdir", keywords, - path_converter, &path)) { - return NULL; - } + path : path_t(nullable=True, allow_fd='PATH_HAVE_FDOPENDIR') = None + +Return a list containing the names of the files in the directory. +path can be specified as either str or bytes. If path is bytes, + the filenames returned will also be bytes; in all other circumstances + the filenames returned will be str. +If path is None, uses the path='.'. +On some platforms, path may also be specified as an open file descriptor;\ + the file descriptor must refer to a directory. + If this functionality is unavailable, using it raises NotImplementedError. + +The list is in arbitrary order. It does not include the special +entries '.' and '..' even if they are present in the directory. + + +[clinic start generated code]*/ + +static PyObject * +os_listdir_impl(PyModuleDef *module, path_t *path) +/*[clinic end generated code: output=1fbe67c1f780c8b7 input=09e300416e3cd729]*/ +{ #if defined(MS_WINDOWS) && !defined(HAVE_OPENDIR) - return_value = _listdir_windows_no_opendir(&path, list); + return _listdir_windows_no_opendir(path, NULL); #else - return_value = _posix_listdir(&path, list); + return _posix_listdir(path, NULL); #endif - path_cleanup(&path); - return return_value; } #ifdef MS_WINDOWS /* A helper function for abspath on win32 */ +/* AC 3.5: probably just convert to using path converter */ static PyObject * posix__getfullpathname(PyObject *self, PyObject *args) { @@ -3949,36 +3768,35 @@ posix__getfullpathname(PyObject *self, PyObject *args) Py_FileSystemDefaultEncoding, NULL); } return PyBytes_FromString(outbuf); -} /* end of posix__getfullpathname */ +} +/*[clinic input] +os._getfinalpathname + + path: unicode + / + +A helper function for samepath on windows. +[clinic start generated code]*/ -/* A helper function for samepath on windows */ static PyObject * -posix__getfinalpathname(PyObject *self, PyObject *args) +os__getfinalpathname_impl(PyModuleDef *module, PyObject *path) +/*[clinic end generated code: output=8be81a5f51a34bcf input=71d5e89334891bf4]*/ { HANDLE hFile; int buf_size; wchar_t *target_path; int result_length; - PyObject *po, *result; - wchar_t *path; + PyObject *result; + wchar_t *path_wchar; - if (!PyArg_ParseTuple(args, "U|:_getfinalpathname", &po)) - return NULL; - path = PyUnicode_AsUnicode(po); - if (path == NULL) + path_wchar = PyUnicode_AsUnicode(path); + if (path_wchar == NULL) return NULL; - if(!check_GetFinalPathNameByHandle()) { - /* If the OS doesn't have GetFinalPathNameByHandle, return a - NotImplementedError. */ - return PyErr_Format(PyExc_NotImplementedError, - "GetFinalPathNameByHandle not available on this platform"); - } - hFile = CreateFileW( - path, + path_wchar, 0, /* desired access */ 0, /* share mode */ NULL, /* security attributes */ @@ -3988,37 +3806,37 @@ posix__getfinalpathname(PyObject *self, PyObject *args) NULL); if(hFile == INVALID_HANDLE_VALUE) - return win32_error_object("CreateFileW", po); + return win32_error_object("CreateFileW", path); /* We have a good handle to the target, use it to determine the target path name. */ - buf_size = Py_GetFinalPathNameByHandleW(hFile, 0, 0, VOLUME_NAME_NT); + buf_size = GetFinalPathNameByHandleW(hFile, 0, 0, VOLUME_NAME_NT); if(!buf_size) - return win32_error_object("GetFinalPathNameByHandle", po); + return win32_error_object("GetFinalPathNameByHandle", path); target_path = PyMem_New(wchar_t, buf_size+1); if(!target_path) return PyErr_NoMemory(); - result_length = Py_GetFinalPathNameByHandleW(hFile, target_path, - buf_size, VOLUME_NAME_DOS); + result_length = GetFinalPathNameByHandleW(hFile, target_path, + buf_size, VOLUME_NAME_DOS); if(!result_length) - return win32_error_object("GetFinalPathNamyByHandle", po); + return win32_error_object("GetFinalPathNamyByHandle", path); if(!CloseHandle(hFile)) - return win32_error_object("CloseHandle", po); + return win32_error_object("CloseHandle", path); target_path[result_length] = 0; result = PyUnicode_FromWideChar(target_path, result_length); PyMem_Free(target_path); return result; - -} /* end of posix__getfinalpathname */ +} PyDoc_STRVAR(posix__isdir__doc__, "Return true if the pathname refers to an existing directory."); +/* AC 3.5: convert using path converter */ static PyObject * posix__isdir(PyObject *self, PyObject *args) { @@ -4055,22 +3873,26 @@ check: Py_RETURN_FALSE; } -PyDoc_STRVAR(posix__getvolumepathname__doc__, -"Return volume mount point of the specified path."); -/* A helper function for ismount on windows */ +/*[clinic input] +os._getvolumepathname + + path: unicode + +A helper function for ismount on Win32. +[clinic start generated code]*/ + static PyObject * -posix__getvolumepathname(PyObject *self, PyObject *args) +os__getvolumepathname_impl(PyModuleDef *module, PyObject *path) +/*[clinic end generated code: output=79a0ba729f956dbe input=7eacadc40acbda6b]*/ { - PyObject *po, *result; - wchar_t *path, *mountpath=NULL; + PyObject *result; + wchar_t *path_wchar, *mountpath=NULL; size_t buflen; BOOL ret; - if (!PyArg_ParseTuple(args, "U|:_getvolumepathname", &po)) - return NULL; - path = PyUnicode_AsUnicodeAndSize(po, &buflen); - if (path == NULL) + path_wchar = PyUnicode_AsUnicodeAndSize(path, &buflen); + if (path_wchar == NULL) return NULL; buflen += 1; @@ -4087,12 +3909,12 @@ posix__getvolumepathname(PyObject *self, PyObject *args) return PyErr_NoMemory(); Py_BEGIN_ALLOW_THREADS - ret = GetVolumePathNameW(path, mountpath, + ret = GetVolumePathNameW(path_wchar, mountpath, Py_SAFE_DOWNCAST(buflen, size_t, DWORD)); Py_END_ALLOW_THREADS if (!ret) { - result = win32_error_object("_getvolumepathname", po); + result = win32_error_object("_getvolumepathname", path); goto exit; } result = PyUnicode_FromWideChar(mountpath, wcslen(mountpath)); @@ -4101,78 +3923,66 @@ exit: PyMem_Free(mountpath); return result; } -/* end of posix__getvolumepathname */ #endif /* MS_WINDOWS */ -PyDoc_STRVAR(posix_mkdir__doc__, -"mkdir(path, mode=0o777, *, dir_fd=None)\n\n\ -Create a directory.\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 implemented on your platform.\n\ - If it is unavailable, using it will raise a NotImplementedError.\n\ -\n\ -The mode argument is ignored on Windows."); + +/*[clinic input] +os.mkdir + + path : path_t + + mode: int = 0o777 + + * + + dir_fd : dir_fd(requires='mkdirat') = None + +# "mkdir(path, mode=0o777, *, dir_fd=None)\n\n\ + +Create a directory. + +If dir_fd is 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. +dir_fd may not be implemented on your platform. + If it is unavailable, using it will raise a NotImplementedError. + +The mode argument is ignored on Windows. +[clinic start generated code]*/ static PyObject * -posix_mkdir(PyObject *self, PyObject *args, PyObject *kwargs) +os_mkdir_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd) +/*[clinic end generated code: output=8bf1f738873ef2c5 input=e965f68377e9b1ce]*/ { - path_t path; - int mode = 0777; - int dir_fd = DEFAULT_DIR_FD; - static char *keywords[] = {"path", "mode", "dir_fd", NULL}; - PyObject *return_value = NULL; int result; - memset(&path, 0, sizeof(path)); - path.function_name = "mkdir"; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|i$O&:mkdir", keywords, - path_converter, &path, &mode, -#ifdef HAVE_MKDIRAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd -#endif - )) - return NULL; - #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS - if (path.wide) - result = CreateDirectoryW(path.wide, NULL); + if (path->wide) + result = CreateDirectoryW(path->wide, NULL); else - result = CreateDirectoryA(path.narrow, NULL); + result = CreateDirectoryA(path->narrow, NULL); Py_END_ALLOW_THREADS - if (!result) { - return_value = path_error(&path); - goto exit; - } + if (!result) + return path_error(path); #else Py_BEGIN_ALLOW_THREADS #if HAVE_MKDIRAT if (dir_fd != DEFAULT_DIR_FD) - result = mkdirat(dir_fd, path.narrow, mode); + result = mkdirat(dir_fd, path->narrow, mode); else #endif #if ( defined(__WATCOMC__) || defined(PYCC_VACPP) ) && !defined(__QNX__) - result = mkdir(path.narrow); + result = mkdir(path->narrow); #else - result = mkdir(path.narrow, mode); + result = mkdir(path->narrow, mode); #endif Py_END_ALLOW_THREADS - if (result < 0) { - return_value = path_error(&path); - goto exit; - } + if (result < 0) + return path_error(path); #endif - return_value = Py_None; - Py_INCREF(Py_None); -exit: - path_cleanup(&path); - return return_value; + Py_RETURN_NONE; } @@ -4183,17 +3993,20 @@ exit: #ifdef HAVE_NICE -PyDoc_STRVAR(posix_nice__doc__, -"nice(inc) -> new_priority\n\n\ -Decrease the priority of process by inc and return the new priority."); +/*[clinic input] +os.nice + + increment: int + / + +Add increment to the priority of process and return the new priority. +[clinic start generated code]*/ static PyObject * -posix_nice(PyObject *self, PyObject *args) +os_nice_impl(PyModuleDef *module, int increment) +/*[clinic end generated code: output=8870418a3fc07b51 input=864be2d402a21da2]*/ { - int increment, value; - - if (!PyArg_ParseTuple(args, "i:nice", &increment)) - return NULL; + int value; /* There are two flavours of 'nice': one that returns the new priority (as required by almost all standards out there) and the @@ -4220,17 +4033,21 @@ posix_nice(PyObject *self, PyObject *args) #ifdef HAVE_GETPRIORITY -PyDoc_STRVAR(posix_getpriority__doc__, -"getpriority(which, who) -> current_priority\n\n\ -Get program scheduling priority."); +/*[clinic input] +os.getpriority + + which: int + who: int + +Return program scheduling priority. +[clinic start generated code]*/ static PyObject * -posix_getpriority(PyObject *self, PyObject *args) +os_getpriority_impl(PyModuleDef *module, int which, int who) +/*[clinic end generated code: output=4759937aa5b67ed6 input=9be615d40e2544ef]*/ { - int which, who, retval; + int retval; - if (!PyArg_ParseTuple(args, "ii", &which, &who)) - return NULL; errno = 0; retval = getpriority(which, who); if (errno != 0) @@ -4241,18 +4058,23 @@ posix_getpriority(PyObject *self, PyObject *args) #ifdef HAVE_SETPRIORITY -PyDoc_STRVAR(posix_setpriority__doc__, -"setpriority(which, who, prio) -> None\n\n\ -Set program scheduling priority."); +/*[clinic input] +os.setpriority + + which: int + who: int + priority: int + +Set program scheduling priority. +[clinic start generated code]*/ static PyObject * -posix_setpriority(PyObject *self, PyObject *args) +os_setpriority_impl(PyModuleDef *module, int which, int who, int priority) +/*[clinic end generated code: output=6497d3301547e7d5 input=710ccbf65b9dc513]*/ { - int which, who, prio, retval; + int retval; - if (!PyArg_ParseTuple(args, "iii", &which, &who, &prio)) - return NULL; - retval = setpriority(which, who, prio); + retval = setpriority(which, who, priority); if (retval == -1) return posix_error(); Py_RETURN_NONE; @@ -4261,17 +4083,10 @@ posix_setpriority(PyObject *self, PyObject *args) static PyObject * -internal_rename(PyObject *args, PyObject *kwargs, int is_replace) +internal_rename(path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd, int is_replace) { char *function_name = is_replace ? "replace" : "rename"; - path_t src; - path_t dst; - int src_dir_fd = DEFAULT_DIR_FD; - int dst_dir_fd = DEFAULT_DIR_FD; int dir_fd_specified; - PyObject *return_value = NULL; - char format[24]; - static char *keywords[] = {"src", "dst", "src_dir_fd", "dst_dir_fd", NULL}; #ifdef MS_WINDOWS BOOL result; @@ -4280,210 +4095,198 @@ internal_rename(PyObject *args, PyObject *kwargs, int is_replace) int result; #endif - memset(&src, 0, sizeof(src)); - memset(&dst, 0, sizeof(dst)); - src.function_name = function_name; - dst.function_name = function_name; - strcpy(format, "O&O&|$O&O&:"); - strcat(format, function_name); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, format, keywords, - path_converter, &src, - path_converter, &dst, - dir_fd_converter, &src_dir_fd, - dir_fd_converter, &dst_dir_fd)) - return NULL; - dir_fd_specified = (src_dir_fd != DEFAULT_DIR_FD) || (dst_dir_fd != DEFAULT_DIR_FD); #ifndef HAVE_RENAMEAT if (dir_fd_specified) { argument_unavailable_error(function_name, "src_dir_fd and dst_dir_fd"); - goto exit; + return NULL; } #endif - if ((src.narrow && dst.wide) || (src.wide && dst.narrow)) { + if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) { PyErr_Format(PyExc_ValueError, "%s: src and dst must be the same type", function_name); - goto exit; + return NULL; } #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS - if (src.wide) - result = MoveFileExW(src.wide, dst.wide, flags); + if (src->wide) + result = MoveFileExW(src->wide, dst->wide, flags); else - result = MoveFileExA(src.narrow, dst.narrow, flags); + result = MoveFileExA(src->narrow, dst->narrow, flags); Py_END_ALLOW_THREADS - if (!result) { - return_value = path_error2(&src, &dst); - goto exit; - } + if (!result) + return path_error2(src, dst); #else Py_BEGIN_ALLOW_THREADS #ifdef HAVE_RENAMEAT if (dir_fd_specified) - result = renameat(src_dir_fd, src.narrow, dst_dir_fd, dst.narrow); + result = renameat(src_dir_fd, src->narrow, dst_dir_fd, dst->narrow); else #endif - result = rename(src.narrow, dst.narrow); + result = rename(src->narrow, dst->narrow); Py_END_ALLOW_THREADS - if (result) { - return_value = path_error2(&src, &dst); - goto exit; - } + if (result) + return path_error2(src, dst); #endif - - Py_INCREF(Py_None); - return_value = Py_None; -exit: - path_cleanup(&src); - path_cleanup(&dst); - return return_value; + Py_RETURN_NONE; } -PyDoc_STRVAR(posix_rename__doc__, -"rename(src, dst, *, src_dir_fd=None, dst_dir_fd=None)\n\n\ -Rename a file or directory.\n\ -\n\ -If either src_dir_fd or dst_dir_fd is not None, it should be a file\n\ - descriptor open to a directory, and the respective path string (src or dst)\n\ - should be relative; the path will then be relative to that directory.\n\ -src_dir_fd and dst_dir_fd, may not be implemented on your platform.\n\ - If they are unavailable, using them will raise a NotImplementedError."); + +/*[clinic input] +os.rename + + src : path_t + dst : path_t + * + src_dir_fd : dir_fd = None + dst_dir_fd : dir_fd = None + +Rename a file or directory. + +If either src_dir_fd or dst_dir_fd is not None, it should be a file + descriptor open to a directory, and the respective path string (src or dst) + should be relative; the path will then be relative to that directory. +src_dir_fd and dst_dir_fd, may not be implemented on your platform. + If they are unavailable, using them will raise a NotImplementedError. +[clinic start generated code]*/ static PyObject * -posix_rename(PyObject *self, PyObject *args, PyObject *kwargs) +os_rename_impl(PyModuleDef *module, path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd) +/*[clinic end generated code: output=1bb520bf2fad186d input=faa61c847912c850]*/ { - return internal_rename(args, kwargs, 0); + return internal_rename(src, dst, src_dir_fd, dst_dir_fd, 0); } -PyDoc_STRVAR(posix_replace__doc__, -"replace(src, dst, *, src_dir_fd=None, dst_dir_fd=None)\n\n\ -Rename a file or directory, overwriting the destination.\n\ -\n\ -If either src_dir_fd or dst_dir_fd is not None, it should be a file\n\ - descriptor open to a directory, and the respective path string (src or dst)\n\ - should be relative; the path will then be relative to that directory.\n\ -src_dir_fd and dst_dir_fd, may not be implemented on your platform.\n\ - If they are unavailable, using them will raise a NotImplementedError."); + +/*[clinic input] +os.replace = os.rename + +Rename a file or directory, overwriting the destination. + +If either src_dir_fd or dst_dir_fd is not None, it should be a file + descriptor open to a directory, and the respective path string (src or dst) + should be relative; the path will then be relative to that directory. +src_dir_fd and dst_dir_fd, may not be implemented on your platform. + If they are unavailable, using them will raise a NotImplementedError." +[clinic start generated code]*/ static PyObject * -posix_replace(PyObject *self, PyObject *args, PyObject *kwargs) +os_replace_impl(PyModuleDef *module, path_t *src, path_t *dst, int src_dir_fd, int dst_dir_fd) +/*[clinic end generated code: output=aa9ddad55fdef8e3 input=25515dfb107c8421]*/ { - return internal_rename(args, kwargs, 1); + return internal_rename(src, dst, src_dir_fd, dst_dir_fd, 1); } -PyDoc_STRVAR(posix_rmdir__doc__, -"rmdir(path, *, dir_fd=None)\n\n\ -Remove a directory.\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 implemented on your platform.\n\ - If it is unavailable, using it will raise a NotImplementedError."); + +/*[clinic input] +os.rmdir + + path: path_t + * + dir_fd: dir_fd(requires='unlinkat') = None + +Remove a directory. + +If dir_fd is 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. +dir_fd may not be implemented on your platform. + If it is unavailable, using it will raise a NotImplementedError. +[clinic start generated code]*/ static PyObject * -posix_rmdir(PyObject *self, PyObject *args, PyObject *kwargs) +os_rmdir_impl(PyModuleDef *module, path_t *path, int dir_fd) +/*[clinic end generated code: output=cabadec80d5a77c7 input=38c8b375ca34a7e2]*/ { - path_t path; - int dir_fd = DEFAULT_DIR_FD; - static char *keywords[] = {"path", "dir_fd", NULL}; int result; - PyObject *return_value = NULL; - - memset(&path, 0, sizeof(path)); - path.function_name = "rmdir"; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:rmdir", keywords, - path_converter, &path, -#ifdef HAVE_UNLINKAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd -#endif - )) - return NULL; Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS - if (path.wide) - result = RemoveDirectoryW(path.wide); + if (path->wide) + result = RemoveDirectoryW(path->wide); else - result = RemoveDirectoryA(path.narrow); + result = RemoveDirectoryA(path->narrow); result = !result; /* Windows, success=1, UNIX, success=0 */ #else #ifdef HAVE_UNLINKAT if (dir_fd != DEFAULT_DIR_FD) - result = unlinkat(dir_fd, path.narrow, AT_REMOVEDIR); + result = unlinkat(dir_fd, path->narrow, AT_REMOVEDIR); else #endif - result = rmdir(path.narrow); + result = rmdir(path->narrow); #endif Py_END_ALLOW_THREADS - if (result) { - return_value = path_error(&path); - goto exit; - } - - return_value = Py_None; - Py_INCREF(Py_None); + if (result) + return path_error(path); -exit: - path_cleanup(&path); - return return_value; + Py_RETURN_NONE; } #ifdef HAVE_SYSTEM -PyDoc_STRVAR(posix_system__doc__, -"system(command) -> exit_status\n\n\ -Execute the command (a string) in a subshell."); - -static PyObject * -posix_system(PyObject *self, PyObject *args) -{ - long sts; #ifdef MS_WINDOWS - wchar_t *command; - if (!PyArg_ParseTuple(args, "u:system", &command)) - return NULL; +/*[clinic input] +os.system -> long + + command: Py_UNICODE +Execute the command in a subshell. +[clinic start generated code]*/ + +static long +os_system_impl(PyModuleDef *module, Py_UNICODE *command) +/*[clinic end generated code: output=4c3bd5abcd9c29e7 input=303f5ce97df606b0]*/ +{ + long result; Py_BEGIN_ALLOW_THREADS - sts = _wsystem(command); + result = _wsystem(command); Py_END_ALLOW_THREADS -#else - PyObject *command_obj; - char *command; - if (!PyArg_ParseTuple(args, "O&:system", - PyUnicode_FSConverter, &command_obj)) - return NULL; + return result; +} +#else /* MS_WINDOWS */ +/*[clinic input] +os.system -> long + + command: FSConverter + +Execute the command in a subshell. +[clinic start generated code]*/ - command = PyBytes_AsString(command_obj); +static long +os_system_impl(PyModuleDef *module, PyObject *command) +/*[clinic end generated code: output=800f775e10b7be55 input=86a58554ba6094af]*/ +{ + long result; + char *bytes = PyBytes_AsString(command); Py_BEGIN_ALLOW_THREADS - sts = system(command); + result = system(bytes); Py_END_ALLOW_THREADS - Py_DECREF(command_obj); -#endif - return PyLong_FromLong(sts); + return result; } #endif +#endif /* HAVE_SYSTEM */ + + +/*[clinic input] +os.umask + mask: int + / -PyDoc_STRVAR(posix_umask__doc__, -"umask(new_mask) -> old_mask\n\n\ -Set the current numeric umask and return the previous umask."); +Set the current numeric umask and return the previous umask. +[clinic start generated code]*/ static PyObject * -posix_umask(PyObject *self, PyObject *args) +os_umask_impl(PyModuleDef *module, int mask) +/*[clinic end generated code: output=9e1fe3c9f14d6a05 input=ab6bfd9b24d8a7e8]*/ { - int i; - if (!PyArg_ParseTuple(args, "i:umask", &i)) - return NULL; - i = (int)umask(i); + int i = (int)umask(mask); if (i < 0) return posix_error(); return PyLong_FromLong((long)i); @@ -4512,7 +4315,10 @@ BOOL WINAPI Py_DeleteFileW(LPCWSTR lpFileName) find_data_handle = FindFirstFileW(lpFileName, &find_data); if(find_data_handle != INVALID_HANDLE_VALUE) { - is_link = find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK; + /* IO_REPARSE_TAG_SYMLINK if it is a symlink and + IO_REPARSE_TAG_MOUNT_POINT if it is a junction point. */ + is_link = find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK || + find_data.dwReserved0 == IO_REPARSE_TAG_MOUNT_POINT; FindClose(find_data_handle); } } @@ -4525,81 +4331,71 @@ BOOL WINAPI Py_DeleteFileW(LPCWSTR lpFileName) } #endif /* MS_WINDOWS */ -PyDoc_STRVAR(posix_unlink__doc__, -"unlink(path, *, dir_fd=None)\n\n\ -Remove a file (same as remove()).\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 implemented on your platform.\n\ - If it is unavailable, using it will raise a NotImplementedError."); -PyDoc_STRVAR(posix_remove__doc__, -"remove(path, *, dir_fd=None)\n\n\ -Remove a file (same as unlink()).\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 implemented on your platform.\n\ - If it is unavailable, using it will raise a NotImplementedError."); +/*[clinic input] +os.unlink + + path: path_t + * + dir_fd: dir_fd(requires='unlinkat')=None + +Remove a file (same as remove()). + +If dir_fd is 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. +dir_fd may not be implemented on your platform. + If it is unavailable, using it will raise a NotImplementedError. + +[clinic start generated code]*/ static PyObject * -posix_unlink(PyObject *self, PyObject *args, PyObject *kwargs) +os_unlink_impl(PyModuleDef *module, path_t *path, int dir_fd) +/*[clinic end generated code: output=474afd5cd09b237e input=d7bcde2b1b2a2552]*/ { - path_t path; - int dir_fd = DEFAULT_DIR_FD; - static char *keywords[] = {"path", "dir_fd", NULL}; int result; - PyObject *return_value = NULL; - - memset(&path, 0, sizeof(path)); - path.function_name = "unlink"; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:unlink", keywords, - path_converter, &path, -#ifdef HAVE_UNLINKAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd -#endif - )) - return NULL; Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS - if (path.wide) - result = Py_DeleteFileW(path.wide); + if (path->wide) + result = Py_DeleteFileW(path->wide); else - result = DeleteFileA(path.narrow); + result = DeleteFileA(path->narrow); result = !result; /* Windows, success=1, UNIX, success=0 */ #else #ifdef HAVE_UNLINKAT if (dir_fd != DEFAULT_DIR_FD) - result = unlinkat(dir_fd, path.narrow, 0); + result = unlinkat(dir_fd, path->narrow, 0); else #endif /* HAVE_UNLINKAT */ - result = unlink(path.narrow); + result = unlink(path->narrow); #endif Py_END_ALLOW_THREADS - if (result) { - return_value = path_error(&path); - goto exit; - } - - return_value = Py_None; - Py_INCREF(Py_None); + if (result) + return path_error(path); -exit: - path_cleanup(&path); - return return_value; + Py_RETURN_NONE; } -PyDoc_STRVAR(posix_uname__doc__, -"uname() -> uname_result\n\n\ -Return an object identifying the current operating system.\n\ -The object behaves like a named tuple with the following fields:\n\ - (sysname, nodename, release, version, machine)"); +/*[clinic input] +os.remove = os.unlink + +Remove a file (same as unlink()). + +If dir_fd is 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. +dir_fd may not be implemented on your platform. + If it is unavailable, using it will raise a NotImplementedError. +[clinic start generated code]*/ + +static PyObject * +os_remove_impl(PyModuleDef *module, path_t *path, int dir_fd) +/*[clinic end generated code: output=d0d5149e64832b9e input=e05c5ab55cd30983]*/ +{ + return os_unlink_impl(module, path, dir_fd); +} + static PyStructSequence_Field uname_result_fields[] = { {"sysname", "operating system name"}, @@ -4629,8 +4425,19 @@ static PyTypeObject UnameResultType; #ifdef HAVE_UNAME +/*[clinic input] +os.uname + +Return an object identifying the current operating system. + +The object behaves like a named tuple with the following fields: + (sysname, nodename, release, version, machine) + +[clinic start generated code]*/ + static PyObject * -posix_uname(PyObject *self, PyObject *noargs) +os_uname_impl(PyModuleDef *module) +/*[clinic end generated code: output=01e1421b757e753f input=e68bd246db3043ed]*/ { struct utsname u; int res; @@ -4669,31 +4476,6 @@ posix_uname(PyObject *self, PyObject *noargs) #endif /* HAVE_UNAME */ -PyDoc_STRVAR(posix_utime__doc__, -"utime(path, times=None, *, ns=None, dir_fd=None, follow_symlinks=True)\n\ -Set the access and modified time of path.\n\ -\n\ -path may always be specified as a string.\n\ -On some platforms, path may also be specified as an open file descriptor.\n\ - If this functionality is unavailable, using it raises an exception.\n\ -\n\ -If times is not None, it must be a tuple (atime, mtime);\n\ - atime and mtime should be expressed as float seconds since the epoch.\n\ -If ns is not None, it must be a tuple (atime_ns, mtime_ns);\n\ - atime_ns and mtime_ns should be expressed as integer nanoseconds\n\ - since the epoch.\n\ -If both times and ns are None, utime uses the current time.\n\ -Specifying tuples for both times and ns is an error.\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 follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, utime will modify 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\n\ - as an open file descriptor.\n\ -dir_fd and follow_symlinks may not be available on your platform.\n\ - If they are unavailable, using them will raise a NotImplementedError."); typedef struct { int now; @@ -4779,6 +4561,9 @@ utime_dir_fd(utime_t *ut, int dir_fd, char *path, int follow_symlinks) #endif } + #define FUTIMENSAT_DIR_FD_CONVERTER dir_fd_converter +#else + #define FUTIMENSAT_DIR_FD_CONVERTER dir_fd_unavailable #endif #define UTIME_HAVE_FD (defined(HAVE_FUTIMES) || defined(HAVE_FUTIMENS)) @@ -4797,6 +4582,9 @@ utime_fd(utime_t *ut, int fd) #endif } + #define PATH_UTIME_HAVE_FD 1 +#else + #define PATH_UTIME_HAVE_FD 0 #endif @@ -4862,19 +4650,49 @@ exit: return result; } -static PyObject * -posix_utime(PyObject *self, PyObject *args, PyObject *kwargs) -{ - path_t path; - PyObject *times = NULL; - PyObject *ns = NULL; - int dir_fd = DEFAULT_DIR_FD; - int follow_symlinks = 1; - char *keywords[] = {"path", "times", "ns", "dir_fd", - "follow_symlinks", NULL}; - utime_t utime; +/*[clinic input] +os.utime + path: path_t(allow_fd='PATH_UTIME_HAVE_FD') + times: object = NULL + * + ns: object = NULL + dir_fd: dir_fd(requires='futimensat') = None + follow_symlinks: bool=True + +# "utime(path, times=None, *, ns=None, dir_fd=None, follow_symlinks=True)\n\ + +Set the access and modified time of path. + +path may always be specified as a string. +On some platforms, path may also be specified as an open file descriptor. + If this functionality is unavailable, using it raises an exception. + +If times is not None, it must be a tuple (atime, mtime); + atime and mtime should be expressed as float seconds since the epoch. +If ns is not None, it must be a tuple (atime_ns, mtime_ns); + atime_ns and mtime_ns should be expressed as integer nanoseconds + since the epoch. +If both times and ns are None, utime uses the current time. +Specifying tuples for both times and ns is an error. + +If dir_fd is 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. +If follow_symlinks is False, and the last element of the path is a symbolic + link, utime will modify the symbolic link itself instead of the file the + link points to. +It is an error to use dir_fd or follow_symlinks when specifying path + as an open file descriptor. +dir_fd and follow_symlinks may not be available on your platform. + If they are unavailable, using them will raise a NotImplementedError. + +[clinic start generated code]*/ + +static PyObject * +os_utime_impl(PyModuleDef *module, path_t *path, PyObject *times, PyObject *ns, int dir_fd, int follow_symlinks) +/*[clinic end generated code: output=c52d8fd0d1067f0b input=1f18c17d5941aa82]*/ +{ #ifdef MS_WINDOWS HANDLE hFile; FILETIME atime, mtime; @@ -4883,25 +4701,9 @@ posix_utime(PyObject *self, PyObject *args, PyObject *kwargs) #endif PyObject *return_value = NULL; + utime_t utime; - memset(&path, 0, sizeof(path)); - path.function_name = "utime"; memset(&utime, 0, sizeof(utime_t)); -#if UTIME_HAVE_FD - path.allow_fd = 1; -#endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O&|O$OO&p:utime", keywords, - path_converter, &path, - ×, &ns, -#if UTIME_HAVE_DIR_FD - dir_fd_converter, &dir_fd, -#else - dir_fd_unavailable, &dir_fd, -#endif - &follow_symlinks - )) - return NULL; if (times && (times != Py_None) && ns) { PyErr_SetString(PyExc_ValueError, @@ -4921,9 +4723,9 @@ posix_utime(PyObject *self, PyObject *args, PyObject *kwargs) } utime.now = 0; if (_PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 0), - &a_sec, &a_nsec, _PyTime_ROUND_DOWN) == -1 || + &a_sec, &a_nsec, _PyTime_ROUND_FLOOR) == -1 || _PyTime_ObjectToTimespec(PyTuple_GET_ITEM(times, 1), - &m_sec, &m_nsec, _PyTime_ROUND_DOWN) == -1) { + &m_sec, &m_nsec, _PyTime_ROUND_FLOOR) == -1) { goto exit; } utime.atime_s = a_sec; @@ -4955,9 +4757,9 @@ posix_utime(PyObject *self, PyObject *args, PyObject *kwargs) goto exit; #endif - if (path_and_dir_fd_invalid("utime", &path, dir_fd) || - dir_fd_and_fd_invalid("utime", dir_fd, path.fd) || - fd_and_follow_symlinks_invalid("utime", path.fd, follow_symlinks)) + if (path_and_dir_fd_invalid("utime", path, dir_fd) || + dir_fd_and_fd_invalid("utime", dir_fd, path->fd) || + fd_and_follow_symlinks_invalid("utime", path->fd, follow_symlinks)) goto exit; #if !defined(HAVE_UTIMENSAT) @@ -4971,17 +4773,17 @@ posix_utime(PyObject *self, PyObject *args, PyObject *kwargs) #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS - if (path.wide) - hFile = CreateFileW(path.wide, FILE_WRITE_ATTRIBUTES, 0, + if (path->wide) + hFile = CreateFileW(path->wide, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); else - hFile = CreateFileA(path.narrow, FILE_WRITE_ATTRIBUTES, 0, + hFile = CreateFileA(path->narrow, FILE_WRITE_ATTRIBUTES, 0, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL); Py_END_ALLOW_THREADS if (hFile == INVALID_HANDLE_VALUE) { - path_error(&path); + path_error(path); goto exit; } @@ -4990,8 +4792,8 @@ posix_utime(PyObject *self, PyObject *args, PyObject *kwargs) atime = mtime; } else { - time_t_to_FILE_TIME(utime.atime_s, utime.atime_ns, &atime); - time_t_to_FILE_TIME(utime.mtime_s, utime.mtime_ns, &mtime); + _Py_time_t_to_FILE_TIME(utime.atime_s, utime.atime_ns, &atime); + _Py_time_t_to_FILE_TIME(utime.mtime_s, utime.mtime_ns, &mtime); } if (!SetFileTime(hFile, NULL, &atime, &mtime)) { /* Avoid putting the file name into the error here, @@ -5006,23 +4808,23 @@ posix_utime(PyObject *self, PyObject *args, PyObject *kwargs) #if UTIME_HAVE_NOFOLLOW_SYMLINKS if ((!follow_symlinks) && (dir_fd == DEFAULT_DIR_FD)) - result = utime_nofollow_symlinks(&utime, path.narrow); + result = utime_nofollow_symlinks(&utime, path->narrow); else #endif #if UTIME_HAVE_DIR_FD if ((dir_fd != DEFAULT_DIR_FD) || (!follow_symlinks)) - result = utime_dir_fd(&utime, dir_fd, path.narrow, follow_symlinks); + result = utime_dir_fd(&utime, dir_fd, path->narrow, follow_symlinks); else #endif #if UTIME_HAVE_FD - if (path.fd != -1) - result = utime_fd(&utime, path.fd); + if (path->fd != -1) + result = utime_fd(&utime, path->fd); else #endif - result = utime_default(&utime, path.narrow); + result = utime_default(&utime, path->narrow); Py_END_ALLOW_THREADS @@ -5038,7 +4840,6 @@ posix_utime(PyObject *self, PyObject *args, PyObject *kwargs) return_value = Py_None; exit: - path_cleanup(&path); #ifdef MS_WINDOWS if (hFile != INVALID_HANDLE_VALUE) CloseHandle(hFile); @@ -5048,17 +4849,20 @@ exit: /* Process operations */ -PyDoc_STRVAR(posix__exit__doc__, -"_exit(status)\n\n\ -Exit to the system with specified status, without normal exit processing."); + +/*[clinic input] +os._exit + + status: int + +Exit to the system with specified status, without normal exit processing. +[clinic start generated code]*/ static PyObject * -posix__exit(PyObject *self, PyObject *args) +os__exit_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=472a3cbaf68f3621 input=5e6d57556b0c4a62]*/ { - int sts; - if (!PyArg_ParseTuple(args, "i:_exit", &sts)) - return NULL; - _exit(sts); + _exit(status); return NULL; /* Make gcc -Wall happy */ } @@ -5196,96 +5000,82 @@ fail: } #endif + #ifdef HAVE_EXECV -PyDoc_STRVAR(posix_execv__doc__, -"execv(path, args)\n\n\ -Execute an executable path with arguments, replacing current process.\n\ -\n\ - path: path of executable file\n\ - args: tuple or list of strings"); +/*[clinic input] +os.execv + + path: FSConverter + Path of executable file. + argv: object + Tuple or list of strings. + / + +Execute an executable path with arguments, replacing current process. +[clinic start generated code]*/ static PyObject * -posix_execv(PyObject *self, PyObject *args) +os_execv_impl(PyModuleDef *module, PyObject *path, PyObject *argv) +/*[clinic end generated code: output=9221f08143146fff input=96041559925e5229]*/ { - PyObject *opath; - char *path; - PyObject *argv; + char *path_char; char **argvlist; Py_ssize_t argc; /* execv has two arguments: (path, argv), where argv is a list or tuple of strings. */ - if (!PyArg_ParseTuple(args, "O&O:execv", - PyUnicode_FSConverter, - &opath, &argv)) - return NULL; - path = PyBytes_AsString(opath); + path_char = PyBytes_AsString(path); if (!PyList_Check(argv) && !PyTuple_Check(argv)) { PyErr_SetString(PyExc_TypeError, "execv() arg 2 must be a tuple or list"); - Py_DECREF(opath); return NULL; } argc = PySequence_Size(argv); if (argc < 1) { PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty"); - Py_DECREF(opath); return NULL; } argvlist = parse_arglist(argv, &argc); if (argvlist == NULL) { - Py_DECREF(opath); return NULL; } - execv(path, argvlist); + execv(path_char, argvlist); /* If we get here it's definitely an error */ free_string_array(argvlist, argc); - Py_DECREF(opath); return posix_error(); } -PyDoc_STRVAR(posix_execve__doc__, -"execve(path, args, env)\n\n\ -Execute a path with arguments and environment, replacing current process.\n\ -\n\ - path: path of executable file\n\ - args: tuple or list of arguments\n\ - env: dictionary of strings mapping to strings\n\ -\n\ -On some platforms, you may specify an open file descriptor for path;\n\ - execve will execute the program the file descriptor is open to.\n\ - If this functionality is unavailable, using it raises NotImplementedError."); + +/*[clinic input] +os.execve + + path: path_t(allow_fd='PATH_HAVE_FEXECVE') + Path of executable file. + argv: object + Tuple or list of strings. + env: object + Dictionary of strings mapping to strings. + +Execute an executable path with arguments, replacing current process. +[clinic start generated code]*/ static PyObject * -posix_execve(PyObject *self, PyObject *args, PyObject *kwargs) +os_execve_impl(PyModuleDef *module, path_t *path, PyObject *argv, PyObject *env) +/*[clinic end generated code: output=7758d4f230d8aac6 input=626804fa092606d9]*/ { - path_t path; - PyObject *argv, *env; char **argvlist = NULL; char **envlist; Py_ssize_t argc, envc; - static char *keywords[] = {"path", "argv", "environment", NULL}; /* execve has three arguments: (path, argv, env), where argv is a list or tuple of strings and env is a dictionary like posix.environ. */ - memset(&path, 0, sizeof(path)); - path.function_name = "execve"; -#ifdef HAVE_FEXECVE - path.allow_fd = 1; -#endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&OO:execve", keywords, - path_converter, &path, - &argv, &env - )) - return NULL; - if (!PyList_Check(argv) && !PyTuple_Check(argv)) { PyErr_SetString(PyExc_TypeError, "execve: argv must be a tuple or list"); @@ -5308,15 +5098,15 @@ posix_execve(PyObject *self, PyObject *args, PyObject *kwargs) goto fail; #ifdef HAVE_FEXECVE - if (path.fd > -1) - fexecve(path.fd, argvlist, envlist); + if (path->fd > -1) + fexecve(path->fd, argvlist, envlist); else #endif - execve(path.narrow, argvlist, envlist); + execve(path->narrow, argvlist, envlist); /* If we get here it's definitely an error */ - path_error(&path); + path_error(path); while (--envc >= 0) PyMem_DEL(envlist[envc]); @@ -5324,29 +5114,33 @@ posix_execve(PyObject *self, PyObject *args, PyObject *kwargs) fail: if (argvlist) free_string_array(argvlist, argc); - path_cleanup(&path); return NULL; } #endif /* HAVE_EXECV */ #ifdef HAVE_SPAWNV -PyDoc_STRVAR(posix_spawnv__doc__, -"spawnv(mode, path, args)\n\n\ -Execute the program 'path' in a new process.\n\ -\n\ - mode: mode of process creation\n\ - path: path of executable file\n\ - args: tuple or list of strings"); +/*[clinic input] +os.spawnv + + mode: int + Mode of process creation. + path: FSConverter + Path of executable file. + argv: object + Tuple or list of strings. + / + +Execute the program specified by path in a new process. +[clinic start generated code]*/ static PyObject * -posix_spawnv(PyObject *self, PyObject *args) +os_spawnv_impl(PyModuleDef *module, int mode, PyObject *path, PyObject *argv) +/*[clinic end generated code: output=140a7945484c8cc5 input=042c91dfc1e6debc]*/ { - PyObject *opath; - char *path; - PyObject *argv; + char *path_char; char **argvlist; - int mode, i; + int i; Py_ssize_t argc; Py_intptr_t spawnval; PyObject *(*getitem)(PyObject *, Py_ssize_t); @@ -5354,11 +5148,7 @@ posix_spawnv(PyObject *self, PyObject *args) /* spawnv has three arguments: (mode, path, argv), where argv is a list or tuple of strings. */ - if (!PyArg_ParseTuple(args, "iO&O:spawnv", &mode, - PyUnicode_FSConverter, - &opath, &argv)) - return NULL; - path = PyBytes_AsString(opath); + path_char = PyBytes_AsString(path); if (PyList_Check(argv)) { argc = PyList_Size(argv); getitem = PyList_GetItem; @@ -5370,13 +5160,11 @@ posix_spawnv(PyObject *self, PyObject *args) else { PyErr_SetString(PyExc_TypeError, "spawnv() arg 2 must be a tuple or list"); - Py_DECREF(opath); return NULL; } argvlist = PyMem_NEW(char *, argc+1); if (argvlist == NULL) { - Py_DECREF(opath); return PyErr_NoMemory(); } for (i = 0; i < argc; i++) { @@ -5386,7 +5174,6 @@ posix_spawnv(PyObject *self, PyObject *args) PyErr_SetString( PyExc_TypeError, "spawnv() arg 2 must contain only strings"); - Py_DECREF(opath); return NULL; } } @@ -5396,11 +5183,10 @@ posix_spawnv(PyObject *self, PyObject *args) mode = _P_OVERLAY; Py_BEGIN_ALLOW_THREADS - spawnval = _spawnv(mode, path, argvlist); + spawnval = _spawnv(mode, path_char, argvlist); Py_END_ALLOW_THREADS free_string_array(argvlist, argc); - Py_DECREF(opath); if (spawnval == -1) return posix_error(); @@ -5409,25 +5195,30 @@ posix_spawnv(PyObject *self, PyObject *args) } -PyDoc_STRVAR(posix_spawnve__doc__, -"spawnve(mode, path, args, env)\n\n\ -Execute the program 'path' in a new process.\n\ -\n\ - mode: mode of process creation\n\ - path: path of executable file\n\ - args: tuple or list of arguments\n\ - env: dictionary of strings mapping to strings"); +/*[clinic input] +os.spawnve + + mode: int + Mode of process creation. + path: FSConverter + Path of executable file. + argv: object + Tuple or list of strings. + env: object + Dictionary of strings mapping to strings. + / + +Execute the program specified by path in a new process. +[clinic start generated code]*/ static PyObject * -posix_spawnve(PyObject *self, PyObject *args) +os_spawnve_impl(PyModuleDef *module, int mode, PyObject *path, PyObject *argv, PyObject *env) +/*[clinic end generated code: output=1c52955789461be8 input=02362fd937963f8f]*/ { - PyObject *opath; - char *path; - PyObject *argv, *env; + char *path_char; char **argvlist; char **envlist; PyObject *res = NULL; - int mode; Py_ssize_t argc, i, envc; Py_intptr_t spawnval; PyObject *(*getitem)(PyObject *, Py_ssize_t); @@ -5437,11 +5228,7 @@ posix_spawnve(PyObject *self, PyObject *args) argv is a list or tuple of strings and env is a dictionary like posix.environ. */ - if (!PyArg_ParseTuple(args, "iO&OO:spawnve", &mode, - PyUnicode_FSConverter, - &opath, &argv, &env)) - return NULL; - path = PyBytes_AsString(opath); + path_char = PyBytes_AsString(path); if (PyList_Check(argv)) { argc = PyList_Size(argv); getitem = PyList_GetItem; @@ -5485,7 +5272,7 @@ posix_spawnve(PyObject *self, PyObject *args) mode = _P_OVERLAY; Py_BEGIN_ALLOW_THREADS - spawnval = _spawnve(mode, path, argvlist, envlist); + spawnval = _spawnve(mode, path_char, argvlist, envlist); Py_END_ALLOW_THREADS if (spawnval == -1) @@ -5499,7 +5286,6 @@ posix_spawnve(PyObject *self, PyObject *args) fail_1: free_string_array(argvlist, lastarg); fail_0: - Py_DECREF(opath); return res; } @@ -5507,14 +5293,17 @@ posix_spawnve(PyObject *self, PyObject *args) #ifdef HAVE_FORK1 -PyDoc_STRVAR(posix_fork1__doc__, -"fork1() -> pid\n\n\ -Fork a child process with a single multiplexed (i.e., not bound) thread.\n\ -\n\ -Return 0 to child process and PID of child to parent process."); +/*[clinic input] +os.fork1 + +Fork a child process with a single multiplexed (i.e., not bound) thread. + +Return 0 to child process and PID of child to parent process. +[clinic start generated code]*/ static PyObject * -posix_fork1(PyObject *self, PyObject *noargs) +os_fork1_impl(PyModuleDef *module) +/*[clinic end generated code: output=e27b4f66419c9dcf input=12db02167893926e]*/ { pid_t pid; int result = 0; @@ -5537,17 +5326,21 @@ posix_fork1(PyObject *self, PyObject *noargs) } return PyLong_FromPid(pid); } -#endif +#endif /* HAVE_FORK1 */ #ifdef HAVE_FORK -PyDoc_STRVAR(posix_fork__doc__, -"fork() -> pid\n\n\ -Fork a child process.\n\ -Return 0 to child process and PID of child to parent process."); +/*[clinic input] +os.fork + +Fork a child process. + +Return 0 to child process and PID of child to parent process. +[clinic start generated code]*/ static PyObject * -posix_fork(PyObject *self, PyObject *noargs) +os_fork_impl(PyModuleDef *module) +/*[clinic end generated code: output=898b1ecd3498ba12 input=13c956413110eeaa]*/ { pid_t pid; int result = 0; @@ -5570,92 +5363,106 @@ posix_fork(PyObject *self, PyObject *noargs) } return PyLong_FromPid(pid); } -#endif +#endif /* HAVE_FORK */ -#ifdef HAVE_SCHED_H +#ifdef HAVE_SCHED_H #ifdef HAVE_SCHED_GET_PRIORITY_MAX +/*[clinic input] +os.sched_get_priority_max + + policy: int -PyDoc_STRVAR(posix_sched_get_priority_max__doc__, -"sched_get_priority_max(policy)\n\n\ -Get the maximum scheduling priority for *policy*."); +Get the maximum scheduling priority for policy. +[clinic start generated code]*/ static PyObject * -posix_sched_get_priority_max(PyObject *self, PyObject *args) +os_sched_get_priority_max_impl(PyModuleDef *module, int policy) +/*[clinic end generated code: output=a6a30fa5071f2d81 input=2097b7998eca6874]*/ { - int policy, max; + int max; - if (!PyArg_ParseTuple(args, "i:sched_get_priority_max", &policy)) - return NULL; max = sched_get_priority_max(policy); if (max < 0) return posix_error(); return PyLong_FromLong(max); } -PyDoc_STRVAR(posix_sched_get_priority_min__doc__, -"sched_get_priority_min(policy)\n\n\ -Get the minimum scheduling priority for *policy*."); + +/*[clinic input] +os.sched_get_priority_min + + policy: int + +Get the minimum scheduling priority for policy. +[clinic start generated code]*/ static PyObject * -posix_sched_get_priority_min(PyObject *self, PyObject *args) +os_sched_get_priority_min_impl(PyModuleDef *module, int policy) +/*[clinic end generated code: output=5ca3ed6bc43e9b20 input=21bc8fa0d70983bf]*/ { - int policy, min; - - if (!PyArg_ParseTuple(args, "i:sched_get_priority_min", &policy)) - return NULL; - min = sched_get_priority_min(policy); + int min = sched_get_priority_min(policy); if (min < 0) return posix_error(); return PyLong_FromLong(min); } - #endif /* HAVE_SCHED_GET_PRIORITY_MAX */ + #ifdef HAVE_SCHED_SETSCHEDULER +/*[clinic input] +os.sched_getscheduler + pid: pid_t + / -PyDoc_STRVAR(posix_sched_getscheduler__doc__, -"sched_getscheduler(pid)\n\n\ -Get the scheduling policy for the process with a PID of *pid*.\n\ -Passing a PID of 0 returns the scheduling policy for the calling process."); +Get the scheduling policy for the process identifiedy by pid. + +Passing 0 for pid returns the scheduling policy for the calling process. +[clinic start generated code]*/ static PyObject * -posix_sched_getscheduler(PyObject *self, PyObject *args) +os_sched_getscheduler_impl(PyModuleDef *module, pid_t pid) +/*[clinic end generated code: output=8cd63c15caf54fa9 input=5f14cfd1f189e1a0]*/ { - pid_t pid; int policy; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_getscheduler", &pid)) - return NULL; policy = sched_getscheduler(pid); if (policy < 0) return posix_error(); return PyLong_FromLong(policy); } +#endif /* HAVE_SCHED_SETSCHEDULER */ -#endif #if defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SCHED_SETPARAM) +/*[clinic input] +class os.sched_param "PyObject *" "&SchedParamType" + +@classmethod +os.sched_param.__new__ + + sched_priority: object + A scheduling parameter. + +Current has only one field: sched_priority"); +[clinic start generated code]*/ static PyObject * -sched_param_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +os_sched_param_impl(PyTypeObject *type, PyObject *sched_priority) +/*[clinic end generated code: output=48f4067d60f48c13 input=73a4c22f7071fc62]*/ { - PyObject *res, *priority; - static char *kwlist[] = {"sched_priority", NULL}; + PyObject *res; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:sched_param", kwlist, &priority)) - return NULL; res = PyStructSequence_New(type); if (!res) return NULL; - Py_INCREF(priority); - PyStructSequence_SET_ITEM(res, 0, priority); + Py_INCREF(sched_priority); + PyStructSequence_SET_ITEM(res, 0, sched_priority); return res; } -PyDoc_STRVAR(sched_param__doc__, -"sched_param(sched_priority): A scheduling parameter.\n\n\ -Current has only one field: sched_priority"); + +PyDoc_VAR(os_sched_param__doc__); static PyStructSequence_Field sched_param_fields[] = { {"sched_priority", "the scheduling priority"}, @@ -5664,7 +5471,7 @@ static PyStructSequence_Field sched_param_fields[] = { static PyStructSequence_Desc sched_param_desc = { "sched_param", /* name */ - sched_param__doc__, /* doc */ + os_sched_param__doc__, /* doc */ sched_param_fields, 1 }; @@ -5688,118 +5495,132 @@ convert_sched_param(PyObject *param, struct sched_param *res) res->sched_priority = Py_SAFE_DOWNCAST(priority, long, int); return 1; } +#endif /* defined(HAVE_SCHED_SETSCHEDULER) || defined(HAVE_SCHED_SETPARAM) */ -#endif #ifdef HAVE_SCHED_SETSCHEDULER +/*[clinic input] +os.sched_setscheduler -PyDoc_STRVAR(posix_sched_setscheduler__doc__, -"sched_setscheduler(pid, policy, param)\n\n\ -Set the scheduling policy, *policy*, for *pid*.\n\ -If *pid* is 0, the calling process is changed.\n\ -*param* is an instance of sched_param."); + pid: pid_t + policy: int + param: sched_param + / -static PyObject * -posix_sched_setscheduler(PyObject *self, PyObject *args) -{ - pid_t pid; - int policy; - struct sched_param param; +Set the scheduling policy for the process identified by pid. - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "iO&:sched_setscheduler", - &pid, &policy, &convert_sched_param, ¶m)) - return NULL; +If pid is 0, the calling process is changed. +param is an instance of sched_param. +[clinic start generated code]*/ +static PyObject * +os_sched_setscheduler_impl(PyModuleDef *module, pid_t pid, int policy, struct sched_param *param) +/*[clinic end generated code: output=97f40f8384e554b0 input=c581f9469a5327dd]*/ +{ /* ** sched_setscheduler() returns 0 in Linux, but the previous ** scheduling policy under Solaris/Illumos, and others. ** On error, -1 is returned in all Operating Systems. */ - if (sched_setscheduler(pid, policy, ¶m) == -1) + if (sched_setscheduler(pid, policy, param) == -1) return posix_error(); Py_RETURN_NONE; } +#endif /* HAVE_SCHED_SETSCHEDULER*/ -#endif #ifdef HAVE_SCHED_SETPARAM +/*[clinic input] +os.sched_getparam + pid: pid_t + / + +Returns scheduling parameters for the process identified by pid. -PyDoc_STRVAR(posix_sched_getparam__doc__, -"sched_getparam(pid) -> sched_param\n\n\ -Returns scheduling parameters for the process with *pid* as an instance of the\n\ -sched_param class. A PID of 0 means the calling process."); +If pid is 0, returns parameters for the calling process. +Return value is an instance of sched_param. +[clinic start generated code]*/ static PyObject * -posix_sched_getparam(PyObject *self, PyObject *args) +os_sched_getparam_impl(PyModuleDef *module, pid_t pid) +/*[clinic end generated code: output=f42c5bd2604ecd08 input=18a1ef9c2efae296]*/ { - pid_t pid; struct sched_param param; - PyObject *res, *priority; + PyObject *result; + PyObject *priority; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_getparam", &pid)) - return NULL; if (sched_getparam(pid, ¶m)) return posix_error(); - res = PyStructSequence_New(&SchedParamType); - if (!res) + result = PyStructSequence_New(&SchedParamType); + if (!result) return NULL; priority = PyLong_FromLong(param.sched_priority); if (!priority) { - Py_DECREF(res); + Py_DECREF(result); return NULL; } - PyStructSequence_SET_ITEM(res, 0, priority); - return res; + PyStructSequence_SET_ITEM(result, 0, priority); + return result; } -PyDoc_STRVAR(posix_sched_setparam__doc__, -"sched_setparam(pid, param)\n\n\ -Set scheduling parameters for a process with PID *pid*.\n\ -A PID of 0 means the calling process."); + +/*[clinic input] +os.sched_setparam + pid: pid_t + param: sched_param + / + +Set scheduling parameters for the process identified by pid. + +If pid is 0, sets parameters for the calling process. +param should be an instance of sched_param. +[clinic start generated code]*/ static PyObject * -posix_sched_setparam(PyObject *self, PyObject *args) +os_sched_setparam_impl(PyModuleDef *module, pid_t pid, struct sched_param *param) +/*[clinic end generated code: output=c6560b34395bb343 input=6b8d6dfcecdc21bd]*/ { - pid_t pid; - struct sched_param param; - - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O&:sched_setparam", - &pid, &convert_sched_param, ¶m)) - return NULL; - if (sched_setparam(pid, ¶m)) + if (sched_setparam(pid, param)) return posix_error(); Py_RETURN_NONE; } +#endif /* HAVE_SCHED_SETPARAM */ -#endif #ifdef HAVE_SCHED_RR_GET_INTERVAL +/*[clinic input] +os.sched_rr_get_interval -> double + pid: pid_t + / -PyDoc_STRVAR(posix_sched_rr_get_interval__doc__, -"sched_rr_get_interval(pid) -> float\n\n\ -Return the round-robin quantum for the process with PID *pid* in seconds."); +Return the round-robin quantum for the process identified by pid, in seconds. -static PyObject * -posix_sched_rr_get_interval(PyObject *self, PyObject *args) +Value returned is a float. +[clinic start generated code]*/ + +static double +os_sched_rr_get_interval_impl(PyModuleDef *module, pid_t pid) +/*[clinic end generated code: output=7adc137a86dea581 input=2a973da15cca6fae]*/ { - pid_t pid; struct timespec interval; - - if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_rr_get_interval", &pid)) - return NULL; - if (sched_rr_get_interval(pid, &interval)) - return posix_error(); - return PyFloat_FromDouble((double)interval.tv_sec + 1e-9*interval.tv_nsec); + if (sched_rr_get_interval(pid, &interval)) { + posix_error(); + return -1.0; + } + return (double)interval.tv_sec + 1e-9*interval.tv_nsec; } +#endif /* HAVE_SCHED_RR_GET_INTERVAL */ -#endif -PyDoc_STRVAR(posix_sched_yield__doc__, -"sched_yield()\n\n\ -Voluntarily relinquish the CPU."); +/*[clinic input] +os.sched_yield + +Voluntarily relinquish the CPU. +[clinic start generated code]*/ static PyObject * -posix_sched_yield(PyObject *self, PyObject *noargs) +os_sched_yield_impl(PyModuleDef *module) +/*[clinic end generated code: output=d7bd51869c4cb6a8 input=e54d6f98189391d4]*/ { if (sched_yield()) return posix_error(); @@ -5807,39 +5628,41 @@ posix_sched_yield(PyObject *self, PyObject *noargs) } #ifdef HAVE_SCHED_SETAFFINITY - /* The minimum number of CPUs allocated in a cpu_set_t */ static const int NCPUS_START = sizeof(unsigned long) * CHAR_BIT; -PyDoc_STRVAR(posix_sched_setaffinity__doc__, -"sched_setaffinity(pid, cpu_set)\n\n\ -Set the affinity of the process with PID *pid* to *cpu_set*."); +/*[clinic input] +os.sched_setaffinity + pid: pid_t + mask : object + / + +Set the CPU affinity of the process identified by pid to mask. + +mask should be an iterable of integers identifying CPUs. +[clinic start generated code]*/ static PyObject * -posix_sched_setaffinity(PyObject *self, PyObject *args) +os_sched_setaffinity_impl(PyModuleDef *module, pid_t pid, PyObject *mask) +/*[clinic end generated code: output=582bcbf40d3253a9 input=a0791a597c7085ba]*/ { - pid_t pid; int ncpus; size_t setsize; - cpu_set_t *mask = NULL; - PyObject *iterable, *iterator = NULL, *item; + cpu_set_t *cpu_set = NULL; + PyObject *iterator = NULL, *item; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "O:sched_setaffinity", - &pid, &iterable)) - return NULL; - - iterator = PyObject_GetIter(iterable); + iterator = PyObject_GetIter(mask); if (iterator == NULL) return NULL; ncpus = NCPUS_START; setsize = CPU_ALLOC_SIZE(ncpus); - mask = CPU_ALLOC(ncpus); - if (mask == NULL) { + cpu_set = CPU_ALLOC(ncpus); + if (cpu_set == NULL) { PyErr_NoMemory(); goto error; } - CPU_ZERO_S(setsize, mask); + CPU_ZERO_S(setsize, cpu_set); while ((item = PyIter_Next(iterator))) { long cpu; @@ -5880,48 +5703,50 @@ posix_sched_setaffinity(PyObject *self, PyObject *args) } newsetsize = CPU_ALLOC_SIZE(newncpus); CPU_ZERO_S(newsetsize, newmask); - memcpy(newmask, mask, setsize); - CPU_FREE(mask); + memcpy(newmask, cpu_set, setsize); + CPU_FREE(cpu_set); setsize = newsetsize; - mask = newmask; + cpu_set = newmask; ncpus = newncpus; } - CPU_SET_S(cpu, setsize, mask); + CPU_SET_S(cpu, setsize, cpu_set); } Py_CLEAR(iterator); - if (sched_setaffinity(pid, setsize, mask)) { + if (sched_setaffinity(pid, setsize, cpu_set)) { posix_error(); goto error; } - CPU_FREE(mask); + CPU_FREE(cpu_set); Py_RETURN_NONE; error: - if (mask) - CPU_FREE(mask); + if (cpu_set) + CPU_FREE(cpu_set); Py_XDECREF(iterator); return NULL; } -PyDoc_STRVAR(posix_sched_getaffinity__doc__, -"sched_getaffinity(pid, ncpus) -> cpu_set\n\n\ -Return the affinity of the process with PID *pid*.\n\ -The returned cpu_set will be of size *ncpus*."); + +/*[clinic input] +os.sched_getaffinity + pid: pid_t + / + +Return the affinity of the process identified by pid. + +The affinity is returned as a set of CPU identifiers. +[clinic start generated code]*/ static PyObject * -posix_sched_getaffinity(PyObject *self, PyObject *args) +os_sched_getaffinity_impl(PyModuleDef *module, pid_t pid) +/*[clinic end generated code: output=b431a8f310e369e7 input=eaf161936874b8a1]*/ { - pid_t pid; int cpu, ncpus, count; size_t setsize; cpu_set_t *mask = NULL; PyObject *res = NULL; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":sched_getaffinity", - &pid)) - return NULL; - ncpus = NCPUS_START; while (1) { setsize = CPU_ALLOC_SIZE(ncpus); @@ -5971,6 +5796,7 @@ error: #endif /* HAVE_SCHED_H */ + /* AIX uses /dev/ptc but is otherwise the same as /dev/ptmx */ /* IRIX has both /dev/ptc and /dev/ptmx, use ptmx */ #if defined(HAVE_DEV_PTC) && !defined(HAVE_DEV_PTMX) @@ -5997,13 +5823,20 @@ error: #endif #endif /* defined(HAVE_OPENPTY) || defined(HAVE_FORKPTY) || defined(HAVE_DEV_PTMX */ + #if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) -PyDoc_STRVAR(posix_openpty__doc__, -"openpty() -> (master_fd, slave_fd)\n\n\ -Open a pseudo-terminal, returning open fd's for both master and slave end.\n"); +/*[clinic input] +os.openpty + +Open a pseudo-terminal. + +Return a tuple of (master_fd, slave_fd) containing open file descriptors +for both the master and slave ends. +[clinic start generated code]*/ static PyObject * -posix_openpty(PyObject *self, PyObject *noargs) +os_openpty_impl(PyModuleDef *module) +/*[clinic end generated code: output=358e571c1ba135ee input=f3d99fd99e762907]*/ { int master_fd = -1, slave_fd = -1; #ifndef HAVE_OPENPTY @@ -6034,7 +5867,7 @@ posix_openpty(PyObject *self, PyObject *noargs) slave_fd = _Py_open(slave_name, O_RDWR); if (slave_fd < 0) - goto posix_error; + goto error; #else master_fd = open(DEV_PTY_FILE, O_RDWR | O_NOCTTY); /* open master */ @@ -6062,8 +5895,8 @@ posix_openpty(PyObject *self, PyObject *noargs) goto posix_error; slave_fd = _Py_open(slave_name, O_RDWR | O_NOCTTY); /* open slave */ - if (slave_fd < 0) - goto posix_error; + if (slave_fd == -1) + goto error; if (_Py_set_inheritable(master_fd, 0, NULL) < 0) goto posix_error; @@ -6081,9 +5914,7 @@ posix_openpty(PyObject *self, PyObject *noargs) posix_error: posix_error(); -#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) error: -#endif if (master_fd != -1) close(master_fd); if (slave_fd != -1) @@ -6092,15 +5923,22 @@ error: } #endif /* defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) */ + #ifdef HAVE_FORKPTY -PyDoc_STRVAR(posix_forkpty__doc__, -"forkpty() -> (pid, master_fd)\n\n\ -Fork a new process with a new pseudo-terminal as controlling tty.\n\n\ -Like fork(), return 0 as pid to child process, and PID of child to parent.\n\ -To both, return fd of newly opened pseudo-terminal.\n"); +/*[clinic input] +os.forkpty + +Fork a new process with a new pseudo-terminal as controlling tty. + +Returns a tuple of (pid, master_fd). +Like fork(), return pid of 0 to the child process, +and pid of child to the parent process. +To both, return fd of newly opened pseudo-terminal. +[clinic start generated code]*/ static PyObject * -posix_forkpty(PyObject *self, PyObject *noargs) +os_forkpty_impl(PyModuleDef *module) +/*[clinic end generated code: output=a11b8391dce3cb57 input=f1f7f4bae3966010]*/ { int master_fd = -1, result = 0; pid_t pid; @@ -6124,59 +5962,73 @@ posix_forkpty(PyObject *self, PyObject *noargs) } return Py_BuildValue("(Ni)", PyLong_FromPid(pid), master_fd); } -#endif +#endif /* HAVE_FORKPTY */ #ifdef HAVE_GETEGID -PyDoc_STRVAR(posix_getegid__doc__, -"getegid() -> egid\n\n\ -Return the current process's effective group id."); +/*[clinic input] +os.getegid + +Return the current process's effective group id. +[clinic start generated code]*/ static PyObject * -posix_getegid(PyObject *self, PyObject *noargs) +os_getegid_impl(PyModuleDef *module) +/*[clinic end generated code: output=90f433a8c0b1d919 input=1596f79ad1107d5d]*/ { return _PyLong_FromGid(getegid()); } -#endif +#endif /* HAVE_GETEGID */ #ifdef HAVE_GETEUID -PyDoc_STRVAR(posix_geteuid__doc__, -"geteuid() -> euid\n\n\ -Return the current process's effective user id."); +/*[clinic input] +os.geteuid + +Return the current process's effective user id. +[clinic start generated code]*/ static PyObject * -posix_geteuid(PyObject *self, PyObject *noargs) +os_geteuid_impl(PyModuleDef *module) +/*[clinic end generated code: output=1a532c4a66874357 input=4644c662d3bd9f19]*/ { return _PyLong_FromUid(geteuid()); } -#endif +#endif /* HAVE_GETEUID */ #ifdef HAVE_GETGID -PyDoc_STRVAR(posix_getgid__doc__, -"getgid() -> gid\n\n\ -Return the current process's group id."); +/*[clinic input] +os.getgid + +Return the current process's group id. +[clinic start generated code]*/ static PyObject * -posix_getgid(PyObject *self, PyObject *noargs) +os_getgid_impl(PyModuleDef *module) +/*[clinic end generated code: output=91a22021b74ea46b input=58796344cd87c0f6]*/ { return _PyLong_FromGid(getgid()); } -#endif +#endif /* HAVE_GETGID */ -PyDoc_STRVAR(posix_getpid__doc__, -"getpid() -> pid\n\n\ -Return the current process id"); +/*[clinic input] +os.getpid + +Return the current process id. +[clinic start generated code]*/ static PyObject * -posix_getpid(PyObject *self, PyObject *noargs) +os_getpid_impl(PyModuleDef *module) +/*[clinic end generated code: output=8fbf3a934ee09e62 input=5a9a00f0ab68aa00]*/ { return PyLong_FromPid(getpid()); } #ifdef HAVE_GETGROUPLIST + +/* AC 3.5: funny apple logic below */ PyDoc_STRVAR(posix_getgrouplist__doc__, "getgrouplist(user, group) -> list of groups to which a user belongs\n\n\ Returns a list of groups to which a user belongs.\n\n\ @@ -6249,15 +6101,19 @@ posix_getgrouplist(PyObject *self, PyObject *args) return list; } -#endif +#endif /* HAVE_GETGROUPLIST */ + #ifdef HAVE_GETGROUPS -PyDoc_STRVAR(posix_getgroups__doc__, -"getgroups() -> list of group IDs\n\n\ -Return list of supplemental group IDs for the process."); +/*[clinic input] +os.getgroups + +Return list of supplemental group IDs for the process. +[clinic start generated code]*/ static PyObject * -posix_getgroups(PyObject *self, PyObject *noargs) +os_getgroups_impl(PyModuleDef *module) +/*[clinic end generated code: output=6e7c4fd2db6d5c60 input=d3f109412e6a155c]*/ { PyObject *result = NULL; @@ -6356,7 +6212,7 @@ posix_getgroups(PyObject *self, PyObject *noargs) return result; } -#endif +#endif /* HAVE_GETGROUPS */ #ifdef HAVE_INITGROUPS PyDoc_STRVAR(posix_initgroups__doc__, @@ -6365,6 +6221,7 @@ Call the system initgroups() to initialize the group access list with all of\n\ the groups of which the specified username is a member, plus the specified\n\ group id."); +/* AC 3.5: funny apple logic */ static PyObject * posix_initgroups(PyObject *self, PyObject *args) { @@ -6397,20 +6254,23 @@ posix_initgroups(PyObject *self, PyObject *args) Py_INCREF(Py_None); return Py_None; } -#endif +#endif /* HAVE_INITGROUPS */ + #ifdef HAVE_GETPGID -PyDoc_STRVAR(posix_getpgid__doc__, -"getpgid(pid) -> pgid\n\n\ -Call the system call getpgid()."); +/*[clinic input] +os.getpgid + + pid: pid_t + +Call the system call getpgid(), and return the result. +[clinic start generated code]*/ static PyObject * -posix_getpgid(PyObject *self, PyObject *args) +os_getpgid_impl(PyModuleDef *module, pid_t pid) +/*[clinic end generated code: output=70e713b4d54b7c61 input=39d710ae3baaf1c7]*/ { - pid_t pid, pgid; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":getpgid", &pid)) - return NULL; - pgid = getpgid(pid); + pid_t pgid = getpgid(pid); if (pgid < 0) return posix_error(); return PyLong_FromPid(pgid); @@ -6419,12 +6279,15 @@ posix_getpgid(PyObject *self, PyObject *args) #ifdef HAVE_GETPGRP -PyDoc_STRVAR(posix_getpgrp__doc__, -"getpgrp() -> pgrp\n\n\ -Return the current process group id."); +/*[clinic input] +os.getpgrp + +Return the current process group id. +[clinic start generated code]*/ static PyObject * -posix_getpgrp(PyObject *self, PyObject *noargs) +os_getpgrp_impl(PyModuleDef *module) +/*[clinic end generated code: output=cf3403585846811f input=6846fb2bb9a3705e]*/ { #ifdef GETPGRP_HAVE_ARG return PyLong_FromPid(getpgrp(0)); @@ -6436,12 +6299,15 @@ posix_getpgrp(PyObject *self, PyObject *noargs) #ifdef HAVE_SETPGRP -PyDoc_STRVAR(posix_setpgrp__doc__, -"setpgrp()\n\n\ -Make this process the process group leader."); +/*[clinic input] +os.setpgrp + +Make the current process the leader of its process group. +[clinic start generated code]*/ static PyObject * -posix_setpgrp(PyObject *self, PyObject *noargs) +os_setpgrp_impl(PyModuleDef *module) +/*[clinic end generated code: output=59650f55a963d7ac input=1f0619fcb5731e7e]*/ { #ifdef SETPGRP_HAVE_ARG if (setpgrp(0, 0) < 0) @@ -6452,7 +6318,6 @@ posix_setpgrp(PyObject *self, PyObject *noargs) Py_INCREF(Py_None); return Py_None; } - #endif /* HAVE_SETPGRP */ #ifdef HAVE_GETPPID @@ -6499,14 +6364,19 @@ win32_getppid() } #endif /*MS_WINDOWS*/ -PyDoc_STRVAR(posix_getppid__doc__, -"getppid() -> ppid\n\n\ -Return the parent's process id. If the parent process has already exited,\n\ -Windows machines will still return its id; others systems will return the id\n\ -of the 'init' process (1)."); + +/*[clinic input] +os.getppid + +Return the parent's process id. + +If the parent process has already exited, Windows machines will still +return its id; others systems will return the id of the 'init' process (1). +[clinic start generated code]*/ static PyObject * -posix_getppid(PyObject *self, PyObject *noargs) +os_getppid_impl(PyModuleDef *module) +/*[clinic end generated code: output=4e49c8e7a8738cd2 input=e637cb87539c030e]*/ { #ifdef MS_WINDOWS return win32_getppid(); @@ -6518,12 +6388,15 @@ posix_getppid(PyObject *self, PyObject *noargs) #ifdef HAVE_GETLOGIN -PyDoc_STRVAR(posix_getlogin__doc__, -"getlogin() -> string\n\n\ -Return the actual login name."); +/*[clinic input] +os.getlogin + +Return the actual login name. +[clinic start generated code]*/ static PyObject * -posix_getlogin(PyObject *self, PyObject *noargs) +os_getlogin_impl(PyModuleDef *module) +/*[clinic end generated code: output=037ebdb3e4b5dac1 input=2a21ab1e917163df]*/ { PyObject *result = NULL; #ifdef MS_WINDOWS @@ -6556,77 +6429,54 @@ posix_getlogin(PyObject *self, PyObject *noargs) } #endif /* HAVE_GETLOGIN */ + #ifdef HAVE_GETUID -PyDoc_STRVAR(posix_getuid__doc__, -"getuid() -> uid\n\n\ -Return the current process's user id."); +/*[clinic input] +os.getuid + +Return the current process's user id. +[clinic start generated code]*/ static PyObject * -posix_getuid(PyObject *self, PyObject *noargs) +os_getuid_impl(PyModuleDef *module) +/*[clinic end generated code: output=03a8b894cefb3fa5 input=b53c8b35f110a516]*/ { return _PyLong_FromUid(getuid()); } -#endif +#endif /* HAVE_GETUID */ + +#ifdef MS_WINDOWS +#define HAVE_KILL +#endif /* MS_WINDOWS */ #ifdef HAVE_KILL -PyDoc_STRVAR(posix_kill__doc__, -"kill(pid, sig)\n\n\ -Kill a process with a signal."); +/*[clinic input] +os.kill -static PyObject * -posix_kill(PyObject *self, PyObject *args) -{ - pid_t pid; - int sig; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:kill", &pid, &sig)) - return NULL; - if (kill(pid, sig) == -1) - return posix_error(); - Py_INCREF(Py_None); - return Py_None; -} -#endif + pid: pid_t + signal: Py_ssize_t + / -#ifdef HAVE_KILLPG -PyDoc_STRVAR(posix_killpg__doc__, -"killpg(pgid, sig)\n\n\ -Kill a process group with a signal."); +Kill a process with a signal. +[clinic start generated code]*/ static PyObject * -posix_killpg(PyObject *self, PyObject *args) +os_kill_impl(PyModuleDef *module, pid_t pid, Py_ssize_t signal) +/*[clinic end generated code: output=74f907dd00a83c26 input=61a36b86ca275ab9]*/ +#ifndef MS_WINDOWS { - int sig; - pid_t pgid; - /* XXX some man pages make the `pgid` parameter an int, others - a pid_t. Since getpgrp() returns a pid_t, we assume killpg should - take the same type. Moreover, pid_t is always at least as wide as - int (else compilation of this module fails), which is safe. */ - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:killpg", &pgid, &sig)) - return NULL; - if (killpg(pgid, sig) == -1) + if (kill(pid, (int)signal) == -1) return posix_error(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -#endif - -#ifdef MS_WINDOWS -PyDoc_STRVAR(win32_kill__doc__, -"kill(pid, sig)\n\n\ -Kill a process with a signal."); - -static PyObject * -win32_kill(PyObject *self, PyObject *args) +#else /* !MS_WINDOWS */ { PyObject *result; - pid_t pid; - DWORD sig, err; + DWORD sig = (DWORD)signal; + DWORD err; HANDLE handle; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "k:kill", &pid, &sig)) - return NULL; - /* Console processes which share a common console can be sent CTRL+C or CTRL+BREAK events, provided they handle said events. */ if (sig == CTRL_C_EVENT || sig == CTRL_BREAK_EVENT) { @@ -6657,103 +6507,138 @@ win32_kill(PyObject *self, PyObject *args) CloseHandle(handle); return result; } -#endif /* MS_WINDOWS */ +#endif /* !MS_WINDOWS */ +#endif /* HAVE_KILL */ -#ifdef HAVE_PLOCK +#ifdef HAVE_KILLPG +/*[clinic input] +os.killpg + + pgid: pid_t + signal: int + / + +Kill a process group with a signal. +[clinic start generated code]*/ + +static PyObject * +os_killpg_impl(PyModuleDef *module, pid_t pgid, int signal) +/*[clinic end generated code: output=3434a766ef945f93 input=38b5449eb8faec19]*/ +{ + /* XXX some man pages make the `pgid` parameter an int, others + a pid_t. Since getpgrp() returns a pid_t, we assume killpg should + take the same type. Moreover, pid_t is always at least as wide as + int (else compilation of this module fails), which is safe. */ + if (killpg(pgid, signal) == -1) + return posix_error(); + Py_RETURN_NONE; +} +#endif /* HAVE_KILLPG */ + + +#ifdef HAVE_PLOCK #ifdef HAVE_SYS_LOCK_H #include <sys/lock.h> #endif -PyDoc_STRVAR(posix_plock__doc__, -"plock(op)\n\n\ +/*[clinic input] +os.plock + op: int + / + Lock program segments into memory."); +[clinic start generated code]*/ static PyObject * -posix_plock(PyObject *self, PyObject *args) +os_plock_impl(PyModuleDef *module, int op) +/*[clinic end generated code: output=5cb851f81b914984 input=e6e5e348e1525f60]*/ { - int op; - if (!PyArg_ParseTuple(args, "i:plock", &op)) - return NULL; if (plock(op) == -1) return posix_error(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -#endif +#endif /* HAVE_PLOCK */ + #ifdef HAVE_SETUID -PyDoc_STRVAR(posix_setuid__doc__, -"setuid(uid)\n\n\ -Set the current process's user id."); +/*[clinic input] +os.setuid + + uid: uid_t + / + +Set the current process's user id. +[clinic start generated code]*/ static PyObject * -posix_setuid(PyObject *self, PyObject *args) +os_setuid_impl(PyModuleDef *module, uid_t uid) +/*[clinic end generated code: output=941ea9a8d1e5d565 input=c921a3285aa22256]*/ { - uid_t uid; - if (!PyArg_ParseTuple(args, "O&:setuid", _Py_Uid_Converter, &uid)) - return NULL; if (setuid(uid) < 0) return posix_error(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #endif /* HAVE_SETUID */ #ifdef HAVE_SETEUID -PyDoc_STRVAR(posix_seteuid__doc__, -"seteuid(uid)\n\n\ -Set the current process's effective user id."); +/*[clinic input] +os.seteuid + + euid: uid_t + / + +Set the current process's effective user id. +[clinic start generated code]*/ static PyObject * -posix_seteuid (PyObject *self, PyObject *args) +os_seteuid_impl(PyModuleDef *module, uid_t euid) +/*[clinic end generated code: output=66f4f6823a648d6d input=ba93d927e4781aa9]*/ { - uid_t euid; - if (!PyArg_ParseTuple(args, "O&:seteuid", _Py_Uid_Converter, &euid)) - return NULL; - if (seteuid(euid) < 0) { + if (seteuid(euid) < 0) return posix_error(); - } else { - Py_INCREF(Py_None); - return Py_None; - } + Py_RETURN_NONE; } #endif /* HAVE_SETEUID */ + #ifdef HAVE_SETEGID -PyDoc_STRVAR(posix_setegid__doc__, -"setegid(gid)\n\n\ -Set the current process's effective group id."); +/*[clinic input] +os.setegid + + egid: gid_t + / + +Set the current process's effective group id. +[clinic start generated code]*/ static PyObject * -posix_setegid (PyObject *self, PyObject *args) +os_setegid_impl(PyModuleDef *module, gid_t egid) +/*[clinic end generated code: output=ca094a69a081a60f input=4080526d0ccd6ce3]*/ { - gid_t egid; - if (!PyArg_ParseTuple(args, "O&:setegid", _Py_Gid_Converter, &egid)) - return NULL; - if (setegid(egid) < 0) { + if (setegid(egid) < 0) return posix_error(); - } else { - Py_INCREF(Py_None); - return Py_None; - } + Py_RETURN_NONE; } #endif /* HAVE_SETEGID */ + #ifdef HAVE_SETREUID -PyDoc_STRVAR(posix_setreuid__doc__, -"setreuid(ruid, euid)\n\n\ -Set the current process's real and effective user ids."); +/*[clinic input] +os.setreuid + + ruid: uid_t + euid: uid_t + / + +Set the current process's real and effective user ids. +[clinic start generated code]*/ static PyObject * -posix_setreuid (PyObject *self, PyObject *args) +os_setreuid_impl(PyModuleDef *module, uid_t ruid, uid_t euid) +/*[clinic end generated code: output=b2938c3e73d27ec7 input=0ca8978de663880c]*/ { - uid_t ruid, euid; - if (!PyArg_ParseTuple(args, "O&O&:setreuid", - _Py_Uid_Converter, &ruid, - _Py_Uid_Converter, &euid)) - return NULL; if (setreuid(ruid, euid) < 0) { return posix_error(); } else { @@ -6763,53 +6648,62 @@ posix_setreuid (PyObject *self, PyObject *args) } #endif /* HAVE_SETREUID */ + #ifdef HAVE_SETREGID -PyDoc_STRVAR(posix_setregid__doc__, -"setregid(rgid, egid)\n\n\ -Set the current process's real and effective group ids."); +/*[clinic input] +os.setregid + + rgid: gid_t + egid: gid_t + / + +Set the current process's real and effective group ids. +[clinic start generated code]*/ static PyObject * -posix_setregid (PyObject *self, PyObject *args) +os_setregid_impl(PyModuleDef *module, gid_t rgid, gid_t egid) +/*[clinic end generated code: output=db18f1839ababe3d input=c59499f72846db78]*/ { - gid_t rgid, egid; - if (!PyArg_ParseTuple(args, "O&O&:setregid", - _Py_Gid_Converter, &rgid, - _Py_Gid_Converter, &egid)) - return NULL; - if (setregid(rgid, egid) < 0) { + if (setregid(rgid, egid) < 0) return posix_error(); - } else { - Py_INCREF(Py_None); - return Py_None; - } + Py_RETURN_NONE; } #endif /* HAVE_SETREGID */ + #ifdef HAVE_SETGID -PyDoc_STRVAR(posix_setgid__doc__, -"setgid(gid)\n\n\ -Set the current process's group id."); +/*[clinic input] +os.setgid + gid: gid_t + / + +Set the current process's group id. +[clinic start generated code]*/ static PyObject * -posix_setgid(PyObject *self, PyObject *args) +os_setgid_impl(PyModuleDef *module, gid_t gid) +/*[clinic end generated code: output=756cb42c6abd9d87 input=27d30c4059045dc6]*/ { - gid_t gid; - if (!PyArg_ParseTuple(args, "O&:setgid", _Py_Gid_Converter, &gid)) - return NULL; if (setgid(gid) < 0) return posix_error(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #endif /* HAVE_SETGID */ + #ifdef HAVE_SETGROUPS -PyDoc_STRVAR(posix_setgroups__doc__, -"setgroups(list)\n\n\ -Set the groups of the current process to list."); +/*[clinic input] +os.setgroups + + groups: object + / + +Set the groups of the current process to list. +[clinic start generated code]*/ static PyObject * -posix_setgroups(PyObject *self, PyObject *groups) +os_setgroups(PyModuleDef *module, PyObject *groups) +/*[clinic end generated code: output=7945c2e3cc817c58 input=fa742ca3daf85a7e]*/ { int i, len; gid_t grouplist[MAX_GROUPS]; @@ -6910,83 +6804,114 @@ wait_helper(pid_t pid, int status, struct rusage *ru) } #endif /* HAVE_WAIT3 || HAVE_WAIT4 */ + #ifdef HAVE_WAIT3 -PyDoc_STRVAR(posix_wait3__doc__, -"wait3(options) -> (pid, status, rusage)\n\n\ -Wait for completion of a child process."); +/*[clinic input] +os.wait3 + + options: int +Wait for completion of a child process. + +Returns a tuple of information about the child process: + (pid, status, rusage) +[clinic start generated code]*/ static PyObject * -posix_wait3(PyObject *self, PyObject *args) +os_wait3_impl(PyModuleDef *module, int options) +/*[clinic end generated code: output=e18af4924dc54945 input=8ac4c56956b61710]*/ { pid_t pid; - int options; struct rusage ru; + int async_err = 0; WAIT_TYPE status; WAIT_STATUS_INT(status) = 0; - if (!PyArg_ParseTuple(args, "i:wait3", &options)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - pid = wait3(&status, options, &ru); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + pid = wait3(&status, options, &ru); + Py_END_ALLOW_THREADS + } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (pid < 0) + return (!async_err) ? posix_error() : NULL; return wait_helper(pid, WAIT_STATUS_INT(status), &ru); } #endif /* HAVE_WAIT3 */ + #ifdef HAVE_WAIT4 -PyDoc_STRVAR(posix_wait4__doc__, -"wait4(pid, options) -> (pid, status, rusage)\n\n\ -Wait for completion of a given child process."); +/*[clinic input] + +os.wait4 + + pid: pid_t + options: int + +Wait for completion of a specific child process. + +Returns a tuple of information about the child process: + (pid, status, rusage) +[clinic start generated code]*/ static PyObject * -posix_wait4(PyObject *self, PyObject *args) +os_wait4_impl(PyModuleDef *module, pid_t pid, int options) +/*[clinic end generated code: output=714f19e6ff01e099 input=d11deed0750600ba]*/ { - pid_t pid; - int options; + pid_t res; struct rusage ru; + int async_err = 0; WAIT_TYPE status; WAIT_STATUS_INT(status) = 0; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:wait4", &pid, &options)) - return NULL; - - Py_BEGIN_ALLOW_THREADS - pid = wait4(pid, &status, options, &ru); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + res = wait4(pid, &status, options, &ru); + Py_END_ALLOW_THREADS + } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res < 0) + return (!async_err) ? posix_error() : NULL; - return wait_helper(pid, WAIT_STATUS_INT(status), &ru); + return wait_helper(res, WAIT_STATUS_INT(status), &ru); } #endif /* HAVE_WAIT4 */ + #if defined(HAVE_WAITID) && !defined(__APPLE__) -PyDoc_STRVAR(posix_waitid__doc__, -"waitid(idtype, id, options) -> waitid_result\n\n\ -Wait for the completion of one or more child processes.\n\n\ -idtype can be P_PID, P_PGID or P_ALL.\n\ -id specifies the pid to wait on.\n\ -options is constructed from the ORing of one or more of WEXITED, WSTOPPED\n\ -or WCONTINUED and additionally may be ORed with WNOHANG or WNOWAIT.\n\ -Returns either waitid_result or None if WNOHANG is specified and there are\n\ -no children in a waitable state."); +/*[clinic input] +os.waitid + + idtype: idtype_t + Must be one of be P_PID, P_PGID or P_ALL. + id: id_t + The id to wait on. + options: int + Constructed from the ORing of one or more of WEXITED, WSTOPPED + or WCONTINUED and additionally may be ORed with WNOHANG or WNOWAIT. + / + +Returns the result of waiting for a process or processes. + +Returns either waitid_result or None if WNOHANG is specified and there are +no children in a waitable state. +[clinic start generated code]*/ static PyObject * -posix_waitid(PyObject *self, PyObject *args) +os_waitid_impl(PyModuleDef *module, idtype_t idtype, id_t id, int options) +/*[clinic end generated code: output=5c0192750e22fa2e input=d8e7f76e052b7920]*/ { PyObject *result; - idtype_t idtype; - id_t id; - int options, res; + int res; + int async_err = 0; siginfo_t si; si.si_pid = 0; - if (!PyArg_ParseTuple(args, "i" _Py_PARSE_PID "i:waitid", &idtype, &id, &options)) - return NULL; - Py_BEGIN_ALLOW_THREADS - res = waitid(idtype, id, &si, options); - Py_END_ALLOW_THREADS - if (res == -1) - return posix_error(); + + do { + Py_BEGIN_ALLOW_THREADS + res = waitid(idtype, id, &si, options); + Py_END_ALLOW_THREADS + } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res < 0) + return (!async_err) ? posix_error() : NULL; if (si.si_pid == 0) Py_RETURN_NONE; @@ -7007,79 +6932,111 @@ posix_waitid(PyObject *self, PyObject *args) return result; } -#endif +#endif /* defined(HAVE_WAITID) && !defined(__APPLE__) */ + + +#if defined(HAVE_WAITPID) +/*[clinic input] +os.waitpid + pid: pid_t + options: int + / -#ifdef HAVE_WAITPID -PyDoc_STRVAR(posix_waitpid__doc__, -"waitpid(pid, options) -> (pid, status)\n\n\ -Wait for completion of a given child process."); +Wait for completion of a given child process. + +Returns a tuple of information regarding the child process: + (pid, status) + +The options argument is ignored on Windows. +[clinic start generated code]*/ static PyObject * -posix_waitpid(PyObject *self, PyObject *args) +os_waitpid_impl(PyModuleDef *module, pid_t pid, int options) +/*[clinic end generated code: output=5e3593353d54b15b input=0bf1666b8758fda3]*/ { - pid_t pid; - int options; + pid_t res; + int async_err = 0; WAIT_TYPE status; WAIT_STATUS_INT(status) = 0; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:waitpid", &pid, &options)) - return NULL; - Py_BEGIN_ALLOW_THREADS - pid = waitpid(pid, &status, options); - Py_END_ALLOW_THREADS - if (pid == -1) - return posix_error(); + do { + Py_BEGIN_ALLOW_THREADS + res = waitpid(pid, &status, options); + Py_END_ALLOW_THREADS + } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res < 0) + return (!async_err) ? posix_error() : NULL; - return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status)); + return Py_BuildValue("Ni", PyLong_FromPid(res), WAIT_STATUS_INT(status)); } - #elif defined(HAVE_CWAIT) - /* MS C has a variant of waitpid() that's usable for most purposes. */ -PyDoc_STRVAR(posix_waitpid__doc__, -"waitpid(pid, options) -> (pid, status << 8)\n\n" -"Wait for completion of a given process. options is ignored on Windows."); +/*[clinic input] +os.waitpid + pid: Py_intptr_t + options: int + / + +Wait for completion of a given process. + +Returns a tuple of information regarding the process: + (pid, status << 8) + +The options argument is ignored on Windows. +[clinic start generated code]*/ static PyObject * -posix_waitpid(PyObject *self, PyObject *args) +os_waitpid_impl(PyModuleDef *module, Py_intptr_t pid, int options) +/*[clinic end generated code: output=fc1d520db019625f input=444c8f51cca5b862]*/ { - Py_intptr_t pid; - int status, options; + int status; + Py_intptr_t res; + int async_err = 0; - if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR "i:waitpid", &pid, &options)) - return NULL; - Py_BEGIN_ALLOW_THREADS - pid = _cwait(&status, pid, options); - Py_END_ALLOW_THREADS - if (pid == -1) - return posix_error(); + do { + Py_BEGIN_ALLOW_THREADS + res = _cwait(&status, pid, options); + Py_END_ALLOW_THREADS + } while (res < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (res != 0) + return (!async_err) ? posix_error() : NULL; /* shift the status left a byte so this is more like the POSIX waitpid */ - return Py_BuildValue(_Py_PARSE_INTPTR "i", pid, status << 8); + return Py_BuildValue(_Py_PARSE_INTPTR "i", res, status << 8); } -#endif /* HAVE_WAITPID || HAVE_CWAIT */ +#endif + #ifdef HAVE_WAIT -PyDoc_STRVAR(posix_wait__doc__, -"wait() -> (pid, status)\n\n\ -Wait for completion of a child process."); +/*[clinic input] +os.wait + +Wait for completion of a child process. + +Returns a tuple of information about the child process: + (pid, status) +[clinic start generated code]*/ static PyObject * -posix_wait(PyObject *self, PyObject *noargs) +os_wait_impl(PyModuleDef *module) +/*[clinic end generated code: output=4a7f4978393e0654 input=03b0182d4a4700ce]*/ { pid_t pid; + int async_err = 0; WAIT_TYPE status; WAIT_STATUS_INT(status) = 0; - Py_BEGIN_ALLOW_THREADS - pid = wait(&status); - Py_END_ALLOW_THREADS - if (pid == -1) - return posix_error(); + do { + Py_BEGIN_ALLOW_THREADS + pid = wait(&status); + Py_END_ALLOW_THREADS + } while (pid < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (pid < 0) + return (!async_err) ? posix_error() : NULL; return Py_BuildValue("Ni", PyLong_FromPid(pid), WAIT_STATUS_INT(status)); } -#endif +#endif /* HAVE_WAIT */ #if defined(HAVE_READLINK) || defined(MS_WINDOWS) @@ -7095,6 +7052,7 @@ dir_fd may not be implemented on your platform.\n\ #ifdef HAVE_READLINK +/* AC 3.5: merge win32 and not together */ static PyObject * posix_readlink(PyObject *self, PyObject *args, PyObject *kwargs) { @@ -7109,12 +7067,7 @@ posix_readlink(PyObject *self, PyObject *args, PyObject *kwargs) path.function_name = "readlink"; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|$O&:readlink", keywords, path_converter, &path, -#ifdef HAVE_READLINKAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd -#endif - )) + READLINKAT_DIR_FD_CONVERTER, &dir_fd)) return NULL; Py_BEGIN_ALLOW_THREADS @@ -7140,23 +7093,86 @@ exit: return return_value; } - #endif /* HAVE_READLINK */ +#if !defined(HAVE_READLINK) && defined(MS_WINDOWS) + +static PyObject * +win_readlink(PyObject *self, PyObject *args, PyObject *kwargs) +{ + wchar_t *path; + DWORD n_bytes_returned; + DWORD io_result; + PyObject *po, *result; + int dir_fd; + HANDLE reparse_point_handle; + + char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer; + wchar_t *print_name; + + static char *keywords[] = {"path", "dir_fd", NULL}; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "U|$O&:readlink", keywords, + &po, + dir_fd_unavailable, &dir_fd + )) + return NULL; + + path = PyUnicode_AsUnicode(po); + if (path == NULL) + return NULL; + + /* First get a handle to the reparse point */ + Py_BEGIN_ALLOW_THREADS + reparse_point_handle = CreateFileW( + path, + 0, + 0, + 0, + OPEN_EXISTING, + FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, + 0); + Py_END_ALLOW_THREADS + + if (reparse_point_handle==INVALID_HANDLE_VALUE) + return win32_error_object("readlink", po); + + Py_BEGIN_ALLOW_THREADS + /* New call DeviceIoControl to read the reparse point */ + io_result = DeviceIoControl( + reparse_point_handle, + FSCTL_GET_REPARSE_POINT, + 0, 0, /* in buffer */ + target_buffer, sizeof(target_buffer), + &n_bytes_returned, + 0 /* we're not using OVERLAPPED_IO */ + ); + CloseHandle(reparse_point_handle); + Py_END_ALLOW_THREADS + + if (io_result==0) + return win32_error_object("readlink", po); + + if (rdb->ReparseTag != IO_REPARSE_TAG_SYMLINK) + { + PyErr_SetString(PyExc_ValueError, + "not a symbolic link"); + return NULL; + } + print_name = rdb->SymbolicLinkReparseBuffer.PathBuffer + + rdb->SymbolicLinkReparseBuffer.PrintNameOffset; + + result = PyUnicode_FromWideChar(print_name, + rdb->SymbolicLinkReparseBuffer.PrintNameLength/2); + return result; +} + +#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */ + + #ifdef HAVE_SYMLINK -PyDoc_STRVAR(posix_symlink__doc__, -"symlink(src, dst, target_is_directory=False, *, dir_fd=None)\n\n\ -Create a symbolic link pointing to src named dst.\n\n\ -target_is_directory is required on Windows if the target is to be\n\ - interpreted as a directory. (On Windows, symlink requires\n\ - Windows 6.0 or greater, and raises a NotImplementedError otherwise.)\n\ - target_is_directory is ignored on non-Windows platforms.\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 implemented on your platform.\n\ - If it is unavailable, using it will raise a NotImplementedError."); #if defined(MS_WINDOWS) @@ -7302,189 +7318,101 @@ _check_dirA(char *src, char *dest) && src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY ); } - #endif + +/*[clinic input] +os.symlink + src: path_t + dst: path_t + target_is_directory: bool = False + * + dir_fd: dir_fd(requires='symlinkat')=None + +# "symlink(src, dst, target_is_directory=False, *, dir_fd=None)\n\n\ + +Create a symbolic link pointing to src named dst. + +target_is_directory is required on Windows if the target is to be + interpreted as a directory. (On Windows, symlink requires + Windows 6.0 or greater, and raises a NotImplementedError otherwise.) + target_is_directory is ignored on non-Windows platforms. + +If dir_fd is 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. +dir_fd may not be implemented on your platform. + If it is unavailable, using it will raise a NotImplementedError. + +[clinic start generated code]*/ + static PyObject * -posix_symlink(PyObject *self, PyObject *args, PyObject *kwargs) +os_symlink_impl(PyModuleDef *module, path_t *src, path_t *dst, int target_is_directory, int dir_fd) +/*[clinic end generated code: output=11aa03f278bb2c8a input=e820ec4472547bc3]*/ { - path_t src; - path_t dst; - int dir_fd = DEFAULT_DIR_FD; - int target_is_directory = 0; - static char *keywords[] = {"src", "dst", "target_is_directory", - "dir_fd", NULL}; - PyObject *return_value; #ifdef MS_WINDOWS DWORD result; #else int result; #endif - memset(&src, 0, sizeof(src)); - src.function_name = "symlink"; - src.argument_name = "src"; - memset(&dst, 0, sizeof(dst)); - dst.function_name = "symlink"; - dst.argument_name = "dst"; - #ifdef MS_WINDOWS if (!check_CreateSymbolicLink()) { PyErr_SetString(PyExc_NotImplementedError, "CreateSymbolicLink functions not found"); - return NULL; + return NULL; } if (!win32_can_symlink) { PyErr_SetString(PyExc_OSError, "symbolic link privilege not held"); - return NULL; + return NULL; } #endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|i$O&:symlink", - keywords, - path_converter, &src, - path_converter, &dst, - &target_is_directory, -#ifdef HAVE_SYMLINKAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd -#endif - )) - return NULL; - - if ((src.narrow && dst.wide) || (src.wide && dst.narrow)) { + if ((src->narrow && dst->wide) || (src->wide && dst->narrow)) { PyErr_SetString(PyExc_ValueError, "symlink: src and dst must be the same type"); - return_value = NULL; - goto exit; + return NULL; } #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS - if (dst.wide) { + if (dst->wide) { /* if src is a directory, ensure target_is_directory==1 */ - target_is_directory |= _check_dirW(src.wide, dst.wide); - result = Py_CreateSymbolicLinkW(dst.wide, src.wide, + target_is_directory |= _check_dirW(src->wide, dst->wide); + result = Py_CreateSymbolicLinkW(dst->wide, src->wide, target_is_directory); } else { /* if src is a directory, ensure target_is_directory==1 */ - target_is_directory |= _check_dirA(src.narrow, dst.narrow); - result = Py_CreateSymbolicLinkA(dst.narrow, src.narrow, + target_is_directory |= _check_dirA(src->narrow, dst->narrow); + result = Py_CreateSymbolicLinkA(dst->narrow, src->narrow, target_is_directory); } Py_END_ALLOW_THREADS - if (!result) { - return_value = path_error2(&src, &dst); - goto exit; - } + if (!result) + return path_error2(src, dst); #else Py_BEGIN_ALLOW_THREADS #if HAVE_SYMLINKAT if (dir_fd != DEFAULT_DIR_FD) - result = symlinkat(src.narrow, dir_fd, dst.narrow); + result = symlinkat(src->narrow, dir_fd, dst->narrow); else #endif - result = symlink(src.narrow, dst.narrow); + result = symlink(src->narrow, dst->narrow); Py_END_ALLOW_THREADS - if (result) { - return_value = path_error2(&src, &dst); - goto exit; - } + if (result) + return path_error2(src, dst); #endif - return_value = Py_None; - Py_INCREF(Py_None); - goto exit; /* silence "unused label" warning */ -exit: - path_cleanup(&src); - path_cleanup(&dst); - return return_value; + Py_RETURN_NONE; } - #endif /* HAVE_SYMLINK */ -#if !defined(HAVE_READLINK) && defined(MS_WINDOWS) - -static PyObject * -win_readlink(PyObject *self, PyObject *args, PyObject *kwargs) -{ - wchar_t *path; - DWORD n_bytes_returned; - DWORD io_result; - PyObject *po, *result; - int dir_fd; - HANDLE reparse_point_handle; - - char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; - REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer; - wchar_t *print_name; - - static char *keywords[] = {"path", "dir_fd", NULL}; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "U|$O&:readlink", keywords, - &po, - dir_fd_unavailable, &dir_fd - )) - return NULL; - - path = PyUnicode_AsUnicode(po); - if (path == NULL) - return NULL; - - /* First get a handle to the reparse point */ - Py_BEGIN_ALLOW_THREADS - reparse_point_handle = CreateFileW( - path, - 0, - 0, - 0, - OPEN_EXISTING, - FILE_FLAG_OPEN_REPARSE_POINT|FILE_FLAG_BACKUP_SEMANTICS, - 0); - Py_END_ALLOW_THREADS - - if (reparse_point_handle==INVALID_HANDLE_VALUE) - return win32_error_object("readlink", po); - - Py_BEGIN_ALLOW_THREADS - /* New call DeviceIoControl to read the reparse point */ - io_result = DeviceIoControl( - reparse_point_handle, - FSCTL_GET_REPARSE_POINT, - 0, 0, /* in buffer */ - target_buffer, sizeof(target_buffer), - &n_bytes_returned, - 0 /* we're not using OVERLAPPED_IO */ - ); - CloseHandle(reparse_point_handle); - Py_END_ALLOW_THREADS - - if (io_result==0) - return win32_error_object("readlink", po); - - if (rdb->ReparseTag != IO_REPARSE_TAG_SYMLINK) - { - PyErr_SetString(PyExc_ValueError, - "not a symbolic link"); - return NULL; - } - print_name = rdb->SymbolicLinkReparseBuffer.PathBuffer + - rdb->SymbolicLinkReparseBuffer.PrintNameOffset; - - result = PyUnicode_FromWideChar(print_name, - rdb->SymbolicLinkReparseBuffer.PrintNameLength/2); - return result; -} - -#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */ static PyStructSequence_Field times_result_fields[] = { @@ -7550,15 +7478,26 @@ build_times_result(double user, double system, return value; } -PyDoc_STRVAR(posix_times__doc__, -"times() -> times_result\n\n\ -Return an object containing floating point numbers indicating process\n\ -times. The object behaves like a named tuple with these fields:\n\ - (utime, stime, cutime, cstime, elapsed_time)"); -#if defined(MS_WINDOWS) +#ifndef MS_WINDOWS +#define NEED_TICKS_PER_SECOND +static long ticks_per_second = -1; +#endif /* MS_WINDOWS */ + +/*[clinic input] +os.times + +Return a collection containing process timing information. + +The object returned behaves like a named tuple with these fields: + (utime, stime, cutime, cstime, elapsed_time) +All fields are floating point numbers. +[clinic start generated code]*/ + static PyObject * -posix_times(PyObject *self, PyObject *noargs) +os_times_impl(PyModuleDef *module) +/*[clinic end generated code: output=df0a63ebe6e6f091 input=2bf9df3d6ab2e48b]*/ +#ifdef MS_WINDOWS { FILETIME create, exit, kernel, user; HANDLE hProc; @@ -7578,12 +7517,10 @@ posix_times(PyObject *self, PyObject *noargs) (double)0, (double)0); } -#else /* Not Windows */ -#define NEED_TICKS_PER_SECOND -static long ticks_per_second = -1; -static PyObject * -posix_times(PyObject *self, PyObject *noargs) +#else /* MS_WINDOWS */ { + + struct tms t; clock_t c; errno = 0; @@ -7597,23 +7534,25 @@ posix_times(PyObject *self, PyObject *noargs) (double)t.tms_cstime / ticks_per_second, (double)c / ticks_per_second); } -#endif - +#endif /* MS_WINDOWS */ #endif /* HAVE_TIMES */ #ifdef HAVE_GETSID -PyDoc_STRVAR(posix_getsid__doc__, -"getsid(pid) -> sid\n\n\ -Call the system call getsid()."); +/*[clinic input] +os.getsid + + pid: pid_t + / + +Call the system call getsid(pid) and return the result. +[clinic start generated code]*/ static PyObject * -posix_getsid(PyObject *self, PyObject *args) +os_getsid_impl(PyModuleDef *module, pid_t pid) +/*[clinic end generated code: output=a074f80c0e6bfb38 input=eeb2b923a30ce04e]*/ { - pid_t pid; int sid; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":getsid", &pid)) - return NULL; sid = getsid(pid); if (sid < 0) return posix_error(); @@ -7623,53 +7562,60 @@ posix_getsid(PyObject *self, PyObject *args) #ifdef HAVE_SETSID -PyDoc_STRVAR(posix_setsid__doc__, -"setsid()\n\n\ -Call the system call setsid()."); +/*[clinic input] +os.setsid + +Call the system call setsid(). +[clinic start generated code]*/ static PyObject * -posix_setsid(PyObject *self, PyObject *noargs) +os_setsid_impl(PyModuleDef *module) +/*[clinic end generated code: output=398fc152ae327330 input=5fff45858e2f0776]*/ { if (setsid() < 0) return posix_error(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #endif /* HAVE_SETSID */ + #ifdef HAVE_SETPGID -PyDoc_STRVAR(posix_setpgid__doc__, -"setpgid(pid, pgrp)\n\n\ -Call the system call setpgid()."); +/*[clinic input] +os.setpgid + + pid: pid_t + pgrp: pid_t + / + +Call the system call setpgid(pid, pgrp). +[clinic start generated code]*/ static PyObject * -posix_setpgid(PyObject *self, PyObject *args) +os_setpgid_impl(PyModuleDef *module, pid_t pid, pid_t pgrp) +/*[clinic end generated code: output=7079a8e932912841 input=fceb395eca572e1a]*/ { - pid_t pid; - int pgrp; - if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:setpgid", &pid, &pgrp)) - return NULL; if (setpgid(pid, pgrp) < 0) return posix_error(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #endif /* HAVE_SETPGID */ #ifdef HAVE_TCGETPGRP -PyDoc_STRVAR(posix_tcgetpgrp__doc__, -"tcgetpgrp(fd) -> pgid\n\n\ -Return the process group associated with the terminal given by a fd."); +/*[clinic input] +os.tcgetpgrp + + fd: int + / + +Return the process group associated with the terminal specified by fd. +[clinic start generated code]*/ static PyObject * -posix_tcgetpgrp(PyObject *self, PyObject *args) +os_tcgetpgrp_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=ebb6dc5f111c7dc0 input=7f6c18eac10ada86]*/ { - int fd; - pid_t pgid; - if (!PyArg_ParseTuple(args, "i:tcgetpgrp", &fd)) - return NULL; - pgid = tcgetpgrp(fd); + pid_t pgid = tcgetpgrp(fd); if (pgid < 0) return posix_error(); return PyLong_FromPid(pgid); @@ -7678,21 +7624,23 @@ posix_tcgetpgrp(PyObject *self, PyObject *args) #ifdef HAVE_TCSETPGRP -PyDoc_STRVAR(posix_tcsetpgrp__doc__, -"tcsetpgrp(fd, pgid)\n\n\ -Set the process group associated with the terminal given by a fd."); +/*[clinic input] +os.tcsetpgrp + + fd: int + pgid: pid_t + / + +Set the process group associated with the terminal specified by fd. +[clinic start generated code]*/ static PyObject * -posix_tcsetpgrp(PyObject *self, PyObject *args) +os_tcsetpgrp_impl(PyModuleDef *module, int fd, pid_t pgid) +/*[clinic end generated code: output=3e4b05177462cd22 input=5bdc997c6a619020]*/ { - int fd; - pid_t pgid; - if (!PyArg_ParseTuple(args, "i" _Py_PARSE_PID ":tcsetpgrp", &fd, &pgid)) - return NULL; if (tcsetpgrp(fd, pgid) < 0) return posix_error(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } #endif /* HAVE_TCSETPGRP */ @@ -7702,121 +7650,122 @@ posix_tcsetpgrp(PyObject *self, PyObject *args) extern int _Py_open_cloexec_works; #endif -PyDoc_STRVAR(posix_open__doc__, -"open(path, flags, mode=0o777, *, dir_fd=None)\n\n\ -Open a file for low level IO. Returns a file handle (integer).\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 implemented on your platform.\n\ - If it is unavailable, using it will raise a NotImplementedError."); -static PyObject * -posix_open(PyObject *self, PyObject *args, PyObject *kwargs) +/*[clinic input] +os.open -> int + path: path_t + flags: int + mode: int = 0o777 + * + dir_fd: dir_fd(requires='openat') = None + +# "open(path, flags, mode=0o777, *, dir_fd=None)\n\n\ + +Open a file for low level IO. Returns a file descriptor (integer). + +If dir_fd is 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. +dir_fd may not be implemented on your platform. + If it is unavailable, using it will raise a NotImplementedError. +[clinic start generated code]*/ + +static int +os_open_impl(PyModuleDef *module, path_t *path, int flags, int mode, int dir_fd) +/*[clinic end generated code: output=c95a64f0e62f199b input=ad8623b29acd2934]*/ { - path_t path; - int flags; - int mode = 0777; - int dir_fd = DEFAULT_DIR_FD; int fd; - PyObject *return_value = NULL; - static char *keywords[] = {"path", "flags", "mode", "dir_fd", NULL}; + int async_err = 0; + #ifdef O_CLOEXEC int *atomic_flag_works = &_Py_open_cloexec_works; #elif !defined(MS_WINDOWS) int *atomic_flag_works = NULL; #endif - memset(&path, 0, sizeof(path)); - path.function_name = "open"; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&i|i$O&:open", keywords, - path_converter, &path, - &flags, &mode, -#ifdef HAVE_OPENAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd -#endif - )) - return NULL; - #ifdef MS_WINDOWS flags |= O_NOINHERIT; #elif defined(O_CLOEXEC) flags |= O_CLOEXEC; #endif - Py_BEGIN_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS - if (path.wide) - fd = _wopen(path.wide, flags, mode); - else + if (path->wide) + fd = _wopen(path->wide, flags, mode); + else #endif #ifdef HAVE_OPENAT - if (dir_fd != DEFAULT_DIR_FD) - fd = openat(dir_fd, path.narrow, flags, mode); - else + if (dir_fd != DEFAULT_DIR_FD) + fd = openat(dir_fd, path->narrow, flags, mode); + else #endif - fd = open(path.narrow, flags, mode); - Py_END_ALLOW_THREADS + fd = open(path->narrow, flags, mode); + Py_END_ALLOW_THREADS + } while (fd < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (fd == -1) { - PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path.object); - goto exit; + if (!async_err) + PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, path->object); + return -1; } #ifndef MS_WINDOWS if (_Py_set_inheritable(fd, 0, atomic_flag_works) < 0) { close(fd); - goto exit; + return -1; } #endif - return_value = PyLong_FromLong((long)fd); - -exit: - path_cleanup(&path); - return return_value; + return fd; } -PyDoc_STRVAR(posix_close__doc__, -"close(fd)\n\n\ -Close a file descriptor (for low level IO)."); -/* -The underscore at end of function name avoids a name clash with the libc -function posix_close. -*/ +/*[clinic input] +os.close + + fd: int + +Close a file descriptor. +[clinic start generated code]*/ + static PyObject * -posix_close_(PyObject *self, PyObject *args) +os_close_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=47bf2ea536445a26 input=2bc42451ca5c3223]*/ { - int fd, res; - if (!PyArg_ParseTuple(args, "i:close", &fd)) - return NULL; + int res; if (!_PyVerify_fd(fd)) return posix_error(); + /* We do not want to retry upon EINTR: see http://lwn.net/Articles/576478/ + * and http://linux.derkeiler.com/Mailing-Lists/Kernel/2005-09/3000.html + * for more details. + */ Py_BEGIN_ALLOW_THREADS res = close(fd); Py_END_ALLOW_THREADS if (res < 0) return posix_error(); - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } -PyDoc_STRVAR(posix_closerange__doc__, -"closerange(fd_low, fd_high)\n\n\ -Closes all file descriptors in [fd_low, fd_high), ignoring errors."); +/*[clinic input] +os.closerange + + fd_low: int + fd_high: int + / + +Closes all file descriptors in [fd_low, fd_high), ignoring errors. +[clinic start generated code]*/ static PyObject * -posix_closerange(PyObject *self, PyObject *args) +os_closerange_impl(PyModuleDef *module, int fd_low, int fd_high) +/*[clinic end generated code: output=70e6adb95220ba96 input=5855a3d053ebd4ec]*/ { - int fd_from, fd_to, i; - if (!PyArg_ParseTuple(args, "ii:closerange", &fd_from, &fd_to)) - return NULL; + int i; Py_BEGIN_ALLOW_THREADS - for (i = fd_from; i < fd_to; i++) + for (i = fd_low; i < fd_high; i++) if (_PyVerify_fd(i)) close(i); Py_END_ALLOW_THREADS @@ -7824,36 +7773,36 @@ posix_closerange(PyObject *self, PyObject *args) } -PyDoc_STRVAR(posix_dup__doc__, -"dup(fd) -> fd2\n\n\ -Return a duplicate of a file descriptor."); - -static PyObject * -posix_dup(PyObject *self, PyObject *args) -{ - int fd; +/*[clinic input] +os.dup -> int - if (!PyArg_ParseTuple(args, "i:dup", &fd)) - return NULL; + fd: int + / - fd = _Py_dup(fd); - if (fd == -1) - return NULL; +Return a duplicate of a file descriptor. +[clinic start generated code]*/ - return PyLong_FromLong((long)fd); +static int +os_dup_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=f4bbac8c7652d05e input=6f10f7ea97f7852a]*/ +{ + return _Py_dup(fd); } -PyDoc_STRVAR(posix_dup2__doc__, -"dup2(old_fd, new_fd)\n\n\ -Duplicate file descriptor."); +/*[clinic input] +os.dup2 + fd: int + fd2: int + inheritable: bool=True + +Duplicate file descriptor. +[clinic start generated code]*/ static PyObject * -posix_dup2(PyObject *self, PyObject *args, PyObject *kwargs) +os_dup2_impl(PyModuleDef *module, int fd, int fd2, int inheritable) +/*[clinic end generated code: output=9a099d95881a7923 input=76e96f511be0352f]*/ { - static char *keywords[] = {"fd", "fd2", "inheritable", NULL}; - int fd, fd2; - int inheritable = 1; int res; #if defined(HAVE_DUP3) && \ !(defined(HAVE_FCNTL_H) && defined(F_DUP2FD_CLOEXEC)) @@ -7861,13 +7810,13 @@ posix_dup2(PyObject *self, PyObject *args, PyObject *kwargs) int dup3_works = -1; #endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ii|i:dup2", keywords, - &fd, &fd2, &inheritable)) - return NULL; - if (!_PyVerify_fd_dup2(fd, fd2)) return posix_error(); + /* dup2() can fail with EINTR if the target FD is already open, because it + * then has to be closed. See os_close_impl() for why we don't handle EINTR + * upon close(), and therefore below. + */ #ifdef MS_WINDOWS Py_BEGIN_ALLOW_THREADS res = dup2(fd, fd2); @@ -7925,30 +7874,34 @@ posix_dup2(PyObject *self, PyObject *args, PyObject *kwargs) #endif - Py_INCREF(Py_None); - return Py_None; + Py_RETURN_NONE; } + #ifdef HAVE_LOCKF -PyDoc_STRVAR(posix_lockf__doc__, -"lockf(fd, cmd, len)\n\n\ -Apply, test or remove a POSIX lock on an open file descriptor.\n\n\ -fd is an open file descriptor.\n\ -cmd specifies the command to use - one of F_LOCK, F_TLOCK, F_ULOCK or\n\ -F_TEST.\n\ -len specifies the section of the file to lock."); +/*[clinic input] +os.lockf + + fd: int + An open file descriptor. + command: int + One of F_LOCK, F_TLOCK, F_ULOCK or F_TEST. + length: Py_off_t + The number of bytes to lock, starting at the current position. + / + +Apply, test or remove a POSIX lock on an open file descriptor. + +[clinic start generated code]*/ static PyObject * -posix_lockf(PyObject *self, PyObject *args) +os_lockf_impl(PyModuleDef *module, int fd, int command, Py_off_t length) +/*[clinic end generated code: output=25ff778f9e2fbf1b input=65da41d2106e9b79]*/ { - int fd, cmd, res; - off_t len; - if (!PyArg_ParseTuple(args, "iiO&:lockf", - &fd, &cmd, _parse_off_t, &len)) - return NULL; + int res; Py_BEGIN_ALLOW_THREADS - res = lockf(fd, cmd, len); + res = lockf(fd, command, length); Py_END_ALLOW_THREADS if (res < 0) @@ -7956,95 +7909,103 @@ posix_lockf(PyObject *self, PyObject *args) Py_RETURN_NONE; } -#endif +#endif /* HAVE_LOCKF */ -PyDoc_STRVAR(posix_lseek__doc__, -"lseek(fd, pos, how) -> newpos\n\n\ -Set the current position of a file descriptor.\n\ -Return the new cursor position in bytes, starting from the beginning."); +/*[clinic input] +os.lseek -> Py_off_t -static PyObject * -posix_lseek(PyObject *self, PyObject *args) + fd: int + position: Py_off_t + how: int + / + +Set the position of a file descriptor. Return the new position. + +Return the new cursor position in number of bytes +relative to the beginning of the file. +[clinic start generated code]*/ + +static Py_off_t +os_lseek_impl(PyModuleDef *module, int fd, Py_off_t position, int how) +/*[clinic end generated code: output=65d4ab96d664998c input=902654ad3f96a6d3]*/ { - int fd, how; -#ifdef MS_WINDOWS - PY_LONG_LONG pos, res; -#else - off_t pos, res; -#endif - PyObject *posobj; - if (!PyArg_ParseTuple(args, "iOi:lseek", &fd, &posobj, &how)) - return NULL; + Py_off_t result; + + if (!_PyVerify_fd(fd)) { + posix_error(); + return -1; + } #ifdef SEEK_SET /* Turn 0, 1, 2 into SEEK_{SET,CUR,END} */ switch (how) { - case 0: how = SEEK_SET; break; - case 1: how = SEEK_CUR; break; - case 2: how = SEEK_END; break; + case 0: how = SEEK_SET; break; + case 1: how = SEEK_CUR; break; + case 2: how = SEEK_END; break; } #endif /* SEEK_END */ -#if !defined(HAVE_LARGEFILE_SUPPORT) - pos = PyLong_AsLong(posobj); -#else - pos = PyLong_AsLongLong(posobj); -#endif if (PyErr_Occurred()) - return NULL; + return -1; - if (!_PyVerify_fd(fd)) - return posix_error(); + if (!_PyVerify_fd(fd)) { + posix_error(); + return -1; + } Py_BEGIN_ALLOW_THREADS #ifdef MS_WINDOWS - res = _lseeki64(fd, pos, how); + result = _lseeki64(fd, position, how); #else - res = lseek(fd, pos, how); + result = lseek(fd, position, how); #endif Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); + if (result < 0) + posix_error(); -#if !defined(HAVE_LARGEFILE_SUPPORT) - return PyLong_FromLong(res); -#else - return PyLong_FromLongLong(res); -#endif + return result; } -PyDoc_STRVAR(posix_read__doc__, -"read(fd, buffersize) -> bytes\n\n\ -Read a file descriptor."); +/*[clinic input] +os.read + fd: int + length: Py_ssize_t + / + +Read from a file descriptor. Returns a bytes object. +[clinic start generated code]*/ static PyObject * -posix_read(PyObject *self, PyObject *args) +os_read_impl(PyModuleDef *module, int fd, Py_ssize_t length) +/*[clinic end generated code: output=be24f44178455e8b input=1df2eaa27c0bf1d3]*/ { - int fd, size; Py_ssize_t n; PyObject *buffer; - if (!PyArg_ParseTuple(args, "ii:read", &fd, &size)) - return NULL; - if (size < 0) { + + if (length < 0) { errno = EINVAL; return posix_error(); } - buffer = PyBytes_FromStringAndSize((char *)NULL, size); + +#ifdef MS_WINDOWS + /* On Windows, the count parameter of read() is an int */ + if (length > INT_MAX) + length = INT_MAX; +#endif + + buffer = PyBytes_FromStringAndSize((char *)NULL, length); if (buffer == NULL) return NULL; - if (!_PyVerify_fd(fd)) { - Py_DECREF(buffer); - return posix_error(); - } - Py_BEGIN_ALLOW_THREADS - n = read(fd, PyBytes_AS_STRING(buffer), size); - Py_END_ALLOW_THREADS - if (n < 0) { + + n = _Py_read(fd, PyBytes_AS_STRING(buffer), length); + if (n == -1) { Py_DECREF(buffer); - return posix_error(); + return NULL; } - if (n != size) + + if (n != length) _PyBytes_Resize(&buffer, n); + return buffer; } @@ -8106,120 +8067,133 @@ iov_cleanup(struct iovec *iov, Py_buffer *buf, int cnt) } #endif + #ifdef HAVE_READV -PyDoc_STRVAR(posix_readv__doc__, -"readv(fd, buffers) -> bytesread\n\n\ -Read from a file descriptor fd into a number of mutable, bytes-like\n\ -objects (\"buffers\"). readv will transfer data into each buffer\n\ -until it is full and then move on to the next buffer in the sequence\n\ -to hold the rest of the data.\n\n\ -readv returns the total number of bytes read (which may be less than\n\ -the total capacity of all the buffers."); +/*[clinic input] +os.readv -> Py_ssize_t -static PyObject * -posix_readv(PyObject *self, PyObject *args) + fd: int + buffers: object + / + +Read from a file descriptor fd into an iterable of buffers. + +The buffers should be mutable buffers accepting bytes. +readv will transfer data into each buffer until it is full +and then move on to the next buffer in the sequence to hold +the rest of the data. + +readv returns the total number of bytes read, +which may be less than the total capacity of all the buffers. +[clinic start generated code]*/ + +static Py_ssize_t +os_readv_impl(PyModuleDef *module, int fd, PyObject *buffers) +/*[clinic end generated code: output=00fc56ff1800059f input=e679eb5dbfa0357d]*/ { - int fd, cnt; + int cnt; Py_ssize_t n; - PyObject *seq; + int async_err = 0; struct iovec *iov; Py_buffer *buf; - if (!PyArg_ParseTuple(args, "iO:readv", &fd, &seq)) - return NULL; - if (!PySequence_Check(seq)) { + if (!PySequence_Check(buffers)) { PyErr_SetString(PyExc_TypeError, "readv() arg 2 must be a sequence"); - return NULL; + return -1; } - cnt = PySequence_Size(seq); - if (iov_setup(&iov, &buf, seq, cnt, PyBUF_WRITABLE) < 0) - return NULL; + cnt = PySequence_Size(buffers); - Py_BEGIN_ALLOW_THREADS - n = readv(fd, iov, cnt); - Py_END_ALLOW_THREADS + if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_WRITABLE) < 0) + return -1; + + do { + Py_BEGIN_ALLOW_THREADS + n = readv(fd, iov, cnt); + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); iov_cleanup(iov, buf, cnt); - if (n < 0) - return posix_error(); + if (n < 0) { + if (!async_err) + posix_error(); + return -1; + } - return PyLong_FromSsize_t(n); + return n; } -#endif +#endif /* HAVE_READV */ + #ifdef HAVE_PREAD -PyDoc_STRVAR(posix_pread__doc__, -"pread(fd, buffersize, offset) -> string\n\n\ -Read from a file descriptor, fd, at a position of offset. It will read up\n\ -to buffersize number of bytes. The file offset remains unchanged."); +/*[clinic input] +# TODO length should be size_t! but Python doesn't support parsing size_t yet. +os.pread + + fd: int + length: int + offset: Py_off_t + / + +Read a number of bytes from a file descriptor starting at a particular offset. + +Read length bytes from file descriptor fd, starting at offset bytes from +the beginning of the file. The file offset remains unchanged. +[clinic start generated code]*/ static PyObject * -posix_pread(PyObject *self, PyObject *args) +os_pread_impl(PyModuleDef *module, int fd, int length, Py_off_t offset) +/*[clinic end generated code: output=90d1fed87f68fa33 input=084948dcbaa35d4c]*/ { - int fd, size; - off_t offset; Py_ssize_t n; + int async_err = 0; PyObject *buffer; - if (!PyArg_ParseTuple(args, "iiO&:pread", &fd, &size, _parse_off_t, &offset)) - return NULL; - if (size < 0) { + if (length < 0) { errno = EINVAL; return posix_error(); } - buffer = PyBytes_FromStringAndSize((char *)NULL, size); + buffer = PyBytes_FromStringAndSize((char *)NULL, length); if (buffer == NULL) return NULL; if (!_PyVerify_fd(fd)) { Py_DECREF(buffer); return posix_error(); } - Py_BEGIN_ALLOW_THREADS - n = pread(fd, PyBytes_AS_STRING(buffer), size, offset); - Py_END_ALLOW_THREADS + + do { + Py_BEGIN_ALLOW_THREADS + n = pread(fd, PyBytes_AS_STRING(buffer), length, offset); + Py_END_ALLOW_THREADS + } while (n < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + if (n < 0) { Py_DECREF(buffer); - return posix_error(); + return (!async_err) ? posix_error() : NULL; } - if (n != size) + if (n != length) _PyBytes_Resize(&buffer, n); return buffer; } -#endif +#endif /* HAVE_PREAD */ -PyDoc_STRVAR(posix_write__doc__, -"write(fd, data) -> byteswritten\n\n\ -Write bytes to a file descriptor."); -static PyObject * -posix_write(PyObject *self, PyObject *args) -{ - Py_buffer pbuf; - int fd; - Py_ssize_t size, len; +/*[clinic input] +os.write -> Py_ssize_t - if (!PyArg_ParseTuple(args, "iy*:write", &fd, &pbuf)) - return NULL; - if (!_PyVerify_fd(fd)) { - PyBuffer_Release(&pbuf); - return posix_error(); - } - len = pbuf.len; - Py_BEGIN_ALLOW_THREADS -#ifdef MS_WINDOWS - if (len > INT_MAX) - len = INT_MAX; - size = write(fd, pbuf.buf, (int)len); -#else - size = write(fd, pbuf.buf, len); -#endif - Py_END_ALLOW_THREADS - PyBuffer_Release(&pbuf); - if (size < 0) - return posix_error(); - return PyLong_FromSsize_t(size); + fd: int + data: Py_buffer + / + +Write a bytes object to a file descriptor. +[clinic start generated code]*/ + +static Py_ssize_t +os_write_impl(PyModuleDef *module, int fd, Py_buffer *data) +/*[clinic end generated code: output=58845c93c9ee1dda input=3207e28963234f3c]*/ +{ + return _Py_write(fd, data->buf, data->len); } #ifdef HAVE_SENDFILE @@ -8229,11 +8203,13 @@ sendfile(out, in, offset, nbytes, headers=None, trailers=None, flags=0)\n\ -> byteswritten\n\ Copy nbytes bytes from file descriptor in to file descriptor out."); +/* AC 3.5: don't bother converting, has optional group*/ static PyObject * posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict) { int in, out; Py_ssize_t ret; + int async_err = 0; off_t offset; #if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__APPLE__) @@ -8254,10 +8230,10 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict) #ifdef __APPLE__ if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiO&O&|OOi:sendfile", - keywords, &out, &in, _parse_off_t, &offset, _parse_off_t, &sbytes, + keywords, &out, &in, Py_off_t_converter, &offset, Py_off_t_converter, &sbytes, #else if (!PyArg_ParseTupleAndKeywords(args, kwdict, "iiO&n|OOi:sendfile", - keywords, &out, &in, _parse_off_t, &offset, &len, + keywords, &out, &in, Py_off_t_converter, &offset, &len, #endif &headers, &trailers, &flags)) return NULL; @@ -8296,13 +8272,15 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict) } } - Py_BEGIN_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS #ifdef __APPLE__ - ret = sendfile(in, out, offset, &sbytes, &sf, flags); + ret = sendfile(in, out, offset, &sbytes, &sf, flags); #else - ret = sendfile(in, out, offset, len, &sf, &sbytes, flags); + ret = sendfile(in, out, offset, len, &sf, &sbytes, flags); #endif - Py_END_ALLOW_THREADS + Py_END_ALLOW_THREADS + } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (sf.headers != NULL) iov_cleanup(sf.headers, hbuf, sf.hdr_cnt); @@ -8321,7 +8299,7 @@ posix_sendfile(PyObject *self, PyObject *args, PyObject *kwdict) return posix_error(); } } - return posix_error(); + return (!async_err) ? posix_error() : NULL; } goto done; @@ -8342,76 +8320,102 @@ done: return NULL; #ifdef linux if (offobj == Py_None) { - Py_BEGIN_ALLOW_THREADS - ret = sendfile(out, in, NULL, count); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + ret = sendfile(out, in, NULL, count); + Py_END_ALLOW_THREADS + } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (ret < 0) - return posix_error(); + return (!async_err) ? posix_error() : NULL; return Py_BuildValue("n", ret); } #endif - if (!_parse_off_t(offobj, &offset)) + if (!Py_off_t_converter(offobj, &offset)) return NULL; - Py_BEGIN_ALLOW_THREADS - ret = sendfile(out, in, &offset, count); - Py_END_ALLOW_THREADS + + do { + Py_BEGIN_ALLOW_THREADS + ret = sendfile(out, in, &offset, count); + Py_END_ALLOW_THREADS + } while (ret < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (ret < 0) - return posix_error(); + return (!async_err) ? posix_error() : NULL; return Py_BuildValue("n", ret); #endif } -#endif +#endif /* HAVE_SENDFILE */ -PyDoc_STRVAR(posix_fstat__doc__, -"fstat(fd) -> stat result\n\n\ -Like stat(), but for an open file descriptor.\n\ -Equivalent to stat(fd=fd)."); + +/*[clinic input] +os.fstat + + fd : int + +Perform a stat system call on the given file descriptor. + +Like stat(), but for an open file descriptor. +Equivalent to os.stat(fd). +[clinic start generated code]*/ static PyObject * -posix_fstat(PyObject *self, PyObject *args) +os_fstat_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=d71fe98bf042b626 input=27e0e0ebbe5600c9]*/ { - int fd; STRUCT_STAT st; int res; - if (!PyArg_ParseTuple(args, "i:fstat", &fd)) - return NULL; - Py_BEGIN_ALLOW_THREADS - res = FSTAT(fd, &st); - Py_END_ALLOW_THREADS + int async_err = 0; + + do { + Py_BEGIN_ALLOW_THREADS + res = FSTAT(fd, &st); + Py_END_ALLOW_THREADS + } while (res != 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); if (res != 0) { #ifdef MS_WINDOWS return PyErr_SetFromWindowsErr(0); #else - return posix_error(); + return (!async_err) ? posix_error() : NULL; #endif } return _pystat_fromstructstat(&st); } -PyDoc_STRVAR(posix_isatty__doc__, -"isatty(fd) -> bool\n\n\ -Return True if the file descriptor 'fd' is an open file descriptor\n\ -connected to the slave end of a terminal."); -static PyObject * -posix_isatty(PyObject *self, PyObject *args) +/*[clinic input] +os.isatty -> bool + fd: int + / + +Return True if the fd is connected to a terminal. + +Return True if the file descriptor is an open file descriptor +connected to the slave end of a terminal. +[clinic start generated code]*/ + +static int +os_isatty_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=acec9d3c29d16d33 input=08ce94aa1eaf7b5e]*/ { - int fd; - if (!PyArg_ParseTuple(args, "i:isatty", &fd)) - return NULL; if (!_PyVerify_fd(fd)) - return PyBool_FromLong(0); - return PyBool_FromLong(isatty(fd)); + return 0; + return isatty(fd); } + #ifdef HAVE_PIPE -PyDoc_STRVAR(posix_pipe__doc__, -"pipe() -> (read_end, write_end)\n\n\ -Create a pipe."); +/*[clinic input] +os.pipe + +Create a pipe. + +Returns a tuple of two file descriptors: + (read_fd, write_fd) +[clinic start generated code]*/ static PyObject * -posix_pipe(PyObject *self, PyObject *noargs) +os_pipe_impl(PyModuleDef *module) +/*[clinic end generated code: output=6b0cd3f868ec3c40 input=02535e8c8fa6c4d4]*/ { int fds[2]; #ifdef MS_WINDOWS @@ -8479,25 +8483,30 @@ posix_pipe(PyObject *self, PyObject *noargs) } #endif /* HAVE_PIPE */ + #ifdef HAVE_PIPE2 -PyDoc_STRVAR(posix_pipe2__doc__, -"pipe2(flags) -> (read_end, write_end)\n\n\ -Create a pipe with flags set atomically.\n\ -flags can be constructed by ORing together one or more of these values:\n\ -O_NONBLOCK, O_CLOEXEC.\n\ -"); +/*[clinic input] +os.pipe2 + + flags: int + / + +Create a pipe with flags set atomically. + +Returns a tuple of two file descriptors: + (read_fd, write_fd) + +flags can be constructed by ORing together one or more of these values: +O_NONBLOCK, O_CLOEXEC. +[clinic start generated code]*/ static PyObject * -posix_pipe2(PyObject *self, PyObject *arg) +os_pipe2_impl(PyModuleDef *module, int flags) +/*[clinic end generated code: output=c15b6075d0c6b2e7 input=f261b6e7e63c6817]*/ { - int flags; int fds[2]; int res; - flags = _PyLong_AsInt(arg); - if (flags == -1 && PyErr_Occurred()) - return NULL; - res = pipe2(fds, flags); if (res != 0) return posix_error(); @@ -8505,306 +8514,309 @@ posix_pipe2(PyObject *self, PyObject *arg) } #endif /* HAVE_PIPE2 */ + #ifdef HAVE_WRITEV -PyDoc_STRVAR(posix_writev__doc__, -"writev(fd, buffers) -> byteswritten\n\n\ -Write the contents of *buffers* to file descriptor *fd*. *buffers*\n\ -must be a sequence of bytes-like objects.\n\n\ -writev writes the contents of each object to the file descriptor\n\ -and returns the total number of bytes written."); +/*[clinic input] +os.writev -> Py_ssize_t + fd: int + buffers: object + / -static PyObject * -posix_writev(PyObject *self, PyObject *args) +Iterate over buffers, and write the contents of each to a file descriptor. + +Returns the total number of bytes written. +buffers must be a sequence of bytes-like objects. +[clinic start generated code]*/ + +static Py_ssize_t +os_writev_impl(PyModuleDef *module, int fd, PyObject *buffers) +/*[clinic end generated code: output=a48925dbf2d5c238 input=5b8d17fe4189d2fe]*/ { - int fd, cnt; - Py_ssize_t res; - PyObject *seq; + int cnt; + Py_ssize_t result; + int async_err = 0; struct iovec *iov; Py_buffer *buf; - if (!PyArg_ParseTuple(args, "iO:writev", &fd, &seq)) - return NULL; - if (!PySequence_Check(seq)) { + + if (!PySequence_Check(buffers)) { PyErr_SetString(PyExc_TypeError, "writev() arg 2 must be a sequence"); - return NULL; + return -1; } - cnt = PySequence_Size(seq); + cnt = PySequence_Size(buffers); - if (iov_setup(&iov, &buf, seq, cnt, PyBUF_SIMPLE) < 0) { - return NULL; + if (iov_setup(&iov, &buf, buffers, cnt, PyBUF_SIMPLE) < 0) { + return -1; } - Py_BEGIN_ALLOW_THREADS - res = writev(fd, iov, cnt); - Py_END_ALLOW_THREADS + do { + Py_BEGIN_ALLOW_THREADS + result = writev(fd, iov, cnt); + Py_END_ALLOW_THREADS + } while (result < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); iov_cleanup(iov, buf, cnt); - if (res < 0) - return posix_error(); + if (result < 0 && !async_err) + posix_error(); - return PyLong_FromSsize_t(res); + return result; } -#endif +#endif /* HAVE_WRITEV */ + #ifdef HAVE_PWRITE -PyDoc_STRVAR(posix_pwrite__doc__, -"pwrite(fd, string, offset) -> byteswritten\n\n\ -Write string to a file descriptor, fd, from offset, leaving the file\n\ -offset unchanged."); +/*[clinic input] +os.pwrite -> Py_ssize_t -static PyObject * -posix_pwrite(PyObject *self, PyObject *args) + fd: int + buffer: Py_buffer + offset: Py_off_t + / + +Write bytes to a file descriptor starting at a particular offset. + +Write buffer to fd, starting at offset bytes from the beginning of +the file. Returns the number of bytes writte. Does not change the +current file offset. +[clinic start generated code]*/ + +static Py_ssize_t +os_pwrite_impl(PyModuleDef *module, int fd, Py_buffer *buffer, Py_off_t offset) +/*[clinic end generated code: output=95225f3b496feaf3 input=19903f1b3dd26377]*/ { - Py_buffer pbuf; - int fd; - off_t offset; Py_ssize_t size; - - if (!PyArg_ParseTuple(args, "iy*O&:pwrite", &fd, &pbuf, _parse_off_t, &offset)) - return NULL; + int async_err = 0; if (!_PyVerify_fd(fd)) { - PyBuffer_Release(&pbuf); - return posix_error(); + posix_error(); + return -1; } - Py_BEGIN_ALLOW_THREADS - size = pwrite(fd, pbuf.buf, (size_t)pbuf.len, offset); - Py_END_ALLOW_THREADS - PyBuffer_Release(&pbuf); - if (size < 0) - return posix_error(); - return PyLong_FromSsize_t(size); + + do { + Py_BEGIN_ALLOW_THREADS + size = pwrite(fd, buffer->buf, (size_t)buffer->len, offset); + Py_END_ALLOW_THREADS + } while (size < 0 && errno == EINTR && !(async_err = PyErr_CheckSignals())); + + if (size < 0 && !async_err) + posix_error(); + return size; } -#endif +#endif /* HAVE_PWRITE */ + #ifdef HAVE_MKFIFO -PyDoc_STRVAR(posix_mkfifo__doc__, -"mkfifo(path, mode=0o666, *, dir_fd=None)\n\n\ -Create a FIFO (a POSIX named pipe).\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 implemented on your platform.\n\ - If it is unavailable, using it will raise a NotImplementedError."); +/*[clinic input] +os.mkfifo + + path: path_t + mode: int=0o666 + * + dir_fd: dir_fd(requires='mkfifoat')=None + +Create a "fifo" (a POSIX named pipe). + +If dir_fd is 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. +dir_fd may not be implemented on your platform. + If it is unavailable, using it will raise a NotImplementedError. +[clinic start generated code]*/ static PyObject * -posix_mkfifo(PyObject *self, PyObject *args, PyObject *kwargs) +os_mkfifo_impl(PyModuleDef *module, path_t *path, int mode, int dir_fd) +/*[clinic end generated code: output=8f5f5e72c630049a input=73032e98a36e0e19]*/ { - path_t path; - int mode = 0666; - int dir_fd = DEFAULT_DIR_FD; int result; - PyObject *return_value = NULL; - static char *keywords[] = {"path", "mode", "dir_fd", NULL}; + int async_err = 0; - memset(&path, 0, sizeof(path)); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|i$O&:mkfifo", keywords, - path_converter, &path, - &mode, + do { + Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKFIFOAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd + if (dir_fd != DEFAULT_DIR_FD) + result = mkfifoat(dir_fd, path->narrow, mode); + else #endif - )) - return NULL; + result = mkfifo(path->narrow, mode); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; - Py_BEGIN_ALLOW_THREADS -#ifdef HAVE_MKFIFOAT - if (dir_fd != DEFAULT_DIR_FD) - result = mkfifoat(dir_fd, path.narrow, mode); - else -#endif - result = mkfifo(path.narrow, mode); - Py_END_ALLOW_THREADS + Py_RETURN_NONE; +} +#endif /* HAVE_MKFIFO */ - if (result < 0) { - return_value = posix_error(); - goto exit; - } - return_value = Py_None; - Py_INCREF(Py_None); +#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) +/*[clinic input] +os.mknod -exit: - path_cleanup(&path); - return return_value; -} -#endif + path: path_t + mode: int=0o600 + device: dev_t=0 + * + dir_fd: dir_fd(requires='mknodat')=None -#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) -PyDoc_STRVAR(posix_mknod__doc__, -"mknod(filename, mode=0o600, device=0, *, dir_fd=None)\n\n\ -Create a filesystem node (file, device special file or named pipe)\n\ -named filename. mode specifies both the permissions to use and the\n\ -type of node to be created, being combined (bitwise OR) with one of\n\ -S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. For S_IFCHR and S_IFBLK,\n\ -device defines the newly created device special file (probably using\n\ -os.makedev()), otherwise it is ignored.\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 implemented on your platform.\n\ - If it is unavailable, using it will raise a NotImplementedError."); +Create a node in the file system. +Create a node in the file system (file, device special file or named pipe) +at path. mode specifies both the permissions to use and the +type of node to be created, being combined (bitwise OR) with one of +S_IFREG, S_IFCHR, S_IFBLK, and S_IFIFO. If S_IFCHR or S_IFBLK is set on mode, +device defines the newly created device special file (probably using +os.makedev()). Otherwise device is ignored. + +If dir_fd is 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. +dir_fd may not be implemented on your platform. + If it is unavailable, using it will raise a NotImplementedError. +[clinic start generated code]*/ static PyObject * -posix_mknod(PyObject *self, PyObject *args, PyObject *kwargs) +os_mknod_impl(PyModuleDef *module, path_t *path, int mode, dev_t device, int dir_fd) +/*[clinic end generated code: output=f7f813e8847de12f input=ee44531551a4d83b]*/ { - path_t path; - int mode = 0666; - dev_t device = 0; - int dir_fd = DEFAULT_DIR_FD; int result; - PyObject *return_value = NULL; - static char *keywords[] = {"path", "mode", "device", "dir_fd", NULL}; + int async_err = 0; - memset(&path, 0, sizeof(path)); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|iO&$O&:mknod", keywords, - path_converter, &path, - &mode, _Py_Dev_Converter, &device, + do { + Py_BEGIN_ALLOW_THREADS #ifdef HAVE_MKNODAT - dir_fd_converter, &dir_fd -#else - dir_fd_unavailable, &dir_fd + if (dir_fd != DEFAULT_DIR_FD) + result = mknodat(dir_fd, path->narrow, mode, device); + else #endif - )) - return NULL; + result = mknod(path->narrow, mode, device); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; - Py_BEGIN_ALLOW_THREADS -#ifdef HAVE_MKNODAT - if (dir_fd != DEFAULT_DIR_FD) - result = mknodat(dir_fd, path.narrow, mode, device); - else -#endif - result = mknod(path.narrow, mode, device); - Py_END_ALLOW_THREADS + Py_RETURN_NONE; +} +#endif /* defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) */ - if (result < 0) { - return_value = posix_error(); - goto exit; - } - return_value = Py_None; - Py_INCREF(Py_None); +#ifdef HAVE_DEVICE_MACROS +/*[clinic input] +os.major -> unsigned_int -exit: - path_cleanup(&path); - return return_value; -} -#endif + device: dev_t + / -#ifdef HAVE_DEVICE_MACROS -PyDoc_STRVAR(posix_major__doc__, -"major(device) -> major number\n\ -Extracts a device major number from a raw device number."); +Extracts a device major number from a raw device number. +[clinic start generated code]*/ -static PyObject * -posix_major(PyObject *self, PyObject *args) +static unsigned int +os_major_impl(PyModuleDef *module, dev_t device) +/*[clinic end generated code: output=ba55693ab49bac34 input=1e16a4d30c4d4462]*/ { - dev_t device; - if (!PyArg_ParseTuple(args, "O&:major", _Py_Dev_Converter, &device)) - return NULL; - return PyLong_FromLong((long)major(device)); + return major(device); } -PyDoc_STRVAR(posix_minor__doc__, -"minor(device) -> minor number\n\ -Extracts a device minor number from a raw device number."); -static PyObject * -posix_minor(PyObject *self, PyObject *args) +/*[clinic input] +os.minor -> unsigned_int + + device: dev_t + / + +Extracts a device minor number from a raw device number. +[clinic start generated code]*/ + +static unsigned int +os_minor_impl(PyModuleDef *module, dev_t device) +/*[clinic end generated code: output=2867219ebf274e27 input=0842c6d23f24c65e]*/ { - dev_t device; - if (!PyArg_ParseTuple(args, "O&:minor", _Py_Dev_Converter, &device)) - return NULL; - return PyLong_FromLong((long)minor(device)); + return minor(device); } -PyDoc_STRVAR(posix_makedev__doc__, -"makedev(major, minor) -> device number\n\ -Composes a raw device number from the major and minor device numbers."); -static PyObject * -posix_makedev(PyObject *self, PyObject *args) +/*[clinic input] +os.makedev -> dev_t + + major: int + minor: int + / + +Composes a raw device number from the major and minor device numbers. +[clinic start generated code]*/ + +static dev_t +os_makedev_impl(PyModuleDef *module, int major, int minor) +/*[clinic end generated code: output=7cb6264352437660 input=4b9fd8fc73cbe48f]*/ { - int major, minor; - if (!PyArg_ParseTuple(args, "ii:makedev", &major, &minor)) - return NULL; - return _PyLong_FromDev(makedev(major, minor)); + return makedev(major, minor); } -#endif /* device macros */ +#endif /* HAVE_DEVICE_MACROS */ #ifdef HAVE_FTRUNCATE -PyDoc_STRVAR(posix_ftruncate__doc__, -"ftruncate(fd, length)\n\n\ -Truncate a file to a specified length."); +/*[clinic input] +os.ftruncate + + fd: int + length: Py_off_t + / + +Truncate a file, specified by file descriptor, to a specific length. +[clinic start generated code]*/ static PyObject * -posix_ftruncate(PyObject *self, PyObject *args) +os_ftruncate_impl(PyModuleDef *module, int fd, Py_off_t length) +/*[clinic end generated code: output=3666f401d76bf834 input=63b43641e52818f2]*/ { - int fd; - off_t length; - int res; - - if (!PyArg_ParseTuple(args, "iO&:ftruncate", &fd, _parse_off_t, &length)) - return NULL; + int result; + int async_err = 0; - Py_BEGIN_ALLOW_THREADS - res = ftruncate(fd, length); - Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); - Py_INCREF(Py_None); - return Py_None; + do { + Py_BEGIN_ALLOW_THREADS + result = ftruncate(fd, length); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; + Py_RETURN_NONE; } -#endif +#endif /* HAVE_FTRUNCATE */ + #ifdef HAVE_TRUNCATE -PyDoc_STRVAR(posix_truncate__doc__, -"truncate(path, length)\n\n\ -Truncate the file given by path to length bytes.\n\ -On some platforms, path may also be specified as an open file descriptor.\n\ - If this functionality is unavailable, using it raises an exception."); +/*[clinic input] +os.truncate + path: path_t(allow_fd='PATH_HAVE_FTRUNCATE') + length: Py_off_t + +Truncate a file, specified by path, to a specific length. + +On some platforms, path may also be specified as an open file descriptor. + If this functionality is unavailable, using it raises an exception. +[clinic start generated code]*/ static PyObject * -posix_truncate(PyObject *self, PyObject *args, PyObject *kwargs) +os_truncate_impl(PyModuleDef *module, path_t *path, Py_off_t length) +/*[clinic end generated code: output=f60a9e08370e9e2e input=77229cf0b50a9b77]*/ { - path_t path; - off_t length; - int res; - PyObject *result = NULL; - static char *keywords[] = {"path", "length", NULL}; - - memset(&path, 0, sizeof(path)); - path.function_name = "truncate"; -#ifdef HAVE_FTRUNCATE - path.allow_fd = 1; -#endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:truncate", keywords, - path_converter, &path, - _parse_off_t, &length)) - return NULL; + int result; Py_BEGIN_ALLOW_THREADS #ifdef HAVE_FTRUNCATE - if (path.fd != -1) - res = ftruncate(path.fd, length); + if (path->fd != -1) + result = ftruncate(path->fd, length); else #endif - res = truncate(path.narrow, length); + result = truncate(path->narrow, length); Py_END_ALLOW_THREADS - if (res < 0) - result = path_error(&path); - else { - Py_INCREF(Py_None); - result = Py_None; - } - path_cleanup(&path); - return result; + if (result < 0) + return path_error(path); + + Py_RETURN_NONE; } -#endif +#endif /* HAVE_TRUNCATE */ + /* Issue #22396: On 32-bit AIX platform, the prototypes of os.posix_fadvise() and os.posix_fallocate() in system headers are wrong if _LARGE_FILES is @@ -8814,186 +8826,209 @@ posix_truncate(PyObject *self, PyObject *args, PyObject *kwargs) # define POSIX_FADVISE_AIX_BUG #endif + #if defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG) -PyDoc_STRVAR(posix_posix_fallocate__doc__, -"posix_fallocate(fd, offset, len)\n\n\ -Ensures that enough disk space is allocated for the file specified by fd\n\ -starting from offset and continuing for len bytes."); +/*[clinic input] +os.posix_fallocate + + fd: int + offset: Py_off_t + length: Py_off_t + / + +Ensure a file has allocated at least a particular number of bytes on disk. + +Ensure that the file specified by fd encompasses a range of bytes +starting at offset bytes from the beginning and continuing for length bytes. +[clinic start generated code]*/ static PyObject * -posix_posix_fallocate(PyObject *self, PyObject *args) +os_posix_fallocate_impl(PyModuleDef *module, int fd, Py_off_t offset, Py_off_t length) +/*[clinic end generated code: output=8ae5f7837004d454 input=d7a2ef0ab2ca52fb]*/ { - off_t len, offset; - int res, fd; - - if (!PyArg_ParseTuple(args, "iO&O&:posix_fallocate", - &fd, _parse_off_t, &offset, _parse_off_t, &len)) - return NULL; + int result; + int async_err = 0; - Py_BEGIN_ALLOW_THREADS - res = posix_fallocate(fd, offset, len); - Py_END_ALLOW_THREADS - if (res != 0) { - errno = res; - return posix_error(); - } + do { + Py_BEGIN_ALLOW_THREADS + result = posix_fallocate(fd, offset, length); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; Py_RETURN_NONE; } -#endif +#endif /* HAVE_POSIX_FALLOCATE) && !POSIX_FADVISE_AIX_BUG */ + #if defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG) -PyDoc_STRVAR(posix_posix_fadvise__doc__, -"posix_fadvise(fd, offset, len, advice)\n\n\ -Announces an intention to access data in a specific pattern thus allowing\n\ -the kernel to make optimizations.\n\ -The advice applies to the region of the file specified by fd starting at\n\ -offset and continuing for len bytes.\n\ -advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL,\n\ -POSIX_FADV_RANDOM, POSIX_FADV_NOREUSE, POSIX_FADV_WILLNEED or\n\ -POSIX_FADV_DONTNEED."); +/*[clinic input] +os.posix_fadvise + + fd: int + offset: Py_off_t + length: Py_off_t + advice: int + / + +Announce an intention to access data in a specific pattern. + +Announce an intention to access data in a specific pattern, thus allowing +the kernel to make optimizations. +The advice applies to the region of the file specified by fd starting at +offset and continuing for length bytes. +advice is one of POSIX_FADV_NORMAL, POSIX_FADV_SEQUENTIAL, +POSIX_FADV_RANDOM, POSIX_FADV_NOREUSE, POSIX_FADV_WILLNEED, or +POSIX_FADV_DONTNEED. +[clinic start generated code]*/ static PyObject * -posix_posix_fadvise(PyObject *self, PyObject *args) +os_posix_fadvise_impl(PyModuleDef *module, int fd, Py_off_t offset, Py_off_t length, int advice) +/*[clinic end generated code: output=0e3f09f651661257 input=0fbe554edc2f04b5]*/ { - off_t len, offset; - int res, fd, advice; - - if (!PyArg_ParseTuple(args, "iO&O&i:posix_fadvise", - &fd, _parse_off_t, &offset, _parse_off_t, &len, &advice)) - return NULL; + int result; + int async_err = 0; - Py_BEGIN_ALLOW_THREADS - res = posix_fadvise(fd, offset, len, advice); - Py_END_ALLOW_THREADS - if (res != 0) { - errno = res; - return posix_error(); - } + do { + Py_BEGIN_ALLOW_THREADS + result = posix_fadvise(fd, offset, length, advice); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; Py_RETURN_NONE; } -#endif +#endif /* HAVE_POSIX_FADVISE && !POSIX_FADVISE_AIX_BUG */ #ifdef HAVE_PUTENV -PyDoc_STRVAR(posix_putenv__doc__, -"putenv(key, value)\n\n\ -Change or add an environment variable."); /* Save putenv() parameters as values here, so we can collect them when they * get re-set with another call for the same key. */ static PyObject *posix_putenv_garbage; -static PyObject * -posix_putenv(PyObject *self, PyObject *args) +static void +posix_putenv_garbage_setitem(PyObject *name, PyObject *value) { - PyObject *newstr = NULL; + /* Install the first arg and newstr in posix_putenv_garbage; + * this will cause previous value to be collected. This has to + * happen after the real putenv() call because the old value + * was still accessible until then. */ + if (PyDict_SetItem(posix_putenv_garbage, name, value)) + /* really not much we can do; just leak */ + PyErr_Clear(); + else + Py_DECREF(value); +} + + #ifdef MS_WINDOWS - PyObject *os1, *os2; - wchar_t *newenv; +/*[clinic input] +os.putenv - if (!PyArg_ParseTuple(args, - "UU:putenv", - &os1, &os2)) - return NULL; + name: unicode + value: unicode + / + +Change or add an environment variable. +[clinic start generated code]*/ + +static PyObject * +os_putenv_impl(PyModuleDef *module, PyObject *name, PyObject *value) +/*[clinic end generated code: output=a2438cf95e5a0c1c input=ba586581c2e6105f]*/ +{ + wchar_t *env; - newstr = PyUnicode_FromFormat("%U=%U", os1, os2); - if (newstr == NULL) { + PyObject *unicode = PyUnicode_FromFormat("%U=%U", name, value); + if (unicode == NULL) { PyErr_NoMemory(); - goto error; + return NULL; } - if (_MAX_ENV < PyUnicode_GET_LENGTH(newstr)) { + if (_MAX_ENV < PyUnicode_GET_LENGTH(unicode)) { PyErr_Format(PyExc_ValueError, "the environment variable is longer than %u characters", _MAX_ENV); goto error; } - newenv = PyUnicode_AsUnicode(newstr); - if (newenv == NULL) + env = PyUnicode_AsUnicode(unicode); + if (env == NULL) goto error; - if (_wputenv(newenv)) { + if (_wputenv(env)) { posix_error(); goto error; } -#else - PyObject *os1, *os2; - char *s1, *s2; - char *newenv; - - if (!PyArg_ParseTuple(args, - "O&O&:putenv", - PyUnicode_FSConverter, &os1, - PyUnicode_FSConverter, &os2)) - return NULL; - s1 = PyBytes_AsString(os1); - s2 = PyBytes_AsString(os2); - newstr = PyBytes_FromFormat("%s=%s", s1, s2); - if (newstr == NULL) { - PyErr_NoMemory(); - goto error; - } + posix_putenv_garbage_setitem(name, unicode); + Py_RETURN_NONE; - newenv = PyBytes_AS_STRING(newstr); - if (putenv(newenv)) { - posix_error(); - goto error; - } -#endif +error: + Py_DECREF(unicode); + return NULL; +} +#else /* MS_WINDOWS */ +/*[clinic input] +os.putenv - /* Install the first arg and newstr in posix_putenv_garbage; - * this will cause previous value to be collected. This has to - * happen after the real putenv() call because the old value - * was still accessible until then. */ - if (PyDict_SetItem(posix_putenv_garbage, os1, newstr)) { - /* really not much we can do; just leak */ - PyErr_Clear(); + name: FSConverter + value: FSConverter + / + +Change or add an environment variable. +[clinic start generated code]*/ + +static PyObject * +os_putenv_impl(PyModuleDef *module, PyObject *name, PyObject *value) +/*[clinic end generated code: output=a2438cf95e5a0c1c input=a97bc6152f688d31]*/ +{ + PyObject *bytes = NULL; + char *env; + char *name_string = PyBytes_AsString(name); + char *value_string = PyBytes_AsString(value); + + bytes = PyBytes_FromFormat("%s=%s", name_string, value_string); + if (bytes == NULL) { + PyErr_NoMemory(); + return NULL; } - else { - Py_DECREF(newstr); + + env = PyBytes_AS_STRING(bytes); + if (putenv(env)) { + Py_DECREF(bytes); + return posix_error(); } -#ifndef MS_WINDOWS - Py_DECREF(os1); - Py_DECREF(os2); -#endif + posix_putenv_garbage_setitem(name, bytes); Py_RETURN_NONE; - -error: -#ifndef MS_WINDOWS - Py_DECREF(os1); - Py_DECREF(os2); -#endif - Py_XDECREF(newstr); - return NULL; } -#endif /* putenv */ +#endif /* MS_WINDOWS */ +#endif /* HAVE_PUTENV */ + #ifdef HAVE_UNSETENV -PyDoc_STRVAR(posix_unsetenv__doc__, -"unsetenv(key)\n\n\ -Delete an environment variable."); +/*[clinic input] +os.unsetenv + name: FSConverter + / + +Delete an environment variable. +[clinic start generated code]*/ static PyObject * -posix_unsetenv(PyObject *self, PyObject *args) +os_unsetenv_impl(PyModuleDef *module, PyObject *name) +/*[clinic end generated code: output=25994b57016a2dc9 input=2bb5288a599c7107]*/ { - PyObject *name; #ifndef HAVE_BROKEN_UNSETENV int err; #endif - if (!PyArg_ParseTuple(args, "O&:unsetenv", - - PyUnicode_FSConverter, &name)) - return NULL; - #ifdef HAVE_BROKEN_UNSETENV unsetenv(PyBytes_AS_STRING(name)); #else err = unsetenv(PyBytes_AS_STRING(name)); - if (err) { - Py_DECREF(name); + if (err) return posix_error(); - } #endif /* Remove the key from posix_putenv_garbage; @@ -9005,23 +9040,25 @@ posix_unsetenv(PyObject *self, PyObject *args) /* really not much we can do; just leak */ PyErr_Clear(); } - Py_DECREF(name); Py_RETURN_NONE; } -#endif /* unsetenv */ +#endif /* HAVE_UNSETENV */ + + +/*[clinic input] +os.strerror + + code: int + / -PyDoc_STRVAR(posix_strerror__doc__, -"strerror(code) -> string\n\n\ -Translate an error code to a message string."); +Translate an error code to a message string. +[clinic start generated code]*/ static PyObject * -posix_strerror(PyObject *self, PyObject *args) +os_strerror_impl(PyModuleDef *module, int code) +/*[clinic end generated code: output=0280c6af51e5c9fe input=75a8673d97915a91]*/ { - int code; - char *message; - if (!PyArg_ParseTuple(args, "i:strerror", &code)) - return NULL; - message = strerror(code); + char *message = strerror(code); if (message == NULL) { PyErr_SetString(PyExc_ValueError, "strerror() argument out of range"); @@ -9032,155 +9069,168 @@ posix_strerror(PyObject *self, PyObject *args) #ifdef HAVE_SYS_WAIT_H - #ifdef WCOREDUMP -PyDoc_STRVAR(posix_WCOREDUMP__doc__, -"WCOREDUMP(status) -> bool\n\n\ -Return True if the process returning 'status' was dumped to a core file."); +/*[clinic input] +os.WCOREDUMP -> bool -static PyObject * -posix_WCOREDUMP(PyObject *self, PyObject *args) -{ - WAIT_TYPE status; - WAIT_STATUS_INT(status) = 0; + status: int + / - if (!PyArg_ParseTuple(args, "i:WCOREDUMP", &WAIT_STATUS_INT(status))) - return NULL; +Return True if the process returning status was dumped to a core file. +[clinic start generated code]*/ - return PyBool_FromLong(WCOREDUMP(status)); +static int +os_WCOREDUMP_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=134f70bbe63fbf41 input=8b05e7ab38528d04]*/ +{ + WAIT_TYPE wait_status; + WAIT_STATUS_INT(wait_status) = status; + return WCOREDUMP(wait_status); } #endif /* WCOREDUMP */ + #ifdef WIFCONTINUED -PyDoc_STRVAR(posix_WIFCONTINUED__doc__, -"WIFCONTINUED(status) -> bool\n\n\ -Return True if the process returning 'status' was continued from a\n\ -job control stop."); +/*[clinic input] +os.WIFCONTINUED -> bool -static PyObject * -posix_WIFCONTINUED(PyObject *self, PyObject *args) -{ - WAIT_TYPE status; - WAIT_STATUS_INT(status) = 0; + status: int - if (!PyArg_ParseTuple(args, "i:WCONTINUED", &WAIT_STATUS_INT(status))) - return NULL; +Return True if a particular process was continued from a job control stop. - return PyBool_FromLong(WIFCONTINUED(status)); +Return True if the process returning status was continued from a +job control stop. +[clinic start generated code]*/ + +static int +os_WIFCONTINUED_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=9cdd26543ebb6dcd input=e777e7d38eb25bd9]*/ +{ + WAIT_TYPE wait_status; + WAIT_STATUS_INT(wait_status) = status; + return WIFCONTINUED(wait_status); } #endif /* WIFCONTINUED */ + #ifdef WIFSTOPPED -PyDoc_STRVAR(posix_WIFSTOPPED__doc__, -"WIFSTOPPED(status) -> bool\n\n\ -Return True if the process returning 'status' was stopped."); +/*[clinic input] +os.WIFSTOPPED -> bool -static PyObject * -posix_WIFSTOPPED(PyObject *self, PyObject *args) -{ - WAIT_TYPE status; - WAIT_STATUS_INT(status) = 0; + status: int - if (!PyArg_ParseTuple(args, "i:WIFSTOPPED", &WAIT_STATUS_INT(status))) - return NULL; +Return True if the process returning status was stopped. +[clinic start generated code]*/ - return PyBool_FromLong(WIFSTOPPED(status)); +static int +os_WIFSTOPPED_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=73bf35e44994a724 input=043cb7f1289ef904]*/ +{ + WAIT_TYPE wait_status; + WAIT_STATUS_INT(wait_status) = status; + return WIFSTOPPED(wait_status); } #endif /* WIFSTOPPED */ + #ifdef WIFSIGNALED -PyDoc_STRVAR(posix_WIFSIGNALED__doc__, -"WIFSIGNALED(status) -> bool\n\n\ -Return True if the process returning 'status' was terminated by a signal."); +/*[clinic input] +os.WIFSIGNALED -> bool -static PyObject * -posix_WIFSIGNALED(PyObject *self, PyObject *args) -{ - WAIT_TYPE status; - WAIT_STATUS_INT(status) = 0; + status: int - if (!PyArg_ParseTuple(args, "i:WIFSIGNALED", &WAIT_STATUS_INT(status))) - return NULL; +Return True if the process returning status was terminated by a signal. +[clinic start generated code]*/ - return PyBool_FromLong(WIFSIGNALED(status)); +static int +os_WIFSIGNALED_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=2697975771872420 input=d55ba7cc9ce5dc43]*/ +{ + WAIT_TYPE wait_status; + WAIT_STATUS_INT(wait_status) = status; + return WIFSIGNALED(wait_status); } #endif /* WIFSIGNALED */ + #ifdef WIFEXITED -PyDoc_STRVAR(posix_WIFEXITED__doc__, -"WIFEXITED(status) -> bool\n\n\ -Return true if the process returning 'status' exited using the exit()\n\ -system call."); +/*[clinic input] +os.WIFEXITED -> bool -static PyObject * -posix_WIFEXITED(PyObject *self, PyObject *args) -{ - WAIT_TYPE status; - WAIT_STATUS_INT(status) = 0; + status: int - if (!PyArg_ParseTuple(args, "i:WIFEXITED", &WAIT_STATUS_INT(status))) - return NULL; +Return True if the process returning status exited via the exit() system call. +[clinic start generated code]*/ - return PyBool_FromLong(WIFEXITED(status)); +static int +os_WIFEXITED_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=ca8f8c61f0b8532e input=d63775a6791586c0]*/ +{ + WAIT_TYPE wait_status; + WAIT_STATUS_INT(wait_status) = status; + return WIFEXITED(wait_status); } #endif /* WIFEXITED */ + #ifdef WEXITSTATUS -PyDoc_STRVAR(posix_WEXITSTATUS__doc__, -"WEXITSTATUS(status) -> integer\n\n\ -Return the process return code from 'status'."); +/*[clinic input] +os.WEXITSTATUS -> int -static PyObject * -posix_WEXITSTATUS(PyObject *self, PyObject *args) -{ - WAIT_TYPE status; - WAIT_STATUS_INT(status) = 0; + status: int - if (!PyArg_ParseTuple(args, "i:WEXITSTATUS", &WAIT_STATUS_INT(status))) - return NULL; +Return the process return code from status. +[clinic start generated code]*/ - return Py_BuildValue("i", WEXITSTATUS(status)); +static int +os_WEXITSTATUS_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=ea54da23d9e0f6af input=e1fb4944e377585b]*/ +{ + WAIT_TYPE wait_status; + WAIT_STATUS_INT(wait_status) = status; + return WEXITSTATUS(wait_status); } #endif /* WEXITSTATUS */ + #ifdef WTERMSIG -PyDoc_STRVAR(posix_WTERMSIG__doc__, -"WTERMSIG(status) -> integer\n\n\ -Return the signal that terminated the process that provided the 'status'\n\ -value."); +/*[clinic input] +os.WTERMSIG -> int -static PyObject * -posix_WTERMSIG(PyObject *self, PyObject *args) -{ - WAIT_TYPE status; - WAIT_STATUS_INT(status) = 0; + status: int - if (!PyArg_ParseTuple(args, "i:WTERMSIG", &WAIT_STATUS_INT(status))) - return NULL; +Return the signal that terminated the process that provided the status value. +[clinic start generated code]*/ - return Py_BuildValue("i", WTERMSIG(status)); +static int +os_WTERMSIG_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=4d25367026cb852c input=727fd7f84ec3f243]*/ +{ + WAIT_TYPE wait_status; + WAIT_STATUS_INT(wait_status) = status; + return WTERMSIG(wait_status); } #endif /* WTERMSIG */ + #ifdef WSTOPSIG -PyDoc_STRVAR(posix_WSTOPSIG__doc__, -"WSTOPSIG(status) -> integer\n\n\ -Return the signal that stopped the process that provided\n\ -the 'status' value."); +/*[clinic input] +os.WSTOPSIG -> int -static PyObject * -posix_WSTOPSIG(PyObject *self, PyObject *args) -{ - WAIT_TYPE status; - WAIT_STATUS_INT(status) = 0; + status: int - if (!PyArg_ParseTuple(args, "i:WSTOPSIG", &WAIT_STATUS_INT(status))) - return NULL; +Return the signal that stopped the process that provided the status value. +[clinic start generated code]*/ - return Py_BuildValue("i", WSTOPSIG(status)); +static int +os_WSTOPSIG_impl(PyModuleDef *module, int status) +/*[clinic end generated code: output=54eb9c13b001adb4 input=46ebf1d1b293c5c1]*/ +{ + WAIT_TYPE wait_status; + WAIT_STATUS_INT(wait_status) = status; + return WSTOPSIG(wait_status); } #endif /* WSTOPSIG */ - #endif /* HAVE_SYS_WAIT_H */ @@ -9235,104 +9285,101 @@ _pystatvfs_fromstructstatvfs(struct statvfs st) { return v; } -PyDoc_STRVAR(posix_fstatvfs__doc__, -"fstatvfs(fd) -> statvfs result\n\n\ -Perform an fstatvfs system call on the given fd.\n\ -Equivalent to statvfs(fd)."); + +/*[clinic input] +os.fstatvfs + fd: int + / + +Perform an fstatvfs system call on the given fd. + +Equivalent to statvfs(fd). +[clinic start generated code]*/ static PyObject * -posix_fstatvfs(PyObject *self, PyObject *args) +os_fstatvfs_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=584a94a754497ac0 input=d8122243ac50975e]*/ { - int fd, res; + int result; + int async_err = 0; struct statvfs st; - if (!PyArg_ParseTuple(args, "i:fstatvfs", &fd)) - return NULL; - Py_BEGIN_ALLOW_THREADS - res = fstatvfs(fd, &st); - Py_END_ALLOW_THREADS - if (res != 0) - return posix_error(); + do { + Py_BEGIN_ALLOW_THREADS + result = fstatvfs(fd, &st); + Py_END_ALLOW_THREADS + } while (result != 0 && errno == EINTR && + !(async_err = PyErr_CheckSignals())); + if (result != 0) + return (!async_err) ? posix_error() : NULL; return _pystatvfs_fromstructstatvfs(st); } -#endif /* HAVE_FSTATVFS && HAVE_SYS_STATVFS_H */ +#endif /* defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H) */ #if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) #include <sys/statvfs.h> +/*[clinic input] +os.statvfs -PyDoc_STRVAR(posix_statvfs__doc__, -"statvfs(path)\n\n\ -Perform a statvfs system call on the given path.\n\ -\n\ -path may always be specified as a string.\n\ -On some platforms, path may also be specified as an open file descriptor.\n\ - If this functionality is unavailable, using it raises an exception."); + path: path_t(allow_fd='PATH_HAVE_FSTATVFS') + +Perform a statvfs system call on the given path. + +path may always be specified as a string. +On some platforms, path may also be specified as an open file descriptor. + If this functionality is unavailable, using it raises an exception. +[clinic start generated code]*/ static PyObject * -posix_statvfs(PyObject *self, PyObject *args, PyObject *kwargs) +os_statvfs_impl(PyModuleDef *module, path_t *path) +/*[clinic end generated code: output=5ced07a2cf931f41 input=3f5c35791c669bd9]*/ { - static char *keywords[] = {"path", NULL}; - path_t path; int result; - PyObject *return_value = NULL; struct statvfs st; - memset(&path, 0, sizeof(path)); - path.function_name = "statvfs"; -#ifdef HAVE_FSTATVFS - path.allow_fd = 1; -#endif - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:statvfs", keywords, - path_converter, &path - )) - return NULL; - Py_BEGIN_ALLOW_THREADS #ifdef HAVE_FSTATVFS - if (path.fd != -1) { + if (path->fd != -1) { #ifdef __APPLE__ /* handle weak-linking on Mac OS X 10.3 */ if (fstatvfs == NULL) { - fd_specified("statvfs", path.fd); - goto exit; + fd_specified("statvfs", path->fd); + return NULL; } #endif - result = fstatvfs(path.fd, &st); + result = fstatvfs(path->fd, &st); } else #endif - result = statvfs(path.narrow, &st); + result = statvfs(path->narrow, &st); Py_END_ALLOW_THREADS if (result) { - return_value = path_error(&path); - goto exit; + return path_error(path); } - return_value = _pystatvfs_fromstructstatvfs(st); - -exit: - path_cleanup(&path); - return return_value; + return _pystatvfs_fromstructstatvfs(st); } -#endif /* HAVE_STATVFS */ +#endif /* defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) */ + #ifdef MS_WINDOWS -PyDoc_STRVAR(win32__getdiskusage__doc__, -"_getdiskusage(path) -> (total, free)\n\n\ -Return disk usage statistics about the given path as (total, free) tuple."); +/*[clinic input] +os._getdiskusage + + path: Py_UNICODE + +Return disk usage statistics about the given path as a (total, free) tuple. +[clinic start generated code]*/ static PyObject * -win32__getdiskusage(PyObject *self, PyObject *args) +os__getdiskusage_impl(PyModuleDef *module, Py_UNICODE *path) +/*[clinic end generated code: output=60a9cf33449db1dd input=6458133aed893c78]*/ { BOOL retval; ULARGE_INTEGER _, total, free; - const wchar_t *path; - - if (! PyArg_ParseTuple(args, "u", &path)) - return NULL; Py_BEGIN_ALLOW_THREADS retval = GetDiskFreeSpaceExW(path, &_, &total, &free); @@ -9342,7 +9389,7 @@ win32__getdiskusage(PyObject *self, PyObject *args) return Py_BuildValue("(LL)", total.QuadPart, free.QuadPart); } -#endif +#endif /* MS_WINDOWS */ /* This is used for fpathconf(), pathconf(), confstr() and sysconf(). @@ -9499,81 +9546,73 @@ conv_path_confname(PyObject *arg, int *valuep) } #endif + #ifdef HAVE_FPATHCONF -PyDoc_STRVAR(posix_fpathconf__doc__, -"fpathconf(fd, name) -> integer\n\n\ -Return the configuration limit name for the file descriptor fd.\n\ -If there is no limit, return -1."); +/*[clinic input] +os.fpathconf -> long -static PyObject * -posix_fpathconf(PyObject *self, PyObject *args) + fd: int + name: path_confname + / + +Return the configuration limit name for the file descriptor fd. + +If there is no limit, return -1. +[clinic start generated code]*/ + +static long +os_fpathconf_impl(PyModuleDef *module, int fd, int name) +/*[clinic end generated code: output=082b2922d4441de7 input=5942a024d3777810]*/ { - PyObject *result = NULL; - int name, fd; + long limit; - if (PyArg_ParseTuple(args, "iO&:fpathconf", &fd, - conv_path_confname, &name)) { - long limit; + errno = 0; + limit = fpathconf(fd, name); + if (limit == -1 && errno != 0) + posix_error(); - errno = 0; - limit = fpathconf(fd, name); - if (limit == -1 && errno != 0) - posix_error(); - else - result = PyLong_FromLong(limit); - } - return result; + return limit; } -#endif +#endif /* HAVE_FPATHCONF */ #ifdef HAVE_PATHCONF -PyDoc_STRVAR(posix_pathconf__doc__, -"pathconf(path, name) -> integer\n\n\ -Return the configuration limit name for the file or directory path.\n\ -If there is no limit, return -1.\n\ -On some platforms, path may also be specified as an open file descriptor.\n\ - If this functionality is unavailable, using it raises an exception."); +/*[clinic input] +os.pathconf -> long + path: path_t(allow_fd='PATH_HAVE_FPATHCONF') + name: path_confname -static PyObject * -posix_pathconf(PyObject *self, PyObject *args, PyObject *kwargs) -{ - path_t path; - PyObject *result = NULL; - int name; - static char *keywords[] = {"path", "name", NULL}; +Return the configuration limit name for the file or directory path. - memset(&path, 0, sizeof(path)); - path.function_name = "pathconf"; -#ifdef HAVE_FPATHCONF - path.allow_fd = 1; -#endif - if (PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:pathconf", keywords, - path_converter, &path, - conv_path_confname, &name)) { +If there is no limit, return -1. +On some platforms, path may also be specified as an open file descriptor. + If this functionality is unavailable, using it raises an exception. +[clinic start generated code]*/ + +static long +os_pathconf_impl(PyModuleDef *module, path_t *path, int name) +/*[clinic end generated code: output=3713029e9501f5ab input=bc3e2a985af27e5e]*/ +{ long limit; errno = 0; #ifdef HAVE_FPATHCONF - if (path.fd != -1) - limit = fpathconf(path.fd, name); + if (path->fd != -1) + limit = fpathconf(path->fd, name); else #endif - limit = pathconf(path.narrow, name); + limit = pathconf(path->narrow, name); if (limit == -1 && errno != 0) { if (errno == EINVAL) /* could be a path or name problem */ posix_error(); else - result = path_error(&path); - } - else - result = PyLong_FromLong(limit); + path_error(path); } - path_cleanup(&path); - return result; + + return limit; } -#endif +#endif /* HAVE_PATHCONF */ #ifdef HAVE_CONFSTR static struct constdef posix_constants_confstr[] = { @@ -9737,21 +9776,24 @@ conv_confstr_confname(PyObject *arg, int *valuep) / sizeof(struct constdef)); } -PyDoc_STRVAR(posix_confstr__doc__, -"confstr(name) -> string\n\n\ -Return a string-valued system configuration variable."); + +/*[clinic input] +os.confstr + + name: confstr_confname + / + +Return a string-valued system configuration variable. +[clinic start generated code]*/ static PyObject * -posix_confstr(PyObject *self, PyObject *args) +os_confstr_impl(PyModuleDef *module, int name) +/*[clinic end generated code: output=6ff79c9eed8c2daf input=18fb4d0567242e65]*/ { PyObject *result = NULL; - int name; char buffer[255]; size_t len; - if (!PyArg_ParseTuple(args, "O&:confstr", conv_confstr_confname, &name)) - return NULL; - errno = 0; len = confstr(name, buffer, sizeof(buffer)); if (len == 0) { @@ -9765,10 +9807,12 @@ posix_confstr(PyObject *self, PyObject *args) } if (len >= sizeof(buffer)) { + size_t len2; char *buf = PyMem_Malloc(len); if (buf == NULL) return PyErr_NoMemory(); - confstr(name, buf, len); + len2 = confstr(name, buf, len); + assert(len == len2); result = PyUnicode_DecodeFSDefaultAndSize(buf, len-1); PyMem_Free(buf); } @@ -9776,7 +9820,7 @@ posix_confstr(PyObject *self, PyObject *args) result = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1); return result; } -#endif +#endif /* HAVE_CONFSTR */ #ifdef HAVE_SYSCONF @@ -10283,29 +10327,28 @@ conv_sysconf_confname(PyObject *arg, int *valuep) / sizeof(struct constdef)); } -PyDoc_STRVAR(posix_sysconf__doc__, -"sysconf(name) -> integer\n\n\ -Return an integer-valued system configuration variable."); -static PyObject * -posix_sysconf(PyObject *self, PyObject *args) -{ - PyObject *result = NULL; - int name; +/*[clinic input] +os.sysconf -> long + name: sysconf_confname + / + +Return an integer-valued system configuration variable. +[clinic start generated code]*/ - if (PyArg_ParseTuple(args, "O&:sysconf", conv_sysconf_confname, &name)) { - long value; +static long +os_sysconf_impl(PyModuleDef *module, int name) +/*[clinic end generated code: output=ed567306f58d69c4 input=279e3430a33f29e4]*/ +{ + long value; - errno = 0; - value = sysconf(name); - if (value == -1 && errno != 0) - posix_error(); - else - result = PyLong_FromLong(value); - } - return result; + errno = 0; + value = sysconf(name); + if (value == -1 && errno != 0) + posix_error(); + return value; } -#endif +#endif /* HAVE_SYSCONF */ /* This code is used to ensure that the tables of configuration value names @@ -10382,13 +10425,18 @@ setup_confname_tables(PyObject *module) } -PyDoc_STRVAR(posix_abort__doc__, -"abort() -> does not return!\n\n\ -Abort the interpreter immediately. This 'dumps core' or otherwise fails\n\ -in the hardest way possible on the hosting operating system."); +/*[clinic input] +os.abort + +Abort the interpreter immediately. + +This function 'dumps core' or otherwise fails in the hardest way possible +on the hosting operating system. This function never returns. +[clinic start generated code]*/ static PyObject * -posix_abort(PyObject *self, PyObject *noargs) +os_abort_impl(PyModuleDef *module) +/*[clinic end generated code: output=486bb96647c299b3 input=cf2c7d98bc504047]*/ { abort(); /*NOTREACHED*/ @@ -10397,9 +10445,11 @@ posix_abort(PyObject *self, PyObject *noargs) } #ifdef MS_WINDOWS +/* AC 3.5: change to path_t? but that might change exceptions */ PyDoc_STRVAR(win32_startfile__doc__, -"startfile(filepath [, operation]) - Start a file with its associated\n\ -application.\n\ +"startfile(filepath [, operation])\n\ +\n\ +Start a file with its associated application.\n\ \n\ When \"operation\" is not specified or \"open\", this acts like\n\ double-clicking the file in Explorer, or giving the file name as an\n\ @@ -10416,6 +10466,37 @@ The filepath is relative to the current directory. If you want to use\n\ an absolute path, make sure the first character is not a slash (\"/\");\n\ the underlying Win32 ShellExecute function doesn't work if it is."); +/* Grab ShellExecute dynamically from shell32 */ +static int has_ShellExecute = -1; +static HINSTANCE (CALLBACK *Py_ShellExecuteA)(HWND, LPCSTR, LPCSTR, LPCSTR, + LPCSTR, INT); +static HINSTANCE (CALLBACK *Py_ShellExecuteW)(HWND, LPCWSTR, LPCWSTR, LPCWSTR, + LPCWSTR, INT); +static int +check_ShellExecute() +{ + HINSTANCE hShell32; + + /* only recheck */ + if (-1 == has_ShellExecute) { + Py_BEGIN_ALLOW_THREADS + hShell32 = LoadLibraryW(L"SHELL32"); + Py_END_ALLOW_THREADS + if (hShell32) { + *(FARPROC*)&Py_ShellExecuteA = GetProcAddress(hShell32, + "ShellExecuteA"); + *(FARPROC*)&Py_ShellExecuteW = GetProcAddress(hShell32, + "ShellExecuteW"); + has_ShellExecute = Py_ShellExecuteA && + Py_ShellExecuteW; + } else { + has_ShellExecute = 0; + } + } + return has_ShellExecute; +} + + static PyObject * win32_startfile(PyObject *self, PyObject *args) { @@ -10426,6 +10507,14 @@ win32_startfile(PyObject *self, PyObject *args) HINSTANCE rc; PyObject *unipath, *uoperation = NULL; + + if(!check_ShellExecute()) { + /* If the OS doesn't have ShellExecute, return a + NotImplementedError. */ + return PyErr_Format(PyExc_NotImplementedError, + "startfile not available on this platform"); + } + if (!PyArg_ParseTuple(args, "U|s:startfile", &unipath, &operation)) { PyErr_Clear(); @@ -10454,8 +10543,8 @@ win32_startfile(PyObject *self, PyObject *args) woperation = NULL; Py_BEGIN_ALLOW_THREADS - rc = ShellExecuteW((HWND)0, woperation, wpath, - NULL, NULL, SW_SHOWNORMAL); + rc = Py_ShellExecuteW((HWND)0, woperation, wpath, + NULL, NULL, SW_SHOWNORMAL); Py_END_ALLOW_THREADS Py_XDECREF(uoperation); @@ -10477,8 +10566,8 @@ normal: } filepath = PyBytes_AsString(ofilepath); Py_BEGIN_ALLOW_THREADS - rc = ShellExecute((HWND)0, operation, filepath, - NULL, NULL, SW_SHOWNORMAL); + rc = Py_ShellExecuteA((HWND)0, operation, filepath, + NULL, NULL, SW_SHOWNORMAL); Py_END_ALLOW_THREADS if (rc <= (HINSTANCE)32) { PyObject *errval = win32_error("startfile", filepath); @@ -10489,17 +10578,23 @@ normal: Py_INCREF(Py_None); return Py_None; } -#endif +#endif /* MS_WINDOWS */ + #ifdef HAVE_GETLOADAVG -PyDoc_STRVAR(posix_getloadavg__doc__, -"getloadavg() -> (float, float, float)\n\n\ -Return the number of processes in the system run queue averaged over\n\ -the last 1, 5, and 15 minutes or raises OSError if the load average\n\ -was unobtainable"); +/*[clinic input] +os.getloadavg + +Return average recent system load information. + +Return the number of processes in the system run queue averaged over +the last 1, 5, and 15 minutes as a tuple of three floats. +Raises OSError if the load average was unobtainable. +[clinic start generated code]*/ static PyObject * -posix_getloadavg(PyObject *self, PyObject *noargs) +os_getloadavg_impl(PyModuleDef *module) +/*[clinic end generated code: output=2b64c5b675d74c14 input=3d6d826b76d8a34e]*/ { double loadavg[3]; if (getloadavg(loadavg, 3)!=3) { @@ -10508,72 +10603,83 @@ posix_getloadavg(PyObject *self, PyObject *noargs) } else return Py_BuildValue("ddd", loadavg[0], loadavg[1], loadavg[2]); } -#endif +#endif /* HAVE_GETLOADAVG */ -PyDoc_STRVAR(device_encoding__doc__, -"device_encoding(fd) -> str\n\n\ -Return a string describing the encoding of the device\n\ -if the output is a terminal; else return None."); -static PyObject * -device_encoding(PyObject *self, PyObject *args) -{ - int fd; +/*[clinic input] +os.device_encoding + fd: int - if (!PyArg_ParseTuple(args, "i:device_encoding", &fd)) - return NULL; +Return a string describing the encoding of a terminal's file descriptor. + +The file descriptor must be attached to a terminal. +If the device is not a terminal, return None. +[clinic start generated code]*/ +static PyObject * +os_device_encoding_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=34f14e33468419c1 input=9e1d4a42b66df312]*/ +{ return _Py_device_encoding(fd); } + #ifdef HAVE_SETRESUID -PyDoc_STRVAR(posix_setresuid__doc__, -"setresuid(ruid, euid, suid)\n\n\ -Set the current process's real, effective, and saved user ids."); +/*[clinic input] +os.setresuid -static PyObject* -posix_setresuid (PyObject *self, PyObject *args) + ruid: uid_t + euid: uid_t + suid: uid_t + / + +Set the current process's real, effective, and saved user ids. +[clinic start generated code]*/ + +static PyObject * +os_setresuid_impl(PyModuleDef *module, uid_t ruid, uid_t euid, uid_t suid) +/*[clinic end generated code: output=92cc330812c6ed0f input=9e33cb79a82792f3]*/ { - /* We assume uid_t is no larger than a long. */ - uid_t ruid, euid, suid; - if (!PyArg_ParseTuple(args, "O&O&O&:setresuid", - _Py_Uid_Converter, &ruid, - _Py_Uid_Converter, &euid, - _Py_Uid_Converter, &suid)) - return NULL; if (setresuid(ruid, euid, suid) < 0) return posix_error(); Py_RETURN_NONE; } -#endif +#endif /* HAVE_SETRESUID */ + #ifdef HAVE_SETRESGID -PyDoc_STRVAR(posix_setresgid__doc__, -"setresgid(rgid, egid, sgid)\n\n\ -Set the current process's real, effective, and saved group ids."); +/*[clinic input] +os.setresgid -static PyObject* -posix_setresgid (PyObject *self, PyObject *args) + rgid: gid_t + egid: gid_t + sgid: gid_t + / + +Set the current process's real, effective, and saved group ids. +[clinic start generated code]*/ + +static PyObject * +os_setresgid_impl(PyModuleDef *module, gid_t rgid, gid_t egid, gid_t sgid) +/*[clinic end generated code: output=e91dc4842a604429 input=33e9e0785ef426b1]*/ { - gid_t rgid, egid, sgid; - if (!PyArg_ParseTuple(args, "O&O&O&:setresgid", - _Py_Gid_Converter, &rgid, - _Py_Gid_Converter, &egid, - _Py_Gid_Converter, &sgid)) - return NULL; if (setresgid(rgid, egid, sgid) < 0) return posix_error(); Py_RETURN_NONE; } -#endif +#endif /* HAVE_SETRESGID */ + #ifdef HAVE_GETRESUID -PyDoc_STRVAR(posix_getresuid__doc__, -"getresuid() -> (ruid, euid, suid)\n\n\ -Get tuple of the current process's real, effective, and saved user ids."); +/*[clinic input] +os.getresuid -static PyObject* -posix_getresuid (PyObject *self, PyObject *noargs) +Return a tuple of the current process's real, effective, and saved user ids. +[clinic start generated code]*/ + +static PyObject * +os_getresuid_impl(PyModuleDef *module) +/*[clinic end generated code: output=9ddef62faae8e477 input=41ccfa8e1f6517ad]*/ { uid_t ruid, euid, suid; if (getresuid(&ruid, &euid, &suid) < 0) @@ -10582,90 +10688,87 @@ posix_getresuid (PyObject *self, PyObject *noargs) _PyLong_FromUid(euid), _PyLong_FromUid(suid)); } -#endif +#endif /* HAVE_GETRESUID */ + #ifdef HAVE_GETRESGID -PyDoc_STRVAR(posix_getresgid__doc__, -"getresgid() -> (rgid, egid, sgid)\n\n\ -Get tuple of the current process's real, effective, and saved group ids."); +/*[clinic input] +os.getresgid -static PyObject* -posix_getresgid (PyObject *self, PyObject *noargs) +Return a tuple of the current process's real, effective, and saved group ids. +[clinic start generated code]*/ + +static PyObject * +os_getresgid_impl(PyModuleDef *module) +/*[clinic end generated code: output=e1a553cbcf16234c input=517e68db9ca32df6]*/ { - uid_t rgid, egid, sgid; + gid_t rgid, egid, sgid; if (getresgid(&rgid, &egid, &sgid) < 0) return posix_error(); return Py_BuildValue("(NNN)", _PyLong_FromGid(rgid), _PyLong_FromGid(egid), _PyLong_FromGid(sgid)); } -#endif +#endif /* HAVE_GETRESGID */ + #ifdef USE_XATTRS +/*[clinic input] +os.getxattr -PyDoc_STRVAR(posix_getxattr__doc__, -"getxattr(path, attribute, *, follow_symlinks=True) -> value\n\n\ -Return the value of extended attribute attribute on path.\n\ -\n\ -path may be either a string or an open file descriptor.\n\ -If follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, getxattr will examine the symbolic link itself instead of the file\n\ - the link points to."); + path: path_t(allow_fd=True) + attribute: path_t + * + follow_symlinks: bool = True + +Return the value of extended attribute attribute on path. + +path may be either a string or an open file descriptor. +If follow_symlinks is False, and the last element of the path is a symbolic + link, getxattr will examine the symbolic link itself instead of the file + the link points to. + +[clinic start generated code]*/ static PyObject * -posix_getxattr(PyObject *self, PyObject *args, PyObject *kwargs) +os_getxattr_impl(PyModuleDef *module, path_t *path, path_t *attribute, int follow_symlinks) +/*[clinic end generated code: output=d90086b314859f8b input=8c8ea3bab78d89c2]*/ { - path_t path; - path_t attribute; - int follow_symlinks = 1; + Py_ssize_t i; PyObject *buffer = NULL; - int i; - static char *keywords[] = {"path", "attribute", "follow_symlinks", NULL}; - memset(&path, 0, sizeof(path)); - memset(&attribute, 0, sizeof(attribute)); - path.function_name = "getxattr"; - attribute.function_name = "getxattr"; - path.allow_fd = 1; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|$p:getxattr", keywords, - path_converter, &path, - path_converter, &attribute, - &follow_symlinks)) + if (fd_and_follow_symlinks_invalid("getxattr", path->fd, follow_symlinks)) return NULL; - if (fd_and_follow_symlinks_invalid("getxattr", path.fd, follow_symlinks)) - goto exit; - for (i = 0; ; i++) { void *ptr; ssize_t result; static Py_ssize_t buffer_sizes[] = {128, XATTR_SIZE_MAX, 0}; Py_ssize_t buffer_size = buffer_sizes[i]; if (!buffer_size) { - path_error(&path); - goto exit; + path_error(path); + return NULL; } buffer = PyBytes_FromStringAndSize(NULL, buffer_size); if (!buffer) - goto exit; + return NULL; ptr = PyBytes_AS_STRING(buffer); Py_BEGIN_ALLOW_THREADS; - if (path.fd >= 0) - result = fgetxattr(path.fd, attribute.narrow, ptr, buffer_size); + if (path->fd >= 0) + result = fgetxattr(path->fd, attribute->narrow, ptr, buffer_size); else if (follow_symlinks) - result = getxattr(path.narrow, attribute.narrow, ptr, buffer_size); + result = getxattr(path->narrow, attribute->narrow, ptr, buffer_size); else - result = lgetxattr(path.narrow, attribute.narrow, ptr, buffer_size); + result = lgetxattr(path->narrow, attribute->narrow, ptr, buffer_size); Py_END_ALLOW_THREADS; if (result < 0) { Py_DECREF(buffer); - buffer = NULL; if (errno == ERANGE) continue; - path_error(&path); - goto exit; + path_error(path); + return NULL; } if (result != buffer_size) { @@ -10675,168 +10778,132 @@ posix_getxattr(PyObject *self, PyObject *args, PyObject *kwargs) break; } -exit: - path_cleanup(&path); - path_cleanup(&attribute); return buffer; } -PyDoc_STRVAR(posix_setxattr__doc__, -"setxattr(path, attribute, value, flags=0, *, follow_symlinks=True)\n\n\ -Set extended attribute attribute on path to value.\n\ -path may be either a string or an open file descriptor.\n\ -If follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, setxattr will modify the symbolic link itself instead of the file\n\ - the link points to."); + +/*[clinic input] +os.setxattr + + path: path_t(allow_fd=True) + attribute: path_t + value: Py_buffer + flags: int = 0 + * + follow_symlinks: bool = True + +Set extended attribute attribute on path to value. + +path may be either a string or an open file descriptor. +If follow_symlinks is False, and the last element of the path is a symbolic + link, setxattr will modify the symbolic link itself instead of the file + the link points to. + +[clinic start generated code]*/ static PyObject * -posix_setxattr(PyObject *self, PyObject *args, PyObject *kwargs) +os_setxattr_impl(PyModuleDef *module, path_t *path, path_t *attribute, Py_buffer *value, int flags, int follow_symlinks) +/*[clinic end generated code: output=e3defa5c4b1ad0ae input=f0d26833992015c2]*/ { - path_t path; - path_t attribute; - Py_buffer value; - int flags = 0; - int follow_symlinks = 1; - int result; - PyObject *return_value = NULL; - static char *keywords[] = {"path", "attribute", "value", - "flags", "follow_symlinks", NULL}; + ssize_t result; - memset(&path, 0, sizeof(path)); - path.function_name = "setxattr"; - path.allow_fd = 1; - memset(&attribute, 0, sizeof(attribute)); - memset(&value, 0, sizeof(value)); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&y*|i$p:setxattr", - keywords, - path_converter, &path, - path_converter, &attribute, - &value, &flags, - &follow_symlinks)) + if (fd_and_follow_symlinks_invalid("setxattr", path->fd, follow_symlinks)) return NULL; - if (fd_and_follow_symlinks_invalid("setxattr", path.fd, follow_symlinks)) - goto exit; - Py_BEGIN_ALLOW_THREADS; - if (path.fd > -1) - result = fsetxattr(path.fd, attribute.narrow, - value.buf, value.len, flags); + if (path->fd > -1) + result = fsetxattr(path->fd, attribute->narrow, + value->buf, value->len, flags); else if (follow_symlinks) - result = setxattr(path.narrow, attribute.narrow, - value.buf, value.len, flags); + result = setxattr(path->narrow, attribute->narrow, + value->buf, value->len, flags); else - result = lsetxattr(path.narrow, attribute.narrow, - value.buf, value.len, flags); + result = lsetxattr(path->narrow, attribute->narrow, + value->buf, value->len, flags); Py_END_ALLOW_THREADS; if (result) { - return_value = path_error(&path); - goto exit; + path_error(path); + return NULL; } - return_value = Py_None; - Py_INCREF(return_value); + Py_RETURN_NONE; +} -exit: - path_cleanup(&path); - path_cleanup(&attribute); - PyBuffer_Release(&value); - return return_value; -} +/*[clinic input] +os.removexattr -PyDoc_STRVAR(posix_removexattr__doc__, -"removexattr(path, attribute, *, follow_symlinks=True)\n\n\ -Remove extended attribute attribute on path.\n\ -path may be either a string or an open file descriptor.\n\ -If follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, removexattr will modify the symbolic link itself instead of the file\n\ - the link points to."); + path: path_t(allow_fd=True) + attribute: path_t + * + follow_symlinks: bool = True + +Remove extended attribute attribute on path. + +path may be either a string or an open file descriptor. +If follow_symlinks is False, and the last element of the path is a symbolic + link, removexattr will modify the symbolic link itself instead of the file + the link points to. + +[clinic start generated code]*/ static PyObject * -posix_removexattr(PyObject *self, PyObject *args, PyObject *kwargs) +os_removexattr_impl(PyModuleDef *module, path_t *path, path_t *attribute, int follow_symlinks) +/*[clinic end generated code: output=4870ec90249af875 input=cdb54834161e3329]*/ { - path_t path; - path_t attribute; - int follow_symlinks = 1; - int result; - PyObject *return_value = NULL; - static char *keywords[] = {"path", "attribute", "follow_symlinks", NULL}; + ssize_t result; - memset(&path, 0, sizeof(path)); - path.function_name = "removexattr"; - memset(&attribute, 0, sizeof(attribute)); - attribute.function_name = "removexattr"; - path.allow_fd = 1; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&|$p:removexattr", - keywords, - path_converter, &path, - path_converter, &attribute, - &follow_symlinks)) + if (fd_and_follow_symlinks_invalid("removexattr", path->fd, follow_symlinks)) return NULL; - if (fd_and_follow_symlinks_invalid("removexattr", path.fd, follow_symlinks)) - goto exit; - Py_BEGIN_ALLOW_THREADS; - if (path.fd > -1) - result = fremovexattr(path.fd, attribute.narrow); + if (path->fd > -1) + result = fremovexattr(path->fd, attribute->narrow); else if (follow_symlinks) - result = removexattr(path.narrow, attribute.narrow); + result = removexattr(path->narrow, attribute->narrow); else - result = lremovexattr(path.narrow, attribute.narrow); + result = lremovexattr(path->narrow, attribute->narrow); Py_END_ALLOW_THREADS; if (result) { - return_value = path_error(&path); - goto exit; + return path_error(path); } - return_value = Py_None; - Py_INCREF(return_value); + Py_RETURN_NONE; +} -exit: - path_cleanup(&path); - path_cleanup(&attribute); - return return_value; -} +/*[clinic input] +os.listxattr -PyDoc_STRVAR(posix_listxattr__doc__, -"listxattr(path='.', *, follow_symlinks=True)\n\n\ -Return a list of extended attributes on path.\n\ -\n\ -path may be either None, a string, or an open file descriptor.\n\ -if path is None, listxattr will examine the current directory.\n\ -If follow_symlinks is False, and the last element of the path is a symbolic\n\ - link, listxattr will examine the symbolic link itself instead of the file\n\ - the link points to."); + path: path_t(allow_fd=True, nullable=True) = None + * + follow_symlinks: bool = True + +Return a list of extended attributes on path. + +path may be either None, a string, or an open file descriptor. +if path is None, listxattr will examine the current directory. +If follow_symlinks is False, and the last element of the path is a symbolic + link, listxattr will examine the symbolic link itself instead of the file + the link points to. +[clinic start generated code]*/ static PyObject * -posix_listxattr(PyObject *self, PyObject *args, PyObject *kwargs) +os_listxattr_impl(PyModuleDef *module, path_t *path, int follow_symlinks) +/*[clinic end generated code: output=a87ad6ce56e42a4f input=08cca53ac0b07c13]*/ { - path_t path; - int follow_symlinks = 1; Py_ssize_t i; PyObject *result = NULL; + const char *name; char *buffer = NULL; - char *name; - static char *keywords[] = {"path", "follow_symlinks", NULL}; - - memset(&path, 0, sizeof(path)); - path.function_name = "listxattr"; - path.allow_fd = 1; - path.fd = -1; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&$p:listxattr", keywords, - path_converter, &path, - &follow_symlinks)) - return NULL; - if (fd_and_follow_symlinks_invalid("listxattr", path.fd, follow_symlinks)) + if (fd_and_follow_symlinks_invalid("listxattr", path->fd, follow_symlinks)) goto exit; - name = path.narrow ? path.narrow : "."; + name = path->narrow ? path->narrow : "."; + for (i = 0; ; i++) { char *start, *trace, *end; ssize_t length; @@ -10844,7 +10911,7 @@ posix_listxattr(PyObject *self, PyObject *args, PyObject *kwargs) Py_ssize_t buffer_size = buffer_sizes[i]; if (!buffer_size) { /* ERANGE */ - path_error(&path); + path_error(path); break; } buffer = PyMem_MALLOC(buffer_size); @@ -10854,8 +10921,8 @@ posix_listxattr(PyObject *self, PyObject *args, PyObject *kwargs) } Py_BEGIN_ALLOW_THREADS; - if (path.fd > -1) - length = flistxattr(path.fd, buffer, buffer_size); + if (path->fd > -1) + length = flistxattr(path->fd, buffer, buffer_size); else if (follow_symlinks) length = listxattr(name, buffer, buffer_size); else @@ -10868,7 +10935,7 @@ posix_listxattr(PyObject *self, PyObject *args, PyObject *kwargs) buffer = NULL; continue; } - path_error(&path); + path_error(path); break; } @@ -10901,43 +10968,43 @@ posix_listxattr(PyObject *self, PyObject *args, PyObject *kwargs) break; } exit: - path_cleanup(&path); if (buffer) PyMem_FREE(buffer); return result; } - #endif /* USE_XATTRS */ -PyDoc_STRVAR(posix_urandom__doc__, -"urandom(n) -> str\n\n\ -Return n random bytes suitable for cryptographic use."); +/*[clinic input] +os.urandom + + size: Py_ssize_t + / + +Return a bytes object containing random bytes suitable for cryptographic use. +[clinic start generated code]*/ static PyObject * -posix_urandom(PyObject *self, PyObject *args) +os_urandom_impl(PyModuleDef *module, Py_ssize_t size) +/*[clinic end generated code: output=e0011f021501f03b input=4067cdb1b6776c29]*/ { - Py_ssize_t size; - PyObject *result; - int ret; + PyObject *bytes; + int result; - /* Read arguments */ - if (!PyArg_ParseTuple(args, "n:urandom", &size)) - return NULL; if (size < 0) return PyErr_Format(PyExc_ValueError, "negative argument not allowed"); - result = PyBytes_FromStringAndSize(NULL, size); - if (result == NULL) + bytes = PyBytes_FromStringAndSize(NULL, size); + if (bytes == NULL) return NULL; - ret = _PyOS_URandom(PyBytes_AS_STRING(result), - PyBytes_GET_SIZE(result)); - if (ret == -1) { - Py_DECREF(result); + result = _PyOS_URandom(PyBytes_AS_STRING(bytes), + PyBytes_GET_SIZE(bytes)); + if (result == -1) { + Py_DECREF(bytes); return NULL; } - return result; + return bytes; } /* Terminal size querying */ @@ -10961,6 +11028,7 @@ static PyStructSequence_Desc TerminalSize_desc = { }; #if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) +/* AC 3.5: fd should accept None */ PyDoc_STRVAR(termsize__doc__, "Return the size of the terminal window as (columns, lines).\n" \ "\n" \ @@ -11046,13 +11114,16 @@ get_terminal_size(PyObject *self, PyObject *args) } #endif /* defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) */ -PyDoc_STRVAR(posix_cpu_count__doc__, -"cpu_count() -> integer\n\n\ -Return the number of CPUs in the system, or None if this value cannot be\n\ -established."); + +/*[clinic input] +os.cpu_count + +Return the number of CPUs in the system; return None if indeterminable. +[clinic start generated code]*/ static PyObject * -posix_cpu_count(PyObject *self) +os_cpu_count_impl(PyModuleDef *module) +/*[clinic end generated code: output=c59ee7f6bce832b8 input=d55e2f8f3823a628]*/ { int ncpu = 0; #ifdef MS_WINDOWS @@ -11081,111 +11152,929 @@ posix_cpu_count(PyObject *self) Py_RETURN_NONE; } -PyDoc_STRVAR(get_inheritable__doc__, - "get_inheritable(fd) -> bool\n" \ + +/*[clinic input] +os.get_inheritable -> bool + + fd: int + / + +Get the close-on-exe flag of the specified file descriptor. +[clinic start generated code]*/ + +static int +os_get_inheritable_impl(PyModuleDef *module, int fd) +/*[clinic end generated code: output=36110bb36efaa21e input=89ac008dc9ab6b95]*/ +{ + if (!_PyVerify_fd(fd)){ + posix_error(); + return -1; + } + + return _Py_get_inheritable(fd); +} + + +/*[clinic input] +os.set_inheritable + fd: int + inheritable: int + / + +Set the inheritable flag of the specified file descriptor. +[clinic start generated code]*/ + +static PyObject * +os_set_inheritable_impl(PyModuleDef *module, int fd, int inheritable) +/*[clinic end generated code: output=2ac5c6ce8623f045 input=9ceaead87a1e2402]*/ +{ + if (!_PyVerify_fd(fd)) + return posix_error(); + + if (_Py_set_inheritable(fd, inheritable, NULL) < 0) + return NULL; + Py_RETURN_NONE; +} + + +#ifdef MS_WINDOWS +/*[clinic input] +os.get_handle_inheritable -> bool + handle: Py_intptr_t + / + +Get the close-on-exe flag of the specified file descriptor. +[clinic start generated code]*/ + +static int +os_get_handle_inheritable_impl(PyModuleDef *module, Py_intptr_t handle) +/*[clinic end generated code: output=3b7b3e1b43f312b6 input=5f7759443aae3dc5]*/ +{ + DWORD flags; + + if (!GetHandleInformation((HANDLE)handle, &flags)) { + PyErr_SetFromWindowsErr(0); + return -1; + } + + return flags & HANDLE_FLAG_INHERIT; +} + + +/*[clinic input] +os.set_handle_inheritable + handle: Py_intptr_t + inheritable: bool + / + +Set the inheritable flag of the specified handle. +[clinic start generated code]*/ + +static PyObject * +os_set_handle_inheritable_impl(PyModuleDef *module, Py_intptr_t handle, int inheritable) +/*[clinic end generated code: output=627aa5b158b69338 input=e64b2b2730469def]*/ +{ + DWORD flags = inheritable ? HANDLE_FLAG_INHERIT : 0; + if (!SetHandleInformation((HANDLE)handle, HANDLE_FLAG_INHERIT, flags)) { + PyErr_SetFromWindowsErr(0); + return NULL; + } + Py_RETURN_NONE; +} +#endif /* MS_WINDOWS */ + +#ifndef MS_WINDOWS +PyDoc_STRVAR(get_blocking__doc__, + "get_blocking(fd) -> bool\n" \ "\n" \ - "Get the close-on-exe flag of the specified file descriptor."); + "Get the blocking mode of the file descriptor:\n" \ + "False if the O_NONBLOCK flag is set, True if the flag is cleared."); static PyObject* -posix_get_inheritable(PyObject *self, PyObject *args) +posix_get_blocking(PyObject *self, PyObject *args) { int fd; - int inheritable; + int blocking; - if (!PyArg_ParseTuple(args, "i:get_inheritable", &fd)) + if (!PyArg_ParseTuple(args, "i:get_blocking", &fd)) return NULL; if (!_PyVerify_fd(fd)) return posix_error(); - inheritable = _Py_get_inheritable(fd); - if (inheritable < 0) + blocking = _Py_get_blocking(fd); + if (blocking < 0) return NULL; - return PyBool_FromLong(inheritable); + return PyBool_FromLong(blocking); } -PyDoc_STRVAR(set_inheritable__doc__, - "set_inheritable(fd, inheritable)\n" \ +PyDoc_STRVAR(set_blocking__doc__, + "set_blocking(fd, blocking)\n" \ "\n" \ - "Set the inheritable flag of the specified file descriptor."); + "Set the blocking mode of the specified file descriptor.\n" \ + "Set the O_NONBLOCK flag if blocking is False,\n" \ + "clear the O_NONBLOCK flag otherwise."); static PyObject* -posix_set_inheritable(PyObject *self, PyObject *args) +posix_set_blocking(PyObject *self, PyObject *args) { - int fd, inheritable; + int fd, blocking; - if (!PyArg_ParseTuple(args, "ii:set_inheritable", &fd, &inheritable)) + if (!PyArg_ParseTuple(args, "ii:set_blocking", &fd, &blocking)) return NULL; if (!_PyVerify_fd(fd)) return posix_error(); - if (_Py_set_inheritable(fd, inheritable, NULL) < 0) + if (_Py_set_blocking(fd, blocking) < 0) return NULL; Py_RETURN_NONE; } +#endif /* !MS_WINDOWS */ + + +PyDoc_STRVAR(posix_scandir__doc__, +"scandir(path='.') -> iterator of DirEntry objects for given path"); +static char *follow_symlinks_keywords[] = {"follow_symlinks", NULL}; +typedef struct { + PyObject_HEAD + PyObject *name; + PyObject *path; + PyObject *stat; + PyObject *lstat; #ifdef MS_WINDOWS -PyDoc_STRVAR(get_handle_inheritable__doc__, - "get_handle_inheritable(fd) -> bool\n" \ - "\n" \ - "Get the close-on-exe flag of the specified file descriptor."); + struct _Py_stat_struct win32_lstat; + __int64 win32_file_index; + int got_file_index; +#else /* POSIX */ +#ifdef HAVE_DIRENT_D_TYPE + unsigned char d_type; +#endif + ino_t d_ino; +#endif +} DirEntry; -static PyObject* -posix_get_handle_inheritable(PyObject *self, PyObject *args) +static void +DirEntry_dealloc(DirEntry *entry) { - Py_intptr_t handle; - DWORD flags; + Py_XDECREF(entry->name); + Py_XDECREF(entry->path); + Py_XDECREF(entry->stat); + Py_XDECREF(entry->lstat); + Py_TYPE(entry)->tp_free((PyObject *)entry); +} + +/* Forward reference */ +static int +DirEntry_test_mode(DirEntry *self, int follow_symlinks, unsigned short mode_bits); + +/* Set exception and return -1 on error, 0 for False, 1 for True */ +static int +DirEntry_is_symlink(DirEntry *self) +{ +#ifdef MS_WINDOWS + return (self->win32_lstat.st_mode & S_IFMT) == S_IFLNK; +#elif defined(HAVE_DIRENT_D_TYPE) + /* POSIX */ + if (self->d_type != DT_UNKNOWN) + return self->d_type == DT_LNK; + else + return DirEntry_test_mode(self, 0, S_IFLNK); +#else + /* POSIX without d_type */ + return DirEntry_test_mode(self, 0, S_IFLNK); +#endif +} - if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR ":get_handle_inheritable", &handle)) +static PyObject * +DirEntry_py_is_symlink(DirEntry *self) +{ + int result; + + result = DirEntry_is_symlink(self); + if (result == -1) return NULL; + return PyBool_FromLong(result); +} - if (!GetHandleInformation((HANDLE)handle, &flags)) { - PyErr_SetFromWindowsErr(0); +static PyObject * +DirEntry_fetch_stat(DirEntry *self, int follow_symlinks) +{ + int result; + struct _Py_stat_struct st; + +#ifdef MS_WINDOWS + wchar_t *path; + + path = PyUnicode_AsUnicode(self->path); + if (!path) return NULL; + + if (follow_symlinks) + result = win32_stat_w(path, &st); + else + result = win32_lstat_w(path, &st); + + if (result != 0) { + return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, + 0, self->path); } +#else /* POSIX */ + PyObject *bytes; + char *path; + + if (!PyUnicode_FSConverter(self->path, &bytes)) + return NULL; + path = PyBytes_AS_STRING(bytes); + + if (follow_symlinks) + result = STAT(path, &st); + else + result = LSTAT(path, &st); + Py_DECREF(bytes); - return PyBool_FromLong(flags & HANDLE_FLAG_INHERIT); + if (result != 0) + return PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError, self->path); +#endif + + return _pystat_fromstructstat(&st); } -PyDoc_STRVAR(set_handle_inheritable__doc__, - "set_handle_inheritable(fd, inheritable)\n" \ - "\n" \ - "Set the inheritable flag of the specified handle."); +static PyObject * +DirEntry_get_lstat(DirEntry *self) +{ + if (!self->lstat) { +#ifdef MS_WINDOWS + self->lstat = _pystat_fromstructstat(&self->win32_lstat); +#else /* POSIX */ + self->lstat = DirEntry_fetch_stat(self, 0); +#endif + } + Py_XINCREF(self->lstat); + return self->lstat; +} -static PyObject* -posix_set_handle_inheritable(PyObject *self, PyObject *args) +static PyObject * +DirEntry_get_stat(DirEntry *self, int follow_symlinks) { - int inheritable = 1; - Py_intptr_t handle; - DWORD flags; + if (!follow_symlinks) + return DirEntry_get_lstat(self); + + if (!self->stat) { + int result = DirEntry_is_symlink(self); + if (result == -1) + return NULL; + else if (result) + self->stat = DirEntry_fetch_stat(self, 1); + else + self->stat = DirEntry_get_lstat(self); + } + + Py_XINCREF(self->stat); + return self->stat; +} - if (!PyArg_ParseTuple(args, _Py_PARSE_INTPTR "i:set_handle_inheritable", - &handle, &inheritable)) +static PyObject * +DirEntry_stat(DirEntry *self, PyObject *args, PyObject *kwargs) +{ + int follow_symlinks = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$p:DirEntry.stat", + follow_symlinks_keywords, &follow_symlinks)) return NULL; - if (inheritable) - flags = HANDLE_FLAG_INHERIT; - else - flags = 0; - if (!SetHandleInformation((HANDLE)handle, HANDLE_FLAG_INHERIT, flags)) { - PyErr_SetFromWindowsErr(0); + return DirEntry_get_stat(self, follow_symlinks); +} + +/* Set exception and return -1 on error, 0 for False, 1 for True */ +static int +DirEntry_test_mode(DirEntry *self, int follow_symlinks, unsigned short mode_bits) +{ + PyObject *stat = NULL; + PyObject *st_mode = NULL; + long mode; + int result; +#if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE) + int is_symlink; + int need_stat; +#endif +#ifdef MS_WINDOWS + unsigned long dir_bits; +#endif + _Py_IDENTIFIER(st_mode); + +#ifdef MS_WINDOWS + is_symlink = (self->win32_lstat.st_mode & S_IFMT) == S_IFLNK; + need_stat = follow_symlinks && is_symlink; +#elif defined(HAVE_DIRENT_D_TYPE) + is_symlink = self->d_type == DT_LNK; + need_stat = self->d_type == DT_UNKNOWN || (follow_symlinks && is_symlink); +#endif + +#if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE) + if (need_stat) { +#endif + stat = DirEntry_get_stat(self, follow_symlinks); + if (!stat) { + if (PyErr_ExceptionMatches(PyExc_FileNotFoundError)) { + /* If file doesn't exist (anymore), then return False + (i.e., say it's not a file/directory) */ + PyErr_Clear(); + return 0; + } + goto error; + } + st_mode = _PyObject_GetAttrId(stat, &PyId_st_mode); + if (!st_mode) + goto error; + + mode = PyLong_AsLong(st_mode); + if (mode == -1 && PyErr_Occurred()) + goto error; + Py_CLEAR(st_mode); + Py_CLEAR(stat); + result = (mode & S_IFMT) == mode_bits; +#if defined(MS_WINDOWS) || defined(HAVE_DIRENT_D_TYPE) + } + else if (is_symlink) { + assert(mode_bits != S_IFLNK); + result = 0; + } + else { + assert(mode_bits == S_IFDIR || mode_bits == S_IFREG); +#ifdef MS_WINDOWS + dir_bits = self->win32_lstat.st_file_attributes & FILE_ATTRIBUTE_DIRECTORY; + if (mode_bits == S_IFDIR) + result = dir_bits != 0; + else + result = dir_bits == 0; +#else /* POSIX */ + if (mode_bits == S_IFDIR) + result = self->d_type == DT_DIR; + else + result = self->d_type == DT_REG; +#endif + } +#endif + + return result; + +error: + Py_XDECREF(st_mode); + Py_XDECREF(stat); + return -1; +} + +static PyObject * +DirEntry_py_test_mode(DirEntry *self, int follow_symlinks, unsigned short mode_bits) +{ + int result; + + result = DirEntry_test_mode(self, follow_symlinks, mode_bits); + if (result == -1) + return NULL; + return PyBool_FromLong(result); +} + +static PyObject * +DirEntry_is_dir(DirEntry *self, PyObject *args, PyObject *kwargs) +{ + int follow_symlinks = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$p:DirEntry.is_dir", + follow_symlinks_keywords, &follow_symlinks)) + return NULL; + + return DirEntry_py_test_mode(self, follow_symlinks, S_IFDIR); +} + +static PyObject * +DirEntry_is_file(DirEntry *self, PyObject *args, PyObject *kwargs) +{ + int follow_symlinks = 1; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|$p:DirEntry.is_file", + follow_symlinks_keywords, &follow_symlinks)) return NULL; + + return DirEntry_py_test_mode(self, follow_symlinks, S_IFREG); +} + +static PyObject * +DirEntry_inode(DirEntry *self) +{ +#ifdef MS_WINDOWS + if (!self->got_file_index) { + wchar_t *path; + struct _Py_stat_struct stat; + + path = PyUnicode_AsUnicode(self->path); + if (!path) + return NULL; + + if (win32_lstat_w(path, &stat) != 0) { + return PyErr_SetExcFromWindowsErrWithFilenameObject(PyExc_OSError, + 0, self->path); + } + + self->win32_file_index = stat.st_ino; + self->got_file_index = 1; } - Py_RETURN_NONE; + return PyLong_FromLongLong((PY_LONG_LONG)self->win32_file_index); +#else /* POSIX */ +#ifdef HAVE_LARGEFILE_SUPPORT + return PyLong_FromLongLong((PY_LONG_LONG)self->d_ino); +#else + return PyLong_FromLong((long)self->d_ino); +#endif +#endif } -#endif /* MS_WINDOWS */ +static PyObject * +DirEntry_repr(DirEntry *self) +{ + return PyUnicode_FromFormat("<DirEntry %R>", self->name); +} + +static PyMemberDef DirEntry_members[] = { + {"name", T_OBJECT_EX, offsetof(DirEntry, name), READONLY, + "the entry's base filename, relative to scandir() \"path\" argument"}, + {"path", T_OBJECT_EX, offsetof(DirEntry, path), READONLY, + "the entry's full path name; equivalent to os.path.join(scandir_path, entry.name)"}, + {NULL} +}; + +static PyMethodDef DirEntry_methods[] = { + {"is_dir", (PyCFunction)DirEntry_is_dir, METH_VARARGS | METH_KEYWORDS, + "return True if the entry is a directory; cached per entry" + }, + {"is_file", (PyCFunction)DirEntry_is_file, METH_VARARGS | METH_KEYWORDS, + "return True if the entry is a file; cached per entry" + }, + {"is_symlink", (PyCFunction)DirEntry_py_is_symlink, METH_NOARGS, + "return True if the entry is a symbolic link; cached per entry" + }, + {"stat", (PyCFunction)DirEntry_stat, METH_VARARGS | METH_KEYWORDS, + "return stat_result object for the entry; cached per entry" + }, + {"inode", (PyCFunction)DirEntry_inode, METH_NOARGS, + "return inode of the entry; cached per entry", + }, + {NULL} +}; + +PyTypeObject DirEntryType = { + PyVarObject_HEAD_INIT(NULL, 0) + MODNAME ".DirEntry", /* tp_name */ + sizeof(DirEntry), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)DirEntry_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)DirEntry_repr, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + DirEntry_methods, /* tp_methods */ + DirEntry_members, /* tp_members */ +}; + +#ifdef MS_WINDOWS + +static wchar_t * +join_path_filenameW(wchar_t *path_wide, wchar_t* filename) +{ + Py_ssize_t path_len; + Py_ssize_t size; + wchar_t *result; + wchar_t ch; + + if (!path_wide) { /* Default arg: "." */ + path_wide = L"."; + path_len = 1; + } + else { + path_len = wcslen(path_wide); + } + + /* The +1's are for the path separator and the NUL */ + size = path_len + 1 + wcslen(filename) + 1; + result = PyMem_New(wchar_t, size); + if (!result) { + PyErr_NoMemory(); + return NULL; + } + wcscpy(result, path_wide); + if (path_len > 0) { + ch = result[path_len - 1]; + if (ch != SEP && ch != ALTSEP && ch != L':') + result[path_len++] = SEP; + wcscpy(result + path_len, filename); + } + return result; +} + +static PyObject * +DirEntry_from_find_data(path_t *path, WIN32_FIND_DATAW *dataW) +{ + DirEntry *entry; + BY_HANDLE_FILE_INFORMATION file_info; + ULONG reparse_tag; + wchar_t *joined_path; + + entry = PyObject_New(DirEntry, &DirEntryType); + if (!entry) + return NULL; + entry->name = NULL; + entry->path = NULL; + entry->stat = NULL; + entry->lstat = NULL; + entry->got_file_index = 0; + + entry->name = PyUnicode_FromWideChar(dataW->cFileName, -1); + if (!entry->name) + goto error; + + joined_path = join_path_filenameW(path->wide, dataW->cFileName); + if (!joined_path) + goto error; + + entry->path = PyUnicode_FromWideChar(joined_path, -1); + PyMem_Free(joined_path); + if (!entry->path) + goto error; + + find_data_to_file_info_w(dataW, &file_info, &reparse_tag); + _Py_attribute_data_to_stat(&file_info, reparse_tag, &entry->win32_lstat); + + return (PyObject *)entry; + +error: + Py_DECREF(entry); + return NULL; +} + +#else /* POSIX */ + +static char * +join_path_filename(char *path_narrow, char* filename, Py_ssize_t filename_len) +{ + Py_ssize_t path_len; + Py_ssize_t size; + char *result; + + if (!path_narrow) { /* Default arg: "." */ + path_narrow = "."; + path_len = 1; + } + else { + path_len = strlen(path_narrow); + } + + if (filename_len == -1) + filename_len = strlen(filename); + + /* The +1's are for the path separator and the NUL */ + size = path_len + 1 + filename_len + 1; + result = PyMem_New(char, size); + if (!result) { + PyErr_NoMemory(); + return NULL; + } + strcpy(result, path_narrow); + if (path_len > 0 && result[path_len - 1] != '/') + result[path_len++] = '/'; + strcpy(result + path_len, filename); + return result; +} + +static PyObject * +DirEntry_from_posix_info(path_t *path, char *name, Py_ssize_t name_len, + ino_t d_ino +#ifdef HAVE_DIRENT_D_TYPE + , unsigned char d_type +#endif + ) +{ + DirEntry *entry; + char *joined_path; + + entry = PyObject_New(DirEntry, &DirEntryType); + if (!entry) + return NULL; + entry->name = NULL; + entry->path = NULL; + entry->stat = NULL; + entry->lstat = NULL; + + joined_path = join_path_filename(path->narrow, name, name_len); + if (!joined_path) + goto error; + + if (!path->narrow || !PyBytes_Check(path->object)) { + entry->name = PyUnicode_DecodeFSDefaultAndSize(name, name_len); + entry->path = PyUnicode_DecodeFSDefault(joined_path); + } + else { + entry->name = PyBytes_FromStringAndSize(name, name_len); + entry->path = PyBytes_FromString(joined_path); + } + PyMem_Free(joined_path); + if (!entry->name || !entry->path) + goto error; + +#ifdef HAVE_DIRENT_D_TYPE + entry->d_type = d_type; +#endif + entry->d_ino = d_ino; + + return (PyObject *)entry; + +error: + Py_XDECREF(entry); + return NULL; +} + +#endif + + +typedef struct { + PyObject_HEAD + path_t path; +#ifdef MS_WINDOWS + HANDLE handle; + WIN32_FIND_DATAW file_data; + int first_time; +#else /* POSIX */ + DIR *dirp; +#endif +} ScandirIterator; + +#ifdef MS_WINDOWS + +static void +ScandirIterator_close(ScandirIterator *iterator) +{ + if (iterator->handle == INVALID_HANDLE_VALUE) + return; + + Py_BEGIN_ALLOW_THREADS + FindClose(iterator->handle); + Py_END_ALLOW_THREADS + iterator->handle = INVALID_HANDLE_VALUE; +} + +static PyObject * +ScandirIterator_iternext(ScandirIterator *iterator) +{ + WIN32_FIND_DATAW *file_data = &iterator->file_data; + BOOL success; + + /* Happens if the iterator is iterated twice */ + if (iterator->handle == INVALID_HANDLE_VALUE) { + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } + + while (1) { + if (!iterator->first_time) { + Py_BEGIN_ALLOW_THREADS + success = FindNextFileW(iterator->handle, file_data); + Py_END_ALLOW_THREADS + if (!success) { + if (GetLastError() != ERROR_NO_MORE_FILES) + return path_error(&iterator->path); + /* No more files found in directory, stop iterating */ + break; + } + } + iterator->first_time = 0; + + /* Skip over . and .. */ + if (wcscmp(file_data->cFileName, L".") != 0 && + wcscmp(file_data->cFileName, L"..") != 0) + return DirEntry_from_find_data(&iterator->path, file_data); + + /* Loop till we get a non-dot directory or finish iterating */ + } + + ScandirIterator_close(iterator); + + PyErr_SetNone(PyExc_StopIteration); + return NULL; +} + +#else /* POSIX */ + +static void +ScandirIterator_close(ScandirIterator *iterator) +{ + if (!iterator->dirp) + return; + + Py_BEGIN_ALLOW_THREADS + closedir(iterator->dirp); + Py_END_ALLOW_THREADS + iterator->dirp = NULL; + return; +} + +static PyObject * +ScandirIterator_iternext(ScandirIterator *iterator) +{ + struct dirent *direntp; + Py_ssize_t name_len; + int is_dot; + + /* Happens if the iterator is iterated twice */ + if (!iterator->dirp) { + PyErr_SetNone(PyExc_StopIteration); + return NULL; + } + + while (1) { + errno = 0; + Py_BEGIN_ALLOW_THREADS + direntp = readdir(iterator->dirp); + Py_END_ALLOW_THREADS + + if (!direntp) { + if (errno != 0) + return path_error(&iterator->path); + /* No more files found in directory, stop iterating */ + break; + } + + /* Skip over . and .. */ + name_len = NAMLEN(direntp); + is_dot = direntp->d_name[0] == '.' && + (name_len == 1 || (direntp->d_name[1] == '.' && name_len == 2)); + if (!is_dot) { + return DirEntry_from_posix_info(&iterator->path, direntp->d_name, + name_len, direntp->d_ino +#ifdef HAVE_DIRENT_D_TYPE + , direntp->d_type +#endif + ); + } + + /* Loop till we get a non-dot directory or finish iterating */ + } + + ScandirIterator_close(iterator); + + PyErr_SetNone(PyExc_StopIteration); + return NULL; +} + +#endif + +static void +ScandirIterator_dealloc(ScandirIterator *iterator) +{ + ScandirIterator_close(iterator); + Py_XDECREF(iterator->path.object); + path_cleanup(&iterator->path); + Py_TYPE(iterator)->tp_free((PyObject *)iterator); +} + +PyTypeObject ScandirIteratorType = { + PyVarObject_HEAD_INIT(NULL, 0) + MODNAME ".ScandirIterator", /* tp_name */ + sizeof(ScandirIterator), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)ScandirIterator_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)ScandirIterator_iternext, /* tp_iternext */ +}; + +static PyObject * +posix_scandir(PyObject *self, PyObject *args, PyObject *kwargs) +{ + ScandirIterator *iterator; + static char *keywords[] = {"path", NULL}; +#ifdef MS_WINDOWS + wchar_t *path_strW; +#else + char *path; +#endif + + iterator = PyObject_New(ScandirIterator, &ScandirIteratorType); + if (!iterator) + return NULL; + memset(&iterator->path, 0, sizeof(path_t)); + iterator->path.function_name = "scandir"; + iterator->path.nullable = 1; + +#ifdef MS_WINDOWS + iterator->handle = INVALID_HANDLE_VALUE; +#else + iterator->dirp = NULL; +#endif + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:scandir", keywords, + path_converter, &iterator->path)) + goto error; + + /* path_converter doesn't keep path.object around, so do it + manually for the lifetime of the iterator here (the refcount + is decremented in ScandirIterator_dealloc) + */ + Py_XINCREF(iterator->path.object); + +#ifdef MS_WINDOWS + if (iterator->path.narrow) { + PyErr_SetString(PyExc_TypeError, + "os.scandir() doesn't support bytes path on Windows, use Unicode instead"); + goto error; + } + iterator->first_time = 1; + + path_strW = join_path_filenameW(iterator->path.wide, L"*.*"); + if (!path_strW) + goto error; + + Py_BEGIN_ALLOW_THREADS + iterator->handle = FindFirstFileW(path_strW, &iterator->file_data); + Py_END_ALLOW_THREADS + + PyMem_Free(path_strW); + + if (iterator->handle == INVALID_HANDLE_VALUE) { + path_error(&iterator->path); + goto error; + } +#else /* POSIX */ + if (iterator->path.narrow) + path = iterator->path.narrow; + else + path = "."; + + errno = 0; + Py_BEGIN_ALLOW_THREADS + iterator->dirp = opendir(path); + Py_END_ALLOW_THREADS + + if (!iterator->dirp) { + path_error(&iterator->path); + goto error; + } +#endif + + return (PyObject *)iterator; + +error: + Py_DECREF(iterator); + return NULL; +} + + +#include "clinic/posixmodule.c.h" /*[clinic input] dump buffer [clinic start generated code]*/ - -#ifndef OS_TTYNAME_METHODDEF - #define OS_TTYNAME_METHODDEF -#endif /* !defined(OS_TTYNAME_METHODDEF) */ -/*[clinic end generated code: output=5d071bbc8f49ea12 input=524ce2e021e4eba6]*/ +/*[clinic end generated code: output=da39a3ee5e6b4b0d input=524ce2e021e4eba6]*/ static PyMethodDef posix_methods[] = { @@ -11193,71 +12082,26 @@ static PyMethodDef posix_methods[] = { OS_STAT_METHODDEF OS_ACCESS_METHODDEF OS_TTYNAME_METHODDEF - - {"chdir", (PyCFunction)posix_chdir, - METH_VARARGS | METH_KEYWORDS, - posix_chdir__doc__}, -#ifdef HAVE_CHFLAGS - {"chflags", (PyCFunction)posix_chflags, - METH_VARARGS | METH_KEYWORDS, - posix_chflags__doc__}, -#endif /* HAVE_CHFLAGS */ - {"chmod", (PyCFunction)posix_chmod, - METH_VARARGS | METH_KEYWORDS, - posix_chmod__doc__}, -#ifdef HAVE_FCHMOD - {"fchmod", posix_fchmod, METH_VARARGS, posix_fchmod__doc__}, -#endif /* HAVE_FCHMOD */ -#ifdef HAVE_CHOWN - {"chown", (PyCFunction)posix_chown, - METH_VARARGS | METH_KEYWORDS, - posix_chown__doc__}, -#endif /* HAVE_CHOWN */ -#ifdef HAVE_LCHMOD - {"lchmod", posix_lchmod, METH_VARARGS, posix_lchmod__doc__}, -#endif /* HAVE_LCHMOD */ -#ifdef HAVE_FCHOWN - {"fchown", posix_fchown, METH_VARARGS, posix_fchown__doc__}, -#endif /* HAVE_FCHOWN */ -#ifdef HAVE_LCHFLAGS - {"lchflags", posix_lchflags, METH_VARARGS, posix_lchflags__doc__}, -#endif /* HAVE_LCHFLAGS */ -#ifdef HAVE_LCHOWN - {"lchown", posix_lchown, METH_VARARGS, posix_lchown__doc__}, -#endif /* HAVE_LCHOWN */ -#ifdef HAVE_CHROOT - {"chroot", posix_chroot, METH_VARARGS, posix_chroot__doc__}, -#endif -#ifdef HAVE_CTERMID - {"ctermid", posix_ctermid, METH_NOARGS, posix_ctermid__doc__}, -#endif - {"getcwd", (PyCFunction)posix_getcwd_unicode, - METH_NOARGS, posix_getcwd__doc__}, - {"getcwdb", (PyCFunction)posix_getcwd_bytes, - METH_NOARGS, posix_getcwdb__doc__}, -#if defined(HAVE_LINK) || defined(MS_WINDOWS) - {"link", (PyCFunction)posix_link, - METH_VARARGS | METH_KEYWORDS, - posix_link__doc__}, -#endif /* HAVE_LINK */ - {"listdir", (PyCFunction)posix_listdir, - METH_VARARGS | METH_KEYWORDS, - posix_listdir__doc__}, - {"lstat", (PyCFunction)posix_lstat, - METH_VARARGS | METH_KEYWORDS, - posix_lstat__doc__}, - {"mkdir", (PyCFunction)posix_mkdir, - METH_VARARGS | METH_KEYWORDS, - posix_mkdir__doc__}, -#ifdef HAVE_NICE - {"nice", posix_nice, METH_VARARGS, posix_nice__doc__}, -#endif /* HAVE_NICE */ -#ifdef HAVE_GETPRIORITY - {"getpriority", posix_getpriority, METH_VARARGS, posix_getpriority__doc__}, -#endif /* HAVE_GETPRIORITY */ -#ifdef HAVE_SETPRIORITY - {"setpriority", posix_setpriority, METH_VARARGS, posix_setpriority__doc__}, -#endif /* HAVE_SETPRIORITY */ + OS_CHDIR_METHODDEF + OS_CHFLAGS_METHODDEF + OS_CHMOD_METHODDEF + OS_FCHMOD_METHODDEF + OS_LCHMOD_METHODDEF + OS_CHOWN_METHODDEF + OS_FCHOWN_METHODDEF + OS_LCHOWN_METHODDEF + OS_LCHFLAGS_METHODDEF + OS_CHROOT_METHODDEF + OS_CTERMID_METHODDEF + OS_GETCWD_METHODDEF + OS_GETCWDB_METHODDEF + OS_LINK_METHODDEF + OS_LISTDIR_METHODDEF + OS_LSTAT_METHODDEF + OS_MKDIR_METHODDEF + OS_NICE_METHODDEF + OS_GETPRIORITY_METHODDEF + OS_SETPRIORITY_METHODDEF #ifdef HAVE_READLINK {"readlink", (PyCFunction)posix_readlink, METH_VARARGS | METH_KEYWORDS, @@ -11268,376 +12112,164 @@ static PyMethodDef posix_methods[] = { METH_VARARGS | METH_KEYWORDS, readlink__doc__}, #endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */ - {"rename", (PyCFunction)posix_rename, - METH_VARARGS | METH_KEYWORDS, - posix_rename__doc__}, - {"replace", (PyCFunction)posix_replace, - METH_VARARGS | METH_KEYWORDS, - posix_replace__doc__}, - {"rmdir", (PyCFunction)posix_rmdir, - METH_VARARGS | METH_KEYWORDS, - posix_rmdir__doc__}, + OS_RENAME_METHODDEF + OS_REPLACE_METHODDEF + OS_RMDIR_METHODDEF {"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__}, -#if defined(HAVE_SYMLINK) - {"symlink", (PyCFunction)posix_symlink, - METH_VARARGS | METH_KEYWORDS, - posix_symlink__doc__}, -#endif /* HAVE_SYMLINK */ -#ifdef HAVE_SYSTEM - {"system", posix_system, METH_VARARGS, posix_system__doc__}, -#endif - {"umask", posix_umask, METH_VARARGS, posix_umask__doc__}, -#ifdef HAVE_UNAME - {"uname", posix_uname, METH_NOARGS, posix_uname__doc__}, -#endif /* HAVE_UNAME */ - {"unlink", (PyCFunction)posix_unlink, - METH_VARARGS | METH_KEYWORDS, - posix_unlink__doc__}, - {"remove", (PyCFunction)posix_unlink, - METH_VARARGS | METH_KEYWORDS, - posix_remove__doc__}, - {"utime", (PyCFunction)posix_utime, - METH_VARARGS | METH_KEYWORDS, posix_utime__doc__}, -#ifdef HAVE_TIMES - {"times", posix_times, METH_NOARGS, posix_times__doc__}, -#endif /* HAVE_TIMES */ - {"_exit", posix__exit, METH_VARARGS, posix__exit__doc__}, -#ifdef HAVE_EXECV - {"execv", posix_execv, METH_VARARGS, posix_execv__doc__}, - {"execve", (PyCFunction)posix_execve, - METH_VARARGS | METH_KEYWORDS, - posix_execve__doc__}, -#endif /* HAVE_EXECV */ -#ifdef HAVE_SPAWNV - {"spawnv", posix_spawnv, METH_VARARGS, posix_spawnv__doc__}, - {"spawnve", posix_spawnve, METH_VARARGS, posix_spawnve__doc__}, -#endif /* HAVE_SPAWNV */ -#ifdef HAVE_FORK1 - {"fork1", posix_fork1, METH_NOARGS, posix_fork1__doc__}, -#endif /* HAVE_FORK1 */ -#ifdef HAVE_FORK - {"fork", posix_fork, METH_NOARGS, posix_fork__doc__}, -#endif /* HAVE_FORK */ -#ifdef HAVE_SCHED_H -#ifdef HAVE_SCHED_GET_PRIORITY_MAX - {"sched_get_priority_max", posix_sched_get_priority_max, METH_VARARGS, posix_sched_get_priority_max__doc__}, - {"sched_get_priority_min", posix_sched_get_priority_min, METH_VARARGS, posix_sched_get_priority_min__doc__}, -#endif -#ifdef HAVE_SCHED_SETPARAM - {"sched_getparam", posix_sched_getparam, METH_VARARGS, posix_sched_getparam__doc__}, -#endif -#ifdef HAVE_SCHED_SETSCHEDULER - {"sched_getscheduler", posix_sched_getscheduler, METH_VARARGS, posix_sched_getscheduler__doc__}, -#endif -#ifdef HAVE_SCHED_RR_GET_INTERVAL - {"sched_rr_get_interval", posix_sched_rr_get_interval, METH_VARARGS, posix_sched_rr_get_interval__doc__}, -#endif -#ifdef HAVE_SCHED_SETPARAM - {"sched_setparam", posix_sched_setparam, METH_VARARGS, posix_sched_setparam__doc__}, -#endif -#ifdef HAVE_SCHED_SETSCHEDULER - {"sched_setscheduler", posix_sched_setscheduler, METH_VARARGS, posix_sched_setscheduler__doc__}, -#endif - {"sched_yield", posix_sched_yield, METH_NOARGS, posix_sched_yield__doc__}, -#ifdef HAVE_SCHED_SETAFFINITY - {"sched_setaffinity", posix_sched_setaffinity, METH_VARARGS, posix_sched_setaffinity__doc__}, - {"sched_getaffinity", posix_sched_getaffinity, METH_VARARGS, posix_sched_getaffinity__doc__}, -#endif -#endif /* HAVE_SCHED_H */ -#if defined(HAVE_OPENPTY) || defined(HAVE__GETPTY) || defined(HAVE_DEV_PTMX) - {"openpty", posix_openpty, METH_NOARGS, posix_openpty__doc__}, -#endif /* HAVE_OPENPTY || HAVE__GETPTY || HAVE_DEV_PTMX */ -#ifdef HAVE_FORKPTY - {"forkpty", posix_forkpty, METH_NOARGS, posix_forkpty__doc__}, -#endif /* HAVE_FORKPTY */ -#ifdef HAVE_GETEGID - {"getegid", posix_getegid, METH_NOARGS, posix_getegid__doc__}, -#endif /* HAVE_GETEGID */ -#ifdef HAVE_GETEUID - {"geteuid", posix_geteuid, METH_NOARGS, posix_geteuid__doc__}, -#endif /* HAVE_GETEUID */ -#ifdef HAVE_GETGID - {"getgid", posix_getgid, METH_NOARGS, posix_getgid__doc__}, -#endif /* HAVE_GETGID */ + OS_SYMLINK_METHODDEF + OS_SYSTEM_METHODDEF + OS_UMASK_METHODDEF + OS_UNAME_METHODDEF + OS_UNLINK_METHODDEF + OS_REMOVE_METHODDEF + OS_UTIME_METHODDEF + OS_TIMES_METHODDEF + OS__EXIT_METHODDEF + OS_EXECV_METHODDEF + OS_EXECVE_METHODDEF + OS_SPAWNV_METHODDEF + OS_SPAWNVE_METHODDEF + OS_FORK1_METHODDEF + OS_FORK_METHODDEF + OS_SCHED_GET_PRIORITY_MAX_METHODDEF + OS_SCHED_GET_PRIORITY_MIN_METHODDEF + OS_SCHED_GETPARAM_METHODDEF + OS_SCHED_GETSCHEDULER_METHODDEF + OS_SCHED_RR_GET_INTERVAL_METHODDEF + OS_SCHED_SETPARAM_METHODDEF + OS_SCHED_SETSCHEDULER_METHODDEF + OS_SCHED_YIELD_METHODDEF + OS_SCHED_SETAFFINITY_METHODDEF + OS_SCHED_GETAFFINITY_METHODDEF + OS_OPENPTY_METHODDEF + OS_FORKPTY_METHODDEF + OS_GETEGID_METHODDEF + OS_GETEUID_METHODDEF + OS_GETGID_METHODDEF #ifdef HAVE_GETGROUPLIST {"getgrouplist", posix_getgrouplist, METH_VARARGS, posix_getgrouplist__doc__}, #endif -#ifdef HAVE_GETGROUPS - {"getgroups", posix_getgroups, METH_NOARGS, posix_getgroups__doc__}, -#endif - {"getpid", posix_getpid, METH_NOARGS, posix_getpid__doc__}, -#ifdef HAVE_GETPGRP - {"getpgrp", posix_getpgrp, METH_NOARGS, posix_getpgrp__doc__}, -#endif /* HAVE_GETPGRP */ -#ifdef HAVE_GETPPID - {"getppid", posix_getppid, METH_NOARGS, posix_getppid__doc__}, -#endif /* HAVE_GETPPID */ -#ifdef HAVE_GETUID - {"getuid", posix_getuid, METH_NOARGS, posix_getuid__doc__}, -#endif /* HAVE_GETUID */ -#ifdef HAVE_GETLOGIN - {"getlogin", posix_getlogin, METH_NOARGS, posix_getlogin__doc__}, -#endif -#ifdef HAVE_KILL - {"kill", posix_kill, METH_VARARGS, posix_kill__doc__}, -#endif /* HAVE_KILL */ -#ifdef HAVE_KILLPG - {"killpg", posix_killpg, METH_VARARGS, posix_killpg__doc__}, -#endif /* HAVE_KILLPG */ -#ifdef HAVE_PLOCK - {"plock", posix_plock, METH_VARARGS, posix_plock__doc__}, -#endif /* HAVE_PLOCK */ + OS_GETGROUPS_METHODDEF + OS_GETPID_METHODDEF + OS_GETPGRP_METHODDEF + OS_GETPPID_METHODDEF + OS_GETUID_METHODDEF + OS_GETLOGIN_METHODDEF + OS_KILL_METHODDEF + OS_KILLPG_METHODDEF + OS_PLOCK_METHODDEF #ifdef MS_WINDOWS {"startfile", win32_startfile, METH_VARARGS, win32_startfile__doc__}, - {"kill", win32_kill, METH_VARARGS, win32_kill__doc__}, #endif -#ifdef HAVE_SETUID - {"setuid", posix_setuid, METH_VARARGS, posix_setuid__doc__}, -#endif /* HAVE_SETUID */ -#ifdef HAVE_SETEUID - {"seteuid", posix_seteuid, METH_VARARGS, posix_seteuid__doc__}, -#endif /* HAVE_SETEUID */ -#ifdef HAVE_SETEGID - {"setegid", posix_setegid, METH_VARARGS, posix_setegid__doc__}, -#endif /* HAVE_SETEGID */ -#ifdef HAVE_SETREUID - {"setreuid", posix_setreuid, METH_VARARGS, posix_setreuid__doc__}, -#endif /* HAVE_SETREUID */ -#ifdef HAVE_SETREGID - {"setregid", posix_setregid, METH_VARARGS, posix_setregid__doc__}, -#endif /* HAVE_SETREGID */ -#ifdef HAVE_SETGID - {"setgid", posix_setgid, METH_VARARGS, posix_setgid__doc__}, -#endif /* HAVE_SETGID */ -#ifdef HAVE_SETGROUPS - {"setgroups", posix_setgroups, METH_O, posix_setgroups__doc__}, -#endif /* HAVE_SETGROUPS */ + OS_SETUID_METHODDEF + OS_SETEUID_METHODDEF + OS_SETREUID_METHODDEF + OS_SETGID_METHODDEF + OS_SETEGID_METHODDEF + OS_SETREGID_METHODDEF + OS_SETGROUPS_METHODDEF #ifdef HAVE_INITGROUPS {"initgroups", posix_initgroups, METH_VARARGS, posix_initgroups__doc__}, #endif /* HAVE_INITGROUPS */ -#ifdef HAVE_GETPGID - {"getpgid", posix_getpgid, METH_VARARGS, posix_getpgid__doc__}, -#endif /* HAVE_GETPGID */ -#ifdef HAVE_SETPGRP - {"setpgrp", posix_setpgrp, METH_NOARGS, posix_setpgrp__doc__}, -#endif /* HAVE_SETPGRP */ -#ifdef HAVE_WAIT - {"wait", posix_wait, METH_NOARGS, posix_wait__doc__}, -#endif /* HAVE_WAIT */ -#ifdef HAVE_WAIT3 - {"wait3", posix_wait3, METH_VARARGS, posix_wait3__doc__}, -#endif /* HAVE_WAIT3 */ -#ifdef HAVE_WAIT4 - {"wait4", posix_wait4, METH_VARARGS, posix_wait4__doc__}, -#endif /* HAVE_WAIT4 */ -#if defined(HAVE_WAITID) && !defined(__APPLE__) - {"waitid", posix_waitid, METH_VARARGS, posix_waitid__doc__}, -#endif -#if defined(HAVE_WAITPID) || defined(HAVE_CWAIT) - {"waitpid", posix_waitpid, METH_VARARGS, posix_waitpid__doc__}, -#endif /* HAVE_WAITPID */ -#ifdef HAVE_GETSID - {"getsid", posix_getsid, METH_VARARGS, posix_getsid__doc__}, -#endif /* HAVE_GETSID */ -#ifdef HAVE_SETSID - {"setsid", posix_setsid, METH_NOARGS, posix_setsid__doc__}, -#endif /* HAVE_SETSID */ -#ifdef HAVE_SETPGID - {"setpgid", posix_setpgid, METH_VARARGS, posix_setpgid__doc__}, -#endif /* HAVE_SETPGID */ -#ifdef HAVE_TCGETPGRP - {"tcgetpgrp", posix_tcgetpgrp, METH_VARARGS, posix_tcgetpgrp__doc__}, -#endif /* HAVE_TCGETPGRP */ -#ifdef HAVE_TCSETPGRP - {"tcsetpgrp", posix_tcsetpgrp, METH_VARARGS, posix_tcsetpgrp__doc__}, -#endif /* HAVE_TCSETPGRP */ - {"open", (PyCFunction)posix_open,\ - METH_VARARGS | METH_KEYWORDS, - posix_open__doc__}, - {"close", posix_close_, METH_VARARGS, posix_close__doc__}, - {"closerange", posix_closerange, METH_VARARGS, posix_closerange__doc__}, - {"device_encoding", device_encoding, METH_VARARGS, device_encoding__doc__}, - {"dup", posix_dup, METH_VARARGS, posix_dup__doc__}, - {"dup2", (PyCFunction)posix_dup2, - METH_VARARGS | METH_KEYWORDS, posix_dup2__doc__}, -#ifdef HAVE_LOCKF - {"lockf", posix_lockf, METH_VARARGS, posix_lockf__doc__}, -#endif - {"lseek", posix_lseek, METH_VARARGS, posix_lseek__doc__}, - {"read", posix_read, METH_VARARGS, posix_read__doc__}, -#ifdef HAVE_READV - {"readv", posix_readv, METH_VARARGS, posix_readv__doc__}, -#endif -#ifdef HAVE_PREAD - {"pread", posix_pread, METH_VARARGS, posix_pread__doc__}, -#endif - {"write", posix_write, METH_VARARGS, posix_write__doc__}, -#ifdef HAVE_WRITEV - {"writev", posix_writev, METH_VARARGS, posix_writev__doc__}, -#endif -#ifdef HAVE_PWRITE - {"pwrite", posix_pwrite, METH_VARARGS, posix_pwrite__doc__}, -#endif + OS_GETPGID_METHODDEF + OS_SETPGRP_METHODDEF + OS_WAIT_METHODDEF + OS_WAIT3_METHODDEF + OS_WAIT4_METHODDEF + OS_WAITID_METHODDEF + OS_WAITPID_METHODDEF + OS_GETSID_METHODDEF + OS_SETSID_METHODDEF + OS_SETPGID_METHODDEF + OS_TCGETPGRP_METHODDEF + OS_TCSETPGRP_METHODDEF + OS_OPEN_METHODDEF + OS_CLOSE_METHODDEF + OS_CLOSERANGE_METHODDEF + OS_DEVICE_ENCODING_METHODDEF + OS_DUP_METHODDEF + OS_DUP2_METHODDEF + OS_LOCKF_METHODDEF + OS_LSEEK_METHODDEF + OS_READ_METHODDEF + OS_READV_METHODDEF + OS_PREAD_METHODDEF + OS_WRITE_METHODDEF + OS_WRITEV_METHODDEF + OS_PWRITE_METHODDEF #ifdef HAVE_SENDFILE {"sendfile", (PyCFunction)posix_sendfile, METH_VARARGS | METH_KEYWORDS, posix_sendfile__doc__}, #endif - {"fstat", posix_fstat, METH_VARARGS, posix_fstat__doc__}, - {"isatty", posix_isatty, METH_VARARGS, posix_isatty__doc__}, -#ifdef HAVE_PIPE - {"pipe", posix_pipe, METH_NOARGS, posix_pipe__doc__}, -#endif -#ifdef HAVE_PIPE2 - {"pipe2", posix_pipe2, METH_O, posix_pipe2__doc__}, -#endif -#ifdef HAVE_MKFIFO - {"mkfifo", (PyCFunction)posix_mkfifo, - METH_VARARGS | METH_KEYWORDS, - posix_mkfifo__doc__}, -#endif -#if defined(HAVE_MKNOD) && defined(HAVE_MAKEDEV) - {"mknod", (PyCFunction)posix_mknod, - METH_VARARGS | METH_KEYWORDS, - posix_mknod__doc__}, -#endif -#ifdef HAVE_DEVICE_MACROS - {"major", posix_major, METH_VARARGS, posix_major__doc__}, - {"minor", posix_minor, METH_VARARGS, posix_minor__doc__}, - {"makedev", posix_makedev, METH_VARARGS, posix_makedev__doc__}, -#endif -#ifdef HAVE_FTRUNCATE - {"ftruncate", posix_ftruncate, METH_VARARGS, posix_ftruncate__doc__}, -#endif -#ifdef HAVE_TRUNCATE - {"truncate", (PyCFunction)posix_truncate, - METH_VARARGS | METH_KEYWORDS, - posix_truncate__doc__}, -#endif -#if defined(HAVE_POSIX_FALLOCATE) && !defined(POSIX_FADVISE_AIX_BUG) - {"posix_fallocate", posix_posix_fallocate, METH_VARARGS, posix_posix_fallocate__doc__}, -#endif -#if defined(HAVE_POSIX_FADVISE) && !defined(POSIX_FADVISE_AIX_BUG) - {"posix_fadvise", posix_posix_fadvise, METH_VARARGS, posix_posix_fadvise__doc__}, -#endif -#ifdef HAVE_PUTENV - {"putenv", posix_putenv, METH_VARARGS, posix_putenv__doc__}, -#endif -#ifdef HAVE_UNSETENV - {"unsetenv", posix_unsetenv, METH_VARARGS, posix_unsetenv__doc__}, -#endif - {"strerror", posix_strerror, METH_VARARGS, posix_strerror__doc__}, -#ifdef HAVE_FCHDIR - {"fchdir", posix_fchdir, METH_O, posix_fchdir__doc__}, -#endif -#ifdef HAVE_FSYNC - {"fsync", posix_fsync, METH_O, posix_fsync__doc__}, -#endif -#ifdef HAVE_SYNC - {"sync", posix_sync, METH_NOARGS, posix_sync__doc__}, -#endif -#ifdef HAVE_FDATASYNC - {"fdatasync", posix_fdatasync, METH_O, posix_fdatasync__doc__}, -#endif -#ifdef HAVE_SYS_WAIT_H -#ifdef WCOREDUMP - {"WCOREDUMP", posix_WCOREDUMP, METH_VARARGS, posix_WCOREDUMP__doc__}, -#endif /* WCOREDUMP */ -#ifdef WIFCONTINUED - {"WIFCONTINUED",posix_WIFCONTINUED, METH_VARARGS, posix_WIFCONTINUED__doc__}, -#endif /* WIFCONTINUED */ -#ifdef WIFSTOPPED - {"WIFSTOPPED", posix_WIFSTOPPED, METH_VARARGS, posix_WIFSTOPPED__doc__}, -#endif /* WIFSTOPPED */ -#ifdef WIFSIGNALED - {"WIFSIGNALED", posix_WIFSIGNALED, METH_VARARGS, posix_WIFSIGNALED__doc__}, -#endif /* WIFSIGNALED */ -#ifdef WIFEXITED - {"WIFEXITED", posix_WIFEXITED, METH_VARARGS, posix_WIFEXITED__doc__}, -#endif /* WIFEXITED */ -#ifdef WEXITSTATUS - {"WEXITSTATUS", posix_WEXITSTATUS, METH_VARARGS, posix_WEXITSTATUS__doc__}, -#endif /* WEXITSTATUS */ -#ifdef WTERMSIG - {"WTERMSIG", posix_WTERMSIG, METH_VARARGS, posix_WTERMSIG__doc__}, -#endif /* WTERMSIG */ -#ifdef WSTOPSIG - {"WSTOPSIG", posix_WSTOPSIG, METH_VARARGS, posix_WSTOPSIG__doc__}, -#endif /* WSTOPSIG */ -#endif /* HAVE_SYS_WAIT_H */ -#if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H) - {"fstatvfs", posix_fstatvfs, METH_VARARGS, posix_fstatvfs__doc__}, -#endif -#if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) - {"statvfs", (PyCFunction)posix_statvfs, - METH_VARARGS | METH_KEYWORDS, - posix_statvfs__doc__}, -#endif -#ifdef HAVE_CONFSTR - {"confstr", posix_confstr, METH_VARARGS, posix_confstr__doc__}, -#endif -#ifdef HAVE_SYSCONF - {"sysconf", posix_sysconf, METH_VARARGS, posix_sysconf__doc__}, -#endif -#ifdef HAVE_FPATHCONF - {"fpathconf", posix_fpathconf, METH_VARARGS, posix_fpathconf__doc__}, -#endif -#ifdef HAVE_PATHCONF - {"pathconf", (PyCFunction)posix_pathconf, - METH_VARARGS | METH_KEYWORDS, - posix_pathconf__doc__}, -#endif - {"abort", posix_abort, METH_NOARGS, posix_abort__doc__}, + OS_FSTAT_METHODDEF + OS_ISATTY_METHODDEF + OS_PIPE_METHODDEF + OS_PIPE2_METHODDEF + OS_MKFIFO_METHODDEF + OS_MKNOD_METHODDEF + OS_MAJOR_METHODDEF + OS_MINOR_METHODDEF + OS_MAKEDEV_METHODDEF + OS_FTRUNCATE_METHODDEF + OS_TRUNCATE_METHODDEF + OS_POSIX_FALLOCATE_METHODDEF + OS_POSIX_FADVISE_METHODDEF + OS_PUTENV_METHODDEF + OS_UNSETENV_METHODDEF + OS_STRERROR_METHODDEF + OS_FCHDIR_METHODDEF + OS_FSYNC_METHODDEF + OS_SYNC_METHODDEF + OS_FDATASYNC_METHODDEF + OS_WCOREDUMP_METHODDEF + OS_WIFCONTINUED_METHODDEF + OS_WIFSTOPPED_METHODDEF + OS_WIFSIGNALED_METHODDEF + OS_WIFEXITED_METHODDEF + OS_WEXITSTATUS_METHODDEF + OS_WTERMSIG_METHODDEF + OS_WSTOPSIG_METHODDEF + OS_FSTATVFS_METHODDEF + OS_STATVFS_METHODDEF + OS_CONFSTR_METHODDEF + OS_SYSCONF_METHODDEF + OS_FPATHCONF_METHODDEF + OS_PATHCONF_METHODDEF + OS_ABORT_METHODDEF #ifdef MS_WINDOWS {"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL}, - {"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL}, {"_isdir", posix__isdir, METH_VARARGS, posix__isdir__doc__}, - {"_getdiskusage", win32__getdiskusage, METH_VARARGS, win32__getdiskusage__doc__}, - {"_getvolumepathname", posix__getvolumepathname, METH_VARARGS, posix__getvolumepathname__doc__}, -#endif -#ifdef HAVE_GETLOADAVG - {"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__}, -#endif - {"urandom", posix_urandom, METH_VARARGS, posix_urandom__doc__}, -#ifdef HAVE_SETRESUID - {"setresuid", posix_setresuid, METH_VARARGS, posix_setresuid__doc__}, -#endif -#ifdef HAVE_SETRESGID - {"setresgid", posix_setresgid, METH_VARARGS, posix_setresgid__doc__}, -#endif -#ifdef HAVE_GETRESUID - {"getresuid", posix_getresuid, METH_NOARGS, posix_getresuid__doc__}, -#endif -#ifdef HAVE_GETRESGID - {"getresgid", posix_getresgid, METH_NOARGS, posix_getresgid__doc__}, #endif + OS__GETDISKUSAGE_METHODDEF + OS__GETFINALPATHNAME_METHODDEF + OS__GETVOLUMEPATHNAME_METHODDEF + OS_GETLOADAVG_METHODDEF + OS_URANDOM_METHODDEF + OS_SETRESUID_METHODDEF + OS_SETRESGID_METHODDEF + OS_GETRESUID_METHODDEF + OS_GETRESGID_METHODDEF + + OS_GETXATTR_METHODDEF + OS_SETXATTR_METHODDEF + OS_REMOVEXATTR_METHODDEF + OS_LISTXATTR_METHODDEF -#ifdef USE_XATTRS - {"setxattr", (PyCFunction)posix_setxattr, - METH_VARARGS | METH_KEYWORDS, - posix_setxattr__doc__}, - {"getxattr", (PyCFunction)posix_getxattr, - METH_VARARGS | METH_KEYWORDS, - posix_getxattr__doc__}, - {"removexattr", (PyCFunction)posix_removexattr, - METH_VARARGS | METH_KEYWORDS, - posix_removexattr__doc__}, - {"listxattr", (PyCFunction)posix_listxattr, - METH_VARARGS | METH_KEYWORDS, - posix_listxattr__doc__}, -#endif #if defined(TERMSIZE_USE_CONIO) || defined(TERMSIZE_USE_IOCTL) {"get_terminal_size", get_terminal_size, METH_VARARGS, termsize__doc__}, #endif - {"cpu_count", (PyCFunction)posix_cpu_count, - METH_NOARGS, posix_cpu_count__doc__}, - {"get_inheritable", posix_get_inheritable, METH_VARARGS, get_inheritable__doc__}, - {"set_inheritable", posix_set_inheritable, METH_VARARGS, set_inheritable__doc__}, -#ifdef MS_WINDOWS - {"get_handle_inheritable", posix_get_handle_inheritable, - METH_VARARGS, get_handle_inheritable__doc__}, - {"set_handle_inheritable", posix_set_handle_inheritable, - METH_VARARGS, set_handle_inheritable__doc__}, + OS_CPU_COUNT_METHODDEF + OS_GET_INHERITABLE_METHODDEF + OS_SET_INHERITABLE_METHODDEF + OS_GET_HANDLE_INHERITABLE_METHODDEF + OS_SET_HANDLE_INHERITABLE_METHODDEF +#ifndef MS_WINDOWS + {"get_blocking", posix_get_blocking, METH_VARARGS, get_blocking__doc__}, + {"set_blocking", posix_set_blocking, METH_VARARGS, set_blocking__doc__}, #endif + {"scandir", (PyCFunction)posix_scandir, + METH_VARARGS | METH_KEYWORDS, + posix_scandir__doc__}, {NULL, NULL} /* Sentinel */ }; @@ -12080,15 +12712,6 @@ all_ins(PyObject *m) } -#if (defined(_MSC_VER) || defined(__WATCOMC__) || defined(__BORLANDC__)) && !defined(__QNX__) -#define INITFUNC PyInit_nt -#define MODNAME "nt" - -#else -#define INITFUNC PyInit_posix -#define MODNAME "posix" -#endif - static struct PyModuleDef posixmodule = { PyModuleDef_HEAD_INIT, MODNAME, @@ -12302,13 +12925,19 @@ INITFUNC(void) sched_param_desc.name = MODNAME ".sched_param"; if (PyStructSequence_InitType2(&SchedParamType, &sched_param_desc) < 0) return NULL; - SchedParamType.tp_new = sched_param_new; + SchedParamType.tp_new = os_sched_param; #endif /* initialize TerminalSize_info */ if (PyStructSequence_InitType2(&TerminalSizeType, &TerminalSize_desc) < 0) return NULL; + + /* initialize scandir types */ + if (PyType_Ready(&ScandirIteratorType) < 0) + return NULL; + if (PyType_Ready(&DirEntryType) < 0) + return NULL; } #if defined(HAVE_WAITID) && !defined(__APPLE__) Py_INCREF((PyObject*) &WaitidResultType); |