/Modules/posixmodule.c
http://unladen-swallow.googlecode.com/ · C · 9117 lines · 7549 code · 929 blank · 639 comment · 1330 complexity · 45aba128b4b8ee359a4c42560351554e MD5 · raw file
Large files are truncated click here to view the full file
- /* POSIX module implementation */
- /* This file is also used for Windows NT/MS-Win and OS/2. In that case the
- module actually calls itself 'nt' or 'os2', not 'posix', and a few
- 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'. For OS/2, the compiler
- independent macro PYOS_OS2 should be defined. On OS/2 the default
- compiler is assumed to be IBM's VisualAge C++ (VACPP). PYCC_GCC is used
- as the compiler specific macro for the EMX port of gcc to OS/2. */
- /* 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"
- #include "structseq.h"
- #if defined(__VMS)
- # include <unixio.h>
- #endif /* defined(__VMS) */
- #ifdef __cplusplus
- extern "C" {
- #endif
- PyDoc_STRVAR(posix__doc__,
- "This module provides access to operating system functionality that is\n\
- standardized by the C Standard and the POSIX standard (a thinly\n\
- disguised Unix interface). Refer to the library manual and\n\
- corresponding Unix manual entries for more information on calls.");
- #ifndef Py_USING_UNICODE
- /* This is used in signatures of functions. */
- #define Py_UNICODE void
- #endif
- #if defined(PYOS_OS2)
- #define INCL_DOS
- #define INCL_DOSERRORS
- #define INCL_DOSPROCESS
- #define INCL_NOPMAPI
- #include <os2.h>
- #if defined(PYCC_GCC)
- #include <ctype.h>
- #include <io.h>
- #include <stdio.h>
- #include <process.h>
- #endif
- #include "osdefs.h"
- #endif
- #ifdef HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif /* HAVE_SYS_TYPES_H */
- #ifdef HAVE_SYS_STAT_H
- #include <sys/stat.h>
- #endif /* HAVE_SYS_STAT_H */
- #ifdef HAVE_SYS_WAIT_H
- #include <sys/wait.h> /* For WNOHANG */
- #endif
- #ifdef HAVE_SIGNAL_H
- #include <signal.h>
- #endif
- #ifdef HAVE_FCNTL_H
- #include <fcntl.h>
- #endif /* HAVE_FCNTL_H */
- #ifdef HAVE_GRP_H
- #include <grp.h>
- #endif
- #ifdef HAVE_SYSEXITS_H
- #include <sysexits.h>
- #endif /* HAVE_SYSEXITS_H */
- #ifdef HAVE_SYS_LOADAVG_H
- #include <sys/loadavg.h>
- #endif
- /* Various compilers have only certain posix functions */
- /* XXX Gosh I wish these were all moved into pyconfig.h */
- #if defined(PYCC_VACPP) && defined(PYOS_OS2)
- #include <process.h>
- #else
- #if defined(__WATCOMC__) && !defined(__QNX__) /* Watcom compiler */
- #define HAVE_GETCWD 1
- #define HAVE_OPENDIR 1
- #define HAVE_SYSTEM 1
- #if defined(__OS2__)
- #define HAVE_EXECV 1
- #define HAVE_WAIT 1
- #endif
- #include <process.h>
- #else
- #ifdef __BORLANDC__ /* Borland compiler */
- #define HAVE_EXECV 1
- #define HAVE_GETCWD 1
- #define HAVE_OPENDIR 1
- #define HAVE_PIPE 1
- #define HAVE_POPEN 1
- #define HAVE_SYSTEM 1
- #define HAVE_WAIT 1
- #else
- #ifdef _MSC_VER /* Microsoft compiler */
- #define HAVE_GETCWD 1
- #define HAVE_SPAWNV 1
- #define HAVE_EXECV 1
- #define HAVE_PIPE 1
- #define HAVE_POPEN 1
- #define HAVE_SYSTEM 1
- #define HAVE_CWAIT 1
- #define HAVE_FSYNC 1
- #define fsync _commit
- #else
- #if defined(PYOS_OS2) && defined(PYCC_GCC) || defined(__VMS)
- /* Everything needed is defined in PC/os2emx/pyconfig.h or vms/pyconfig.h */
- #else /* all other compilers */
- /* Unix functions that the configure script doesn't check for */
- #define HAVE_EXECV 1
- #define HAVE_FORK 1
- #if defined(__USLC__) && defined(__SCO_VERSION__) /* SCO UDK Compiler */
- #define HAVE_FORK1 1
- #endif
- #define HAVE_GETCWD 1
- #define HAVE_GETEGID 1
- #define HAVE_GETEUID 1
- #define HAVE_GETGID 1
- #define HAVE_GETPPID 1
- #define HAVE_GETUID 1
- #define HAVE_KILL 1
- #define HAVE_OPENDIR 1
- #define HAVE_PIPE 1
- #ifndef __rtems__
- #define HAVE_POPEN 1
- #endif
- #define HAVE_SYSTEM 1
- #define HAVE_WAIT 1
- #define HAVE_TTYNAME 1
- #endif /* PYOS_OS2 && PYCC_GCC && __VMS */
- #endif /* _MSC_VER */
- #endif /* __BORLANDC__ */
- #endif /* ! __WATCOMC__ || __QNX__ */
- #endif /* ! __IBMC__ */
- #ifndef _MSC_VER
- #if defined(__sgi)&&_COMPILER_VERSION>=700
- /* declare ctermid_r if compiling with MIPSPro 7.x in ANSI C mode
- (default) */
- extern char *ctermid_r(char *);
- #endif
- #ifndef HAVE_UNISTD_H
- #if defined(PYCC_VACPP)
- extern int mkdir(char *);
- #else
- #if ( defined(__WATCOMC__) || defined(_MSC_VER) ) && !defined(__QNX__)
- extern int mkdir(const char *);
- #else
- extern int mkdir(const char *, mode_t);
- #endif
- #endif
- #if defined(__IBMC__) || defined(__IBMCPP__)
- extern int chdir(char *);
- extern int rmdir(char *);
- #else
- 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*/
- /*#ifdef HAVE_LCHMOD
- extern int lchmod(const char *, mode_t);
- #endif*/
- extern int chown(const char *, uid_t, gid_t);
- extern char *getcwd(char *, int);
- extern char *strerror(int);
- extern int link(const char *, const char *);
- extern int rename(const char *, const char *);
- extern int stat(const char *, struct stat *);
- extern int unlink(const char *);
- extern int pclose(FILE *);
- #ifdef HAVE_SYMLINK
- extern int symlink(const char *, const char *);
- #endif /* HAVE_SYMLINK */
- #ifdef HAVE_LSTAT
- extern int lstat(const char *, struct stat *);
- #endif /* HAVE_LSTAT */
- #endif /* !HAVE_UNISTD_H */
- #endif /* !_MSC_VER */
- #ifdef HAVE_UTIME_H
- #include <utime.h>
- #endif /* HAVE_UTIME_H */
- #ifdef HAVE_SYS_UTIME_H
- #include <sys/utime.h>
- #define HAVE_UTIME_H /* pretend we do for the rest of this file */
- #endif /* HAVE_SYS_UTIME_H */
- #ifdef HAVE_SYS_TIMES_H
- #include <sys/times.h>
- #endif /* HAVE_SYS_TIMES_H */
- #ifdef HAVE_SYS_PARAM_H
- #include <sys/param.h>
- #endif /* HAVE_SYS_PARAM_H */
- #ifdef HAVE_SYS_UTSNAME_H
- #include <sys/utsname.h>
- #endif /* HAVE_SYS_UTSNAME_H */
- #ifdef HAVE_DIRENT_H
- #include <dirent.h>
- #define NAMLEN(dirent) strlen((dirent)->d_name)
- #else
- #if defined(__WATCOMC__) && !defined(__QNX__)
- #include <direct.h>
- #define NAMLEN(dirent) strlen((dirent)->d_name)
- #else
- #define dirent direct
- #define NAMLEN(dirent) (dirent)->d_namlen
- #endif
- #ifdef HAVE_SYS_NDIR_H
- #include <sys/ndir.h>
- #endif
- #ifdef HAVE_SYS_DIR_H
- #include <sys/dir.h>
- #endif
- #ifdef HAVE_NDIR_H
- #include <ndir.h>
- #endif
- #endif
- #ifdef _MSC_VER
- #ifdef HAVE_DIRECT_H
- #include <direct.h>
- #endif
- #ifdef HAVE_IO_H
- #include <io.h>
- #endif
- #ifdef HAVE_PROCESS_H
- #include <process.h>
- #endif
- #include "osdefs.h"
- #include <windows.h>
- #include <shellapi.h> /* for ShellExecute() */
- #define popen _popen
- #define pclose _pclose
- #endif /* _MSC_VER */
- #if defined(PYCC_VACPP) && defined(PYOS_OS2)
- #include <io.h>
- #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
- /* Emulate some macros on systems that have a union instead of macros */
- #ifndef WIFEXITED
- #define WIFEXITED(u_wait) (!(u_wait).w_termsig && !(u_wait).w_coredump)
- #endif
- #ifndef WEXITSTATUS
- #define WEXITSTATUS(u_wait) (WIFEXITED(u_wait)?((u_wait).w_retcode):-1)
- #endif
- #ifndef WTERMSIG
- #define WTERMSIG(u_wait) ((u_wait).w_termsig)
- #endif
- #define WAIT_TYPE union wait
- #define WAIT_STATUS_INT(s) (s.w_status)
- #else /* !UNION_WAIT */
- #define WAIT_TYPE int
- #define WAIT_STATUS_INT(s) (s)
- #endif /* UNION_WAIT */
- /* Issue #1983: pid_t can be longer than a C long on some systems */
- #if !defined(SIZEOF_PID_T) || SIZEOF_PID_T == SIZEOF_INT
- #define PARSE_PID "i"
- #define PyLong_FromPid PyInt_FromLong
- #define PyLong_AsPid PyInt_AsLong
- #elif SIZEOF_PID_T == SIZEOF_LONG
- #define PARSE_PID "l"
- #define PyLong_FromPid PyInt_FromLong
- #define PyLong_AsPid PyInt_AsLong
- #elif defined(SIZEOF_LONG_LONG) && SIZEOF_PID_T == SIZEOF_LONG_LONG
- #define PARSE_PID "L"
- #define PyLong_FromPid PyLong_FromLongLong
- #define PyLong_AsPid PyInt_AsLongLong
- #else
- #error "sizeof(pid_t) is neither sizeof(int), sizeof(long) or sizeof(long long)"
- #endif /* SIZEOF_PID_T */
- /* Don't use the "_r" form if we don't need it (also, won't have a
- prototype for it, at least on Solaris -- maybe others as well?). */
- #if defined(HAVE_CTERMID_R) && defined(WITH_THREAD)
- #define USE_CTERMID_R
- #endif
- #if defined(HAVE_TMPNAM_R) && defined(WITH_THREAD)
- #define USE_TMPNAM_R
- #endif
- /* choose the appropriate stat and fstat functions and return structs */
- #undef STAT
- #if defined(MS_WIN64) || defined(MS_WINDOWS)
- # define STAT win32_stat
- # define FSTAT win32_fstat
- # define STRUCT_STAT struct win32_stat
- #else
- # define STAT stat
- # define FSTAT fstat
- # define STRUCT_STAT struct stat
- #endif
- #if defined(MAJOR_IN_MKDEV)
- #include <sys/mkdev.h>
- #else
- #if defined(MAJOR_IN_SYSMACROS)
- #include <sys/sysmacros.h>
- #endif
- #if defined(HAVE_MKNOD) && defined(HAVE_SYS_MKDEV_H)
- #include <sys/mkdev.h>
- #endif
- #endif
- /* Return a dictionary corresponding to the POSIX environment table */
- #ifdef WITH_NEXT_FRAMEWORK
- /* On Darwin/MacOSX a shared library or framework has no access to
- ** environ directly, we must obtain it with _NSGetEnviron().
- */
- #include <crt_externs.h>
- static char **environ;
- #elif !defined(_MSC_VER) && ( !defined(__WATCOMC__) || defined(__QNX__) )
- extern char **environ;
- #endif /* !_MSC_VER */
- static PyObject *
- convertenviron(void)
- {
- PyObject *d;
- char **e;
- d = PyDict_New();
- if (d == NULL)
- return NULL;
- #ifdef WITH_NEXT_FRAMEWORK
- if (environ == NULL)
- environ = *_NSGetEnviron();
- #endif
- if (environ == NULL)
- return d;
- /* This part ignores errors */
- for (e = environ; *e != NULL; e++) {
- PyObject *k;
- PyObject *v;
- char *p = strchr(*e, '=');
- if (p == NULL)
- continue;
- k = PyString_FromStringAndSize(*e, (int)(p-*e));
- if (k == NULL) {
- PyErr_Clear();
- continue;
- }
- v = PyString_FromString(p+1);
- if (v == NULL) {
- PyErr_Clear();
- Py_DECREF(k);
- continue;
- }
- if (PyDict_GetItem(d, k) == NULL) {
- if (PyDict_SetItem(d, k, v) != 0)
- PyErr_Clear();
- }
- Py_DECREF(k);
- Py_DECREF(v);
- }
- #if defined(PYOS_OS2)
- {
- APIRET rc;
- char buffer[1024]; /* OS/2 Provides a Documented Max of 1024 Chars */
- rc = DosQueryExtLIBPATH(buffer, BEGIN_LIBPATH);
- if (rc == NO_ERROR) { /* (not a type, envname is NOT 'BEGIN_LIBPATH') */
- PyObject *v = PyString_FromString(buffer);
- PyDict_SetItemString(d, "BEGINLIBPATH", v);
- Py_DECREF(v);
- }
- rc = DosQueryExtLIBPATH(buffer, END_LIBPATH);
- if (rc == NO_ERROR) { /* (not a typo, envname is NOT 'END_LIBPATH') */
- PyObject *v = PyString_FromString(buffer);
- PyDict_SetItemString(d, "ENDLIBPATH", v);
- Py_DECREF(v);
- }
- }
- #endif
- return d;
- }
- /* Set a POSIX-specific error from errno, and return NULL */
- static PyObject *
- posix_error(void)
- {
- return PyErr_SetFromErrno(PyExc_OSError);
- }
- static PyObject *
- posix_error_with_filename(char* name)
- {
- return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
- }
- #ifdef Py_WIN_WIDE_FILENAMES
- static PyObject *
- posix_error_with_unicode_filename(Py_UNICODE* name)
- {
- return PyErr_SetFromErrnoWithUnicodeFilename(PyExc_OSError, name);
- }
- #endif /* Py_WIN_WIDE_FILENAMES */
- static PyObject *
- posix_error_with_allocated_filename(char* name)
- {
- PyObject *rc = PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
- PyMem_Free(name);
- return rc;
- }
- #ifdef MS_WINDOWS
- static PyObject *
- win32_error(char* function, char* filename)
- {
- /* XXX We should pass the function name along in the future.
- (_winreg.c also wants to pass the function name.)
- This would however require an additional param to the
- Windows error object, which is non-trivial.
- */
- errno = GetLastError();
- if (filename)
- return PyErr_SetFromWindowsErrWithFilename(errno, filename);
- else
- return PyErr_SetFromWindowsErr(errno);
- }
- #ifdef Py_WIN_WIDE_FILENAMES
- static PyObject *
- win32_error_unicode(char* function, Py_UNICODE* filename)
- {
- /* XXX - see win32_error for comments on 'function' */
- errno = GetLastError();
- if (filename)
- return PyErr_SetFromWindowsErrWithUnicodeFilename(errno, filename);
- else
- return PyErr_SetFromWindowsErr(errno);
- }
- static PyObject *_PyUnicode_FromFileSystemEncodedObject(register PyObject *obj)
- {
- }
- static int
- convert_to_unicode(PyObject **param)
- {
- if (PyUnicode_CheckExact(*param))
- Py_INCREF(*param);
- else if (PyUnicode_Check(*param))
- /* For a Unicode subtype that's not a Unicode object,
- return a true Unicode object with the same data. */
- *param = PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(*param),
- PyUnicode_GET_SIZE(*param));
- else
- *param = PyUnicode_FromEncodedObject(*param,
- Py_FileSystemDefaultEncoding,
- "strict");
- return (*param) != NULL;
- }
- #endif /* Py_WIN_WIDE_FILENAMES */
- #endif
- #if defined(PYOS_OS2)
- /**********************************************************************
- * Helper Function to Trim and Format OS/2 Messages
- **********************************************************************/
- static void
- os2_formatmsg(char *msgbuf, int msglen, char *reason)
- {
- msgbuf[msglen] = '\0'; /* OS/2 Doesn't Guarantee a Terminator */
- if (strlen(msgbuf) > 0) { /* If Non-Empty Msg, Trim CRLF */
- char *lastc = &msgbuf[ strlen(msgbuf)-1 ];
- while (lastc > msgbuf && isspace(Py_CHARMASK(*lastc)))
- *lastc-- = '\0'; /* Trim Trailing Whitespace (CRLF) */
- }
- /* Add Optional Reason Text */
- if (reason) {
- strcat(msgbuf, " : ");
- strcat(msgbuf, reason);
- }
- }
- /**********************************************************************
- * Decode an OS/2 Operating System Error Code
- *
- * A convenience function to lookup an OS/2 error code and return a
- * text message we can use to raise a Python exception.
- *
- * Notes:
- * The messages for errors returned from the OS/2 kernel reside in
- * the file OSO001.MSG in the \OS2 directory hierarchy.
- *
- **********************************************************************/
- static char *
- os2_strerror(char *msgbuf, int msgbuflen, int errorcode, char *reason)
- {
- APIRET rc;
- ULONG msglen;
- /* Retrieve Kernel-Related Error Message from OSO001.MSG File */
- Py_BEGIN_ALLOW_THREADS
- rc = DosGetMessage(NULL, 0, msgbuf, msgbuflen,
- errorcode, "oso001.msg", &msglen);
- Py_END_ALLOW_THREADS
- if (rc == NO_ERROR)
- os2_formatmsg(msgbuf, msglen, reason);
- else
- PyOS_snprintf(msgbuf, msgbuflen,
- "unknown OS error #%d", errorcode);
- return msgbuf;
- }
- /* Set an OS/2-specific error and return NULL. OS/2 kernel
- errors are not in a global variable e.g. 'errno' nor are
- they congruent with posix error numbers. */
- static PyObject * os2_error(int code)
- {
- char text[1024];
- PyObject *v;
- os2_strerror(text, sizeof(text), code, "");
- v = Py_BuildValue("(is)", code, text);
- if (v != NULL) {
- PyErr_SetObject(PyExc_OSError, v);
- Py_DECREF(v);
- }
- return NULL; /* Signal to Python that an Exception is Pending */
- }
- #endif /* OS2 */
- /* POSIX generic methods */
- static PyObject *
- posix_fildes(PyObject *fdobj, int (*func)(int))
- {
- int fd;
- int res;
- fd = PyObject_AsFileDescriptor(fdobj);
- if (fd < 0)
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = (*func)(fd);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error();
- Py_INCREF(Py_None);
- return Py_None;
- }
- #ifdef Py_WIN_WIDE_FILENAMES
- static int
- unicode_file_names(void)
- {
- static int canusewide = -1;
- if (canusewide == -1) {
- /* As per doc for ::GetVersion(), this is the correct test for
- the Windows NT family. */
- canusewide = (GetVersion() < 0x80000000) ? 1 : 0;
- }
- return canusewide;
- }
- #endif
- static PyObject *
- posix_1str(PyObject *args, char *format, int (*func)(const char*))
- {
- char *path1 = NULL;
- int res;
- if (!PyArg_ParseTuple(args, format,
- Py_FileSystemDefaultEncoding, &path1))
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = (*func)(path1);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error_with_allocated_filename(path1);
- PyMem_Free(path1);
- Py_INCREF(Py_None);
- return Py_None;
- }
- static PyObject *
- posix_2str(PyObject *args,
- char *format,
- int (*func)(const char *, const char *))
- {
- char *path1 = NULL, *path2 = NULL;
- int res;
- if (!PyArg_ParseTuple(args, format,
- Py_FileSystemDefaultEncoding, &path1,
- Py_FileSystemDefaultEncoding, &path2))
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = (*func)(path1, path2);
- Py_END_ALLOW_THREADS
- PyMem_Free(path1);
- PyMem_Free(path2);
- if (res != 0)
- /* XXX how to report both path1 and path2??? */
- return posix_error();
- Py_INCREF(Py_None);
- 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 * sizeof(wchar_t));
- if (!new_path) {
- SetLastError(ERROR_OUTOFMEMORY);
- return FALSE;
- }
- result = GetCurrentDirectoryW(result, new_path);
- if (!result) {
- free(new_path);
- 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
- - file modification times suffer from forth-and-back conversions between
- UTC and local time
- Therefore, we implement our own stat, based on the Win32 API directly.
- */
- #define HAVE_STAT_NSEC 1
- struct win32_stat{
- int st_dev;
- __int64 st_ino;
- unsigned short st_mode;
- int st_nlink;
- int st_uid;
- int st_gid;
- int st_rdev;
- __int64 st_size;
- int st_atime;
- int st_atime_nsec;
- int st_mtime;
- int st_mtime_nsec;
- int 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, int *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. */
- /* 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 / 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(WIN32_FILE_ATTRIBUTE_DATA *info, 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;
- 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);
- return 0;
- }
- /* Emulate GetFileAttributesEx[AW] on Windows 95 */
- static int checked = 0;
- static BOOL (CALLBACK *gfaxa)(LPCSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
- static BOOL (CALLBACK *gfaxw)(LPCWSTR, GET_FILEEX_INFO_LEVELS, LPVOID);
- static void
- check_gfax()
- {
- HINSTANCE hKernel32;
- if (checked)
- return;
- checked = 1;
- hKernel32 = GetModuleHandle("KERNEL32");
- *(FARPROC*)&gfaxa = GetProcAddress(hKernel32, "GetFileAttributesExA");
- *(FARPROC*)&gfaxw = GetProcAddress(hKernel32, "GetFileAttributesExW");
- }
- static BOOL
- attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
- {
- HANDLE hFindFile;
- WIN32_FIND_DATAA FileData;
- hFindFile = FindFirstFileA(pszFile, &FileData);
- if (hFindFile == INVALID_HANDLE_VALUE)
- return FALSE;
- FindClose(hFindFile);
- pfad->dwFileAttributes = FileData.dwFileAttributes;
- pfad->ftCreationTime = FileData.ftCreationTime;
- pfad->ftLastAccessTime = FileData.ftLastAccessTime;
- pfad->ftLastWriteTime = FileData.ftLastWriteTime;
- pfad->nFileSizeHigh = FileData.nFileSizeHigh;
- pfad->nFileSizeLow = FileData.nFileSizeLow;
- return TRUE;
- }
- static BOOL
- attributes_from_dir_w(LPCWSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
- {
- HANDLE hFindFile;
- WIN32_FIND_DATAW FileData;
- hFindFile = FindFirstFileW(pszFile, &FileData);
- if (hFindFile == INVALID_HANDLE_VALUE)
- return FALSE;
- FindClose(hFindFile);
- pfad->dwFileAttributes = FileData.dwFileAttributes;
- pfad->ftCreationTime = FileData.ftCreationTime;
- pfad->ftLastAccessTime = FileData.ftLastAccessTime;
- pfad->ftLastWriteTime = FileData.ftLastWriteTime;
- pfad->nFileSizeHigh = FileData.nFileSizeHigh;
- pfad->nFileSizeLow = FileData.nFileSizeLow;
- return TRUE;
- }
- static BOOL WINAPI
- Py_GetFileAttributesExA(LPCSTR pszFile,
- GET_FILEEX_INFO_LEVELS level,
- LPVOID pv)
- {
- BOOL result;
- LPWIN32_FILE_ATTRIBUTE_DATA pfad = pv;
- /* First try to use the system's implementation, if that is
- available and either succeeds to gives an error other than
- that it isn't implemented. */
- check_gfax();
- if (gfaxa) {
- result = gfaxa(pszFile, level, pv);
- if (result || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
- return result;
- }
- /* It's either not present, or not implemented.
- Emulate using FindFirstFile. */
- if (level != GetFileExInfoStandard) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- /* Use GetFileAttributes to validate that the file name
- does not contain wildcards (which FindFirstFile would
- accept). */
- if (GetFileAttributesA(pszFile) == 0xFFFFFFFF)
- return FALSE;
- return attributes_from_dir(pszFile, pfad);
- }
- static BOOL WINAPI
- Py_GetFileAttributesExW(LPCWSTR pszFile,
- GET_FILEEX_INFO_LEVELS level,
- LPVOID pv)
- {
- BOOL result;
- LPWIN32_FILE_ATTRIBUTE_DATA pfad = pv;
- /* First try to use the system's implementation, if that is
- available and either succeeds to gives an error other than
- that it isn't implemented. */
- check_gfax();
- if (gfaxa) {
- result = gfaxw(pszFile, level, pv);
- if (result || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
- return result;
- }
- /* It's either not present, or not implemented.
- Emulate using FindFirstFile. */
- if (level != GetFileExInfoStandard) {
- SetLastError(ERROR_INVALID_PARAMETER);
- return FALSE;
- }
- /* Use GetFileAttributes to validate that the file name
- does not contain wildcards (which FindFirstFile would
- accept). */
- if (GetFileAttributesW(pszFile) == 0xFFFFFFFF)
- return FALSE;
- return attributes_from_dir_w(pszFile, pfad);
- }
- static int
- win32_stat(const char* path, struct win32_stat *result)
- {
- WIN32_FILE_ATTRIBUTE_DATA info;
- int code;
- char *dot;
- /* XXX not supported on Win95 and NT 3.x */
- if (!Py_GetFileAttributesExA(path, GetFileExInfoStandard, &info)) {
- if (GetLastError() != ERROR_SHARING_VIOLATION) {
- /* Protocol violation: we explicitly clear errno, instead of
- setting it to a POSIX error. Callers should use GetLastError. */
- errno = 0;
- return -1;
- } else {
- /* Could not get attributes on open file. Fall back to
- reading the directory. */
- if (!attributes_from_dir(path, &info)) {
- /* Very strange. This should not fail now */
- errno = 0;
- return -1;
- }
- }
- }
- code = attribute_data_to_stat(&info, result);
- if (code != 0)
- return code;
- /* Set S_IFEXEC if it is an .exe, .bat, ... */
- dot = strrchr(path, '.');
- if (dot) {
- if (stricmp(dot, ".bat") == 0 ||
- stricmp(dot, ".cmd") == 0 ||
- stricmp(dot, ".exe") == 0 ||
- stricmp(dot, ".com") == 0)
- result->st_mode |= 0111;
- }
- return code;
- }
- static int
- win32_wstat(const wchar_t* path, struct win32_stat *result)
- {
- int code;
- const wchar_t *dot;
- WIN32_FILE_ATTRIBUTE_DATA info;
- /* XXX not supported on Win95 and NT 3.x */
- if (!Py_GetFileAttributesExW(path, GetFileExInfoStandard, &info)) {
- if (GetLastError() != ERROR_SHARING_VIOLATION) {
- /* Protocol violation: we explicitly clear errno, instead of
- setting it to a POSIX error. Callers should use GetLastError. */
- errno = 0;
- return -1;
- } else {
- /* Could not get attributes on open file. Fall back to
- reading the directory. */
- if (!attributes_from_dir_w(path, &info)) {
- /* Very strange. This should not fail now */
- errno = 0;
- return -1;
- }
- }
- }
- code = attribute_data_to_stat(&info, result);
- if (code < 0)
- return code;
- /* Set IFEXEC if it is an .exe, .bat, ... */
- dot = wcsrchr(path, '.');
- if (dot) {
- if (_wcsicmp(dot, L".bat") == 0 ||
- _wcsicmp(dot, L".cmd") == 0 ||
- _wcsicmp(dot, L".exe") == 0 ||
- _wcsicmp(dot, L".com") == 0)
- result->st_mode |= 0111;
- }
- return code;
- }
- static int
- win32_fstat(int file_number, struct win32_stat *result)
- {
- BY_HANDLE_FILE_INFORMATION info;
- HANDLE h;
- int type;
-
- 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;
- }
- /* similar to stat() */
- result->st_mode = attributes_to_mode(info.dwFileAttributes);
- result->st_size = (((__int64)info.nFileSizeHigh)<<32) + info.nFileSizeLow;
- 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);
- /* specific to fstat() */
- result->st_nlink = info.nNumberOfLinks;
- result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow;
- return 0;
- }
- #endif /* MS_WINDOWS */
- PyDoc_STRVAR(stat_result__doc__,
- "stat_result: Result from stat or lstat.\n\n\
- This object may be accessed either as a tuple of\n\
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime)\n\
- or via the attributes st_mode, st_ino, st_dev, st_nlink, st_uid, and so on.\n\
- \n\
- Posix/windows: If your platform supports st_blksize, st_blocks, st_rdev,\n\
- or st_flags, they are available as attributes only.\n\
- \n\
- See os.stat for more information.");
- static PyStructSequence_Field stat_result_fields[] = {
- {"st_mode", "protection bits"},
- {"st_ino", "inode"},
- {"st_dev", "device"},
- {"st_nlink", "number of hard links"},
- {"st_uid", "user ID of owner"},
- {"st_gid", "group ID of owner"},
- {"st_size", "total size, in bytes"},
- /* The NULL is replaced with PyStructSequence_UnnamedField later. */
- {NULL, "integer time of last access"},
- {NULL, "integer time of last modification"},
- {NULL, "integer time of last change"},
- {"st_atime", "time of last access"},
- {"st_mtime", "time of last modification"},
- {"st_ctime", "time of last change"},
- #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
- {"st_blksize", "blocksize for filesystem I/O"},
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
- {"st_blocks", "number of blocks allocated"},
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_RDEV
- {"st_rdev", "device type (if inode device)"},
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_FLAGS
- {"st_flags", "user defined flags for file"},
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_GEN
- {"st_gen", "generation number"},
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
- {"st_birthtime", "time of creation"},
- #endif
- {0}
- };
- #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
- #define ST_BLKSIZE_IDX 13
- #else
- #define ST_BLKSIZE_IDX 12
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
- #define ST_BLOCKS_IDX (ST_BLKSIZE_IDX+1)
- #else
- #define ST_BLOCKS_IDX ST_BLKSIZE_IDX
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_RDEV
- #define ST_RDEV_IDX (ST_BLOCKS_IDX+1)
- #else
- #define ST_RDEV_IDX ST_BLOCKS_IDX
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_FLAGS
- #define ST_FLAGS_IDX (ST_RDEV_IDX+1)
- #else
- #define ST_FLAGS_IDX ST_RDEV_IDX
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_GEN
- #define ST_GEN_IDX (ST_FLAGS_IDX+1)
- #else
- #define ST_GEN_IDX ST_FLAGS_IDX
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
- #define ST_BIRTHTIME_IDX (ST_GEN_IDX+1)
- #else
- #define ST_BIRTHTIME_IDX ST_GEN_IDX
- #endif
- static PyStructSequence_Desc stat_result_desc = {
- "stat_result", /* name */
- stat_result__doc__, /* doc */
- stat_result_fields,
- 10
- };
- PyDoc_STRVAR(statvfs_result__doc__,
- "statvfs_result: Result from statvfs or fstatvfs.\n\n\
- This object may be accessed either as a tuple of\n\
- (bsize, frsize, blocks, bfree, bavail, files, ffree, favail, flag, namemax),\n\
- or via the attributes f_bsize, f_frsize, f_blocks, f_bfree, and so on.\n\
- \n\
- See os.statvfs for more information.");
- static PyStructSequence_Field statvfs_result_fields[] = {
- {"f_bsize", },
- {"f_frsize", },
- {"f_blocks", },
- {"f_bfree", },
- {"f_bavail", },
- {"f_files", },
- {"f_ffree", },
- {"f_favail", },
- {"f_flag", },
- {"f_namemax",},
- {0}
- };
- static PyStructSequence_Desc statvfs_result_desc = {
- "statvfs_result", /* name */
- statvfs_result__doc__, /* doc */
- statvfs_result_fields,
- 10
- };
- static int initialized;
- static PyTypeObject StatResultType;
- static PyTypeObject StatVFSResultType;
- static newfunc structseq_new;
- static PyObject *
- statresult_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
- {
- PyStructSequence *result;
- int i;
- result = (PyStructSequence*)structseq_new(type, args, kwds);
- if (!result)
- return NULL;
- /* If we have been initialized from a tuple,
- st_?time might be set to None. Initialize it
- from the int slots. */
- for (i = 7; i <= 9; i++) {
- if (result->ob_item[i+3] == Py_None) {
- Py_DECREF(Py_None);
- Py_INCREF(result->ob_item[i]);
- result->ob_item[i+3] = result->ob_item[i];
- }
- }
- return (PyObject*)result;
- }
- /* If true, st_?time is float. */
- 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");
- static PyObject*
- stat_float_times(PyObject* self, PyObject *args)
- {
- int newval = -1;
- if (!PyArg_ParseTuple(args, "|i:stat_float_times", &newval))
- return NULL;
- if (newval == -1)
- /* Return old value */
- return PyBool_FromLong(_stat_float_times);
- _stat_float_times = newval;
- Py_INCREF(Py_None);
- return Py_None;
- }
- static void
- fill_time(PyObject *v, int index, time_t sec, unsigned long nsec)
- {
- PyObject *fval,*ival;
- #if SIZEOF_TIME_T > SIZEOF_LONG
- ival = PyLong_FromLongLong((PY_LONG_LONG)sec);
- #else
- ival = PyInt_FromLong((long)sec);
- #endif
- if (!ival)
- return;
- if (_stat_float_times) {
- fval = PyFloat_FromDouble(sec + 1e-9*nsec);
- } else {
- fval = ival;
- Py_INCREF(fval);
- }
- PyStructSequence_SET_ITEM(v, index, ival);
- PyStructSequence_SET_ITEM(v, index+3, fval);
- }
- /* pack a system stat C structure into the Python stat tuple
- (used by posix_stat() and posix_fstat()) */
- static PyObject*
- _pystat_fromstructstat(STRUCT_STAT *st)
- {
- unsigned long ansec, mnsec, cnsec;
- PyObject *v = PyStructSequence_New(&StatResultType);
- if (v == NULL)
- return NULL;
- PyStructSequence_SET_ITEM(v, 0, PyInt_FromLong((long)st->st_mode));
- #ifdef HAVE_LARGEFILE_SUPPORT
- PyStructSequence_SET_ITEM(v, 1,
- PyLong_FromLongLong((PY_LONG_LONG)st->st_ino));
- #else
- PyStructSequence_SET_ITEM(v, 1, PyInt_FromLong((long)st->st_ino));
- #endif
- #if defined(HAVE_LONG_LONG) && !defined(MS_WINDOWS)
- PyStructSequence_SET_ITEM(v, 2,
- PyLong_FromLongLong((PY_LONG_LONG)st->st_dev));
- #else
- PyStructSequence_SET_ITEM(v, 2, PyInt_FromLong((long)st->st_dev));
- #endif
- PyStructSequence_SET_ITEM(v, 3, PyInt_FromLong((long)st->st_nlink));
- PyStructSequence_SET_ITEM(v, 4, PyInt_FromLong((long)st->st_uid));
- PyStructSequence_SET_ITEM(v, 5, PyInt_FromLong((long)st->st_gid));
- #ifdef HAVE_LARGEFILE_SUPPORT
- PyStructSequence_SET_ITEM(v, 6,
- PyLong_FromLongLong((PY_LONG_LONG)st->st_size));
- #else
- PyStructSequence_SET_ITEM(v, 6, PyInt_FromLong(st->st_size));
- #endif
- #if defined(HAVE_STAT_TV_NSEC)
- ansec = st->st_atim.tv_nsec;
- mnsec = st->st_mtim.tv_nsec;
- cnsec = st->st_ctim.tv_nsec;
- #elif defined(HAVE_STAT_TV_NSEC2)
- ansec = st->st_atimespec.tv_nsec;
- mnsec = st->st_mtimespec.tv_nsec;
- cnsec = st->st_ctimespec.tv_nsec;
- #elif defined(HAVE_STAT_NSEC)
- ansec = st->st_atime_nsec;
- mnsec = st->st_mtime_nsec;
- cnsec = st->st_ctime_nsec;
- #else
- ansec = mnsec = cnsec = 0;
- #endif
- fill_time(v, 7, st->st_atime, ansec);
- fill_time(v, 8, st->st_mtime, mnsec);
- fill_time(v, 9, st->st_ctime, cnsec);
- #ifdef HAVE_STRUCT_STAT_ST_BLKSIZE
- PyStructSequence_SET_ITEM(v, ST_BLKSIZE_IDX,
- PyInt_FromLong((long)st->st_blksize));
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_BLOCKS
- PyStructSequence_SET_ITEM(v, ST_BLOCKS_IDX,
- PyInt_FromLong((long)st->st_blocks));
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_RDEV
- PyStructSequence_SET_ITEM(v, ST_RDEV_IDX,
- PyInt_FromLong((long)st->st_rdev));
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_GEN
- PyStructSequence_SET_ITEM(v, ST_GEN_IDX,
- PyInt_FromLong((long)st->st_gen));
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_BIRTHTIME
- {
- PyObject *val;
- unsigned long bsec,bnsec;
- bsec = (long)st->st_birthtime;
- #ifdef HAVE_STAT_TV_NSEC2
- bnsec = st->st_birthtimespec.tv_nsec;
- #else
- bnsec = 0;
- #endif
- if (_stat_float_times) {
- val = PyFloat_FromDouble(bsec + 1e-9*bnsec);
- } else {
- val = PyInt_FromLong((long)bsec);
- }
- PyStructSequence_SET_ITEM(v, ST_BIRTHTIME_IDX,
- val);
- }
- #endif
- #ifdef HAVE_STRUCT_STAT_ST_FLAGS
- PyStructSequence_SET_ITEM(v, ST_FLAGS_IDX,
- PyInt_FromLong((long)st->st_flags));
- #endif
- if (PyErr_Occurred()) {
- Py_DECREF(v);
- return NULL;
- }
- return v;
- }
- #ifdef MS_WINDOWS
- /* IsUNCRoot -- test whether the supplied path is of the form \\SERVER\SHARE\,
- where / can be used in place of \ and the trailing slash is optional.
- Both SERVER and SHARE must have at least one character.
- */
- #define ISSLASHA(c) ((c) == '\\' || (c) == '/')
- #define ISSLASHW(c) ((c) == L'\\' || (c) == L'/')
- #ifndef ARRAYSIZE
- #define ARRAYSIZE(a) (sizeof(a) / sizeof(a[0]))
- #endif
- static BOOL
- IsUNCRootA(char *path, int pathlen)
- {
- #define ISSLASH ISSLASHA
- int i, share;
- if (pathlen < 5 || !ISSLASH(path[0]) || !ISSLASH(path[1]))
- /* minimum UNCRoot is \\x\y */
- return FALSE;
- for (i = 2; i < pathlen ; i++)
- if (ISSLASH(path[i])) break;
- if (i == 2 || i == pathlen)
- /* do not allow \\\SHARE or \\SERVER */
- return FALSE;
- share = i+1;
- for (i = share; i < pathlen; i++)
- if (ISSLASH(path[i])) break;
- return (i != share && (i == pathlen || i == pathlen-1));
- #undef ISSLASH
- }
- #ifdef Py_WIN_WIDE_FILENAMES
- static BOOL
- IsUNCRootW(Py_UNICODE *path, int pathlen)
- {
- #define ISSLASH ISSLASHW
- int i, share;
- if (pathlen < 5 || !ISSLASH(path[0]) || !ISSLASH(path[1]))
- /* minimum UNCRoot is \\x\y */
- return FALSE;
- for (i = 2; i < pathlen ; i++)
- if (ISSLASH(path[i])) break;
- if (i == 2 || i == pathlen)
- /* do not allow \\\SHARE or \\SERVER */
- return FALSE;
- share = i+1;
- for (i = share; i < pathlen; i++)
- if (ISSLASH(path[i])) break;
- return (i != share && (i == pathlen || i == pathlen-1));
- #undef ISSLASH
- }
- #endif /* Py_WIN_WIDE_FILENAMES */
- #endif /* MS_WINDOWS */
- static PyObject *
- posix_do_stat(PyObject *self, PyObject *args,
- char *format,
- #ifdef __VMS
- int (*statfunc)(const char *, STRUCT_STAT *, ...),
- #else
- int (*statfunc)(const char *, STRUCT_STAT *),
- #endif
- char *wformat,
- int (*wstatfunc)(const Py_UNICODE *, STRUCT_STAT *))
- {
- STRUCT_STAT st;
- char *path = NULL; /* pass this to stat; do not free() it */
- char *pathfree = NULL; /* this memory must be free'd */
- int res;
- PyObject *result;
- #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;
- if (PyArg_ParseTuple(args, wformat, &po)) {
- Py_UNICODE *wpath = PyUnicode_AS_UNICODE(po);
- Py_BEGIN_ALLOW_THREADS
- /* PyUnicode_AS_UNICODE result OK without
- thread lock as it is a simple dereference. */
- res = wstatfunc(wpath, &st);
- Py_END_ALLOW_THREADS
- if (res != 0)
- return win32_error_unicode("stat", wpath);
- return _pystat_fromstructstat(&st);
- }
- /* Drop the argument parsing error as narrow strings
- are also valid. */
- PyErr_Clear();
- }
- #endif
- if (!PyArg_ParseTuple(args, format,
- Py_FileSystemDefaultEncoding, &path))
- return NULL;
- pathfree = path;
- Py_BEGIN_ALLOW_THREADS
- res = (*statfunc)(path, &st);
- Py_END_ALLOW_THREADS
- if (res != 0) {
- #ifdef MS_WINDOWS
- result = win32_error("stat", pathfree);
- #else
- result = posix_error_with_filename(pathfree);
- #endif
- }
- else
- result = _pystat_fromstructstat(&st);
- PyMem_Free(pathfree);
- return result;
- }
- /* POSIX methods */
- PyDoc_STRVAR(posix_access__doc__,
- "access(path, mode) -> True if granted, False otherwise\n\n\
- Use the real uid/gid to test for access to a path. Note that most\n\
- operations will use the effective uid/gid, therefore this routine can\n\
- be used in a suid/sgid environment to test if the invoking user has the\n\
- specified access to the path. The mode argument can be F_OK to test\n\
- existence, or the inclusive-OR of R_OK, W_OK, and X_OK.");
- static PyObject *
- posix_access(PyObject *self, PyObject *args)
- {
- char *path;
- int mode;
-
- #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. */
- attr = GetFileAttributesW(PyUnicode_AS_UNICODE(po));
- Py_END_ALLOW_THREADS
- goto finish;
- }
- /* Drop the argument parsing error as narrow strings
- are also valid. */
- PyErr_Clear();
- }
- 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, or if it's a directory, as there are
- no read-only directories on Windows. */
- return PyBool_FromLong(!(mode & 2)
- || !(attr & FILE_ATTRIBUTE_READONLY)
- || (attr & FILE_ATTRIBUTE_DIRECTORY));
- #else
- int res;
- if (!PyArg_ParseTuple(args, "eti:access",
- Py_FileSystemDefaultEncoding, &path, &mode))
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = access(path, mode);
- Py_END_ALLOW_THREADS
- PyMem_Free(path);
- return PyBool_FromLong(res == 0);
- #endif
- }
- #ifndef F_OK
- #define F_OK 0
- #endif
- #ifndef R_OK
- #define R_OK 4
- #endif
- #ifndef W_OK
- #define W_OK 2
- #endif
- #ifndef X_OK
- #define X_OK 1
- #endif
- #ifdef HAVE_TTYNAME
- PyDoc_STRVAR(posix_ttyname__doc__,
- "ttyname(fd) -> string\n\n\
- Return the name of the terminal device connected to 'fd'.");
- static PyObject *
- posix_ttyname(PyObject *self, PyObject *args)
- {
- int id;
- char *ret;
- if (!PyArg_ParseTuple(args, "i:ttyname", &id))
- return NULL;
- #if defined(__VMS)
- /* file descriptor 0 only, the default input device (stdin) */
- if (id == 0) {
- ret = ttyname();
- }
- else {
- ret = NULL;
- }
- #else
- ret = ttyname(id);
- #endif
- if (ret == NULL)
- return posix_error();
- return PyString_FromString(ret);
- }
- #endif
- #ifdef HAVE_CTERMID
- PyDoc_STRVAR(posix_ctermid__doc__,
- "ctermid() -> string\n\n\
- Return the name of the controlling terminal for this process.");
- static PyObject *
- posix_ctermid(PyObject *self, PyObject *noargs)
- {
- char *ret;
- char buffer[L_ctermid];
- #ifdef USE_CTERMID_R
- ret = ctermid_r(buffer);
- #else
- ret = ctermid(buffer);
- #endif
- if (ret == NULL)
- return posix_error();
- return PyString_FromString(buffer);
- }
- #endif
- PyDoc_STRVAR(posix_chdir__doc__,
- "chdir(path)\n\n\
- Change the current working directory to the specified path.");
- static PyObject *
- posix_chdir(PyObject *self, PyObject *args)
- {
- #ifdef MS_WINDOWS
- 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);
- #elif defined(__VMS)
- return posix_1str(args, "et:chdir", (int (*)(const char *))chdir);
- #else
- return posix_1str(args, "et:chdir", chdir);
- #endif
- }
- #ifdef HAVE_FCHDIR
- PyDoc_STRVAR(posix_fchdir__doc__,
- "fchdir(fildes)\n\n\
- Change to the directory of the given file descriptor. fildes must be\n\
- opened on a directory, not a file.");
- static PyObject *
- posix_fchdir(PyObject *self, PyObject *fdobj)
- {
- return posix_fildes(fdobj, fchdir);
- }
- #endif /* HAVE_FCHDIR */
- PyDoc_STRVAR(posix_chmod__doc__,
- "chmod(path, mode)\n\n\
- Change the access permissions of a file.");
- static PyObject *
- posix_chmod(PyObject *self, PyObject *args)
- {
- char *path = NULL;
- 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
- 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)
- return win32_error_unicode("chmod",
- PyUnicode_AS_UNICODE(po));
- Py_INCREF(Py_None);
- return Py_None;
- }
- /* Drop the argument parsing error as narrow strings
- are also valid. */
- PyErr_Clear();
- }
- 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;
- Py_BEGIN_ALLOW_THREADS
- res = chmod(path, i);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error_with_allocated_filename(path);
- PyMem_Free(path);
- Py_INCREF(Py_None);
- return Py_None;
- #endif
- }
- #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.");
- static PyObject *
- posix_fchmod(PyObject *self, PyObject *args)
- {
- 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();
- 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.");
- static PyObject *
- posix_lchmod(PyObject *self, PyObject *args)
- {
- char *path = NULL;
- int i;
- int res;
- if (!PyArg_ParseTuple(args, "eti:lchmod", Py_FileSystemDefaultEncoding,
- &path, &i))
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = lchmod(path, i);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error_with_allocated_filename(path);
- PyMem_Free(path);
- Py_RETURN_NONE;
- }
- #endif /* HAVE_LCHMOD */
- #ifdef HAVE_CHFLAGS
- PyDoc_STRVAR(posix_chflags__doc__,
- "chflags(path, flags)\n\n\
- Set file flags.");
- static PyObject *
- posix_chflags(PyObject *self, PyObject *args)
- {
- char *path;
- unsigned long flags;
- int res;
- if (!PyArg_ParseTuple(args, "etk:chflags",
- Py_FileSystemDefaultEncoding, &path, &flags))
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = chflags(path, flags);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error_with_allocated_filename(path);
- PyMem_Free(path);
- Py_INCREF(Py_None);
- return Py_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.");
- static PyObject *
- posix_lchflags(PyObject *self, PyObject *args)
- {
- char *path;
- unsigned long flags;
- int res;
- if (!PyArg_ParseTuple(args, "etk:lchflags",
- Py_FileSystemDefaultEncoding, &path, &flags))
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = lchflags(path, flags);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error_with_allocated_filename(path);
- PyMem_Free(path);
- Py_INCREF(Py_None);
- return Py_None;
- }
- #endif /* HAVE_LCHFLAGS */
- #ifdef HAVE_CHROOT
- PyDoc_STRVAR(posix_chroot__doc__,
- "chroot(path)\n\n\
- Change root directory to path.");
- static PyObject *
- posix_chroot(PyObject *self, PyObject *args)
- {
- return posix_1str(args, "et:chroot", chroot);
- }
- #endif
- #ifdef HAVE_FSYNC
- PyDoc_STRVAR(posix_fsync__doc__,
- "fsync(fildes)\n\n\
- force write of file with filedescriptor to disk.");
- static PyObject *
- posix_fsync(PyObject *self, PyObject *fdobj)
- {
- return posix_fildes(fdobj, fsync);
- }
- #endif /* HAVE_FSYNC */
- #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.");
- static PyObject *
- posix_fdatasync(PyObject *self, PyObject *fdobj)
- {
- return posix_fildes(fdobj, fdatasync);
- }
- #endif /* HAVE_FDATASYNC */
- #ifdef HAVE_CHOWN
- PyDoc_STRVAR(posix_chown__doc__,
- "chown(path, uid, gid)\n\n\
- Change the owner and group id of path to the numeric uid and gid.");
- static PyObject *
- posix_chown(PyObject *self, PyObject *args)
- {
- char *path = NULL;
- long uid, gid;
- int res;
- if (!PyArg_ParseTuple(args, "etll:chown",
- Py_FileSystemDefaultEncoding, &path,
- &uid, &gid))
- return NULL;
- Py_BEGIN_ALLOW_THREADS
- res = chown(path, (uid_t) uid, (gid_t) gid);
- Py_END_ALLOW_THREADS
- if (res < 0)
- return posix_error_with_allocated_filename(path);
- PyMem_Free(path);
- Py_INCREF(Py_None);
- return Py_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 descri…