summaryrefslogtreecommitdiff
path: root/Modules/_winapi.c
diff options
context:
space:
mode:
authorTim Golden <mail@timgolden.me.uk>2014-04-27 18:00:10 +0100
committerTim Golden <mail@timgolden.me.uk>2014-04-27 18:00:10 +0100
commit4675d798bfdef3ad916d1eef6d5a4d0529ccfda7 (patch)
tree628685ce1f8db9455bb95819f876faa7c56bf020 /Modules/_winapi.c
parentdd41f246875494c9acc6ebd4338f8df3ec6c28f0 (diff)
downloadcpython-git-4675d798bfdef3ad916d1eef6d5a4d0529ccfda7.tar.gz
Issue #18314 os.unlink will now remove junction points on Windows. Patch by Kim Gräsman.
Diffstat (limited to 'Modules/_winapi.c')
-rw-r--r--Modules/_winapi.c109
1 files changed, 109 insertions, 0 deletions
diff --git a/Modules/_winapi.c b/Modules/_winapi.c
index b755178427..80c1e929d9 100644
--- a/Modules/_winapi.c
+++ b/Modules/_winapi.c
@@ -40,6 +40,7 @@
#define WINDOWS_LEAN_AND_MEAN
#include "windows.h"
#include <crtdbg.h>
+#include "winreparse.h"
#if defined(MS_WIN32) && !defined(MS_WIN64)
#define HANDLE_TO_PYNUM(handle) \
@@ -401,6 +402,112 @@ winapi_CreateFile(PyObject *self, PyObject *args)
}
static PyObject *
+winapi_CreateJunction(PyObject *self, PyObject *args)
+{
+ /* Input arguments */
+ LPWSTR src_path = NULL;
+ LPWSTR dst_path = NULL;
+
+ /* Privilege adjustment */
+ HANDLE token = NULL;
+ TOKEN_PRIVILEGES tp;
+
+ /* Reparse data buffer */
+ const USHORT prefix_len = 4;
+ USHORT print_len = 0;
+ USHORT rdb_size = 0;
+ PREPARSE_DATA_BUFFER rdb = NULL;
+
+ /* Junction point creation */
+ HANDLE junction = NULL;
+ DWORD ret = 0;
+
+ if (!PyArg_ParseTuple(args, "uu",
+ &src_path, &dst_path))
+ return NULL;
+
+ if (memcmp(src_path, L"\\??\\", prefix_len * sizeof(WCHAR)) == 0)
+ return PyErr_SetFromWindowsErr(ERROR_INVALID_PARAMETER);
+
+ /* Adjust privileges to allow rewriting directory entry as a
+ junction point. */
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
+ goto cleanup;
+
+ if (!LookupPrivilegeValue(NULL, SE_RESTORE_NAME, &tp.Privileges[0].Luid))
+ goto cleanup;
+
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if (!AdjustTokenPrivileges(token, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
+ NULL, NULL))
+ goto cleanup;
+
+ if (GetFileAttributesW(src_path) == INVALID_FILE_ATTRIBUTES)
+ goto cleanup;
+
+ print_len = (USHORT)GetFullPathNameW(src_path, 0, NULL, NULL);
+ if (print_len == 0)
+ goto cleanup;
+
+ /* NUL terminator should not be part of print_len */
+ --print_len;
+
+ rdb_size = REPARSE_DATA_BUFFER_HEADER_SIZE +
+ sizeof(rdb->MountPointReparseBuffer) -
+ sizeof(rdb->MountPointReparseBuffer.PathBuffer) +
+ /* Two +1's for NUL terminators. */
+ (prefix_len + print_len + 1 + print_len + 1) * sizeof(WCHAR);
+ rdb = (PREPARSE_DATA_BUFFER)PyMem_RawMalloc(rdb_size, 1);
+
+ rdb->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ rdb->ReparseDataLength = rdb_size - REPARSE_DATA_BUFFER_HEADER_SIZE;
+ rdb->MountPointReparseBuffer.SubstituteNameOffset = 0;
+ rdb->MountPointReparseBuffer.SubstituteNameLength =
+ (prefix_len + print_len) * sizeof(WCHAR);
+ rdb->MountPointReparseBuffer.PrintNameOffset =
+ rdb->MountPointReparseBuffer.SubstituteNameLength + sizeof(WCHAR);
+ rdb->MountPointReparseBuffer.PrintNameLength = print_len * sizeof(WCHAR);
+
+ lstrcpyW(rdb->MountPointReparseBuffer.PathBuffer, L"\\??\\");
+ if (GetFullPathNameW(src_path, print_len + 1,
+ rdb->MountPointReparseBuffer.PathBuffer + prefix_len,
+ NULL) == 0)
+ goto cleanup;
+
+ lstrcpyW(rdb->MountPointReparseBuffer.PathBuffer +
+ prefix_len + print_len + 1,
+ rdb->MountPointReparseBuffer.PathBuffer + prefix_len);
+
+ /* Create a directory for the junction point. */
+ if (!CreateDirectoryW(dst_path, NULL))
+ goto cleanup;
+
+ junction = CreateFileW(dst_path, GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (junction == INVALID_HANDLE_VALUE)
+ goto cleanup;
+
+ /* Make the directory entry a junction point. */
+ if (!DeviceIoControl(junction, FSCTL_SET_REPARSE_POINT, rdb, rdb_size,
+ NULL, 0, &ret, NULL))
+ goto cleanup;
+
+cleanup:
+ ret = GetLastError();
+
+ CloseHandle(token);
+ CloseHandle(junction);
+ free(rdb);
+
+ if (ret != 0)
+ return PyErr_SetFromWindowsErr(ret);
+
+ Py_RETURN_NONE;
+}
+
+static PyObject *
winapi_CreateNamedPipe(PyObject *self, PyObject *args)
{
LPCTSTR lpName;
@@ -1225,6 +1332,8 @@ static PyMethodDef winapi_functions[] = {
METH_VARARGS | METH_KEYWORDS, ""},
{"CreateFile", winapi_CreateFile, METH_VARARGS,
""},
+ {"CreateJunction", winapi_CreateJunction, METH_VARARGS,
+ ""},
{"CreateNamedPipe", winapi_CreateNamedPipe, METH_VARARGS,
""},
{"CreatePipe", winapi_CreatePipe, METH_VARARGS,