diff options
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r-- | Modules/posixmodule.c | 653 |
1 files changed, 465 insertions, 188 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c index b51ba5dc54c..7f0a2618efc 100644 --- a/Modules/posixmodule.c +++ b/Modules/posixmodule.c @@ -13,6 +13,18 @@ /* See also ../Dos/dosmodule.c */ +#ifdef __APPLE__ + /* + * Step 1 of support for weak-linking a number of symbols existing on + * OSX 10.4 and later, see the comment in the #ifdef __APPLE__ block + * at the end of this file for more information. + */ +# pragma weak lchown +# pragma weak statvfs +# pragma weak fstatvfs + +#endif /* __APPLE__ */ + #define PY_SSIZE_T_CLEAN #include "Python.h" @@ -250,7 +262,11 @@ extern int lstat(const char *, struct stat *); #endif /* OS2 */ #ifndef MAXPATHLEN +#if defined(PATH_MAX) && PATH_MAX > 1024 +#define MAXPATHLEN PATH_MAX +#else #define MAXPATHLEN 1024 +#endif #endif /* MAXPATHLEN */ #ifdef UNION_WAIT @@ -442,21 +458,29 @@ win32_error_unicode(char* function, Py_UNICODE* filename) static PyObject *_PyUnicode_FromFileSystemEncodedObject(register PyObject *obj) { - /* XXX Perhaps we should make this API an alias of - PyObject_Unicode() instead ?! */ - if (PyUnicode_CheckExact(obj)) { - Py_INCREF(obj); - return obj; - } - if (PyUnicode_Check(obj)) { +} + +/* Function suitable for O& conversion */ +static int +convert_to_unicode(PyObject *arg, void* _param) +{ + PyObject **param = (PyObject**)_param; + if (PyUnicode_CheckExact(arg)) { + Py_INCREF(arg); + *param = arg; + } + else if (PyUnicode_Check(arg)) { /* For a Unicode subtype that's not a Unicode object, return a true Unicode object with the same data. */ - return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(obj), - PyUnicode_GET_SIZE(obj)); + *param = PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(arg), + PyUnicode_GET_SIZE(arg)); + return *param != NULL; } - return PyUnicode_FromEncodedObject(obj, - Py_FileSystemDefaultEncoding, - "strict"); + else + *param = PyUnicode_FromEncodedObject(arg, + Py_FileSystemDefaultEncoding, + "strict"); + return (*param) != NULL; } #endif /* Py_WIN_WIDE_FILENAMES */ @@ -573,35 +597,10 @@ unicode_file_names(void) #endif static PyObject * -posix_1str(PyObject *args, char *format, int (*func)(const char*), - char *wformat, int (*wfunc)(const Py_UNICODE*)) +posix_1str(PyObject *args, char *format, int (*func)(const char*)) { char *path1 = NULL; int res; -#ifdef Py_WIN_WIDE_FILENAMES - if (unicode_file_names()) { - PyUnicodeObject *po; - if (PyArg_ParseTuple(args, wformat, &po)) { - Py_BEGIN_ALLOW_THREADS - /* PyUnicode_AS_UNICODE OK without thread - lock as it is a simple dereference. */ - res = (*wfunc)(PyUnicode_AS_UNICODE(po)); - Py_END_ALLOW_THREADS - if (res < 0) - return posix_error_with_unicode_filename(PyUnicode_AS_UNICODE(po)); - Py_INCREF(Py_None); - return Py_None; - } - /* Drop the argument parsing error as narrow - strings are also valid. */ - PyErr_Clear(); - } -#else - /* Platforms that don't support Unicode filenames - shouldn't be passing these extra params */ - assert(wformat==NULL && wfunc == NULL); -#endif - if (!PyArg_ParseTuple(args, format, Py_FileSystemDefaultEncoding, &path1)) return NULL; @@ -618,52 +617,10 @@ posix_1str(PyObject *args, char *format, int (*func)(const char*), static PyObject * posix_2str(PyObject *args, char *format, - int (*func)(const char *, const char *), - char *wformat, - int (*wfunc)(const Py_UNICODE *, const Py_UNICODE *)) + int (*func)(const char *, const char *)) { char *path1 = NULL, *path2 = NULL; int res; -#ifdef Py_WIN_WIDE_FILENAMES - if (unicode_file_names()) { - PyObject *po1; - PyObject *po2; - if (PyArg_ParseTuple(args, wformat, &po1, &po2)) { - if (PyUnicode_Check(po1) || PyUnicode_Check(po2)) { - PyObject *wpath1; - PyObject *wpath2; - wpath1 = _PyUnicode_FromFileSystemEncodedObject(po1); - wpath2 = _PyUnicode_FromFileSystemEncodedObject(po2); - if (!wpath1 || !wpath2) { - Py_XDECREF(wpath1); - Py_XDECREF(wpath2); - return NULL; - } - Py_BEGIN_ALLOW_THREADS - /* PyUnicode_AS_UNICODE OK without thread - lock as it is a simple dereference. */ - res = (*wfunc)(PyUnicode_AS_UNICODE(wpath1), - PyUnicode_AS_UNICODE(wpath2)); - Py_END_ALLOW_THREADS - Py_XDECREF(wpath1); - Py_XDECREF(wpath2); - if (res != 0) - return posix_error(); - Py_INCREF(Py_None); - return Py_None; - } - /* Else flow through as neither is Unicode. */ - } - /* Drop the argument parsing error as narrow - strings are also valid. */ - PyErr_Clear(); - } -#else - /* Platforms that don't support Unicode filenames - shouldn't be passing these extra params */ - assert(wformat==NULL && wfunc == NULL); -#endif - if (!PyArg_ParseTuple(args, format, Py_FileSystemDefaultEncoding, &path1, Py_FileSystemDefaultEncoding, &path2)) @@ -680,6 +637,101 @@ posix_2str(PyObject *args, return Py_None; } +#ifdef Py_WIN_WIDE_FILENAMES +static PyObject* +win32_1str(PyObject* args, char* func, + char* format, BOOL (__stdcall *funcA)(LPCSTR), + char* wformat, BOOL (__stdcall *funcW)(LPWSTR)) +{ + PyObject *uni; + char *ansi; + BOOL result; + if (unicode_file_names()) { + if (!PyArg_ParseTuple(args, wformat, &uni)) + PyErr_Clear(); + else { + Py_BEGIN_ALLOW_THREADS + result = funcW(PyUnicode_AsUnicode(uni)); + Py_END_ALLOW_THREADS + if (!result) + return win32_error_unicode(func, PyUnicode_AsUnicode(uni)); + Py_INCREF(Py_None); + return Py_None; + } + } + if (!PyArg_ParseTuple(args, format, &ansi)) + return NULL; + Py_BEGIN_ALLOW_THREADS + result = funcA(ansi); + Py_END_ALLOW_THREADS + if (!result) + return win32_error(func, ansi); + Py_INCREF(Py_None); + return Py_None; + +} + +/* This is a reimplementation of the C library's chdir function, + but one that produces Win32 errors instead of DOS error codes. + chdir is essentially a wrapper around SetCurrentDirectory; however, + it also needs to set "magic" environment variables indicating + the per-drive current directory, which are of the form =<drive>: */ +BOOL __stdcall +win32_chdir(LPCSTR path) +{ + char new_path[MAX_PATH+1]; + int result; + char env[4] = "=x:"; + + if(!SetCurrentDirectoryA(path)) + return FALSE; + result = GetCurrentDirectoryA(MAX_PATH+1, new_path); + if (!result) + return FALSE; + /* In the ANSI API, there should not be any paths longer + than MAX_PATH. */ + assert(result <= MAX_PATH+1); + if (strncmp(new_path, "\\\\", 2) == 0 || + strncmp(new_path, "//", 2) == 0) + /* UNC path, nothing to do. */ + return TRUE; + env[1] = new_path[0]; + return SetEnvironmentVariableA(env, new_path); +} + +/* The Unicode version differs from the ANSI version + since the current directory might exceed MAX_PATH characters */ +BOOL __stdcall +win32_wchdir(LPCWSTR path) +{ + wchar_t _new_path[MAX_PATH+1], *new_path = _new_path; + int result; + wchar_t env[4] = L"=x:"; + + if(!SetCurrentDirectoryW(path)) + return FALSE; + result = GetCurrentDirectoryW(MAX_PATH+1, new_path); + if (!result) + return FALSE; + if (result > MAX_PATH+1) { + new_path = malloc(result); + if (!new_path) { + SetLastError(ERROR_OUTOFMEMORY); + return FALSE; + } + } + if (wcsncmp(new_path, L"\\\\", 2) == 0 || + wcsncmp(new_path, L"//", 2) == 0) + /* UNC path, nothing to do. */ + return TRUE; + env[1] = new_path[0]; + result = SetEnvironmentVariableW(env, new_path); + if (new_path != _new_path) + free(new_path); + return result; +} +#endif + #ifdef MS_WINDOWS /* The CRT of Windows has a number of flaws wrt. its stat() implementation: - time stamps are restricted to second resolution @@ -711,13 +763,26 @@ static __int64 secs_between_epochs = 11644473600; /* Seconds between 1.1.1601 an static void FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, int *time_out, int* nsec_out) { - /* XXX endianness */ - __int64 in = *(__int64*)in_ptr; + /* 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. */ /* XXX Win32 supports time stamps past 2038; we currently don't */ *time_out = Py_SAFE_DOWNCAST((in / 10000000) - secs_between_epochs, __int64, int); } +static void +time_t_to_FILE_TIME(int time_in, int nsec_in, FILETIME *out_ptr) +{ + /* XXX endianness */ + __int64 out; + out = time_in + secs_between_epochs; + out = out * 10000000 + nsec_in; + memcpy(out_ptr, &out, sizeof(out)); +} + /* Below, we *know* that ugo+r is 0444 */ #if _S_IREAD != 0400 #error Unsupported C library @@ -1292,24 +1357,39 @@ posix_access(PyObject *self, PyObject *args) { char *path; int mode; - int res; - + #ifdef Py_WIN_WIDE_FILENAMES + DWORD attr; if (unicode_file_names()) { PyUnicodeObject *po; if (PyArg_ParseTuple(args, "Ui:access", &po, &mode)) { Py_BEGIN_ALLOW_THREADS /* PyUnicode_AS_UNICODE OK without thread lock as it is a simple dereference. */ - res = _waccess(PyUnicode_AS_UNICODE(po), mode); + attr = GetFileAttributesW(PyUnicode_AS_UNICODE(po)); Py_END_ALLOW_THREADS - return PyBool_FromLong(res == 0); + goto finish; } /* Drop the argument parsing error as narrow strings are also valid. */ PyErr_Clear(); } -#endif + if (!PyArg_ParseTuple(args, "eti:access", + Py_FileSystemDefaultEncoding, &path, &mode)) + return 0; + Py_BEGIN_ALLOW_THREADS + attr = GetFileAttributesA(path); + Py_END_ALLOW_THREADS + PyMem_Free(path); +finish: + if (attr == 0xFFFFFFFF) + /* File does not exist, or cannot read attributes */ + return PyBool_FromLong(0); + /* Access is possible if either write access wasn't requested, or + the file isn't read-only. */ + return PyBool_FromLong(!(mode & 2) || !(attr && FILE_ATTRIBUTE_READONLY)); +#else + int res; if (!PyArg_ParseTuple(args, "eti:access", Py_FileSystemDefaultEncoding, &path, &mode)) return NULL; @@ -1318,6 +1398,7 @@ posix_access(PyObject *self, PyObject *args) Py_END_ALLOW_THREADS PyMem_Free(path); return PyBool_FromLong(res == 0); +#endif } #ifndef F_OK @@ -1394,14 +1475,13 @@ static PyObject * posix_chdir(PyObject *self, PyObject *args) { #ifdef MS_WINDOWS - return posix_1str(args, "et:chdir", chdir, "U:chdir", _wchdir); + return win32_1str(args, "chdir", "s:chdir", win32_chdir, "U:chdir", win32_wchdir); #elif defined(PYOS_OS2) && defined(PYCC_GCC) - return posix_1str(args, "et:chdir", _chdir2, NULL, NULL); + return posix_1str(args, "et:chdir", _chdir2); #elif defined(__VMS) - return posix_1str(args, "et:chdir", (int (*)(const char *))chdir, - NULL, NULL); + return posix_1str(args, "et:chdir", (int (*)(const char *))chdir); #else - return posix_1str(args, "et:chdir", chdir, NULL, NULL); + return posix_1str(args, "et:chdir", chdir); #endif } @@ -1430,14 +1510,24 @@ posix_chmod(PyObject *self, PyObject *args) int i; int res; #ifdef Py_WIN_WIDE_FILENAMES + DWORD attr; if (unicode_file_names()) { PyUnicodeObject *po; if (PyArg_ParseTuple(args, "Ui|:chmod", &po, &i)) { Py_BEGIN_ALLOW_THREADS - res = _wchmod(PyUnicode_AS_UNICODE(po), i); + attr = GetFileAttributesW(PyUnicode_AS_UNICODE(po)); + if (attr != 0xFFFFFFFF) { + if (i & _S_IWRITE) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + res = SetFileAttributesW(PyUnicode_AS_UNICODE(po), attr); + } + else + res = 0; Py_END_ALLOW_THREADS - if (res < 0) - return posix_error_with_unicode_filename( + if (!res) + return win32_error_unicode("chmod", PyUnicode_AS_UNICODE(po)); Py_INCREF(Py_None); return Py_None; @@ -1446,7 +1536,30 @@ posix_chmod(PyObject *self, PyObject *args) are also valid. */ PyErr_Clear(); } -#endif /* Py_WIN_WIDE_FILENAMES */ + if (!PyArg_ParseTuple(args, "eti:chmod", Py_FileSystemDefaultEncoding, + &path, &i)) + return NULL; + Py_BEGIN_ALLOW_THREADS + attr = GetFileAttributesA(path); + if (attr != 0xFFFFFFFF) { + if (i & _S_IWRITE) + attr &= ~FILE_ATTRIBUTE_READONLY; + else + attr |= FILE_ATTRIBUTE_READONLY; + res = SetFileAttributesA(path, attr); + } + else + res = 0; + Py_END_ALLOW_THREADS + if (!res) { + win32_error("chmod", path); + PyMem_Free(path); + return NULL; + } + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +#else /* Py_WIN_WIDE_FILENAMES */ if (!PyArg_ParseTuple(args, "eti:chmod", Py_FileSystemDefaultEncoding, &path, &i)) return NULL; @@ -1458,6 +1571,7 @@ posix_chmod(PyObject *self, PyObject *args) PyMem_Free(path); Py_INCREF(Py_None); return Py_None; +#endif } @@ -1469,7 +1583,7 @@ Change root directory to path."); static PyObject * posix_chroot(PyObject *self, PyObject *args) { - return posix_1str(args, "et:chroot", chroot, NULL, NULL); + return posix_1str(args, "et:chroot", chroot); } #endif @@ -1593,15 +1707,33 @@ posix_getcwdu(PyObject *self, PyObject *noargs) char *res; #ifdef Py_WIN_WIDE_FILENAMES + DWORD len; if (unicode_file_names()) { - wchar_t *wres; wchar_t wbuf[1026]; + wchar_t *wbuf2 = wbuf; + PyObject *resobj; Py_BEGIN_ALLOW_THREADS - wres = _wgetcwd(wbuf, sizeof wbuf/ sizeof wbuf[0]); + len = GetCurrentDirectoryW(sizeof wbuf/ sizeof wbuf[0], wbuf); + /* If the buffer is large enough, len does not include the + terminating \0. If the buffer is too small, len includes + the space needed for the terminator. */ + if (len >= sizeof wbuf/ sizeof wbuf[0]) { + wbuf2 = malloc(len * sizeof(wchar_t)); + if (wbuf2) + len = GetCurrentDirectoryW(len, wbuf2); + } Py_END_ALLOW_THREADS - if (wres == NULL) - return posix_error(); - return PyUnicode_FromWideChar(wbuf, wcslen(wbuf)); + if (!wbuf2) { + PyErr_NoMemory(); + return NULL; + } + if (!len) { + if (wbuf2 != wbuf) free(wbuf2); + return win32_error("getcwdu", NULL); + } + resobj = PyUnicode_FromWideChar(wbuf2, len); + if (wbuf2 != wbuf) free(wbuf2); + return resobj; } #endif @@ -1628,7 +1760,7 @@ Create a hard link to a file."); static PyObject * posix_link(PyObject *self, PyObject *args) { - return posix_2str(args, "etet:link", link, NULL, NULL); + return posix_2str(args, "etet:link", link); } #endif /* HAVE_LINK */ @@ -1653,37 +1785,46 @@ posix_listdir(PyObject *self, PyObject *args) HANDLE hFindFile; BOOL result; WIN32_FIND_DATA FileData; - /* MAX_PATH characters could mean a bigger encoded string */ - char namebuf[MAX_PATH*2+5]; + char namebuf[MAX_PATH+5]; /* Overallocate for \\*.*\0 */ char *bufptr = namebuf; - Py_ssize_t len = sizeof(namebuf)/sizeof(namebuf[0]); + Py_ssize_t len = sizeof(namebuf)-5; /* only claim to have space for MAX_PATH */ #ifdef Py_WIN_WIDE_FILENAMES /* If on wide-character-capable OS see if argument is Unicode and if so use wide API. */ if (unicode_file_names()) { - PyUnicodeObject *po; + PyObject *po; if (PyArg_ParseTuple(args, "U:listdir", &po)) { WIN32_FIND_DATAW wFileData; - Py_UNICODE wnamebuf[MAX_PATH*2+5]; + Py_UNICODE *wnamebuf; Py_UNICODE wch; - wcsncpy(wnamebuf, PyUnicode_AS_UNICODE(po), MAX_PATH); - wnamebuf[MAX_PATH] = L'\0'; - len = wcslen(wnamebuf); - wch = (len > 0) ? wnamebuf[len-1] : L'\0'; + /* Overallocate for \\*.*\0 */ + len = PyUnicode_GET_SIZE(po); + wnamebuf = malloc((len + 5) * sizeof(wchar_t)); + if (!wnamebuf) { + PyErr_NoMemory(); + return NULL; + } + wcscpy(wnamebuf, PyUnicode_AS_UNICODE(po)); + wch = len > 0 ? wnamebuf[len-1] : '\0'; if (wch != L'/' && wch != L'\\' && wch != L':') - wnamebuf[len++] = L'/'; + wnamebuf[len++] = L'\\'; wcscpy(wnamebuf + len, L"*.*"); - if ((d = PyList_New(0)) == NULL) + if ((d = PyList_New(0)) == NULL) { + free(wnamebuf); return NULL; + } hFindFile = FindFirstFileW(wnamebuf, &wFileData); if (hFindFile == INVALID_HANDLE_VALUE) { - errno = GetLastError(); - if (errno == ERROR_FILE_NOT_FOUND) { + int error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND) { + free(wnamebuf); return d; } Py_DECREF(d); - return win32_error_unicode("FindFirstFileW", wnamebuf); + win32_error_unicode("FindFirstFileW", wnamebuf); + free(wnamebuf); + return NULL; } do { /* Skip over . and .. */ @@ -1710,8 +1851,11 @@ posix_listdir(PyObject *self, PyObject *args) if (FindClose(hFindFile) == FALSE) { Py_DECREF(d); - return win32_error_unicode("FindClose", wnamebuf); + win32_error_unicode("FindClose", wnamebuf); + free(wnamebuf); + return NULL; } + free(wnamebuf); return d; } /* Drop the argument parsing error as narrow strings @@ -1735,8 +1879,8 @@ posix_listdir(PyObject *self, PyObject *args) hFindFile = FindFirstFile(namebuf, &FileData); if (hFindFile == INVALID_HANDLE_VALUE) { - errno = GetLastError(); - if (errno == ERROR_FILE_NOT_FOUND) + int error = GetLastError(); + if (error == ERROR_FILE_NOT_FOUND) return d; Py_DECREF(d); return win32_error("FindFirstFile", namebuf); @@ -1982,10 +2126,10 @@ posix_mkdir(PyObject *self, PyObject *args) Py_BEGIN_ALLOW_THREADS /* PyUnicode_AS_UNICODE OK without thread lock as it is a simple dereference. */ - res = _wmkdir(PyUnicode_AS_UNICODE(po)); + res = CreateDirectoryW(PyUnicode_AS_UNICODE(po), NULL); Py_END_ALLOW_THREADS - if (res < 0) - return posix_error(); + if (!res) + return win32_error_unicode("mkdir", PyUnicode_AS_UNICODE(po)); Py_INCREF(Py_None); return Py_None; } @@ -1993,13 +2137,29 @@ posix_mkdir(PyObject *self, PyObject *args) are also valid. */ PyErr_Clear(); } -#endif + if (!PyArg_ParseTuple(args, "et|i:mkdir", + Py_FileSystemDefaultEncoding, &path, &mode)) + return NULL; + Py_BEGIN_ALLOW_THREADS + /* PyUnicode_AS_UNICODE OK without thread lock as + it is a simple dereference. */ + res = CreateDirectoryA(path, NULL); + Py_END_ALLOW_THREADS + if (!res) { + win32_error("mkdir", path); + PyMem_Free(path); + return NULL; + } + PyMem_Free(path); + Py_INCREF(Py_None); + return Py_None; +#else if (!PyArg_ParseTuple(args, "et|i:mkdir", Py_FileSystemDefaultEncoding, &path, &mode)) return NULL; Py_BEGIN_ALLOW_THREADS -#if ( defined(__WATCOMC__) || defined(_MSC_VER) || defined(PYCC_VACPP) ) && !defined(__QNX__) +#if ( defined(__WATCOMC__) || defined(PYCC_VACPP) ) && !defined(__QNX__) res = mkdir(path); #else res = mkdir(path, mode); @@ -2010,6 +2170,7 @@ posix_mkdir(PyObject *self, PyObject *args) PyMem_Free(path); Py_INCREF(Py_None); return Py_None; +#endif } @@ -2055,7 +2216,6 @@ posix_nice(PyObject *self, PyObject *args) } #endif /* HAVE_NICE */ - PyDoc_STRVAR(posix_rename__doc__, "rename(old, new)\n\n\ Rename a file or directory."); @@ -2064,9 +2224,38 @@ static PyObject * posix_rename(PyObject *self, PyObject *args) { #ifdef MS_WINDOWS - return posix_2str(args, "etet:rename", rename, "OO:rename", _wrename); + PyObject *o1, *o2; + char *p1, *p2; + BOOL result; + if (unicode_file_names()) { + if (!PyArg_ParseTuple(args, "O&O&:rename", + convert_to_unicode, &o1, + convert_to_unicode, &o2)) + PyErr_Clear(); + else { + Py_BEGIN_ALLOW_THREADS + result = MoveFileW(PyUnicode_AsUnicode(o1), + PyUnicode_AsUnicode(o2)); + Py_END_ALLOW_THREADS + Py_DECREF(o1); + Py_DECREF(o2); + if (!result) + return win32_error("rename", NULL); + Py_INCREF(Py_None); + return Py_None; + } + } + if (!PyArg_ParseTuple(args, "ss:rename", &p1, &p2)) + return NULL; + Py_BEGIN_ALLOW_THREADS + result = MoveFileA(p1, p2); + Py_END_ALLOW_THREADS + if (!result) + return win32_error("rename", NULL); + Py_INCREF(Py_None); + return Py_None; #else - return posix_2str(args, "etet:rename", rename, NULL, NULL); + return posix_2str(args, "etet:rename", rename); #endif } @@ -2079,9 +2268,9 @@ static PyObject * posix_rmdir(PyObject *self, PyObject *args) { #ifdef MS_WINDOWS - return posix_1str(args, "et:rmdir", rmdir, "U:rmdir", _wrmdir); + return win32_1str(args, "rmdir", "s:rmdir", RemoveDirectoryA, "U:rmdir", RemoveDirectoryW); #else - return posix_1str(args, "et:rmdir", rmdir, NULL, NULL); + return posix_1str(args, "et:rmdir", rmdir); #endif } @@ -2150,9 +2339,9 @@ static PyObject * posix_unlink(PyObject *self, PyObject *args) { #ifdef MS_WINDOWS - return posix_1str(args, "et:remove", unlink, "U:remove", _wunlink); + return win32_1str(args, "remove", "s:remove", DeleteFileA, "U:remove", DeleteFileW); #else - return posix_1str(args, "et:remove", unlink, NULL, NULL); + return posix_1str(args, "et:remove", unlink); #endif } @@ -2212,7 +2401,7 @@ extract_time(PyObject *t, long* sec, long* usec) } PyDoc_STRVAR(posix_utime__doc__, -"utime(path, (atime, utime))\n\ +"utime(path, (atime, mtime))\n\ utime(path, None)\n\n\ Set the access and modified time of the file to the given values. If the\n\ second form is used, set the access and modified times to the current time."); @@ -2220,6 +2409,84 @@ second form is used, set the access and modified times to the current time."); static PyObject * posix_utime(PyObject *self, PyObject *args) { +#ifdef Py_WIN_WIDE_FILENAMES + PyObject *arg; + PyUnicodeObject *obwpath; + wchar_t *wpath = NULL; + char *apath = NULL; + HANDLE hFile; + long atimesec, mtimesec, ausec, musec; + FILETIME atime, mtime; + PyObject *result = NULL; + + if (unicode_file_names()) { + if (PyArg_ParseTuple(args, "UO|:utime", &obwpath, &arg)) { + wpath = PyUnicode_AS_UNICODE(obwpath); + Py_BEGIN_ALLOW_THREADS + hFile = CreateFileW(wpath, FILE_WRITE_ATTRIBUTES, 0, + NULL, OPEN_EXISTING, 0, NULL); + Py_END_ALLOW_THREADS + if (hFile == INVALID_HANDLE_VALUE) + return win32_error_unicode("utime", wpath); + } else + /* Drop the argument parsing error as narrow strings + are also valid. */ + PyErr_Clear(); + } + if (!wpath) { + if (!PyArg_ParseTuple(args, "etO:utime", + Py_FileSystemDefaultEncoding, &apath, &arg)) + return NULL; + Py_BEGIN_ALLOW_THREADS + hFile = CreateFileA(apath, FILE_WRITE_ATTRIBUTES, 0, + NULL, OPEN_EXISTING, 0, NULL); + Py_END_ALLOW_THREADS + if (hFile == INVALID_HANDLE_VALUE) { + win32_error("utime", apath); + PyMem_Free(apath); + return NULL; + } + PyMem_Free(apath); + } + + if (arg == Py_None) { + SYSTEMTIME now; + GetSystemTime(&now); + if (!SystemTimeToFileTime(&now, &mtime) || + !SystemTimeToFileTime(&now, &atime)) { + win32_error("utime", NULL); + goto done; + } + } + else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) { + PyErr_SetString(PyExc_TypeError, + "utime() arg 2 must be a tuple (atime, mtime)"); + goto done; + } + else { + if (extract_time(PyTuple_GET_ITEM(arg, 0), + &atimesec, &ausec) == -1) + goto done; + time_t_to_FILE_TIME(atimesec, ausec, &atime); + if (extract_time(PyTuple_GET_ITEM(arg, 1), + &mtimesec, &musec) == -1) + goto done; + time_t_to_FILE_TIME(mtimesec, musec, &mtime); + } + if (!SetFileTime(hFile, NULL, &atime, &mtime)) { + /* Avoid putting the file name into the error here, + as that may confuse the user into believing that + something is wrong with the file, when it also + could be the time stamp that gives a problem. */ + win32_error("utime", NULL); + } + Py_INCREF(Py_None); + result = Py_None; +done: + CloseHandle(hFile); + return result; +#else /* Py_WIN_WIDE_FILENAMES */ + char *path = NULL; long atime, mtime, ausec, musec; int res; @@ -2242,33 +2509,13 @@ posix_utime(PyObject *self, PyObject *args) #define UTIME_ARG buf #endif /* HAVE_UTIMES */ - int have_unicode_filename = 0; -#ifdef Py_WIN_WIDE_FILENAMES - PyUnicodeObject *obwpath; - wchar_t *wpath; - if (unicode_file_names()) { - if (PyArg_ParseTuple(args, "UO|:utime", &obwpath, &arg)) { - wpath = PyUnicode_AS_UNICODE(obwpath); - have_unicode_filename = 1; - } else - /* Drop the argument parsing error as narrow strings - are also valid. */ - PyErr_Clear(); - } -#endif /* Py_WIN_WIDE_FILENAMES */ - if (!have_unicode_filename && \ - !PyArg_ParseTuple(args, "etO:utime", + if (!PyArg_ParseTuple(args, "etO:utime", Py_FileSystemDefaultEncoding, &path, &arg)) return NULL; if (arg == Py_None) { /* optional time values not given */ Py_BEGIN_ALLOW_THREADS -#ifdef Py_WIN_WIDE_FILENAMES - if (have_unicode_filename) - res = _wutime(wpath, NULL); - else -#endif /* Py_WIN_WIDE_FILENAMES */ res = utime(path, NULL); Py_END_ALLOW_THREADS } @@ -2299,23 +2546,11 @@ posix_utime(PyObject *self, PyObject *args) Py_END_ALLOW_THREADS #else Py_BEGIN_ALLOW_THREADS -#ifdef Py_WIN_WIDE_FILENAMES - if (have_unicode_filename) - /* utime is OK with utimbuf, but _wutime insists - on _utimbuf (the msvc headers assert the - underscore version is ansi) */ - res = _wutime(wpath, (struct _utimbuf *)UTIME_ARG); - else -#endif /* Py_WIN_WIDE_FILENAMES */ res = utime(path, UTIME_ARG); Py_END_ALLOW_THREADS #endif /* HAVE_UTIMES */ } if (res < 0) { -#ifdef Py_WIN_WIDE_FILENAMES - if (have_unicode_filename) - return posix_error_with_unicode_filename(wpath); -#endif /* Py_WIN_WIDE_FILENAMES */ return posix_error_with_allocated_filename(path); } PyMem_Free(path); @@ -2324,6 +2559,7 @@ posix_utime(PyObject *self, PyObject *args) #undef UTIME_ARG #undef ATIME #undef MTIME +#endif /* Py_WIN_WIDE_FILENAMES */ } @@ -2440,7 +2676,7 @@ posix_execve(PyObject *self, PyObject *args) PyObject *key, *val, *keys=NULL, *vals=NULL; Py_ssize_t i, pos, argc, envc; PyObject *(*getitem)(PyObject *, Py_ssize_t); - int lastarg = 0; + Py_ssize_t lastarg = 0; /* execve has three arguments: (path, argv, env), where argv is a list or tuple of strings and env is a dictionary @@ -2581,7 +2817,8 @@ posix_spawnv(PyObject *self, PyObject *args) char *path; PyObject *argv; char **argvlist; - int mode, i, argc; + int mode, i; + Py_ssize_t argc; Py_intptr_t spawnval; PyObject *(*getitem)(PyObject *, Py_ssize_t); @@ -2670,10 +2907,11 @@ posix_spawnve(PyObject *self, PyObject *args) char **argvlist; char **envlist; PyObject *key, *val, *keys=NULL, *vals=NULL, *res=NULL; - int mode, i, pos, argc, envc; + int mode, pos, envc; + Py_ssize_t argc, i; Py_intptr_t spawnval; PyObject *(*getitem)(PyObject *, Py_ssize_t); - int lastarg = 0; + Py_ssize_t lastarg = 0; /* spawnve has four arguments: (mode, path, argv, env), where argv is a list or tuple of strings and env is a dictionary @@ -4374,7 +4612,7 @@ _PyPopenCreateProcess(char *cmdstring, char modulepath[_MAX_PATH]; struct stat statinfo; GetModuleFileName(NULL, modulepath, sizeof(modulepath)); - for (i = x = 0; modulepath[i]; i++) + for (x = i = 0; modulepath[i]; i++) if (modulepath[i] == SEP) x = i+1; modulepath[x] = '\0'; @@ -4551,7 +4789,7 @@ _PyPopen(char *cmdstring, int mode, int n) switch (mode & (_O_RDONLY | _O_TEXT | _O_BINARY | _O_WRONLY)) { case _O_WRONLY | _O_TEXT: /* Case for writing to child Stdin in text mode. */ - fd1 = _open_osfhandle((intptr_t)hChildStdinWrDup, mode); + fd1 = _open_osfhandle((Py_intptr_t)hChildStdinWrDup, mode); f1 = _fdopen(fd1, "w"); f = PyFile_FromFile(f1, cmdstring, "w", _PyPclose); PyFile_SetBufSize(f, 0); @@ -4562,7 +4800,7 @@ _PyPopen(char *cmdstring, int mode, int n) case _O_RDONLY | _O_TEXT: /* Case for reading from child Stdout in text mode. */ - fd1 = _open_osfhandle((intptr_t)hChildStdoutRdDup, mode); + fd1 = _open_osfhandle((Py_intptr_t)hChildStdoutRdDup, mode); f1 = _fdopen(fd1, "r"); f = PyFile_FromFile(f1, cmdstring, "r", _PyPclose); PyFile_SetBufSize(f, 0); @@ -4573,7 +4811,7 @@ _PyPopen(char *cmdstring, int mode, int n) case _O_RDONLY | _O_BINARY: /* Case for readinig from child Stdout in binary mode. */ - fd1 = _open_osfhandle((intptr_t)hChildStdoutRdDup, mode); + fd1 = _open_osfhandle((Py_intptr_t)hChildStdoutRdDup, mode); f1 = _fdopen(fd1, "rb"); f = PyFile_FromFile(f1, cmdstring, "rb", _PyPclose); PyFile_SetBufSize(f, 0); @@ -4584,7 +4822,7 @@ _PyPopen(char *cmdstring, int mode, int n) case _O_WRONLY | _O_BINARY: /* Case for writing to child Stdin in binary mode. */ - fd1 = _open_osfhandle((intptr_t)hChildStdinWrDup, mode); + fd1 = _open_osfhandle((Py_intptr_t)hChildStdinWrDup, mode); f1 = _fdopen(fd1, "wb"); f = PyFile_FromFile(f1, cmdstring, "wb", _PyPclose); PyFile_SetBufSize(f, 0); @@ -4610,9 +4848,9 @@ _PyPopen(char *cmdstring, int mode, int n) m2 = "wb"; } - fd1 = _open_osfhandle((intptr_t)hChildStdinWrDup, mode); + fd1 = _open_osfhandle((Py_intptr_t)hChildStdinWrDup, mode); f1 = _fdopen(fd1, m2); - fd2 = _open_osfhandle((intptr_t)hChildStdoutRdDup, mode); + fd2 = _open_osfhandle((Py_intptr_t)hChildStdoutRdDup, mode); f2 = _fdopen(fd2, m1); p1 = PyFile_FromFile(f1, cmdstring, m2, _PyPclose); PyFile_SetBufSize(p1, 0); @@ -4642,11 +4880,11 @@ _PyPopen(char *cmdstring, int mode, int n) m2 = "wb"; } - fd1 = _open_osfhandle((intptr_t)hChildStdinWrDup, mode); + fd1 = _open_osfhandle((Py_intptr_t)hChildStdinWrDup, mode); f1 = _fdopen(fd1, m2); - fd2 = _open_osfhandle((intptr_t)hChildStdoutRdDup, mode); + fd2 = _open_osfhandle((Py_intptr_t)hChildStdoutRdDup, mode); f2 = _fdopen(fd2, m1); - fd3 = _open_osfhandle((intptr_t)hChildStderrRdDup, mode); + fd3 = _open_osfhandle((Py_intptr_t)hChildStderrRdDup, mode); f3 = _fdopen(fd3, m1); p1 = PyFile_FromFile(f1, cmdstring, m2, _PyPclose); p2 = PyFile_FromFile(f2, cmdstring, m1, _PyPclose); @@ -5250,7 +5488,7 @@ PyDoc_STRVAR(posix_waitpid__doc__, static PyObject * posix_waitpid(PyObject *self, PyObject *args) { - intptr_t pid; + Py_intptr_t pid; int status, options; if (!PyArg_ParseTuple(args, "ii:waitpid", &pid, &options)) @@ -5339,7 +5577,7 @@ Create a symbolic link pointing to src named dst."); static PyObject * posix_symlink(PyObject *self, PyObject *args) { - return posix_2str(args, "etet:symlink", symlink, NULL, NULL); + return posix_2str(args, "etet:symlink", symlink); } #endif /* HAVE_SYMLINK */ @@ -6280,7 +6518,7 @@ posix_WSTOPSIG(PyObject *self, PyObject *args) #endif /* HAVE_SYS_WAIT_H */ -#if defined(HAVE_FSTATVFS) +#if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H) #ifdef _SCO_DS /* SCO OpenServer 5.0 and later requires _SVID3 before it reveals the needed definitions in sys/statvfs.h */ @@ -6347,10 +6585,10 @@ posix_fstatvfs(PyObject *self, PyObject *args) return _pystatvfs_fromstructstatvfs(st); } -#endif /* HAVE_FSTATVFS */ +#endif /* HAVE_FSTATVFS && HAVE_SYS_STATVFS_H */ -#if defined(HAVE_STATVFS) +#if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) #include <sys/statvfs.h> PyDoc_STRVAR(posix_statvfs__doc__, @@ -7888,10 +8126,10 @@ static PyMethodDef posix_methods[] = { {"WSTOPSIG", posix_WSTOPSIG, METH_VARARGS, posix_WSTOPSIG__doc__}, #endif /* WSTOPSIG */ #endif /* HAVE_SYS_WAIT_H */ -#ifdef HAVE_FSTATVFS +#if defined(HAVE_FSTATVFS) && defined(HAVE_SYS_STATVFS_H) {"fstatvfs", posix_fstatvfs, METH_VARARGS, posix_fstatvfs__doc__}, #endif -#ifdef HAVE_STATVFS +#if defined(HAVE_STATVFS) && defined(HAVE_SYS_STATVFS_H) {"statvfs", posix_statvfs, METH_VARARGS, posix_statvfs__doc__}, #endif #ifdef HAVE_TMPFILE @@ -8264,6 +8502,45 @@ INITFUNC(void) PyModule_AddObject(m, "statvfs_result", (PyObject*) &StatVFSResultType); initialized = 1; + +#ifdef __APPLE__ + /* + * Step 2 of weak-linking support on Mac OS X. + * + * The code below removes functions that are not available on the + * currently active platform. + * + * This block allow one to use a python binary that was build on + * OSX 10.4 on OSX 10.3, without loosing access to new APIs on + * OSX 10.4. + */ +#ifdef HAVE_FSTATVFS + if (fstatvfs == NULL) { + if (PyObject_DelAttrString(m, "fstatvfs") == -1) { + return; + } + } +#endif /* HAVE_FSTATVFS */ + +#ifdef HAVE_STATVFS + if (statvfs == NULL) { + if (PyObject_DelAttrString(m, "statvfs") == -1) { + return; + } + } +#endif /* HAVE_STATVFS */ + +# ifdef HAVE_LCHOWN + if (lchown == NULL) { + if (PyObject_DelAttrString(m, "lchown") == -1) { + return; + } + } +#endif /* HAVE_LCHOWN */ + + +#endif /* __APPLE__ */ + } #ifdef __cplusplus |