mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-09-13 09:17:20 -07:00
Support for junction points/reparse points.
This commit is contained in:
parent
6274002623
commit
40aaeb61f8
@ -0,0 +1,310 @@
|
||||
From 4d377524363a3e33e2df29c38fe16542b6cd0aa1 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 20:56:49 -0700
|
||||
Subject: ntdll: Add support for junction point creation.
|
||||
|
||||
---
|
||||
dlls/ntdll/file.c | 89 ++++++++++++++++++++++++++++++++++++++++++++
|
||||
dlls/ntdll/tests/file.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
include/ntifs.h | 52 ++++++++++++++++++++++++++
|
||||
3 files changed, 235 insertions(+)
|
||||
create mode 100644 include/ntifs.h
|
||||
|
||||
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
|
||||
index d2efcc1..7164d1e 100644
|
||||
--- a/dlls/ntdll/file.c
|
||||
+++ b/dlls/ntdll/file.c
|
||||
@@ -89,12 +89,14 @@
|
||||
#include "winioctl.h"
|
||||
#include "ddk/ntddk.h"
|
||||
#include "ddk/ntddser.h"
|
||||
+#include "ntifs.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(winediag);
|
||||
|
||||
mode_t FILE_umask = 0;
|
||||
|
||||
+#define WINE_TEMPLINK P_tmpdir"/winelink.XXXXXX"
|
||||
#define SECSPERDAY 86400
|
||||
#define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)SECSPERDAY)
|
||||
|
||||
@@ -1470,6 +1472,76 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Retrieve the unix name corresponding to a file handle, remove that directory, and then symlink the
|
||||
+ * requested directory to the location of the old directory.
|
||||
+ */
|
||||
+NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
|
||||
+{
|
||||
+ int dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
|
||||
+ int offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
|
||||
+ WCHAR *dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
|
||||
+ char tmplink[] = WINE_TEMPLINK;
|
||||
+ ANSI_STRING unix_src, unix_dest;
|
||||
+ BOOL dest_allocated = FALSE;
|
||||
+ int dest_fd, needs_close;
|
||||
+ UNICODE_STRING nt_dest;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
|
||||
+ return status;
|
||||
+
|
||||
+ if ((status = server_get_unix_name( handle, &unix_src )))
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ nt_dest.Buffer = dest;
|
||||
+ nt_dest.Length = dest_len;
|
||||
+ if ((status = wine_nt_to_unix_file_name( &nt_dest, &unix_dest, FILE_OPEN, FALSE )))
|
||||
+ goto cleanup;
|
||||
+ dest_allocated = TRUE;
|
||||
+
|
||||
+ TRACE("Linking %s to %s\n", unix_src.Buffer, unix_dest.Buffer);
|
||||
+
|
||||
+ /* Produce the link in a temporary location */
|
||||
+ while(1)
|
||||
+ {
|
||||
+ int fd;
|
||||
+
|
||||
+ memcpy( tmplink, WINE_TEMPLINK, sizeof(tmplink) );
|
||||
+ fd = mkstemps( tmplink, 0 );
|
||||
+ if (fd == -1) break;
|
||||
+ if (!unlink( tmplink ))
|
||||
+ {
|
||||
+ if (!symlink( unix_dest.Buffer, tmplink ))
|
||||
+ break;
|
||||
+ }
|
||||
+ close(fd);
|
||||
+ }
|
||||
+ /* Atomically move the link into position */
|
||||
+ if (rename( tmplink, unix_src.Buffer ))
|
||||
+ {
|
||||
+ unlink( tmplink );
|
||||
+ FIXME("Atomic replace of directory with symbolic link unsupported on this system, may result in race condition.\n");
|
||||
+ if (rmdir( unix_src.Buffer ) < 0)
|
||||
+ {
|
||||
+ status = FILE_GetNtStatus();
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ if (symlink( unix_dest.Buffer, unix_src.Buffer ) < 0)
|
||||
+ {
|
||||
+ status = FILE_GetNtStatus();
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ }
|
||||
+ status = STATUS_SUCCESS;
|
||||
+
|
||||
+cleanup:
|
||||
+ if (dest_allocated) RtlFreeAnsiString( &unix_dest );
|
||||
+ if (needs_close) close( dest_fd );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/**************************************************************************
|
||||
* NtFsControlFile [NTDLL.@]
|
||||
* ZwFsControlFile [NTDLL.@]
|
||||
@@ -1617,6 +1689,23 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
|
||||
}
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ case FSCTL_SET_REPARSE_POINT:
|
||||
+ {
|
||||
+ REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
|
||||
+
|
||||
+ switch(buffer->ReparseTag)
|
||||
+ {
|
||||
+ case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
+ status = FILE_CreateSymlink( handle, buffer );
|
||||
+ break;
|
||||
+ default:
|
||||
+ FIXME("stub: FSCTL_SET_REPARSE_POINT(%x)\n", buffer->ReparseTag);
|
||||
+ status = STATUS_NOT_IMPLEMENTED;
|
||||
+ break;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
case FSCTL_PIPE_LISTEN:
|
||||
case FSCTL_PIPE_WAIT:
|
||||
default:
|
||||
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
|
||||
index 695f034..127681a 100644
|
||||
--- a/dlls/ntdll/tests/file.c
|
||||
+++ b/dlls/ntdll/tests/file.c
|
||||
@@ -37,6 +37,7 @@
|
||||
#include "winternl.h"
|
||||
#include "winuser.h"
|
||||
#include "winioctl.h"
|
||||
+#include "ntifs.h"
|
||||
|
||||
#ifndef IO_COMPLETION_ALL_ACCESS
|
||||
#define IO_COMPLETION_ALL_ACCESS 0x001F0003
|
||||
@@ -2672,6 +2673,98 @@ todo_wine
|
||||
CloseHandle(hfile);
|
||||
}
|
||||
|
||||
+static INT build_reparse_buffer(WCHAR *filename, REPARSE_DATA_BUFFER **pbuffer)
|
||||
+{
|
||||
+ REPARSE_DATA_BUFFER *buffer;
|
||||
+ INT buffer_len, string_len;
|
||||
+ WCHAR *dest;
|
||||
+
|
||||
+ string_len = (lstrlenW(filename)+1)*sizeof(WCHAR);
|
||||
+ buffer_len = FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[1]) + string_len;
|
||||
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
|
||||
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||
+ buffer->ReparseDataLength = sizeof(buffer->MountPointReparseBuffer) + string_len;
|
||||
+ buffer->MountPointReparseBuffer.SubstituteNameLength = string_len - sizeof(WCHAR);
|
||||
+ buffer->MountPointReparseBuffer.PrintNameOffset = string_len;
|
||||
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[0];
|
||||
+ memcpy(dest, filename, string_len);
|
||||
+ *pbuffer = buffer;
|
||||
+ return buffer_len;
|
||||
+}
|
||||
+
|
||||
+static void test_junction_points(void)
|
||||
+{
|
||||
+ static const WCHAR junctionW[] = {'\\','j','u','n','c','t','i','o','n',0};
|
||||
+ WCHAR path[MAX_PATH], junction_path[MAX_PATH], target_path[MAX_PATH];
|
||||
+ static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
|
||||
+ static const WCHAR fooW[] = {'f','o','o',0};
|
||||
+ static WCHAR volW[] = {'c',':','\\',0};
|
||||
+ static const WCHAR dotW[] = {'.',0};
|
||||
+ REPARSE_DATA_BUFFER *buffer = NULL;
|
||||
+ DWORD dwret, dwLen, dwFlags;
|
||||
+ UNICODE_STRING nameW;
|
||||
+ HANDLE hJunction;
|
||||
+ INT buffer_len;
|
||||
+ BOOL bret;
|
||||
+
|
||||
+ /* Create a temporary folder for the junction point tests */
|
||||
+ GetTempFileNameW(dotW, fooW, 0, path);
|
||||
+ DeleteFileW(path);
|
||||
+ if (!CreateDirectoryW(path, NULL))
|
||||
+ {
|
||||
+ win_skip("Unable to create a temporary junction point directory.\n");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Check that the volume this folder is located on supports junction points */
|
||||
+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL);
|
||||
+ volW[0] = nameW.Buffer[4];
|
||||
+ pRtlFreeUnicodeString( &nameW );
|
||||
+ GetVolumeInformationW(volW, 0, 0, 0, &dwLen, &dwFlags, 0, 0);
|
||||
+ if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS))
|
||||
+ {
|
||||
+ skip("File system does not support junction points.\n");
|
||||
+ RemoveDirectoryW(path);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ /* Create the folder to be replaced by a junction point */
|
||||
+ lstrcpyW(junction_path, path);
|
||||
+ lstrcatW(junction_path, junctionW);
|
||||
+ bret = CreateDirectoryW(junction_path, NULL);
|
||||
+ ok(bret, "Failed to create junction point directory.\n");
|
||||
+
|
||||
+ /* Create a destination folder for the junction point to target */
|
||||
+ lstrcpyW(target_path, path);
|
||||
+ lstrcatW(target_path, targetW);
|
||||
+ bret = CreateDirectoryW(target_path, NULL);
|
||||
+ ok(bret, "Failed to create junction point target directory.\n");
|
||||
+ pRtlDosPathNameToNtPathName_U(target_path, &nameW, NULL, NULL);
|
||||
+
|
||||
+ /* Create the junction point */
|
||||
+ hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
|
||||
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
|
||||
+ if (hJunction == INVALID_HANDLE_VALUE)
|
||||
+ {
|
||||
+ win_skip("Failed to open junction point directory handle (0x%x).\n", GetLastError());
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
|
||||
+ bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
|
||||
+ ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
|
||||
+ CloseHandle(hJunction);
|
||||
+
|
||||
+cleanup:
|
||||
+ /* Cleanup */
|
||||
+ pRtlFreeUnicodeString( &nameW );
|
||||
+ HeapFree(GetProcessHeap(), 0, buffer);
|
||||
+ bret = RemoveDirectoryW(junction_path);
|
||||
+ ok(bret, "Failed to remove temporary junction point directory!\n");
|
||||
+ bret = RemoveDirectoryW(target_path);
|
||||
+ ok(bret, "Failed to remove temporary target directory!\n");
|
||||
+ RemoveDirectoryW(path);
|
||||
+}
|
||||
+
|
||||
START_TEST(file)
|
||||
{
|
||||
HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
|
||||
@@ -2725,4 +2818,5 @@ START_TEST(file)
|
||||
test_file_disposition_information();
|
||||
test_query_volume_information_file();
|
||||
test_query_attribute_information_file();
|
||||
+ test_junction_points();
|
||||
}
|
||||
diff --git a/include/ntifs.h b/include/ntifs.h
|
||||
new file mode 100644
|
||||
index 0000000..db07c28
|
||||
--- /dev/null
|
||||
+++ b/include/ntifs.h
|
||||
@@ -0,0 +1,52 @@
|
||||
+/*
|
||||
+ * Win32 definitions for Windows NT
|
||||
+ *
|
||||
+ * Copyright 2012 Erich Hoover
|
||||
+ *
|
||||
+ * This library is free software; you can redistribute it and/or
|
||||
+ * modify it under the terms of the GNU Lesser General Public
|
||||
+ * License as published by the Free Software Foundation; either
|
||||
+ * version 2.1 of the License, or (at your option) any later version.
|
||||
+ *
|
||||
+ * This library is distributed in the hope that it will be useful,
|
||||
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
+ * Lesser General Public License for more details.
|
||||
+ *
|
||||
+ * You should have received a copy of the GNU Lesser General Public
|
||||
+ * License along with this library; if not, write to the Free Software
|
||||
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
||||
+ */
|
||||
+
|
||||
+#ifndef __WINE_NTIFS_H
|
||||
+#define __WINE_NTIFS_H
|
||||
+
|
||||
+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 IO_REPARSE_TAG_MOUNT_POINT 0xa0000003
|
||||
+
|
||||
+#endif /* __WINE_NTIFS_H */
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -0,0 +1,128 @@
|
||||
From c191da3e2cf2136800fbf0658ced3a3534280806 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 20:57:57 -0700
|
||||
Subject: ntdll: Add support for reading junction points.
|
||||
|
||||
---
|
||||
dlls/ntdll/file.c | 63 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
dlls/ntdll/tests/file.c | 14 ++++++++++-
|
||||
2 files changed, 76 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
|
||||
index 7164d1e..56e0ef6 100644
|
||||
--- a/dlls/ntdll/file.c
|
||||
+++ b/dlls/ntdll/file.c
|
||||
@@ -1542,6 +1542,60 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Retrieve the unix name corresponding to a file handle and use that to find the destination of the symlink
|
||||
+ * corresponding to that file handle.
|
||||
+ */
|
||||
+NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
|
||||
+{
|
||||
+ ANSI_STRING unix_src, unix_dest;
|
||||
+ BOOL dest_allocated = FALSE;
|
||||
+ int dest_fd, needs_close;
|
||||
+ UNICODE_STRING nt_dest;
|
||||
+ NTSTATUS status;
|
||||
+ VOID *dest_name;
|
||||
+ ssize_t ret;
|
||||
+
|
||||
+ if ((status = server_get_unix_fd( handle, FILE_ANY_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
|
||||
+ return status;
|
||||
+
|
||||
+ if ((status = server_get_unix_name( handle, &unix_src )))
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ unix_dest.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, PATH_MAX );
|
||||
+ unix_dest.MaximumLength = PATH_MAX;
|
||||
+ dest_allocated = TRUE;
|
||||
+ ret = readlink( unix_src.Buffer, unix_dest.Buffer, unix_dest.MaximumLength );
|
||||
+ if (ret < 0)
|
||||
+ {
|
||||
+ status = FILE_GetNtStatus();
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ unix_dest.Length = ret;
|
||||
+
|
||||
+ if ((status = wine_unix_to_nt_file_name( &unix_dest, &nt_dest )))
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ if (nt_dest.Length > buffer->MountPointReparseBuffer.SubstituteNameLength)
|
||||
+ {
|
||||
+ status = STATUS_BUFFER_TOO_SMALL;
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+
|
||||
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||
+ buffer->MountPointReparseBuffer.SubstituteNameLength = nt_dest.Length;
|
||||
+ buffer->MountPointReparseBuffer.SubstituteNameOffset = 0;
|
||||
+ dest_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset];
|
||||
+ memcpy( dest_name, nt_dest.Buffer, nt_dest.Length );
|
||||
+ status = STATUS_SUCCESS;
|
||||
+
|
||||
+cleanup:
|
||||
+ if (dest_allocated) RtlFreeAnsiString( &unix_dest );
|
||||
+ if (needs_close) close( dest_fd );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/**************************************************************************
|
||||
* NtFsControlFile [NTDLL.@]
|
||||
* ZwFsControlFile [NTDLL.@]
|
||||
@@ -1690,6 +1744,15 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
|
||||
break;
|
||||
}
|
||||
|
||||
+ case FSCTL_GET_REPARSE_POINT:
|
||||
+ {
|
||||
+ REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
|
||||
+ DWORD max_length = out_size-FIELD_OFFSET(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[1]);
|
||||
+
|
||||
+ buffer->MountPointReparseBuffer.SubstituteNameLength = max_length;
|
||||
+ status = FILE_GetSymlink( handle, buffer );
|
||||
+ break;
|
||||
+ }
|
||||
case FSCTL_SET_REPARSE_POINT:
|
||||
{
|
||||
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
|
||||
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
|
||||
index 127681a..595276a 100644
|
||||
--- a/dlls/ntdll/tests/file.c
|
||||
+++ b/dlls/ntdll/tests/file.c
|
||||
@@ -2702,9 +2702,10 @@ static void test_junction_points(void)
|
||||
static const WCHAR dotW[] = {'.',0};
|
||||
REPARSE_DATA_BUFFER *buffer = NULL;
|
||||
DWORD dwret, dwLen, dwFlags;
|
||||
+ INT buffer_len, string_len;
|
||||
UNICODE_STRING nameW;
|
||||
HANDLE hJunction;
|
||||
- INT buffer_len;
|
||||
+ WCHAR *dest;
|
||||
BOOL bret;
|
||||
|
||||
/* Create a temporary folder for the junction point tests */
|
||||
@@ -2752,6 +2753,17 @@ static void test_junction_points(void)
|
||||
buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
|
||||
bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
|
||||
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
|
||||
+
|
||||
+ /* Read back the junction point */
|
||||
+ HeapFree(GetProcessHeap(), 0, buffer);
|
||||
+ buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR);
|
||||
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
|
||||
+ bret = DeviceIoControl(hJunction, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
|
||||
+ string_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
|
||||
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
|
||||
+ ok(bret, "Failed to read junction point!\n");
|
||||
+ ok((memcmp(dest, nameW.Buffer, string_len) == 0), "Junction point destination does not match ('%s' != '%s')!\n",
|
||||
+ wine_dbgstr_w(dest), wine_dbgstr_w(nameW.Buffer));
|
||||
CloseHandle(hJunction);
|
||||
|
||||
cleanup:
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -0,0 +1,159 @@
|
||||
From 9a592e9dd065355f785e997fb72ee5a586665dc0 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:00:21 -0700
|
||||
Subject: ntdll: Add support for deleting junction points.
|
||||
|
||||
---
|
||||
dlls/ntdll/file.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++
|
||||
dlls/ntdll/tests/file.c | 23 +++++++++++++++++++++
|
||||
include/ntifs.h | 11 ++++++++++
|
||||
3 files changed, 85 insertions(+)
|
||||
|
||||
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
|
||||
index 56e0ef6..396bdf9 100644
|
||||
--- a/dlls/ntdll/file.c
|
||||
+++ b/dlls/ntdll/file.c
|
||||
@@ -1596,6 +1596,41 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Retrieve the unix name corresponding to a file handle, remove that symlink, and then recreate
|
||||
+ * a directory at the location of the old filename.
|
||||
+ */
|
||||
+NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
|
||||
+{
|
||||
+ int dest_fd, needs_close;
|
||||
+ ANSI_STRING unix_name;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
|
||||
+ return status;
|
||||
+
|
||||
+ if ((status = server_get_unix_name( handle, &unix_name )))
|
||||
+ goto cleanup;
|
||||
+
|
||||
+ TRACE("Deleting symlink %s\n", unix_name.Buffer);
|
||||
+ if (unlink( unix_name.Buffer ) < 0)
|
||||
+ {
|
||||
+ status = FILE_GetNtStatus();
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ if (mkdir( unix_name.Buffer, 0775 ) < 0)
|
||||
+ {
|
||||
+ status = FILE_GetNtStatus();
|
||||
+ goto cleanup;
|
||||
+ }
|
||||
+ status = STATUS_SUCCESS;
|
||||
+
|
||||
+cleanup:
|
||||
+ if (needs_close) close( dest_fd );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/**************************************************************************
|
||||
* NtFsControlFile [NTDLL.@]
|
||||
* ZwFsControlFile [NTDLL.@]
|
||||
@@ -1744,6 +1779,22 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
|
||||
break;
|
||||
}
|
||||
|
||||
+ case FSCTL_DELETE_REPARSE_POINT:
|
||||
+ {
|
||||
+ REPARSE_GUID_DATA_BUFFER *buffer = (REPARSE_GUID_DATA_BUFFER *)in_buffer;
|
||||
+
|
||||
+ switch(buffer->ReparseTag)
|
||||
+ {
|
||||
+ case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
+ status = FILE_RemoveSymlink( handle, buffer );
|
||||
+ break;
|
||||
+ default:
|
||||
+ FIXME("stub: FSCTL_DELETE_REPARSE_POINT(%x)\n", buffer->ReparseTag);
|
||||
+ status = STATUS_NOT_IMPLEMENTED;
|
||||
+ break;
|
||||
+ }
|
||||
+ break;
|
||||
+ }
|
||||
case FSCTL_GET_REPARSE_POINT:
|
||||
{
|
||||
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
|
||||
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
|
||||
index 595276a..d3c6cf0 100644
|
||||
--- a/dlls/ntdll/tests/file.c
|
||||
+++ b/dlls/ntdll/tests/file.c
|
||||
@@ -2697,12 +2697,15 @@ static void test_junction_points(void)
|
||||
static const WCHAR junctionW[] = {'\\','j','u','n','c','t','i','o','n',0};
|
||||
WCHAR path[MAX_PATH], junction_path[MAX_PATH], target_path[MAX_PATH];
|
||||
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
|
||||
+ FILE_BASIC_INFORMATION old_attrib, new_attrib;
|
||||
static const WCHAR fooW[] = {'f','o','o',0};
|
||||
static WCHAR volW[] = {'c',':','\\',0};
|
||||
+ REPARSE_GUID_DATA_BUFFER guid_buffer;
|
||||
static const WCHAR dotW[] = {'.',0};
|
||||
REPARSE_DATA_BUFFER *buffer = NULL;
|
||||
DWORD dwret, dwLen, dwFlags;
|
||||
INT buffer_len, string_len;
|
||||
+ IO_STATUS_BLOCK iosb;
|
||||
UNICODE_STRING nameW;
|
||||
HANDLE hJunction;
|
||||
WCHAR *dest;
|
||||
@@ -2750,6 +2753,8 @@ static void test_junction_points(void)
|
||||
win_skip("Failed to open junction point directory handle (0x%x).\n", GetLastError());
|
||||
goto cleanup;
|
||||
}
|
||||
+ dwret = NtQueryInformationFile(hJunction, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
|
||||
+ ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%x).\n", dwret);
|
||||
buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
|
||||
bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
|
||||
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
|
||||
@@ -2764,6 +2769,24 @@ static void test_junction_points(void)
|
||||
ok(bret, "Failed to read junction point!\n");
|
||||
ok((memcmp(dest, nameW.Buffer, string_len) == 0), "Junction point destination does not match ('%s' != '%s')!\n",
|
||||
wine_dbgstr_w(dest), wine_dbgstr_w(nameW.Buffer));
|
||||
+
|
||||
+ /* Delete the junction point */
|
||||
+ memset(&old_attrib, 0x00, sizeof(old_attrib));
|
||||
+ old_attrib.LastAccessTime.QuadPart = 0x200deadcafebeef;
|
||||
+ dwret = NtSetInformationFile(hJunction, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
|
||||
+ ok(dwret == STATUS_SUCCESS, "Failed to set junction point folder's attributes (0x%x).\n", dwret);
|
||||
+ memset(&guid_buffer, 0x00, sizeof(guid_buffer));
|
||||
+ guid_buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
|
||||
+ bret = DeviceIoControl(hJunction, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer,
|
||||
+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0);
|
||||
+ ok(bret, "Failed to delete junction point! (0x%x)\n", GetLastError());
|
||||
+ memset(&new_attrib, 0x00, sizeof(new_attrib));
|
||||
+ dwret = NtQueryInformationFile(hJunction, &iosb, &new_attrib, sizeof(new_attrib), FileBasicInformation);
|
||||
+ ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%x).\n", dwret);
|
||||
+ /* conversion bug: we see 0x1c9c380deadbee6 on Wine */
|
||||
+ todo_wine ok(old_attrib.LastAccessTime.QuadPart == new_attrib.LastAccessTime.QuadPart,
|
||||
+ "Junction point folder's access time does not match (0x%llx != 0x%llx).\n",
|
||||
+ new_attrib.LastAccessTime.QuadPart, old_attrib.LastAccessTime.QuadPart);
|
||||
CloseHandle(hJunction);
|
||||
|
||||
cleanup:
|
||||
diff --git a/include/ntifs.h b/include/ntifs.h
|
||||
index db07c28..cb8638b 100644
|
||||
--- a/include/ntifs.h
|
||||
+++ b/include/ntifs.h
|
||||
@@ -47,6 +47,17 @@ typedef struct _REPARSE_DATA_BUFFER {
|
||||
};
|
||||
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
|
||||
|
||||
+typedef struct _REPARSE_GUID_DATA_BUFFER {
|
||||
+ DWORD ReparseTag;
|
||||
+ WORD ReparseDataLength;
|
||||
+ WORD Reserved;
|
||||
+ GUID ReparseGuid;
|
||||
+ struct {
|
||||
+ BYTE DataBuffer[1];
|
||||
+ } GenericReparseBuffer;
|
||||
+} REPARSE_GUID_DATA_BUFFER, *PREPARSE_GUID_DATA_BUFFER;
|
||||
+
|
||||
#define IO_REPARSE_TAG_MOUNT_POINT 0xa0000003
|
||||
+#define REPARSE_GUID_DATA_BUFFER_HEADER_SIZE FIELD_OFFSET(REPARSE_GUID_DATA_BUFFER, GenericReparseBuffer)
|
||||
|
||||
#endif /* __WINE_NTIFS_H */
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -0,0 +1,57 @@
|
||||
From f35e4dc0c96de3e9fbeb4ff1bdefc9db7c7d56d8 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:01:25 -0700
|
||||
Subject: ntdll: Advertise that a file is a junction point.
|
||||
|
||||
---
|
||||
dlls/ntdll/file.c | 7 ++++++-
|
||||
dlls/ntdll/tests/file.c | 5 +++++
|
||||
2 files changed, 11 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
|
||||
index 396bdf9..b4e06d1 100644
|
||||
--- a/dlls/ntdll/file.c
|
||||
+++ b/dlls/ntdll/file.c
|
||||
@@ -1988,10 +1988,11 @@ NTSTATUS fill_stat_info( const struct stat *st, void *ptr, FILE_INFORMATION_CLAS
|
||||
|
||||
get_file_times( st, &info->LastWriteTime, &info->ChangeTime,
|
||||
&info->LastAccessTime, &info->CreationTime );
|
||||
- if (S_ISDIR(st->st_mode)) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
||||
+ if (st->st_mode & S_IFDIR) info->FileAttributes = FILE_ATTRIBUTE_DIRECTORY;
|
||||
else info->FileAttributes = FILE_ATTRIBUTE_ARCHIVE;
|
||||
if (!(st->st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
|
||||
info->FileAttributes |= FILE_ATTRIBUTE_READONLY;
|
||||
+ if ((st->st_mode & S_IFLNK) == S_IFLNK) info->FileAttributes |= FILE_ATTRIBUTE_REPARSE_POINT;
|
||||
}
|
||||
break;
|
||||
case FileStandardInformation:
|
||||
@@ -2657,6 +2658,10 @@ NTSTATUS WINAPI NtQueryAttributesFile( const OBJECT_ATTRIBUTES *attr, FILE_BASIC
|
||||
status = STATUS_INVALID_INFO_CLASS;
|
||||
else
|
||||
{
|
||||
+ struct stat lst;
|
||||
+
|
||||
+ if (lstat( unix_name.Buffer, &lst ) != -1)
|
||||
+ st.st_mode |= (lst.st_mode & S_IFLNK);
|
||||
status = fill_stat_info( &st, info, FileBasicInformation );
|
||||
if (DIR_is_hidden_file( attr->ObjectName ))
|
||||
info->FileAttributes |= FILE_ATTRIBUTE_HIDDEN;
|
||||
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
|
||||
index d3c6cf0..c75ba47 100644
|
||||
--- a/dlls/ntdll/tests/file.c
|
||||
+++ b/dlls/ntdll/tests/file.c
|
||||
@@ -2759,6 +2759,11 @@ static void test_junction_points(void)
|
||||
bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
|
||||
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
|
||||
|
||||
+ /* Check the file attributes of the junction point */
|
||||
+ dwret = GetFileAttributesW(junction_path);
|
||||
+ ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
|
||||
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: %d)\n", dwret);
|
||||
+
|
||||
/* Read back the junction point */
|
||||
HeapFree(GetProcessHeap(), 0, buffer);
|
||||
buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR);
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -0,0 +1,103 @@
|
||||
From e6a876330230784a2b2be6588b94e5555de169da Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:02:11 -0700
|
||||
Subject: kernel32,ntdll: Add support for deleting junction points with
|
||||
RemoveDirectory.
|
||||
|
||||
---
|
||||
dlls/kernel32/path.c | 12 ++++++++++--
|
||||
dlls/ntdll/tests/file.c | 34 +++++++++++++++++++++++++++++++++-
|
||||
2 files changed, 43 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c
|
||||
index 09fb04b..c328cc0 100644
|
||||
--- a/dlls/kernel32/path.c
|
||||
+++ b/dlls/kernel32/path.c
|
||||
@@ -1587,6 +1587,7 @@ BOOL WINAPI CreateDirectoryExW( LPCWSTR template, LPCWSTR path, LPSECURITY_ATTRI
|
||||
*/
|
||||
BOOL WINAPI RemoveDirectoryW( LPCWSTR path )
|
||||
{
|
||||
+ FILE_BASIC_INFORMATION info;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
UNICODE_STRING nt_name;
|
||||
ANSI_STRING unix_name;
|
||||
@@ -1614,15 +1615,22 @@ BOOL WINAPI RemoveDirectoryW( LPCWSTR path )
|
||||
FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
|
||||
if (status == STATUS_SUCCESS)
|
||||
status = wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, FALSE );
|
||||
- RtlFreeUnicodeString( &nt_name );
|
||||
|
||||
if (status != STATUS_SUCCESS)
|
||||
{
|
||||
+ RtlFreeUnicodeString( &nt_name );
|
||||
SetLastError( RtlNtStatusToDosError(status) );
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
- if (!(ret = (rmdir( unix_name.Buffer ) != -1))) FILE_SetDosError();
|
||||
+ status = NtQueryAttributesFile( &attr, &info );
|
||||
+ RtlFreeUnicodeString( &nt_name );
|
||||
+ if ((info.FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) && (info.FileAttributes & FILE_ATTRIBUTE_DIRECTORY))
|
||||
+ ret = (unlink( unix_name.Buffer ) != -1);
|
||||
+ else
|
||||
+ ret = (rmdir( unix_name.Buffer ) != -1);
|
||||
+ if (!ret) FILE_SetDosError();
|
||||
+
|
||||
RtlFreeAnsiString( &unix_name );
|
||||
NtClose( handle );
|
||||
return ret;
|
||||
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
|
||||
index c75ba47..f94a61c 100644
|
||||
--- a/dlls/ntdll/tests/file.c
|
||||
+++ b/dlls/ntdll/tests/file.c
|
||||
@@ -2703,7 +2703,7 @@ static void test_junction_points(void)
|
||||
REPARSE_GUID_DATA_BUFFER guid_buffer;
|
||||
static const WCHAR dotW[] = {'.',0};
|
||||
REPARSE_DATA_BUFFER *buffer = NULL;
|
||||
- DWORD dwret, dwLen, dwFlags;
|
||||
+ DWORD dwret, dwLen, dwFlags, err;
|
||||
INT buffer_len, string_len;
|
||||
IO_STATUS_BLOCK iosb;
|
||||
UNICODE_STRING nameW;
|
||||
@@ -2794,6 +2794,38 @@ static void test_junction_points(void)
|
||||
new_attrib.LastAccessTime.QuadPart, old_attrib.LastAccessTime.QuadPart);
|
||||
CloseHandle(hJunction);
|
||||
|
||||
+ /* Check deleting a junction point as if it were a directory */
|
||||
+ HeapFree(GetProcessHeap(), 0, buffer);
|
||||
+ hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
|
||||
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
|
||||
+ buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
|
||||
+ bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
|
||||
+ ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
|
||||
+ CloseHandle(hJunction);
|
||||
+ bret = RemoveDirectoryW(junction_path);
|
||||
+ ok(bret, "Failed to delete junction point as directory!\n");
|
||||
+ dwret = GetFileAttributesW(junction_path);
|
||||
+ ok(dwret == (DWORD)~0, "Junction point still exists (attributes: 0x%x)!\n", dwret);
|
||||
+
|
||||
+ /* Check deleting a junction point as if it were a file */
|
||||
+ HeapFree(GetProcessHeap(), 0, buffer);
|
||||
+ bret = CreateDirectoryW(junction_path, NULL);
|
||||
+ ok(bret, "Failed to create junction point target directory.\n");
|
||||
+ hJunction = CreateFileW(junction_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
|
||||
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
|
||||
+ buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
|
||||
+ bret = DeviceIoControl(hJunction, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
|
||||
+ ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
|
||||
+ CloseHandle(hJunction);
|
||||
+ bret = DeleteFileW(junction_path);
|
||||
+ ok(!bret, "Succeeded in deleting junction point as file!\n");
|
||||
+ err = GetLastError();
|
||||
+ ok(err == ERROR_ACCESS_DENIED, "Expected last error 0x%x for DeleteFile on junction point (actually 0x%x)!\n",
|
||||
+ ERROR_ACCESS_DENIED, err);
|
||||
+ dwret = GetFileAttributesW(junction_path);
|
||||
+ ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
|
||||
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%x)\n", dwret);
|
||||
+
|
||||
cleanup:
|
||||
/* Cleanup */
|
||||
pRtlFreeUnicodeString( &nameW );
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -0,0 +1,26 @@
|
||||
From cc928f1a52250242fd9e3dec8cd159216535f08f Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:03:47 -0700
|
||||
Subject: kernel32: Advertise junction point support.
|
||||
|
||||
---
|
||||
dlls/kernel32/volume.c | 3 ++-
|
||||
1 file changed, 2 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c
|
||||
index 1509d73..1e3ff7b 100644
|
||||
--- a/dlls/kernel32/volume.c
|
||||
+++ b/dlls/kernel32/volume.c
|
||||
@@ -853,7 +853,8 @@ fill_fs_info: /* now fill in the information that depends on the file system ty
|
||||
default:
|
||||
if (fsname) lstrcpynW( fsname, ntfsW, fsname_len );
|
||||
if (filename_len) *filename_len = 255;
|
||||
- if (flags) *flags = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS;
|
||||
+ if (flags) *flags = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS
|
||||
+ | FILE_SUPPORTS_REPARSE_POINTS;
|
||||
break;
|
||||
}
|
||||
ret = TRUE;
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -0,0 +1,34 @@
|
||||
From f70c0d8ae00629148df5e16efb30960704b8bbf8 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:06:24 -0700
|
||||
Subject: ntdll/tests: Add test for deleting junction point target.
|
||||
|
||||
---
|
||||
dlls/ntdll/tests/file.c | 11 +++++++++++
|
||||
1 file changed, 11 insertions(+)
|
||||
|
||||
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
|
||||
index f94a61c..ffb9ff2 100644
|
||||
--- a/dlls/ntdll/tests/file.c
|
||||
+++ b/dlls/ntdll/tests/file.c
|
||||
@@ -2826,6 +2826,17 @@ static void test_junction_points(void)
|
||||
ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
|
||||
ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%x)\n", dwret);
|
||||
|
||||
+ /* Test deleting a junction point's target */
|
||||
+ dwret = GetFileAttributesW(junction_path);
|
||||
+ ok(dwret == 0x410 || broken(dwret == 0x430) /* win2k */,
|
||||
+ "Unexpected junction point attributes (0x%x != 0x410)!\n", dwret);
|
||||
+ bret = RemoveDirectoryW(target_path);
|
||||
+ ok(bret, "Failed to delete junction point target!\n");
|
||||
+ ok(dwret == 0x410 || broken(dwret == 0x430) /* win2k */,
|
||||
+ "Unexpected junction point attributes (0x%x != 0x410)!\n", dwret);
|
||||
+ bret = CreateDirectoryW(target_path, NULL);
|
||||
+ ok(bret, "Failed to create junction point target directory.\n");
|
||||
+
|
||||
cleanup:
|
||||
/* Cleanup */
|
||||
pRtlFreeUnicodeString( &nameW );
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -0,0 +1,69 @@
|
||||
From f8bf15e30d5e0b9e30ceb644c07449b7782efb72 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Thu, 16 Jan 2014 21:07:43 -0700
|
||||
Subject: ntdll: Use relative paths for creating links.
|
||||
|
||||
---
|
||||
dlls/ntdll/file.c | 39 +++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 39 insertions(+)
|
||||
|
||||
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
|
||||
index b4e06d1..6907b2b 100644
|
||||
--- a/dlls/ntdll/file.c
|
||||
+++ b/dlls/ntdll/file.c
|
||||
@@ -1487,6 +1487,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
|
||||
int dest_fd, needs_close;
|
||||
UNICODE_STRING nt_dest;
|
||||
NTSTATUS status;
|
||||
+ char *p;
|
||||
|
||||
if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
|
||||
return status;
|
||||
@@ -1500,6 +1501,44 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
|
||||
goto cleanup;
|
||||
dest_allocated = TRUE;
|
||||
|
||||
+ p = strstr(unix_src.Buffer, "/dosdevices/");
|
||||
+ if (p)
|
||||
+ {
|
||||
+ int count = -1; /* do not count the slash at the end of dosdevices or the last directory */
|
||||
+
|
||||
+ p += 11; /* strlen("/dosdevices") */
|
||||
+ do
|
||||
+ {
|
||||
+ p++; /* skip the slash */
|
||||
+ count++;
|
||||
+ p = strchr(p, '/');
|
||||
+ } while(p);
|
||||
+ FIXME("found %d directories up.\n", count);
|
||||
+ p = strstr(unix_dest.Buffer, "/dosdevices/");
|
||||
+ if (p)
|
||||
+ {
|
||||
+ ANSI_STRING tmp;
|
||||
+ int dest_len;
|
||||
+ char *d;
|
||||
+
|
||||
+ p += 12; /* strlen("/dosdevices/") */
|
||||
+ dest_len = unix_dest.Length - (p-unix_dest.Buffer) + 1;
|
||||
+ tmp.Length = dest_len + 3*count; /* strlen("../") = 3 */
|
||||
+ tmp.Buffer = RtlAllocateHeap(GetProcessHeap(), 0, tmp.Length);
|
||||
+ d = tmp.Buffer;
|
||||
+ for(; count > 0; count--)
|
||||
+ {
|
||||
+ (d++)[0] = '.';
|
||||
+ (d++)[0] = '.';
|
||||
+ (d++)[0] = '/';
|
||||
+ }
|
||||
+ memcpy(d, p, dest_len);
|
||||
+ RtlFreeAnsiString( &unix_dest );
|
||||
+ unix_dest.Length = tmp.Length;
|
||||
+ unix_dest.Buffer = tmp.Buffer;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
TRACE("Linking %s to %s\n", unix_src.Buffer, unix_dest.Buffer);
|
||||
|
||||
/* Produce the link in a temporary location */
|
||||
--
|
||||
1.7.9.5
|
||||
|
@ -0,0 +1,4 @@
|
||||
Revision: 1
|
||||
Author: Erich E. Hoover
|
||||
Title: Support for junction points/reparse points.
|
||||
|
@ -33,7 +33,7 @@ diff --git a/libs/wine/config.c b/libs/wine/config.c
|
||||
index a273502..5fa0cd5 100644
|
||||
--- a/libs/wine/config.c
|
||||
+++ b/libs/wine/config.c
|
||||
@@ -478,6 +478,34 @@ const char *wine_get_version(void)
|
||||
@@ -478,6 +478,35 @@ const char *wine_get_version(void)
|
||||
return PACKAGE_VERSION;
|
||||
}
|
||||
|
||||
@ -50,6 +50,7 @@ index a273502..5fa0cd5 100644
|
||||
+ { "cbe240e8-2c58-430a-b61c-7fbb9d0e1e11:1", "Sebastian Lackner", "Change return value of stub SetNamedPipeHandleState to TRUE." },
|
||||
+ { "00273da7-72f8-4025-9e96-0c2bc95dacdb:2", "Maarten Lankhorst", "Winepulse patches extracted from https://launchpad.net/~mlankhorst/+archive/ppa/+files/wine1.7_1.7.10-0ubuntu1~saucy1.debian.tar.gz." },
|
||||
+ { "29b2af38-7edd-11e3-a08d-0090f5c75ad5:1", "Erich E. Hoover", "Add support for security access parameters for named pipes." },
|
||||
+ { "4cd13e94-7f2d-11e3-b5eb-0090f5c75ad5:1", "Erich E. Hoover", "Support for junction points/reparse points." },
|
||||
+ { "5fb1f5c8-7f17-11e3-9b62-0090f5c75ad5:1", "Erich E. Hoover", "Implement TransmitFile." },
|
||||
+ { "0b21d7ac-0387-4493-aa38-fbafe3e749f5:1", "Michael Müller", "Decrease minimum SetTimer interval from 15 to 5 ms." },
|
||||
+ { "19835498-8d90-4673-867e-2376af4d7c76:1", "Sebastian Lackner", "Allow to set wined3d strictDrawOrdering via environment variable." },
|
||||
|
Loading…
Reference in New Issue
Block a user