summaryrefslogtreecommitdiffstats
path: root/Modules/posixmodule.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/posixmodule.c')
-rw-r--r--Modules/posixmodule.c2229
1 files changed, 1484 insertions, 745 deletions
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index a836af6..89d3f2f 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -28,7 +28,6 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
-#include "structseq.h"
#if defined(__VMS)
# include <unixio.h>
@@ -121,6 +120,8 @@ corresponding Unix manual entries for more information on calls.");
#else
#ifdef _MSC_VER /* Microsoft compiler */
#define HAVE_GETCWD 1
+#define HAVE_GETPPID 1
+#define HAVE_GETLOGIN 1
#define HAVE_SPAWNV 1
#define HAVE_EXECV 1
#define HAVE_PIPE 1
@@ -262,10 +263,24 @@ extern int lstat(const char *, struct stat *);
#ifdef HAVE_PROCESS_H
#include <process.h>
#endif
+#ifndef VOLUME_NAME_DOS
+#define VOLUME_NAME_DOS 0x0
+#endif
+#ifndef VOLUME_NAME_NT
+#define VOLUME_NAME_NT 0x2
+#endif
+#ifndef IO_REPARSE_TAG_SYMLINK
+#define IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+#endif
#include "osdefs.h"
#include <malloc.h>
#include <windows.h>
#include <shellapi.h> /* for ShellExecute() */
+#include <lmcons.h> /* for UNLEN */
+#ifdef SE_CREATE_SYMBOLIC_LINK_NAME /* Available starting with Vista */
+#define HAVE_SYMLINK
+static int win32_can_symlink = 0;
+#endif
#endif /* _MSC_VER */
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
@@ -303,23 +318,6 @@ extern int lstat(const char *, struct stat *);
#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 PyLong_FromLong
-#define PyLong_AsPid PyLong_AsLong
-#elif SIZEOF_PID_T == SIZEOF_LONG
-#define PARSE_PID "l"
-#define PyLong_FromPid PyLong_FromLong
-#define PyLong_AsPid PyLong_AsLong
-#elif defined(SIZEOF_LONG_LONG) && SIZEOF_PID_T == SIZEOF_LONG_LONG
-#define PARSE_PID "L"
-#define PyLong_FromPid PyLong_FromLongLong
-#define PyLong_AsPid PyLong_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)
@@ -444,6 +442,98 @@ _PyVerify_fd_dup2(int fd1, int fd2)
#define _PyVerify_fd_dup2(A, B) (1)
#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_read_link(HANDLE reparse_point_handle, ULONG *reparse_tag, wchar_t **target_path)
+{
+ char target_buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ REPARSE_DATA_BUFFER *rdb = (REPARSE_DATA_BUFFER *)target_buffer;
+ DWORD n_bytes_returned;
+ const wchar_t *ptr;
+ wchar_t *buf;
+ size_t len;
+
+ if (0 == DeviceIoControl(
+ reparse_point_handle,
+ FSCTL_GET_REPARSE_POINT,
+ NULL, 0, /* in buffer */
+ target_buffer, sizeof(target_buffer),
+ &n_bytes_returned,
+ NULL)) /* we're not using OVERLAPPED_IO */
+ return -1;
+
+ if (reparse_tag)
+ *reparse_tag = rdb->ReparseTag;
+
+ if (target_path) {
+ switch (rdb->ReparseTag) {
+ case IO_REPARSE_TAG_SYMLINK:
+ /* XXX: Maybe should use SubstituteName? */
+ ptr = rdb->SymbolicLinkReparseBuffer.PathBuffer +
+ rdb->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
+ len = rdb->SymbolicLinkReparseBuffer.PrintNameLength/sizeof(WCHAR);
+ break;
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ ptr = rdb->MountPointReparseBuffer.PathBuffer +
+ rdb->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR);
+ len = rdb->MountPointReparseBuffer.SubstituteNameLength/sizeof(WCHAR);
+ break;
+ default:
+ SetLastError(ERROR_REPARSE_TAG_MISMATCH); /* XXX: Proper error code? */
+ return -1;
+ }
+ buf = (wchar_t *)malloc(sizeof(wchar_t)*(len+1));
+ if (!buf) {
+ SetLastError(ERROR_OUTOFMEMORY);
+ return -1;
+ }
+ wcsncpy(buf, ptr, len);
+ buf[len] = L'\0';
+ if (wcsncmp(buf, L"\\??\\", 4) == 0)
+ buf[1] = L'\\';
+ *target_path = buf;
+ }
+
+ return 0;
+}
+#endif /* MS_WINDOWS */
+
/* 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
@@ -517,14 +607,12 @@ convertenviron(void)
char *p = strchr(*e, '=');
if (p == NULL)
continue;
- k = PyUnicode_Decode(*e, (int)(p-*e),
- Py_FileSystemDefaultEncoding, "surrogateescape");
+ k = PyBytes_FromStringAndSize(*e, (int)(p-*e));
if (k == NULL) {
PyErr_Clear();
continue;
}
- v = PyUnicode_Decode(p+1, strlen(p+1),
- Py_FileSystemDefaultEncoding, "surrogateescape");
+ v = PyBytes_FromStringAndSize(p+1, strlen(p+1));
if (v == NULL) {
PyErr_Clear();
Py_DECREF(k);
@@ -555,38 +643,6 @@ convertenviron(void)
return d;
}
-/* Convert a bytes object to a char*. Optionally lock the buffer if it is a
- bytes array. */
-
-static char*
-bytes2str(PyObject* o, int lock)
-{
- if(PyBytes_Check(o))
- return PyBytes_AsString(o);
- else if(PyByteArray_Check(o)) {
- if (lock && PyObject_GetBuffer(o, NULL, 0) < 0)
- /* On a bytearray, this should not fail. */
- PyErr_BadInternalCall();
- return PyByteArray_AsString(o);
- } else {
- /* The FS converter should have verified that this
- is either bytes or bytearray. */
- Py_FatalError("bad object passed to bytes2str");
- /* not reached. */
- return "";
- }
-}
-
-/* Release the lock, decref the object. */
-static void
-release_bytes(PyObject* o)
-{
- if (PyByteArray_Check(o))
- o->ob_type->tp_as_buffer->bf_releasebuffer(o, 0);
- Py_DECREF(o);
-}
-
-
/* Set a POSIX-specific error from errno, and return NULL */
static PyObject *
@@ -600,27 +656,23 @@ posix_error_with_filename(char* name)
return PyErr_SetFromErrnoWithFilename(PyExc_OSError, name);
}
-#ifdef MS_WINDOWS
-static PyObject *
-posix_error_with_unicode_filename(Py_UNICODE* name)
-{
- return PyErr_SetFromErrnoWithUnicodeFilename(PyExc_OSError, name);
-}
-#endif /* MS_WINDOWS */
-
static PyObject *
posix_error_with_allocated_filename(PyObject* name)
{
- PyObject *rc = PyErr_SetFromErrnoWithFilename(PyExc_OSError,
- bytes2str(name, 0));
- release_bytes(name);
+ PyObject *name_str, *rc;
+ name_str = PyUnicode_DecodeFSDefaultAndSize(PyBytes_AsString(name),
+ PyBytes_GET_SIZE(name));
+ Py_DECREF(name);
+ rc = PyErr_SetFromErrnoWithFilenameObject(PyExc_OSError,
+ name_str);
+ Py_XDECREF(name_str);
return rc;
}
#ifdef MS_WINDOWS
static PyObject *
-win32_error(char* function, char* filename)
+win32_error(char* function, const char* filename)
{
/* XXX We should pass the function name along in the future.
(winreg.c also wants to pass the function name.)
@@ -762,20 +814,6 @@ posix_fildes(PyObject *fdobj, int (*func)(int))
return Py_None;
}
-#ifdef MS_WINDOWS
-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*))
{
@@ -785,13 +823,13 @@ posix_1str(PyObject *args, char *format, int (*func)(const char*))
if (!PyArg_ParseTuple(args, format,
PyUnicode_FSConverter, &opath1))
return NULL;
- path1 = bytes2str(opath1, 1);
+ path1 = PyBytes_AsString(opath1);
Py_BEGIN_ALLOW_THREADS
res = (*func)(path1);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(opath1);
- release_bytes(opath1);
+ Py_DECREF(opath1);
Py_INCREF(Py_None);
return Py_None;
}
@@ -809,13 +847,13 @@ posix_2str(PyObject *args,
PyUnicode_FSConverter, &opath2)) {
return NULL;
}
- path1 = bytes2str(opath1, 1);
- path2 = bytes2str(opath2, 1);
+ path1 = PyBytes_AsString(opath1);
+ path2 = PyBytes_AsString(opath2);
Py_BEGIN_ALLOW_THREADS
res = (*func)(path1, path2);
Py_END_ALLOW_THREADS
- release_bytes(opath1);
- release_bytes(opath2);
+ Py_DECREF(opath1);
+ Py_DECREF(opath2);
if (res != 0)
/* XXX how to report both path1 and path2??? */
return posix_error();
@@ -832,18 +870,17 @@ win32_1str(PyObject* args, char* func,
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, 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;
@@ -993,7 +1030,7 @@ attributes_to_mode(DWORD attr)
}
static int
-attribute_data_to_stat(WIN32_FILE_ATTRIBUTE_DATA *info, struct win32_stat *result)
+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);
@@ -1001,28 +1038,20 @@ attribute_data_to_stat(WIN32_FILE_ATTRIBUTE_DATA *info, struct win32_stat *resul
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 & 0170000);
+ /* now set the bits that make this a symlink */
+ result->st_mode |= 0120000;
+ }
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)
+attributes_from_dir(LPCSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag)
{
HANDLE hFindFile;
WIN32_FIND_DATAA FileData;
@@ -1030,17 +1059,22 @@ attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
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;
+ 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;
return TRUE;
}
static BOOL
-attributes_from_dir_w(LPCWSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
+attributes_from_dir_w(LPCWSTR pszFile, BY_HANDLE_FILE_INFORMATION *info, ULONG *reparse_tag)
{
HANDLE hFindFile;
WIN32_FIND_DATAW FileData;
@@ -1048,152 +1082,232 @@ attributes_from_dir_w(LPCWSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
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;
+ 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;
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);
-}
+#ifndef SYMLOOP_MAX
+#define SYMLOOP_MAX ( 88 )
+#endif
-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_xstat_impl_w(const wchar_t *path, struct win32_stat *result, BOOL traverse, int depth);
static int
-win32_stat(const char* path, struct win32_stat *result)
+win32_xstat_impl(const char *path, struct win32_stat *result, BOOL traverse, int depth)
{
- 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;
+ HANDLE hFile;
+ BY_HANDLE_FILE_INFORMATION info;
+ ULONG reparse_tag = 0;
+ wchar_t *target_path;
+ const char *dot;
+
+ if (depth > SYMLOOP_MAX) {
+ SetLastError(ERROR_CANT_RESOLVE_FILENAME); /* XXX: ELOOP? */
+ return -1;
+ }
+
+ hFile = CreateFileA(
+ path,
+ 0, /* desired access */
+ 0, /* share mode */
+ NULL, /* security attributes */
+ OPEN_EXISTING,
+ /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
+ FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ /* Either the target doesn't exist, or we don't have access to
+ get a handle to it. If the former, we need to return an error.
+ If the latter, we can use attributes_from_dir. */
+ if (GetLastError() != ERROR_SHARING_VIOLATION)
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;
+ /* Could not get attributes on open file. Fall back to
+ reading the directory. */
+ if (!attributes_from_dir(path, &info, &reparse_tag))
+ /* Very strange. This should not fail now */
+ return -1;
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ if (traverse) {
+ /* Should traverse, but could not open reparse point handle */
+ SetLastError(ERROR_SHARING_VIOLATION);
return -1;
}
}
+ } else {
+ if (!GetFileInformationByHandle(hFile, &info)) {
+ CloseHandle(hFile);
+ return -1;;
+ }
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ code = win32_read_link(hFile, &reparse_tag, traverse ? &target_path : NULL);
+ CloseHandle(hFile);
+ if (code < 0)
+ return code;
+ if (traverse) {
+ code = win32_xstat_impl_w(target_path, result, traverse, depth + 1);
+ free(target_path);
+ return code;
+ }
+ } else
+ CloseHandle(hFile);
}
- code = attribute_data_to_stat(&info, result);
- if (code != 0)
- return code;
- /* Set S_IFEXEC if it is an .exe, .bat, ... */
+ attribute_data_to_stat(&info, reparse_tag, result);
+
+ /* Set S_IEXEC 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)
+ if (stricmp(dot, ".bat") == 0 || stricmp(dot, ".cmd") == 0 ||
+ stricmp(dot, ".exe") == 0 || stricmp(dot, ".com") == 0)
result->st_mode |= 0111;
}
- return code;
+ return 0;
}
static int
-win32_wstat(const wchar_t* path, struct win32_stat *result)
+win32_xstat_impl_w(const wchar_t *path, struct win32_stat *result, BOOL traverse, int depth)
{
int code;
+ HANDLE hFile;
+ BY_HANDLE_FILE_INFORMATION info;
+ ULONG reparse_tag = 0;
+ wchar_t *target_path;
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;
+
+ if (depth > SYMLOOP_MAX) {
+ SetLastError(ERROR_CANT_RESOLVE_FILENAME); /* XXX: ELOOP? */
+ return -1;
+ }
+
+ hFile = CreateFileW(
+ path,
+ 0, /* desired access */
+ 0, /* share mode */
+ NULL, /* security attributes */
+ OPEN_EXISTING,
+ /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
+ FILE_ATTRIBUTE_NORMAL|FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ /* Either the target doesn't exist, or we don't have access to
+ get a handle to it. If the former, we need to return an error.
+ If the latter, we can use attributes_from_dir. */
+ if (GetLastError() != ERROR_SHARING_VIOLATION)
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;
+ /* Could not get attributes on open file. Fall back to
+ reading the directory. */
+ if (!attributes_from_dir_w(path, &info, &reparse_tag))
+ /* Very strange. This should not fail now */
+ return -1;
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ if (traverse) {
+ /* Should traverse, but could not open reparse point handle */
+ SetLastError(ERROR_SHARING_VIOLATION);
return -1;
}
}
+ } else {
+ if (!GetFileInformationByHandle(hFile, &info)) {
+ CloseHandle(hFile);
+ return -1;;
+ }
+ if (info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ code = win32_read_link(hFile, &reparse_tag, traverse ? &target_path : NULL);
+ CloseHandle(hFile);
+ if (code < 0)
+ return code;
+ if (traverse) {
+ code = win32_xstat_impl_w(target_path, result, traverse, depth + 1);
+ free(target_path);
+ return code;
+ }
+ } else
+ CloseHandle(hFile);
}
- code = attribute_data_to_stat(&info, result);
- if (code < 0)
- return code;
- /* Set IFEXEC if it is an .exe, .bat, ... */
+ attribute_data_to_stat(&info, reparse_tag, result);
+
+ /* Set S_IEXEC 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)
+ 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 0;
+}
+
+static int
+win32_xstat(const char *path, struct win32_stat *result, BOOL traverse)
+{
+ /* Protocol violation: we explicitly clear errno, instead of
+ setting it to a POSIX error. Callers should use GetLastError. */
+ int code = win32_xstat_impl(path, result, traverse, 0);
+ errno = 0;
return code;
}
static int
+win32_xstat_w(const wchar_t *path, struct win32_stat *result, BOOL traverse)
+{
+ /* Protocol violation: we explicitly clear errno, instead of
+ setting it to a POSIX error. Callers should use GetLastError. */
+ int code = win32_xstat_impl_w(path, result, traverse, 0);
+ errno = 0;
+ return code;
+}
+
+/* About the following functions: win32_lstat, win32_lstat_w, win32_stat,
+ win32_stat_w
+
+ In Posix, stat automatically traverses symlinks and returns the stat
+ structure for the target. In Windows, the equivalent GetFileAttributes by
+ default does not traverse symlinks and instead returns attributes for
+ the symlink.
+
+ Therefore, win32_lstat will get the attributes traditionally, and
+ win32_stat will first explicitly resolve the symlink target and then will
+ call win32_lstat on that result.
+
+ The _w represent Unicode equivalents of the aforementioned ANSI functions. */
+
+static int
+win32_lstat(const char* path, struct win32_stat *result)
+{
+ return win32_xstat(path, result, FALSE);
+}
+
+static int
+win32_lstat_w(const wchar_t* path, struct win32_stat *result)
+{
+ return win32_xstat_w(path, result, FALSE);
+}
+
+static int
+win32_stat(const char* path, struct win32_stat *result)
+{
+ return win32_xstat(path, result, TRUE);
+}
+
+static int
+win32_stat_w(const wchar_t* path, struct win32_stat *result)
+{
+ return win32_xstat_w(path, result, TRUE);
+}
+
+static int
win32_fstat(int file_number, struct win32_stat *result)
{
BY_HANDLE_FILE_INFORMATION info;
@@ -1218,7 +1332,7 @@ win32_fstat(int file_number, struct win32_stat *result)
if (type == FILE_TYPE_UNKNOWN) {
DWORD error = GetLastError();
if (error != 0) {
- return -1;
+ return -1;
}
/* else: valid but unknown file */
}
@@ -1235,14 +1349,8 @@ win32_fstat(int file_number, struct win32_stat *result)
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);
+ attribute_data_to_stat(&info, 0, result);
/* specific to fstat() */
- result->st_nlink = info.nNumberOfLinks;
result->st_ino = (((__int64)info.nFileIndexHigh)<<32) + info.nFileIndexLow;
return 0;
}
@@ -1542,66 +1650,6 @@ _pystat_fromstructstat(STRUCT_STAT *st)
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
-}
-
-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 /* MS_WINDOWS */
-
static PyObject *
posix_do_stat(PyObject *self, PyObject *args,
char *format,
@@ -1620,33 +1668,29 @@ posix_do_stat(PyObject *self, PyObject *args,
PyObject *result;
#ifdef MS_WINDOWS
- /* 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);
+ 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
+ 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();
+ 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,
PyUnicode_FSConverter, &opath))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
res = (*statfunc)(path, &st);
Py_END_ALLOW_THREADS
@@ -1661,7 +1705,7 @@ posix_do_stat(PyObject *self, PyObject *args,
else
result = _pystat_fromstructstat(&st);
- release_bytes(opath);
+ Py_DECREF(opath);
return result;
}
@@ -1684,28 +1728,26 @@ posix_access(PyObject *self, PyObject *args)
#ifdef MS_WINDOWS
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();
+ 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, "O&i:access",
PyUnicode_FSConverter, &opath, &mode))
- return 0;
- path = bytes2str(opath, 1);
+ return NULL;
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
attr = GetFileAttributesA(path);
Py_END_ALLOW_THREADS
- release_bytes(opath);
+ Py_DECREF(opath);
finish:
if (attr == 0xFFFFFFFF)
/* File does not exist, or cannot read attributes */
@@ -1721,11 +1763,11 @@ finish:
if (!PyArg_ParseTuple(args, "O&i:access",
PyUnicode_FSConverter, &opath, &mode))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
res = access(path, mode);
Py_END_ALLOW_THREADS
- release_bytes(opath);
+ Py_DECREF(opath);
return PyBool_FromLong(res == 0);
#endif
}
@@ -1841,35 +1883,34 @@ posix_chmod(PyObject *self, PyObject *args)
int res;
#ifdef MS_WINDOWS
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);
- }
+ 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
- res = 0;
- Py_END_ALLOW_THREADS
- if (!res)
- return win32_error_unicode("chmod",
- PyUnicode_AS_UNICODE(po));
- Py_INCREF(Py_None);
- return Py_None;
+ attr |= FILE_ATTRIBUTE_READONLY;
+ res = SetFileAttributesW(PyUnicode_AS_UNICODE(po), attr);
}
- /* Drop the argument parsing error as narrow strings
- are also valid. */
- PyErr_Clear();
+ 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, "O&i:chmod", PyUnicode_FSConverter,
&opath, &i))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
attr = GetFileAttributesA(path);
if (attr != 0xFFFFFFFF) {
@@ -1884,23 +1925,23 @@ posix_chmod(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS
if (!res) {
win32_error("chmod", path);
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
#else /* MS_WINDOWS */
if (!PyArg_ParseTuple(args, "O&i:chmod", PyUnicode_FSConverter,
&opath, &i))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
res = chmod(path, i);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(opath);
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
#endif
@@ -1943,13 +1984,13 @@ posix_lchmod(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O&i:lchmod", PyUnicode_FSConverter,
&opath, &i))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
res = lchmod(path, i);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(opath);
- release_bytes(opath);
+ Py_DECREF(opath);
Py_RETURN_NONE;
}
#endif /* HAVE_LCHMOD */
@@ -1970,13 +2011,13 @@ posix_chflags(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O&k:chflags",
PyUnicode_FSConverter, &opath, &flags))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
res = chflags(path, flags);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(opath);
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
}
@@ -1998,13 +2039,13 @@ posix_lchflags(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O&k:lchflags",
PyUnicode_FSConverter, &opath, &flags))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
res = lchflags(path, flags);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(opath);
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
}
@@ -2069,13 +2110,13 @@ posix_chown(PyObject *self, PyObject *args)
PyUnicode_FSConverter, &opath,
&uid, &gid))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
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(opath);
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
}
@@ -2121,13 +2162,13 @@ posix_lchown(PyObject *self, PyObject *args)
PyUnicode_FSConverter, &opath,
&uid, &gid))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
res = lchown(path, (uid_t) uid, (gid_t) gid);
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(opath);
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
}
@@ -2142,7 +2183,7 @@ posix_getcwd(int use_bytes)
char *res;
#ifdef MS_WINDOWS
- if (!use_bytes && unicode_file_names()) {
+ if (!use_bytes) {
wchar_t wbuf[1026];
wchar_t *wbuf2 = wbuf;
PyObject *resobj;
@@ -2183,7 +2224,7 @@ posix_getcwd(int use_bytes)
return posix_error();
if (use_bytes)
return PyBytes_FromStringAndSize(buf, strlen(buf));
- return PyUnicode_Decode(buf, strlen(buf), Py_FileSystemDefaultEncoding,"surrogateescape");
+ return PyUnicode_DecodeFSDefault(buf);
}
PyDoc_STRVAR(posix_getcwd__doc__,
@@ -2220,12 +2261,60 @@ posix_link(PyObject *self, PyObject *args)
}
#endif /* HAVE_LINK */
+#ifdef MS_WINDOWS
+PyDoc_STRVAR(win32_link__doc__,
+"link(src, dst)\n\n\
+Create a hard link to a file.");
+
+static PyObject *
+win32_link(PyObject *self, PyObject *args)
+{
+ PyObject *osrc, *odst;
+ char *src, *dst;
+ BOOL rslt;
+
+ PyUnicodeObject *usrc, *udst;
+ if (PyArg_ParseTuple(args, "UU:link", &usrc, &udst)) {
+ Py_BEGIN_ALLOW_THREADS
+ rslt = CreateHardLinkW(PyUnicode_AS_UNICODE(udst),
+ PyUnicode_AS_UNICODE(usrc), NULL);
+ Py_END_ALLOW_THREADS
+
+ if (rslt == 0)
+ return win32_error("link", NULL);
+
+ Py_RETURN_NONE;
+ }
+
+ /* Narrow strings also valid. */
+ PyErr_Clear();
+
+ if (!PyArg_ParseTuple(args, "O&O&:link", PyUnicode_FSConverter, &osrc,
+ PyUnicode_FSConverter, &odst))
+ return NULL;
+
+ src = PyBytes_AsString(osrc);
+ dst = PyBytes_AsString(odst);
+
+ Py_BEGIN_ALLOW_THREADS
+ rslt = CreateHardLinkA(dst, src, NULL);
+ Py_END_ALLOW_THREADS
+
+ Py_DECREF(osrc);
+ Py_DECREF(odst);
+ if (rslt == 0)
+ return win32_error("link", NULL);
+
+ Py_RETURN_NONE;
+}
+#endif /* MS_WINDOWS */
+
PyDoc_STRVAR(posix_listdir__doc__,
-"listdir(path) -> list_of_strings\n\n\
+"listdir([path]) -> list_of_strings\n\n\
Return a list containing the names of the entries in the directory.\n\
\n\
- path: path of directory to list\n\
+ path: path of directory to list (default: '.')\n\
\n\
The list is in arbitrary order. It does not include the special\n\
entries '.' and '..' even if they are present in the directory.");
@@ -2246,101 +2335,105 @@ posix_listdir(PyObject *self, PyObject *args)
char *bufptr = namebuf;
Py_ssize_t len = sizeof(namebuf)-5; /* only claim to have space for MAX_PATH */
- /* If on wide-character-capable OS see if argument
- is Unicode and if so use wide API. */
- if (unicode_file_names()) {
- PyObject *po;
- if (PyArg_ParseTuple(args, "U:listdir", &po)) {
- WIN32_FIND_DATAW wFileData;
- Py_UNICODE *wnamebuf;
- /* Overallocate for \\*.*\0 */
+ PyObject *po = NULL;
+ if (PyArg_ParseTuple(args, "|U:listdir", &po)) {
+ WIN32_FIND_DATAW wFileData;
+ Py_UNICODE *wnamebuf, *po_wchars;
+
+ if (po == NULL) { /* Default arg: "." */
+ po_wchars = L".";
+ len = 1;
+ } else {
+ po_wchars = PyUnicode_AS_UNICODE(po);
len = PyUnicode_GET_SIZE(po);
- wnamebuf = malloc((len + 5) * sizeof(wchar_t));
- if (!wnamebuf) {
- PyErr_NoMemory();
- return NULL;
- }
- wcscpy(wnamebuf, PyUnicode_AS_UNICODE(po));
- if (len > 0) {
- Py_UNICODE wch = wnamebuf[len-1];
- if (wch != L'/' && wch != L'\\' && wch != L':')
- wnamebuf[len++] = L'\\';
- wcscpy(wnamebuf + len, L"*.*");
- }
- if ((d = PyList_New(0)) == NULL) {
+ }
+ /* Overallocate for \\*.*\0 */
+ wnamebuf = malloc((len + 5) * sizeof(wchar_t));
+ if (!wnamebuf) {
+ PyErr_NoMemory();
+ return NULL;
+ }
+ wcscpy(wnamebuf, po_wchars);
+ if (len > 0) {
+ Py_UNICODE wch = wnamebuf[len-1];
+ if (wch != L'/' && wch != L'\\' && wch != L':')
+ wnamebuf[len++] = L'\\';
+ wcscpy(wnamebuf + len, L"*.*");
+ }
+ if ((d = PyList_New(0)) == NULL) {
+ free(wnamebuf);
+ return NULL;
+ }
+ Py_BEGIN_ALLOW_THREADS
+ hFindFile = FindFirstFileW(wnamebuf, &wFileData);
+ Py_END_ALLOW_THREADS
+ if (hFindFile == INVALID_HANDLE_VALUE) {
+ int error = GetLastError();
+ if (error == ERROR_FILE_NOT_FOUND) {
free(wnamebuf);
- return NULL;
+ return d;
}
- Py_BEGIN_ALLOW_THREADS
- hFindFile = FindFirstFileW(wnamebuf, &wFileData);
- Py_END_ALLOW_THREADS
- if (hFindFile == INVALID_HANDLE_VALUE) {
- int error = GetLastError();
- if (error == ERROR_FILE_NOT_FOUND) {
- free(wnamebuf);
- return d;
+ Py_DECREF(d);
+ win32_error_unicode("FindFirstFileW", wnamebuf);
+ free(wnamebuf);
+ return NULL;
+ }
+ do {
+ /* Skip over . and .. */
+ if (wcscmp(wFileData.cFileName, L".") != 0 &&
+ wcscmp(wFileData.cFileName, L"..") != 0) {
+ v = PyUnicode_FromUnicode(wFileData.cFileName, wcslen(wFileData.cFileName));
+ if (v == NULL) {
+ Py_DECREF(d);
+ d = NULL;
+ break;
}
- Py_DECREF(d);
- win32_error_unicode("FindFirstFileW", wnamebuf);
- free(wnamebuf);
- return NULL;
- }
- do {
- /* Skip over . and .. */
- if (wcscmp(wFileData.cFileName, L".") != 0 &&
- wcscmp(wFileData.cFileName, L"..") != 0) {
- v = PyUnicode_FromUnicode(wFileData.cFileName, wcslen(wFileData.cFileName));
- if (v == NULL) {
- Py_DECREF(d);
- d = NULL;
- break;
- }
- if (PyList_Append(d, v) != 0) {
- Py_DECREF(v);
- Py_DECREF(d);
- d = NULL;
- break;
- }
+ if (PyList_Append(d, v) != 0) {
Py_DECREF(v);
- }
- Py_BEGIN_ALLOW_THREADS
- result = FindNextFileW(hFindFile, &wFileData);
- Py_END_ALLOW_THREADS
- /* FindNextFile sets error to ERROR_NO_MORE_FILES if
- it got to the end of the directory. */
- if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
Py_DECREF(d);
- win32_error_unicode("FindNextFileW", wnamebuf);
- FindClose(hFindFile);
- free(wnamebuf);
- return NULL;
+ d = NULL;
+ break;
}
- } while (result == TRUE);
-
- if (FindClose(hFindFile) == FALSE) {
+ Py_DECREF(v);
+ }
+ Py_BEGIN_ALLOW_THREADS
+ result = FindNextFileW(hFindFile, &wFileData);
+ Py_END_ALLOW_THREADS
+ /* FindNextFile sets error to ERROR_NO_MORE_FILES if
+ it got to the end of the directory. */
+ if (!result && GetLastError() != ERROR_NO_MORE_FILES) {
Py_DECREF(d);
- win32_error_unicode("FindClose", wnamebuf);
+ win32_error_unicode("FindNextFileW", wnamebuf);
+ FindClose(hFindFile);
free(wnamebuf);
return NULL;
}
+ } while (result == TRUE);
+
+ if (FindClose(hFindFile) == FALSE) {
+ Py_DECREF(d);
+ win32_error_unicode("FindClose", wnamebuf);
free(wnamebuf);
- return d;
+ return NULL;
}
- /* Drop the argument parsing error as narrow strings
- are also valid. */
- PyErr_Clear();
+ free(wnamebuf);
+ return d;
}
+ /* Drop the argument parsing error as narrow strings
+ are also valid. */
+ PyErr_Clear();
if (!PyArg_ParseTuple(args, "O&:listdir",
PyUnicode_FSConverter, &opath))
return NULL;
- if (PyObject_Size(opath)+1 > MAX_PATH) {
+ if (PyBytes_GET_SIZE(opath)+1 > MAX_PATH) {
PyErr_SetString(PyExc_ValueError, "path too long");
Py_DECREF(opath);
return NULL;
}
- strcpy(namebuf, bytes2str(opath, 0));
+ strcpy(namebuf, PyBytes_AsString(opath));
len = PyObject_Size(opath);
+ Py_DECREF(opath);
if (len > 0) {
char ch = namebuf[len-1];
if (ch != SEP && ch != ALTSEP && ch != ':')
@@ -2417,10 +2510,10 @@ posix_listdir(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O&:listdir",
PyUnicode_FSConverter, &oname))
return NULL;
- name = bytes2str(oname);
- len = PyObject_Size(oname);
+ name = PyBytes_AsString(oname);
+ len = PyBytes_GET_SIZE(oname);
if (len >= MAX_PATH) {
- release_bytes(oname);
+ Py_DECREF(oname);
PyErr_SetString(PyExc_ValueError, "path too long");
return NULL;
}
@@ -2433,7 +2526,7 @@ posix_listdir(PyObject *self, PyObject *args)
strcpy(namebuf + len, "*.*");
if ((d = PyList_New(0)) == NULL) {
- release_bytes(oname);
+ Py_DECREF(oname);
return NULL;
}
@@ -2476,7 +2569,7 @@ posix_listdir(PyObject *self, PyObject *args)
} while (DosFindNext(hdir, &ep, sizeof(ep), &srchcnt) == NO_ERROR && srchcnt > 0);
}
- release_bytes(oname);
+ Py_DECREF(oname);
return d;
#else
PyObject *oname;
@@ -2487,13 +2580,18 @@ posix_listdir(PyObject *self, PyObject *args)
int arg_is_unicode = 1;
errno = 0;
- if (!PyArg_ParseTuple(args, "U:listdir", &v)) {
+ /* v is never read, so it does not need to be initialized yet. */
+ if (!PyArg_ParseTuple(args, "|U:listdir", &v)) {
arg_is_unicode = 0;
PyErr_Clear();
}
- if (!PyArg_ParseTuple(args, "O&:listdir", PyUnicode_FSConverter, &oname))
+ oname = NULL;
+ if (!PyArg_ParseTuple(args, "|O&:listdir", PyUnicode_FSConverter, &oname))
return NULL;
- name = bytes2str(oname, 1);
+ if (oname == NULL) { /* Default arg: "." */
+ oname = PyBytes_FromString(".");
+ }
+ name = PyBytes_AsString(oname);
Py_BEGIN_ALLOW_THREADS
dirp = opendir(name);
Py_END_ALLOW_THREADS
@@ -2504,7 +2602,7 @@ posix_listdir(PyObject *self, PyObject *args)
Py_BEGIN_ALLOW_THREADS
closedir(dirp);
Py_END_ALLOW_THREADS
- release_bytes(oname);
+ Py_DECREF(oname);
return NULL;
}
for (;;) {
@@ -2527,33 +2625,17 @@ posix_listdir(PyObject *self, PyObject *args)
(NAMLEN(ep) == 1 ||
(ep->d_name[1] == '.' && NAMLEN(ep) == 2)))
continue;
- v = PyBytes_FromStringAndSize(ep->d_name, NAMLEN(ep));
+ if (arg_is_unicode)
+ v = PyUnicode_DecodeFSDefaultAndSize(ep->d_name, NAMLEN(ep));
+ else
+ v = PyBytes_FromStringAndSize(ep->d_name, NAMLEN(ep));
if (v == NULL) {
- Py_DECREF(d);
- d = NULL;
+ Py_CLEAR(d);
break;
}
- if (arg_is_unicode) {
- PyObject *w;
-
- w = PyUnicode_FromEncodedObject(v,
- Py_FileSystemDefaultEncoding,
- "surrogateescape");
- Py_DECREF(v);
- if (w != NULL)
- v = w;
- else {
- /* Encoding failed to decode ASCII bytes.
- Raise exception. */
- Py_DECREF(d);
- d = NULL;
- break;
- }
- }
if (PyList_Append(d, v) != 0) {
Py_DECREF(v);
- Py_DECREF(d);
- d = NULL;
+ Py_CLEAR(d);
break;
}
Py_DECREF(v);
@@ -2561,7 +2643,7 @@ posix_listdir(PyObject *self, PyObject *args)
Py_BEGIN_ALLOW_THREADS
closedir(dirp);
Py_END_ALLOW_THREADS
- release_bytes(oname);
+ Py_DECREF(oname);
return d;
@@ -2578,53 +2660,165 @@ posix__getfullpathname(PyObject *self, PyObject *args)
char outbuf[MAX_PATH*2];
char *temp;
#ifdef MS_WINDOWS
- if (unicode_file_names()) {
- PyUnicodeObject *po;
- if (PyArg_ParseTuple(args, "U|:_getfullpathname", &po)) {
- Py_UNICODE *wpath = PyUnicode_AS_UNICODE(po);
- Py_UNICODE woutbuf[MAX_PATH*2], *woutbufp = woutbuf;
- Py_UNICODE *wtemp;
- DWORD result;
- PyObject *v;
- result = GetFullPathNameW(wpath,
- sizeof(woutbuf)/sizeof(woutbuf[0]),
- woutbuf, &wtemp);
- if (result > sizeof(woutbuf)/sizeof(woutbuf[0])) {
- woutbufp = malloc(result * sizeof(Py_UNICODE));
- if (!woutbufp)
- return PyErr_NoMemory();
- result = GetFullPathNameW(wpath, result, woutbufp, &wtemp);
- }
- if (result)
- v = PyUnicode_FromUnicode(woutbufp, wcslen(woutbufp));
- else
- v = win32_error_unicode("GetFullPathNameW", wpath);
- if (woutbufp != woutbuf)
- free(woutbufp);
- return v;
+ PyUnicodeObject *po;
+ if (PyArg_ParseTuple(args, "U|:_getfullpathname", &po)) {
+ Py_UNICODE *wpath = PyUnicode_AS_UNICODE(po);
+ Py_UNICODE woutbuf[MAX_PATH*2], *woutbufp = woutbuf;
+ Py_UNICODE *wtemp;
+ DWORD result;
+ PyObject *v;
+ result = GetFullPathNameW(wpath,
+ sizeof(woutbuf)/sizeof(woutbuf[0]),
+ woutbuf, &wtemp);
+ if (result > sizeof(woutbuf)/sizeof(woutbuf[0])) {
+ woutbufp = malloc(result * sizeof(Py_UNICODE));
+ if (!woutbufp)
+ return PyErr_NoMemory();
+ result = GetFullPathNameW(wpath, result, woutbufp, &wtemp);
}
- /* Drop the argument parsing error as narrow strings
- are also valid. */
- PyErr_Clear();
+ if (result)
+ v = PyUnicode_FromUnicode(woutbufp, wcslen(woutbufp));
+ else
+ v = win32_error_unicode("GetFullPathNameW", wpath);
+ if (woutbufp != woutbuf)
+ free(woutbufp);
+ return v;
}
+ /* Drop the argument parsing error as narrow strings
+ are also valid. */
+ PyErr_Clear();
+
#endif
if (!PyArg_ParseTuple (args, "O&:_getfullpathname",
PyUnicode_FSConverter, &opath))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
if (!GetFullPathName(path, sizeof(outbuf)/sizeof(outbuf[0]),
outbuf, &temp)) {
win32_error("GetFullPathName", path);
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
- release_bytes(opath);
+ Py_DECREF(opath);
if (PyUnicode_Check(PyTuple_GetItem(args, 0))) {
return PyUnicode_Decode(outbuf, strlen(outbuf),
Py_FileSystemDefaultEncoding, NULL);
}
return PyBytes_FromString(outbuf);
} /* end of posix__getfullpathname */
+
+/* Grab GetFinalPathNameByHandle dynamically from kernel32 */
+static int has_GetFinalPathNameByHandle = 0;
+static DWORD (CALLBACK *Py_GetFinalPathNameByHandleA)(HANDLE, LPSTR, DWORD,
+ DWORD);
+static DWORD (CALLBACK *Py_GetFinalPathNameByHandleW)(HANDLE, LPWSTR, DWORD,
+ DWORD);
+static int
+check_GetFinalPathNameByHandle()
+{
+ HINSTANCE hKernel32;
+ /* only recheck */
+ if (!has_GetFinalPathNameByHandle)
+ {
+ hKernel32 = GetModuleHandle("KERNEL32");
+ *(FARPROC*)&Py_GetFinalPathNameByHandleA = GetProcAddress(hKernel32,
+ "GetFinalPathNameByHandleA");
+ *(FARPROC*)&Py_GetFinalPathNameByHandleW = GetProcAddress(hKernel32,
+ "GetFinalPathNameByHandleW");
+ has_GetFinalPathNameByHandle = Py_GetFinalPathNameByHandleA &&
+ Py_GetFinalPathNameByHandleW;
+ }
+ return has_GetFinalPathNameByHandle;
+}
+
+/* A helper function for samepath on windows */
+static PyObject *
+posix__getfinalpathname(PyObject *self, PyObject *args)
+{
+ HANDLE hFile;
+ int buf_size;
+ wchar_t *target_path;
+ int result_length;
+ PyObject *result;
+ wchar_t *path;
+
+ if (!PyArg_ParseTuple(args, "u|:_getfinalpathname", &path)) {
+ 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,
+ 0, /* desired access */
+ 0, /* share mode */
+ NULL, /* security attributes */
+ OPEN_EXISTING,
+ /* FILE_FLAG_BACKUP_SEMANTICS is required to open a directory */
+ FILE_FLAG_BACKUP_SEMANTICS,
+ NULL);
+
+ if(hFile == INVALID_HANDLE_VALUE) {
+ return win32_error_unicode("GetFinalPathNamyByHandle", path);
+ return PyErr_Format(PyExc_RuntimeError,
+ "Could not get a handle to file.");
+ }
+
+ /* 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);
+
+ if(!buf_size)
+ return win32_error_unicode("GetFinalPathNameByHandle", path);
+
+ target_path = (wchar_t *)malloc((buf_size+1)*sizeof(wchar_t));
+ if(!target_path)
+ return PyErr_NoMemory();
+
+ result_length = Py_GetFinalPathNameByHandleW(hFile, target_path,
+ buf_size, VOLUME_NAME_DOS);
+ if(!result_length)
+ return win32_error_unicode("GetFinalPathNamyByHandle", path);
+
+ if(!CloseHandle(hFile))
+ return win32_error_unicode("GetFinalPathNameByHandle", path);
+
+ target_path[result_length] = 0;
+ result = PyUnicode_FromUnicode(target_path, result_length);
+ free(target_path);
+ return result;
+
+} /* end of posix__getfinalpathname */
+
+static PyObject *
+posix__getfileinformation(PyObject *self, PyObject *args)
+{
+ HANDLE hFile;
+ BY_HANDLE_FILE_INFORMATION info;
+ int fd;
+
+ if (!PyArg_ParseTuple(args, "i:_getfileinformation", &fd))
+ return NULL;
+
+ if (!_PyVerify_fd(fd))
+ return posix_error();
+
+ hFile = (HANDLE)_get_osfhandle(fd);
+ if (hFile == INVALID_HANDLE_VALUE)
+ return posix_error();
+
+ if (!GetFileInformationByHandle(hFile, &info))
+ return win32_error("_getfileinformation", NULL);
+
+ return Py_BuildValue("iii", info.dwVolumeSerialNumber,
+ info.nFileIndexHigh,
+ info.nFileIndexLow);
+}
#endif /* MS_WINDOWS */
PyDoc_STRVAR(posix_mkdir__doc__,
@@ -2640,27 +2834,25 @@ posix_mkdir(PyObject *self, PyObject *args)
int mode = 0777;
#ifdef MS_WINDOWS
- if (unicode_file_names()) {
- PyUnicodeObject *po;
- if (PyArg_ParseTuple(args, "U|i:mkdir", &po, &mode)) {
- Py_BEGIN_ALLOW_THREADS
- /* PyUnicode_AS_UNICODE OK without thread lock as
- it is a simple dereference. */
- res = CreateDirectoryW(PyUnicode_AS_UNICODE(po), NULL);
- Py_END_ALLOW_THREADS
- if (!res)
- return win32_error_unicode("mkdir", PyUnicode_AS_UNICODE(po));
- Py_INCREF(Py_None);
- return Py_None;
- }
- /* Drop the argument parsing error as narrow strings
- are also valid. */
- PyErr_Clear();
+ PyUnicodeObject *po;
+ if (PyArg_ParseTuple(args, "U|i:mkdir", &po, &mode)) {
+ Py_BEGIN_ALLOW_THREADS
+ /* PyUnicode_AS_UNICODE OK without thread lock as
+ it is a simple dereference. */
+ res = CreateDirectoryW(PyUnicode_AS_UNICODE(po), NULL);
+ Py_END_ALLOW_THREADS
+ if (!res)
+ return win32_error_unicode("mkdir", 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, "O&|i:mkdir",
PyUnicode_FSConverter, &opath, &mode))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
/* PyUnicode_AS_UNICODE OK without thread lock as
it is a simple dereference. */
@@ -2668,10 +2860,10 @@ posix_mkdir(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS
if (!res) {
win32_error("mkdir", path);
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
#else
@@ -2679,7 +2871,7 @@ posix_mkdir(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O&|i:mkdir",
PyUnicode_FSConverter, &opath, &mode))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
Py_BEGIN_ALLOW_THREADS
#if ( defined(__WATCOMC__) || defined(PYCC_VACPP) ) && !defined(__QNX__)
res = mkdir(path);
@@ -2689,7 +2881,7 @@ posix_mkdir(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS
if (res < 0)
return posix_error_with_allocated_filename(opath);
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
#endif
@@ -2749,28 +2941,26 @@ posix_rename(PyObject *self, PyObject *args)
PyObject *o1, *o2;
char *p1, *p2;
BOOL result;
- if (unicode_file_names()) {
- if (!PyArg_ParseTuple(args, "OO:rename", &o1, &o2))
+ if (!PyArg_ParseTuple(args, "OO:rename", &o1, &o2))
goto error;
- if (!convert_to_unicode(&o1))
+ if (!convert_to_unicode(&o1))
goto error;
- if (!convert_to_unicode(&o2)) {
+ if (!convert_to_unicode(&o2)) {
Py_DECREF(o1);
goto error;
- }
- 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;
-error:
- PyErr_Clear();
}
+ 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;
+error:
+ PyErr_Clear();
if (!PyArg_ParseTuple(args, "ss:rename", &p1, &p2))
return NULL;
Py_BEGIN_ALLOW_THREADS
@@ -2809,7 +2999,7 @@ static PyObject *
posix_stat(PyObject *self, PyObject *args)
{
#ifdef MS_WINDOWS
- return posix_do_stat(self, args, "O&:stat", STAT, "U:stat", win32_wstat);
+ return posix_do_stat(self, args, "O&:stat", STAT, "U:stat", win32_stat_w);
#else
return posix_do_stat(self, args, "O&:stat", STAT, NULL, NULL);
#endif
@@ -2840,11 +3030,11 @@ posix_system(PyObject *self, PyObject *args)
PyUnicode_FSConverter, &command_obj))
return NULL;
- command = bytes2str(command_obj, 1);
+ command = PyBytes_AsString(command_obj);
Py_BEGIN_ALLOW_THREADS
sts = system(command);
Py_END_ALLOW_THREADS
- release_bytes(command_obj);
+ Py_DECREF(command_obj);
#endif
return PyLong_FromLong(sts);
}
@@ -2867,6 +3057,41 @@ posix_umask(PyObject *self, PyObject *args)
return PyLong_FromLong((long)i);
}
+#ifdef MS_WINDOWS
+
+/* override the default DeleteFileW behavior so that directory
+symlinks can be removed with this function, the same as with
+Unix symlinks */
+BOOL WINAPI Py_DeleteFileW(LPCWSTR lpFileName)
+{
+ WIN32_FILE_ATTRIBUTE_DATA info;
+ WIN32_FIND_DATAW find_data;
+ HANDLE find_data_handle;
+ int is_directory = 0;
+ int is_link = 0;
+
+ if (GetFileAttributesExW(lpFileName, GetFileExInfoStandard, &info)) {
+ is_directory = info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY;
+
+ /* Get WIN32_FIND_DATA structure for the path to determine if
+ it is a symlink */
+ if(is_directory &&
+ info.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ find_data_handle = FindFirstFileW(lpFileName, &find_data);
+
+ if(find_data_handle != INVALID_HANDLE_VALUE) {
+ is_link = find_data.dwReserved0 == IO_REPARSE_TAG_SYMLINK;
+ FindClose(find_data_handle);
+ }
+ }
+ }
+
+ if (is_directory && is_link)
+ return RemoveDirectoryW(lpFileName);
+
+ return DeleteFileW(lpFileName);
+}
+#endif /* MS_WINDOWS */
PyDoc_STRVAR(posix_unlink__doc__,
"unlink(path)\n\n\
@@ -2880,7 +3105,8 @@ static PyObject *
posix_unlink(PyObject *self, PyObject *args)
{
#ifdef MS_WINDOWS
- return win32_1str(args, "remove", "y:remove", DeleteFileA, "U:remove", DeleteFileW);
+ return win32_1str(args, "remove", "y:remove", DeleteFileA,
+ "U:remove", Py_DeleteFileW);
#else
return posix_1str(args, "O&:remove", unlink);
#endif
@@ -2970,26 +3196,25 @@ posix_utime(PyObject *self, PyObject *args)
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,
- FILE_FLAG_BACKUP_SEMANTICS, 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 (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,
+ FILE_FLAG_BACKUP_SEMANTICS, 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, "O&O:utime",
PyUnicode_FSConverter, &oapath, &arg))
return NULL;
- apath = bytes2str(oapath, 1);
+ apath = PyBytes_AsString(oapath);
Py_BEGIN_ALLOW_THREADS
hFile = CreateFileA(apath, FILE_WRITE_ATTRIBUTES, 0,
NULL, OPEN_EXISTING,
@@ -2997,10 +3222,10 @@ posix_utime(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS
if (hFile == INVALID_HANDLE_VALUE) {
win32_error("utime", apath);
- release_bytes(oapath);
+ Py_DECREF(oapath);
return NULL;
}
- release_bytes(oapath);
+ Py_DECREF(oapath);
}
if (arg == Py_None) {
@@ -3070,7 +3295,7 @@ done:
if (!PyArg_ParseTuple(args, "O&O:utime",
PyUnicode_FSConverter, &opath, &arg))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
if (arg == Py_None) {
/* optional time values not given */
Py_BEGIN_ALLOW_THREADS
@@ -3080,18 +3305,18 @@ done:
else if (!PyTuple_Check(arg) || PyTuple_Size(arg) != 2) {
PyErr_SetString(PyExc_TypeError,
"utime() arg 2 must be a tuple (atime, mtime)");
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
else {
if (extract_time(PyTuple_GET_ITEM(arg, 0),
&atime, &ausec) == -1) {
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
if (extract_time(PyTuple_GET_ITEM(arg, 1),
&mtime, &musec) == -1) {
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
ATIME = atime;
@@ -3111,7 +3336,7 @@ done:
if (res < 0) {
return posix_error_with_allocated_filename(opath);
}
- release_bytes(opath);
+ Py_DECREF(opath);
Py_INCREF(Py_None);
return Py_None;
#undef UTIME_ARG
@@ -3154,12 +3379,11 @@ int fsconvert_strdup(PyObject *o, char**out)
Py_ssize_t size;
if (!PyUnicode_FSConverter(o, &bytes))
return 0;
- size = PyObject_Size(bytes);
+ size = PyBytes_GET_SIZE(bytes);
*out = PyMem_Malloc(size+1);
if (!*out)
return 0;
- /* Don't lock bytes, as we hold the GIL */
- memcpy(*out, bytes2str(bytes, 0), size+1);
+ memcpy(*out, PyBytes_AsString(bytes), size+1);
Py_DECREF(bytes);
return 1;
}
@@ -3191,7 +3415,7 @@ posix_execv(PyObject *self, PyObject *args)
PyUnicode_FSConverter,
&opath, &argv))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
if (PyList_Check(argv)) {
argc = PyList_Size(argv);
getitem = PyList_GetItem;
@@ -3202,18 +3426,18 @@ posix_execv(PyObject *self, PyObject *args)
}
else {
PyErr_SetString(PyExc_TypeError, "execv() arg 2 must be a tuple or list");
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
if (argc < 1) {
PyErr_SetString(PyExc_ValueError, "execv() arg 2 must not be empty");
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
argvlist = PyMem_NEW(char *, argc+1);
if (argvlist == NULL) {
- release_bytes(opath);
+ Py_DECREF(opath);
return PyErr_NoMemory();
}
for (i = 0; i < argc; i++) {
@@ -3222,7 +3446,7 @@ posix_execv(PyObject *self, PyObject *args)
free_string_array(argvlist, i);
PyErr_SetString(PyExc_TypeError,
"execv() arg 2 must contain only strings");
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
@@ -3234,7 +3458,7 @@ posix_execv(PyObject *self, PyObject *args)
/* If we get here it's definitely an error */
free_string_array(argvlist, argc);
- release_bytes(opath);
+ Py_DECREF(opath);
return posix_error();
}
@@ -3347,7 +3571,7 @@ posix_execve(PyObject *self, PyObject *args)
PyUnicode_FSConverter,
&opath, &argv, &env))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
if (PyList_Check(argv)) {
argc = PyList_Size(argv);
getitem = PyList_GetItem;
@@ -3399,7 +3623,7 @@ posix_execve(PyObject *self, PyObject *args)
fail_1:
free_string_array(argvlist, lastarg);
fail_0:
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
#endif /* HAVE_EXECV */
@@ -3433,7 +3657,7 @@ posix_spawnv(PyObject *self, PyObject *args)
PyUnicode_FSConverter,
&opath, &argv))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
if (PyList_Check(argv)) {
argc = PyList_Size(argv);
getitem = PyList_GetItem;
@@ -3445,13 +3669,13 @@ posix_spawnv(PyObject *self, PyObject *args)
else {
PyErr_SetString(PyExc_TypeError,
"spawnv() arg 2 must be a tuple or list");
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
argvlist = PyMem_NEW(char *, argc+1);
if (argvlist == NULL) {
- release_bytes(opath);
+ Py_DECREF(opath);
return PyErr_NoMemory();
}
for (i = 0; i < argc; i++) {
@@ -3461,7 +3685,7 @@ posix_spawnv(PyObject *self, PyObject *args)
PyErr_SetString(
PyExc_TypeError,
"spawnv() arg 2 must contain only strings");
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
}
@@ -3481,7 +3705,7 @@ posix_spawnv(PyObject *self, PyObject *args)
#endif
free_string_array(argvlist, argc);
- release_bytes(opath);
+ Py_DECREF(opath);
if (spawnval == -1)
return posix_error();
@@ -3526,7 +3750,7 @@ posix_spawnve(PyObject *self, PyObject *args)
PyUnicode_FSConverter,
&opath, &argv, &env))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
if (PyList_Check(argv)) {
argc = PyList_Size(argv);
getitem = PyList_GetItem;
@@ -3594,7 +3818,7 @@ posix_spawnve(PyObject *self, PyObject *args)
fail_1:
free_string_array(argvlist, lastarg);
fail_0:
- release_bytes(opath);
+ Py_DECREF(opath);
return res;
}
@@ -3627,7 +3851,7 @@ posix_spawnvp(PyObject *self, PyObject *args)
PyUnicode_FSConverter,
&opath, &argv))
return NULL;
- path = bytes2str(opath);
+ path = PyBytes_AsString(opath);
if (PyList_Check(argv)) {
argc = PyList_Size(argv);
getitem = PyList_GetItem;
@@ -3639,13 +3863,13 @@ posix_spawnvp(PyObject *self, PyObject *args)
else {
PyErr_SetString(PyExc_TypeError,
"spawnvp() arg 2 must be a tuple or list");
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
argvlist = PyMem_NEW(char *, argc+1);
if (argvlist == NULL) {
- release_bytes(opath);
+ Py_DECREF(opath);
return PyErr_NoMemory();
}
for (i = 0; i < argc; i++) {
@@ -3655,7 +3879,7 @@ posix_spawnvp(PyObject *self, PyObject *args)
PyErr_SetString(
PyExc_TypeError,
"spawnvp() arg 2 must contain only strings");
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
}
@@ -3670,7 +3894,7 @@ posix_spawnvp(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS
free_string_array(argvlist, argc);
- release_bytes(opath);
+ Py_DECREF(opath);
if (spawnval == -1)
return posix_error();
@@ -3712,7 +3936,7 @@ posix_spawnvpe(PyObject *self, PyObject *args)
PyUnicode_FSConverter,
&opath, &argv, &env))
return NULL;
- path = bytes2str(opath);
+ path = PyBytes_AsString(opath);
if (PyList_Check(argv)) {
argc = PyList_Size(argv);
getitem = PyList_GetItem;
@@ -3771,7 +3995,7 @@ posix_spawnvpe(PyObject *self, PyObject *args)
fail_1:
free_string_array(argvlist, lastarg);
fail_0:
- release_bytes(opath);
+ Py_DECREF(opath);
return res;
}
#endif /* PYOS_OS2 */
@@ -3789,14 +4013,18 @@ static PyObject *
posix_fork1(PyObject *self, PyObject *noargs)
{
pid_t pid;
- int result;
+ int result = 0;
_PyImport_AcquireLock();
pid = fork1();
- result = _PyImport_ReleaseLock();
+ if (pid == 0) {
+ /* child: this clobbers and resets the import lock. */
+ PyOS_AfterFork();
+ } else {
+ /* parent: release the import lock. */
+ result = _PyImport_ReleaseLock();
+ }
if (pid == -1)
return posix_error();
- if (pid == 0)
- PyOS_AfterFork();
if (result < 0) {
/* Don't clobber the OSError if the fork failed. */
PyErr_SetString(PyExc_RuntimeError,
@@ -3818,14 +4046,18 @@ static PyObject *
posix_fork(PyObject *self, PyObject *noargs)
{
pid_t pid;
- int result;
+ int result = 0;
_PyImport_AcquireLock();
pid = fork();
- result = _PyImport_ReleaseLock();
+ if (pid == 0) {
+ /* child: this clobbers and resets the import lock. */
+ PyOS_AfterFork();
+ } else {
+ /* parent: release the import lock. */
+ result = _PyImport_ReleaseLock();
+ }
if (pid == -1)
return posix_error();
- if (pid == 0)
- PyOS_AfterFork();
if (result < 0) {
/* Don't clobber the OSError if the fork failed. */
PyErr_SetString(PyExc_RuntimeError,
@@ -3851,6 +4083,10 @@ posix_fork(PyObject *self, PyObject *noargs)
#else
#ifdef HAVE_LIBUTIL_H
#include <libutil.h>
+#else
+#ifdef HAVE_UTIL_H
+#include <util.h>
+#endif /* HAVE_UTIL_H */
#endif /* HAVE_LIBUTIL_H */
#endif /* HAVE_PTY_H */
#ifdef HAVE_STROPTS_H
@@ -3934,16 +4170,20 @@ To both, return fd of newly opened pseudo-terminal.\n");
static PyObject *
posix_forkpty(PyObject *self, PyObject *noargs)
{
- int master_fd = -1, result;
+ int master_fd = -1, result = 0;
pid_t pid;
_PyImport_AcquireLock();
pid = forkpty(&master_fd, NULL, NULL, NULL);
- result = _PyImport_ReleaseLock();
+ if (pid == 0) {
+ /* child: this clobbers and resets the import lock. */
+ PyOS_AfterFork();
+ } else {
+ /* parent: release the import lock. */
+ result = _PyImport_ReleaseLock();
+ }
if (pid == -1)
return posix_error();
- if (pid == 0)
- PyOS_AfterFork();
if (result < 0) {
/* Don't clobber the OSError if the fork failed. */
PyErr_SetString(PyExc_RuntimeError,
@@ -4081,6 +4321,36 @@ posix_getgroups(PyObject *self, PyObject *noargs)
}
#endif
+#ifdef HAVE_INITGROUPS
+PyDoc_STRVAR(posix_initgroups__doc__,
+"initgroups(username, gid) -> None\n\n\
+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.");
+
+static PyObject *
+posix_initgroups(PyObject *self, PyObject *args)
+{
+ PyObject *oname;
+ char *username;
+ int res;
+ long gid;
+
+ if (!PyArg_ParseTuple(args, "O&l:initgroups",
+ PyUnicode_FSConverter, &oname, &gid))
+ return NULL;
+ username = PyBytes_AS_STRING(oname);
+
+ res = initgroups(username, (gid_t) gid);
+ Py_DECREF(oname);
+ if (res == -1)
+ return PyErr_SetFromErrno(PyExc_OSError);
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif
+
#ifdef HAVE_GETPGID
PyDoc_STRVAR(posix_getpgid__doc__,
"getpgid(pid) -> pgid\n\n\
@@ -4090,7 +4360,7 @@ static PyObject *
posix_getpgid(PyObject *self, PyObject *args)
{
pid_t pid, pgid;
- if (!PyArg_ParseTuple(args, PARSE_PID ":getpgid", &pid))
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":getpgid", &pid))
return NULL;
pgid = getpgid(pid);
if (pgid < 0)
@@ -4138,16 +4408,65 @@ posix_setpgrp(PyObject *self, PyObject *noargs)
#endif /* HAVE_SETPGRP */
#ifdef HAVE_GETPPID
+
+#ifdef MS_WINDOWS
+#include <tlhelp32.h>
+
+static PyObject*
+win32_getppid()
+{
+ HANDLE snapshot;
+ pid_t mypid;
+ PyObject* result = NULL;
+ BOOL have_record;
+ PROCESSENTRY32 pe;
+
+ mypid = getpid(); /* This function never fails */
+
+ snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (snapshot == INVALID_HANDLE_VALUE)
+ return PyErr_SetFromWindowsErr(GetLastError());
+
+ pe.dwSize = sizeof(pe);
+ have_record = Process32First(snapshot, &pe);
+ while (have_record) {
+ if (mypid == (pid_t)pe.th32ProcessID) {
+ /* We could cache the ulong value in a static variable. */
+ result = PyLong_FromPid((pid_t)pe.th32ParentProcessID);
+ break;
+ }
+
+ have_record = Process32Next(snapshot, &pe);
+ }
+
+ /* If our loop exits and our pid was not found (result will be NULL)
+ * then GetLastError will return ERROR_NO_MORE_FILES. This is an
+ * error anyway, so let's raise it. */
+ if (!result)
+ result = PyErr_SetFromWindowsErr(GetLastError());
+
+ CloseHandle(snapshot);
+
+ return result;
+}
+#endif /*MS_WINDOWS*/
+
PyDoc_STRVAR(posix_getppid__doc__,
"getppid() -> ppid\n\n\
-Return the parent's process id.");
+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).");
static PyObject *
posix_getppid(PyObject *self, PyObject *noargs)
{
+#ifdef MS_WINDOWS
+ return win32_getppid();
+#else
return PyLong_FromPid(getppid());
-}
#endif
+}
+#endif /* HAVE_GETPPID */
#ifdef HAVE_GETLOGIN
@@ -4159,6 +4478,17 @@ static PyObject *
posix_getlogin(PyObject *self, PyObject *noargs)
{
PyObject *result = NULL;
+#ifdef MS_WINDOWS
+ wchar_t user_name[UNLEN + 1];
+ DWORD num_chars = sizeof(user_name)/sizeof(user_name[0]);
+
+ if (GetUserNameW(user_name, &num_chars)) {
+ /* num_chars is the number of unicode chars plus null terminator */
+ result = PyUnicode_FromWideChar(user_name, num_chars - 1);
+ }
+ else
+ result = PyErr_SetFromWindowsErr(GetLastError());
+#else
char *name;
int old_errno = errno;
@@ -4173,10 +4503,10 @@ posix_getlogin(PyObject *self, PyObject *noargs)
else
result = PyUnicode_DecodeFSDefault(name);
errno = old_errno;
-
+#endif
return result;
}
-#endif
+#endif /* HAVE_GETLOGIN */
#ifdef HAVE_GETUID
PyDoc_STRVAR(posix_getuid__doc__,
@@ -4201,7 +4531,7 @@ posix_kill(PyObject *self, PyObject *args)
{
pid_t pid;
int sig;
- if (!PyArg_ParseTuple(args, PARSE_PID "i:kill", &pid, &sig))
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:kill", &pid, &sig))
return NULL;
#if defined(PYOS_OS2) && !defined(PYCC_GCC)
if (sig == XCPT_SIGNAL_INTR || sig == XCPT_SIGNAL_BREAK) {
@@ -4239,7 +4569,7 @@ posix_killpg(PyObject *self, PyObject *args)
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, PARSE_PID "i:killpg", &pgid, &sig))
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:killpg", &pgid, &sig))
return NULL;
if (killpg(pgid, sig) == -1)
return posix_error();
@@ -4248,6 +4578,53 @@ posix_killpg(PyObject *self, PyObject *args)
}
#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)
+{
+ PyObject *result;
+ DWORD pid, sig, err;
+ HANDLE handle;
+
+ if (!PyArg_ParseTuple(args, "kk: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) {
+ if (GenerateConsoleCtrlEvent(sig, pid) == 0) {
+ err = GetLastError();
+ PyErr_SetFromWindowsErr(err);
+ }
+ else
+ Py_RETURN_NONE;
+ }
+
+ /* If the signal is outside of what GenerateConsoleCtrlEvent can use,
+ attempt to open and terminate the process. */
+ handle = OpenProcess(PROCESS_ALL_ACCESS, FALSE, pid);
+ if (handle == NULL) {
+ err = GetLastError();
+ return PyErr_SetFromWindowsErr(err);
+ }
+
+ if (TerminateProcess(handle, sig) == 0) {
+ err = GetLastError();
+ result = PyErr_SetFromWindowsErr(err);
+ } else {
+ Py_INCREF(Py_None);
+ result = Py_None;
+ }
+
+ CloseHandle(handle);
+ return result;
+}
+#endif /* MS_WINDOWS */
+
#ifdef HAVE_PLOCK
#ifdef HAVE_SYS_LOCK_H
@@ -4596,7 +4973,7 @@ posix_wait4(PyObject *self, PyObject *args)
WAIT_TYPE status;
WAIT_STATUS_INT(status) = 0;
- if (!PyArg_ParseTuple(args, PARSE_PID "i:wait4", &pid, &options))
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:wait4", &pid, &options))
return NULL;
Py_BEGIN_ALLOW_THREADS
@@ -4620,7 +4997,7 @@ posix_waitpid(PyObject *self, PyObject *args)
WAIT_TYPE status;
WAIT_STATUS_INT(status) = 0;
- if (!PyArg_ParseTuple(args, PARSE_PID "i:waitpid", &pid, &options))
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:waitpid", &pid, &options))
return NULL;
Py_BEGIN_ALLOW_THREADS
pid = waitpid(pid, &status, options);
@@ -4644,7 +5021,7 @@ posix_waitpid(PyObject *self, PyObject *args)
Py_intptr_t pid;
int status, options;
- if (!PyArg_ParseTuple(args, PARSE_PID "i:waitpid", &pid, &options))
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:waitpid", &pid, &options))
return NULL;
Py_BEGIN_ALLOW_THREADS
pid = _cwait(&status, pid, options);
@@ -4691,7 +5068,8 @@ posix_lstat(PyObject *self, PyObject *args)
return posix_do_stat(self, args, "O&:lstat", lstat, NULL, NULL);
#else /* !HAVE_LSTAT */
#ifdef MS_WINDOWS
- return posix_do_stat(self, args, "O&:lstat", STAT, "U:lstat", win32_wstat);
+ return posix_do_stat(self, args, "O&:lstat", STAT, "U:lstat",
+ win32_lstat_w);
#else
return posix_do_stat(self, args, "O&:lstat", STAT, NULL, NULL);
#endif
@@ -4717,10 +5095,10 @@ posix_readlink(PyObject *self, PyObject *args)
if (!PyArg_ParseTuple(args, "O&:readlink",
PyUnicode_FSConverter, &opath))
return NULL;
- path = bytes2str(opath, 1);
+ path = PyBytes_AsString(opath);
v = PySequence_GetItem(args, 0);
if (v == NULL) {
- release_bytes(opath);
+ Py_DECREF(opath);
return NULL;
}
@@ -4735,28 +5113,16 @@ posix_readlink(PyObject *self, PyObject *args)
if (n < 0)
return posix_error_with_allocated_filename(opath);
- release_bytes(opath);
- v = PyBytes_FromStringAndSize(buf, n);
- if (arg_is_unicode) {
- PyObject *w;
-
- w = PyUnicode_FromEncodedObject(v,
- Py_FileSystemDefaultEncoding,
- "surrogateescape");
- if (w != NULL) {
- Py_DECREF(v);
- v = w;
- }
- else {
- v = NULL;
- }
- }
- return v;
+ Py_DECREF(opath);
+ if (arg_is_unicode)
+ return PyUnicode_DecodeFSDefaultAndSize(buf, n);
+ else
+ return PyBytes_FromStringAndSize(buf, n);
}
#endif /* HAVE_READLINK */
-#ifdef HAVE_SYMLINK
+#if defined(HAVE_SYMLINK) && !defined(MS_WINDOWS)
PyDoc_STRVAR(posix_symlink__doc__,
"symlink(src, dst)\n\n\
Create a symbolic link pointing to src named dst.");
@@ -4768,6 +5134,165 @@ posix_symlink(PyObject *self, PyObject *args)
}
#endif /* HAVE_SYMLINK */
+#if !defined(HAVE_READLINK) && defined(MS_WINDOWS)
+
+PyDoc_STRVAR(win_readlink__doc__,
+"readlink(path) -> path\n\n\
+Return a string representing the path to which the symbolic link points.");
+
+/* Windows readlink implementation */
+static PyObject *
+win_readlink(PyObject *self, PyObject *args)
+{
+ wchar_t *path;
+ DWORD n_bytes_returned;
+ DWORD io_result;
+ PyObject *result;
+ 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;
+
+ if (!PyArg_ParseTuple(args,
+ "u:readlink",
+ &path))
+ 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_unicode("readlink", path);
+ }
+
+ 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_unicode("readlink", path);
+ }
+
+ 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) */
+
+#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
+
+/* Grab CreateSymbolicLinkW dynamically from kernel32 */
+static int has_CreateSymbolicLinkW = 0;
+static DWORD (CALLBACK *Py_CreateSymbolicLinkW)(LPWSTR, LPWSTR, DWORD);
+static int
+check_CreateSymbolicLinkW()
+{
+ HINSTANCE hKernel32;
+ /* only recheck */
+ if (has_CreateSymbolicLinkW)
+ return has_CreateSymbolicLinkW;
+ hKernel32 = GetModuleHandle("KERNEL32");
+ *(FARPROC*)&Py_CreateSymbolicLinkW = GetProcAddress(hKernel32,
+ "CreateSymbolicLinkW");
+ if (Py_CreateSymbolicLinkW)
+ has_CreateSymbolicLinkW = 1;
+ return has_CreateSymbolicLinkW;
+}
+
+PyDoc_STRVAR(win_symlink__doc__,
+"symlink(src, dst, target_is_directory=False)\n\n\
+Create a symbolic link pointing to src named dst.\n\
+target_is_directory is required if the target is to be interpreted as\n\
+a directory.\n\
+This function requires Windows 6.0 or greater, and raises a\n\
+NotImplementedError otherwise.");
+
+static PyObject *
+win_symlink(PyObject *self, PyObject *args, PyObject *kwargs)
+{
+ static char *kwlist[] = {"src", "dest", "target_is_directory", NULL};
+ PyObject *src, *dest;
+ int target_is_directory = 0;
+ DWORD res;
+ WIN32_FILE_ATTRIBUTE_DATA src_info;
+
+ if (!check_CreateSymbolicLinkW())
+ {
+ /* raise NotImplementedError */
+ return PyErr_Format(PyExc_NotImplementedError,
+ "CreateSymbolicLinkW not found");
+ }
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OO|i:symlink",
+ kwlist, &src, &dest, &target_is_directory))
+ return NULL;
+
+ if (win32_can_symlink == 0)
+ return PyErr_Format(PyExc_OSError, "symbolic link privilege not held");
+
+ if (!convert_to_unicode(&src)) { return NULL; }
+ if (!convert_to_unicode(&dest)) {
+ Py_DECREF(src);
+ return NULL;
+ }
+
+ /* if src is a directory, ensure target_is_directory==1 */
+ if(
+ GetFileAttributesExW(
+ PyUnicode_AsUnicode(src), GetFileExInfoStandard, &src_info
+ ))
+ {
+ target_is_directory = target_is_directory ||
+ (src_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
+ }
+
+ Py_BEGIN_ALLOW_THREADS
+ res = Py_CreateSymbolicLinkW(
+ PyUnicode_AsUnicode(dest),
+ PyUnicode_AsUnicode(src),
+ target_is_directory);
+ Py_END_ALLOW_THREADS
+ Py_DECREF(src);
+ Py_DECREF(dest);
+ if (!res)
+ {
+ return win32_error_unicode("symlink", PyUnicode_AsUnicode(src));
+ }
+
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+#endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */
#ifdef HAVE_TIMES
#if defined(PYCC_VACPP) && defined(PYOS_OS2)
@@ -4860,7 +5385,7 @@ posix_getsid(PyObject *self, PyObject *args)
{
pid_t pid;
int sid;
- if (!PyArg_ParseTuple(args, PARSE_PID ":getsid", &pid))
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID ":getsid", &pid))
return NULL;
sid = getsid(pid);
if (sid < 0)
@@ -4895,7 +5420,7 @@ posix_setpgid(PyObject *self, PyObject *args)
{
pid_t pid;
int pgrp;
- if (!PyArg_ParseTuple(args, PARSE_PID "i:setpgid", &pid, &pgrp))
+ if (!PyArg_ParseTuple(args, _Py_PARSE_PID "i:setpgid", &pid, &pgrp))
return NULL;
if (setpgid(pid, pgrp) < 0)
return posix_error();
@@ -4935,7 +5460,7 @@ posix_tcsetpgrp(PyObject *self, PyObject *args)
{
int fd;
pid_t pgid;
- if (!PyArg_ParseTuple(args, "i" PARSE_PID ":tcsetpgrp", &fd, &pgid))
+ if (!PyArg_ParseTuple(args, "i" _Py_PARSE_PID ":tcsetpgrp", &fd, &pgid))
return NULL;
if (tcsetpgrp(fd, pgid) < 0)
return posix_error();
@@ -4960,35 +5485,33 @@ posix_open(PyObject *self, PyObject *args)
int fd;
#ifdef MS_WINDOWS
- if (unicode_file_names()) {
- PyUnicodeObject *po;
- if (PyArg_ParseTuple(args, "Ui|i:mkdir", &po, &flag, &mode)) {
- Py_BEGIN_ALLOW_THREADS
- /* PyUnicode_AS_UNICODE OK without thread
- lock as it is a simple dereference. */
- fd = _wopen(PyUnicode_AS_UNICODE(po), flag, mode);
- Py_END_ALLOW_THREADS
- if (fd < 0)
- return posix_error();
- return PyLong_FromLong((long)fd);
- }
- /* Drop the argument parsing error as narrow strings
- are also valid. */
- PyErr_Clear();
+ PyUnicodeObject *po;
+ if (PyArg_ParseTuple(args, "Ui|i:mkdir", &po, &flag, &mode)) {
+ Py_BEGIN_ALLOW_THREADS
+ /* PyUnicode_AS_UNICODE OK without thread
+ lock as it is a simple dereference. */
+ fd = _wopen(PyUnicode_AS_UNICODE(po), flag, mode);
+ Py_END_ALLOW_THREADS
+ if (fd < 0)
+ return posix_error();
+ return PyLong_FromLong((long)fd);
}
+ /* Drop the argument parsing error as narrow strings
+ are also valid. */
+ PyErr_Clear();
#endif
if (!PyArg_ParseTuple(args, "O&i|i",
PyUnicode_FSConverter, &ofile,
&flag, &mode))
return NULL;
- file = bytes2str(ofile, 1);
+ file = PyBytes_AsString(ofile);
Py_BEGIN_ALLOW_THREADS
fd = open(file, flag, mode);
Py_END_ALLOW_THREADS
if (fd < 0)
return posix_error_with_allocated_filename(ofile);
- release_bytes(ofile);
+ Py_DECREF(ofile);
return PyLong_FromLong((long)fd);
}
@@ -5176,7 +5699,7 @@ posix_write(PyObject *self, PyObject *args)
{
Py_buffer pbuf;
int fd;
- Py_ssize_t size;
+ Py_ssize_t size, len;
if (!PyArg_ParseTuple(args, "iy*:write", &fd, &pbuf))
return NULL;
@@ -5184,8 +5707,15 @@ posix_write(PyObject *self, PyObject *args)
PyBuffer_Release(&pbuf);
return posix_error();
}
+ len = pbuf.len;
Py_BEGIN_ALLOW_THREADS
- size = write(fd, pbuf.buf, (size_t)pbuf.len);
+#if defined(MS_WIN64) || defined(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)
@@ -5448,7 +5978,7 @@ posix_putenv(PyObject *self, PyObject *args)
char *s1, *s2;
char *newenv;
#endif
- PyObject *newstr;
+ PyObject *newstr = NULL;
size_t len;
#ifdef MS_WINDOWS
@@ -5462,8 +5992,8 @@ posix_putenv(PyObject *self, PyObject *args)
PyUnicode_FSConverter, &os1,
PyUnicode_FSConverter, &os2))
return NULL;
- s1 = bytes2str(os1, 1);
- s2 = bytes2str(os2, 1);
+ s1 = PyBytes_AsString(os1);
+ s2 = PyBytes_AsString(os2);
#endif
#if defined(PYOS_OS2)
@@ -5471,15 +6001,19 @@ posix_putenv(PyObject *self, PyObject *args)
APIRET rc;
rc = DosSetExtLIBPATH(s2, BEGIN_LIBPATH);
- if (rc != NO_ERROR)
- return os2_error(rc);
+ if (rc != NO_ERROR) {
+ os2_error(rc);
+ goto error;
+ }
} else if (stricmp(s1, "ENDLIBPATH") == 0) {
APIRET rc;
rc = DosSetExtLIBPATH(s2, END_LIBPATH);
- if (rc != NO_ERROR)
- return os2_error(rc);
+ if (rc != NO_ERROR) {
+ os2_error(rc);
+ goto error;
+ }
} else {
#endif
/* XXX This can leak memory -- not easy to fix :-( */
@@ -5489,36 +6023,40 @@ posix_putenv(PyObject *self, PyObject *args)
len = wcslen(s1) + wcslen(s2) + 2;
newstr = PyUnicode_FromUnicode(NULL, (int)len - 1);
#else
- len = strlen(s1) + strlen(s2) + 2;
+ len = PyBytes_GET_SIZE(os1) + PyBytes_GET_SIZE(os2) + 2;
newstr = PyBytes_FromStringAndSize(NULL, (int)len - 1);
#endif
- if (newstr == NULL)
- return PyErr_NoMemory();
+ if (newstr == NULL) {
+ PyErr_NoMemory();
+ goto error;
+ }
#ifdef MS_WINDOWS
newenv = PyUnicode_AsUnicode(newstr);
_snwprintf(newenv, len, L"%s=%s", s1, s2);
if (_wputenv(newenv)) {
- Py_DECREF(newstr);
posix_error();
- return NULL;
+ goto error;
}
#else
newenv = PyBytes_AS_STRING(newstr);
PyOS_snprintf(newenv, len, "%s=%s", s1, s2);
if (putenv(newenv)) {
- Py_DECREF(newstr);
- release_bytes(os1);
- release_bytes(os2);
posix_error();
- return NULL;
+ goto error;
}
#endif
+
/* 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,
- PyTuple_GET_ITEM(args, 0), newstr)) {
+#ifdef MS_WINDOWS
+ PyTuple_GET_ITEM(args, 0),
+#else
+ os1,
+#endif
+ newstr)) {
/* really not much we can do; just leak */
PyErr_Clear();
}
@@ -5529,12 +6067,20 @@ posix_putenv(PyObject *self, PyObject *args)
#if defined(PYOS_OS2)
}
#endif
+
#ifndef MS_WINDOWS
- release_bytes(os1);
- release_bytes(os2);
+ Py_DECREF(os1);
+ Py_DECREF(os2);
#endif
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
+
+error:
+#ifndef MS_WINDOWS
+ Py_DECREF(os1);
+ Py_DECREF(os2);
+#endif
+ Py_XDECREF(newstr);
+ return NULL;
}
#endif /* putenv */
@@ -5546,10 +6092,20 @@ Delete an environment variable.");
static PyObject *
posix_unsetenv(PyObject *self, PyObject *args)
{
+#ifdef MS_WINDOWS
char *s1;
if (!PyArg_ParseTuple(args, "s:unsetenv", &s1))
return NULL;
+#else
+ PyObject *os1;
+ char *s1;
+
+ if (!PyArg_ParseTuple(args, "O&:unsetenv",
+ PyUnicode_FSConverter, &os1))
+ return NULL;
+ s1 = PyBytes_AsString(os1);
+#endif
unsetenv(s1);
@@ -5559,13 +6115,20 @@ posix_unsetenv(PyObject *self, PyObject *args)
* old value was still accessible until then.
*/
if (PyDict_DelItem(posix_putenv_garbage,
- PyTuple_GET_ITEM(args, 0))) {
+#ifdef MS_WINDOWS
+ PyTuple_GET_ITEM(args, 0)
+#else
+ os1
+#endif
+ )) {
/* really not much we can do; just leak */
PyErr_Clear();
}
- Py_INCREF(Py_None);
- return Py_None;
+#ifndef MS_WINDOWS
+ Py_DECREF(os1);
+#endif
+ Py_RETURN_NONE;
}
#endif /* unsetenv */
@@ -5948,6 +6511,39 @@ static struct constdef posix_constants_pathconf[] = {
#ifdef _PC_VDISABLE
{"PC_VDISABLE", _PC_VDISABLE},
#endif
+#ifdef _PC_ACL_ENABLED
+ {"PC_ACL_ENABLED", _PC_ACL_ENABLED},
+#endif
+#ifdef _PC_MIN_HOLE_SIZE
+ {"PC_MIN_HOLE_SIZE", _PC_MIN_HOLE_SIZE},
+#endif
+#ifdef _PC_ALLOC_SIZE_MIN
+ {"PC_ALLOC_SIZE_MIN", _PC_ALLOC_SIZE_MIN},
+#endif
+#ifdef _PC_REC_INCR_XFER_SIZE
+ {"PC_REC_INCR_XFER_SIZE", _PC_REC_INCR_XFER_SIZE},
+#endif
+#ifdef _PC_REC_MAX_XFER_SIZE
+ {"PC_REC_MAX_XFER_SIZE", _PC_REC_MAX_XFER_SIZE},
+#endif
+#ifdef _PC_REC_MIN_XFER_SIZE
+ {"PC_REC_MIN_XFER_SIZE", _PC_REC_MIN_XFER_SIZE},
+#endif
+#ifdef _PC_REC_XFER_ALIGN
+ {"PC_REC_XFER_ALIGN", _PC_REC_XFER_ALIGN},
+#endif
+#ifdef _PC_SYMLINK_MAX
+ {"PC_SYMLINK_MAX", _PC_SYMLINK_MAX},
+#endif
+#ifdef _PC_XATTR_ENABLED
+ {"PC_XATTR_ENABLED", _PC_XATTR_ENABLED},
+#endif
+#ifdef _PC_XATTR_EXISTS
+ {"PC_XATTR_EXISTS", _PC_XATTR_EXISTS},
+#endif
+#ifdef _PC_TIMESTAMP_RESOLUTION
+ {"PC_TIMESTAMP_RESOLUTION", _PC_TIMESTAMP_RESOLUTION},
+#endif
};
static int
@@ -6191,32 +6787,34 @@ posix_confstr(PyObject *self, PyObject *args)
{
PyObject *result = NULL;
int name;
- char buffer[256];
-
- if (PyArg_ParseTuple(args, "O&:confstr", conv_confstr_confname, &name)) {
+ char buffer[255];
int len;
- errno = 0;
- len = confstr(name, buffer, sizeof(buffer));
- if (len == 0) {
- if (errno) {
- posix_error();
- }
- else {
- result = Py_None;
- Py_INCREF(Py_None);
- }
+ if (!PyArg_ParseTuple(args, "O&:confstr", conv_confstr_confname, &name))
+ return NULL;
+
+ errno = 0;
+ len = confstr(name, buffer, sizeof(buffer));
+ if (len == 0) {
+ if (errno) {
+ posix_error();
+ return NULL;
}
else {
- if ((unsigned int)len >= sizeof(buffer)) {
- result = PyUnicode_FromStringAndSize(NULL, len-1);
- if (result != NULL)
- confstr(name, _PyUnicode_AsString(result), len);
- }
- else
- result = PyUnicode_FromStringAndSize(buffer, len-1);
+ Py_RETURN_NONE;
}
}
+
+ if ((unsigned int)len >= sizeof(buffer)) {
+ char *buf = PyMem_Malloc(len);
+ if (buf == NULL)
+ return PyErr_NoMemory();
+ confstr(name, buf, len);
+ result = PyUnicode_DecodeFSDefaultAndSize(buf, len-1);
+ PyMem_Free(buf);
+ }
+ else
+ result = PyUnicode_DecodeFSDefaultAndSize(buffer, len-1);
return result;
}
#endif
@@ -6867,57 +7465,54 @@ win32_startfile(PyObject *self, PyObject *args)
char *operation = NULL;
HINSTANCE rc;
- if (unicode_file_names()) {
- PyObject *unipath, *woperation = NULL;
- if (!PyArg_ParseTuple(args, "U|s:startfile",
- &unipath, &operation)) {
+ PyObject *unipath, *woperation = NULL;
+ if (!PyArg_ParseTuple(args, "U|s:startfile",
+ &unipath, &operation)) {
+ PyErr_Clear();
+ goto normal;
+ }
+
+ if (operation) {
+ woperation = PyUnicode_DecodeASCII(operation,
+ strlen(operation), NULL);
+ if (!woperation) {
PyErr_Clear();
+ operation = NULL;
goto normal;
}
+ }
+ Py_BEGIN_ALLOW_THREADS
+ rc = ShellExecuteW((HWND)0, woperation ? PyUnicode_AS_UNICODE(woperation) : 0,
+ PyUnicode_AS_UNICODE(unipath),
+ NULL, NULL, SW_SHOWNORMAL);
+ Py_END_ALLOW_THREADS
- if (operation) {
- woperation = PyUnicode_DecodeASCII(operation,
- strlen(operation), NULL);
- if (!woperation) {
- PyErr_Clear();
- operation = NULL;
- goto normal;
- }
- }
-
- Py_BEGIN_ALLOW_THREADS
- rc = ShellExecuteW((HWND)0, woperation ? PyUnicode_AS_UNICODE(woperation) : 0,
- PyUnicode_AS_UNICODE(unipath),
- NULL, NULL, SW_SHOWNORMAL);
- Py_END_ALLOW_THREADS
-
- Py_XDECREF(woperation);
- if (rc <= (HINSTANCE)32) {
- PyObject *errval = win32_error_unicode("startfile",
- PyUnicode_AS_UNICODE(unipath));
- return errval;
- }
- Py_INCREF(Py_None);
- return Py_None;
+ Py_XDECREF(woperation);
+ if (rc <= (HINSTANCE)32) {
+ PyObject *errval = win32_error_unicode("startfile",
+ PyUnicode_AS_UNICODE(unipath));
+ return errval;
}
+ Py_INCREF(Py_None);
+ return Py_None;
normal:
if (!PyArg_ParseTuple(args, "O&|s:startfile",
PyUnicode_FSConverter, &ofilepath,
&operation))
return NULL;
- filepath = bytes2str(ofilepath, 1);
+ filepath = PyBytes_AsString(ofilepath);
Py_BEGIN_ALLOW_THREADS
rc = ShellExecute((HWND)0, operation, filepath,
NULL, NULL, SW_SHOWNORMAL);
Py_END_ALLOW_THREADS
if (rc <= (HINSTANCE)32) {
PyObject *errval = win32_error("startfile", filepath);
- release_bytes(ofilepath);
+ Py_DECREF(ofilepath);
return errval;
}
- release_bytes(ofilepath);
+ Py_DECREF(ofilepath);
Py_INCREF(Py_None);
return Py_None;
}
@@ -7091,6 +7686,82 @@ vms_urandom(PyObject *self, PyObject *args)
}
#endif
+#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.");
+
+static PyObject*
+posix_setresuid (PyObject *self, PyObject *args)
+{
+ /* We assume uid_t is no larger than a long. */
+ long ruid, euid, suid;
+ if (!PyArg_ParseTuple(args, "lll", &ruid, &euid, &suid))
+ return NULL;
+ if (setresuid(ruid, euid, suid) < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#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.");
+
+static PyObject*
+posix_setresgid (PyObject *self, PyObject *args)
+{
+ /* We assume uid_t is no larger than a long. */
+ long rgid, egid, sgid;
+ if (!PyArg_ParseTuple(args, "lll", &rgid, &egid, &sgid))
+ return NULL;
+ if (setresgid(rgid, egid, sgid) < 0)
+ return posix_error();
+ Py_RETURN_NONE;
+}
+#endif
+
+#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.");
+
+static PyObject*
+posix_getresuid (PyObject *self, PyObject *noargs)
+{
+ uid_t ruid, euid, suid;
+ long l_ruid, l_euid, l_suid;
+ if (getresuid(&ruid, &euid, &suid) < 0)
+ return posix_error();
+ /* Force the values into long's as we don't know the size of uid_t. */
+ l_ruid = ruid;
+ l_euid = euid;
+ l_suid = suid;
+ return Py_BuildValue("(lll)", l_ruid, l_euid, l_suid);
+}
+#endif
+
+#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.");
+
+static PyObject*
+posix_getresgid (PyObject *self, PyObject *noargs)
+{
+ uid_t rgid, egid, sgid;
+ long l_rgid, l_egid, l_sgid;
+ if (getresgid(&rgid, &egid, &sgid) < 0)
+ return posix_error();
+ /* Force the values into long's as we don't know the size of uid_t. */
+ l_rgid = rgid;
+ l_egid = egid;
+ l_sgid = sgid;
+ return Py_BuildValue("(lll)", l_rgid, l_egid, l_sgid);
+}
+#endif
+
static PyMethodDef posix_methods[] = {
{"access", posix_access, METH_VARARGS, posix_access__doc__},
#ifdef HAVE_TTYNAME
@@ -7143,13 +7814,20 @@ static PyMethodDef posix_methods[] = {
#ifdef HAVE_READLINK
{"readlink", posix_readlink, METH_VARARGS, posix_readlink__doc__},
#endif /* HAVE_READLINK */
+#if !defined(HAVE_READLINK) && defined(MS_WINDOWS)
+ {"readlink", win_readlink, METH_VARARGS, win_readlink__doc__},
+#endif /* !defined(HAVE_READLINK) && defined(MS_WINDOWS) */
{"rename", posix_rename, METH_VARARGS, posix_rename__doc__},
{"rmdir", posix_rmdir, METH_VARARGS, posix_rmdir__doc__},
{"stat", posix_stat, METH_VARARGS, posix_stat__doc__},
{"stat_float_times", stat_float_times, METH_VARARGS, stat_float_times__doc__},
-#ifdef HAVE_SYMLINK
+#if defined(HAVE_SYMLINK) && !defined(MS_WINDOWS)
{"symlink", posix_symlink, METH_VARARGS, posix_symlink__doc__},
#endif /* HAVE_SYMLINK */
+#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
+ {"symlink", (PyCFunction)win_symlink, METH_VARARGS | METH_KEYWORDS,
+ win_symlink__doc__},
+#endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */
#ifdef HAVE_SYSTEM
{"system", posix_system, METH_VARARGS, posix_system__doc__},
#endif
@@ -7224,6 +7902,8 @@ static PyMethodDef posix_methods[] = {
#endif /* HAVE_PLOCK */
#ifdef MS_WINDOWS
{"startfile", win32_startfile, METH_VARARGS, win32_startfile__doc__},
+ {"kill", win32_kill, METH_VARARGS, win32_kill__doc__},
+ {"link", win32_link, METH_VARARGS, win32_link__doc__},
#endif
#ifdef HAVE_SETUID
{"setuid", posix_setuid, METH_VARARGS, posix_setuid__doc__},
@@ -7246,6 +7926,9 @@ static PyMethodDef posix_methods[] = {
#ifdef HAVE_SETGROUPS
{"setgroups", posix_setgroups, METH_O, posix_setgroups__doc__},
#endif /* HAVE_SETGROUPS */
+#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 */
@@ -7370,6 +8053,8 @@ static PyMethodDef posix_methods[] = {
{"abort", posix_abort, METH_NOARGS, posix_abort__doc__},
#ifdef MS_WINDOWS
{"_getfullpathname", posix__getfullpathname, METH_VARARGS, NULL},
+ {"_getfinalpathname", posix__getfinalpathname, METH_VARARGS, NULL},
+ {"_getfileinformation", posix__getfileinformation, METH_VARARGS, NULL},
#endif
#ifdef HAVE_GETLOADAVG
{"getloadavg", posix_getloadavg, METH_NOARGS, posix_getloadavg__doc__},
@@ -7380,6 +8065,19 @@ static PyMethodDef posix_methods[] = {
#ifdef __VMS
{"urandom", vms_urandom, METH_VARARGS, vms_urandom__doc__},
#endif
+#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
+
{NULL, NULL} /* Sentinel */
};
@@ -7443,6 +8141,35 @@ static int insertvalues(PyObject *module)
}
#endif
+#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
+static int
+enable_symlink()
+{
+ HANDLE tok;
+ TOKEN_PRIVILEGES tok_priv;
+ LUID luid;
+ int meth_idx = 0;
+
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &tok))
+ return 0;
+
+ if (!LookupPrivilegeValue(NULL, SE_CREATE_SYMBOLIC_LINK_NAME, &luid))
+ return 0;
+
+ tok_priv.PrivilegeCount = 1;
+ tok_priv.Privileges[0].Luid = luid;
+ tok_priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!AdjustTokenPrivileges(tok, FALSE, &tok_priv,
+ sizeof(TOKEN_PRIVILEGES),
+ (PTOKEN_PRIVILEGES) NULL, (PDWORD) NULL))
+ return 0;
+
+ /* ERROR_NOT_ALL_ASSIGNED returned when the privilege can't be assigned. */
+ return GetLastError() == ERROR_NOT_ALL_ASSIGNED ? 0 : 1;
+}
+#endif /* defined(HAVE_SYMLINK) && defined(MS_WINDOWS) */
+
static int
all_ins(PyObject *d)
{
@@ -7627,6 +8354,14 @@ all_ins(PyObject *d)
if (ins(d, "EX_NOTFOUND", (long)EX_NOTFOUND)) return -1;
#endif /* EX_NOTFOUND */
+ /* statvfs */
+#ifdef ST_RDONLY
+ if (ins(d, "ST_RDONLY", (long)ST_RDONLY)) return -1;
+#endif /* ST_RDONLY */
+#ifdef ST_NOSUID
+ if (ins(d, "ST_NOSUID", (long)ST_NOSUID)) return -1;
+#endif /* ST_NOSUID */
+
#ifdef HAVE_SPAWNV
#if defined(PYOS_OS2) && defined(PYCC_GCC)
if (ins(d, "P_WAIT", (long)P_WAIT)) return -1;
@@ -7696,6 +8431,10 @@ INITFUNC(void)
{
PyObject *m, *v;
+#if defined(HAVE_SYMLINK) && defined(MS_WINDOWS)
+ win32_can_symlink = enable_symlink();
+#endif
+
m = PyModule_Create(&posixmodule);
if (m == NULL)
return NULL;