ntdll-Junction_Points: Rebase and re-enable.

This commit is contained in:
Zebediah Figura 2020-06-18 20:41:39 -05:00
parent d799e8fd82
commit 8e5546184f
18 changed files with 1041 additions and 852 deletions

View File

@ -1,4 +1,4 @@
From e3e2a837a2dd411b3e265581388fba1050e08c53 Mon Sep 17 00:00:00 2001
From f886d8af24ba52e791535c7a606c4ca97cc5ed8e 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: [PATCH] ntdll: Add support for junction point creation.
@ -6,19 +6,19 @@ Subject: [PATCH] ntdll: Add support for junction point creation.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
configure.ac | 2 +
dlls/ntdll/file.c | 118 ++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/tests/file.c | 101 ++++++++++++++++++++++++++++++++++
dlls/ntdll/unix/file.c | 117 ++++++++++++++++++++++++++++++++++++++++
include/Makefile.in | 1 +
include/ntifs.h | 42 ++++++++++++++
include/wine/port.h | 9 +++
include/ntifs.h | 42 +++++++++++++++
include/wine/port.h | 9 ++++
libs/port/Makefile.in | 1 +
libs/port/renameat2.c | 55 +++++++++++++++++++
8 files changed, 329 insertions(+)
8 files changed, 328 insertions(+)
create mode 100644 include/ntifs.h
create mode 100644 libs/port/renameat2.c
diff --git a/configure.ac b/configure.ac
index 8a76b74e83d..d3bd12a6340 100644
index 9c5f76669df..201ae3c2d98 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2203,6 +2203,8 @@ AC_CHECK_FUNCS(\
@ -30,156 +30,6 @@ index 8a76b74e83d..d3bd12a6340 100644
sched_yield \
select \
setproctitle \
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index b3e881ac3c9..5a4004a61a4 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -21,6 +21,7 @@
#include <stdlib.h>
#include <string.h>
+#include <libgen.h>
#include <stdio.h>
#include <errno.h>
#include <assert.h>
@@ -109,6 +110,7 @@
#include "ddk/ntddser.h"
#define WINE_MOUNTMGR_EXTENSIONS
#include "ddk/mountmgr.h"
+#include "ntifs.h"
WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
@@ -1545,6 +1547,104 @@ 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)
+{
+ BOOL src_allocated = FALSE, dest_allocated = FALSE, tempdir_created = FALSE;
+ int dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ int offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
+ WCHAR *dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
+ char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
+ ANSI_STRING unix_src, unix_dest;
+ char magic_dest[PATH_MAX];
+ int dest_fd, needs_close;
+ UNICODE_STRING nt_dest;
+ NTSTATUS status;
+ int i;
+
+ if ((status = unix_funcs->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;
+ src_allocated = TRUE;
+ nt_dest.Buffer = dest;
+ nt_dest.Length = dest_len;
+ status = wine_nt_to_unix_file_name( &nt_dest, &unix_dest, 0, FALSE );
+ if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
+ goto cleanup;
+ dest_allocated = TRUE;
+
+ TRACE("Linking %s to %s\n", unix_src.Buffer, unix_dest.Buffer);
+
+ /* Encode the reparse tag into the symlink */
+ strcpy( magic_dest, "/" );
+ for (i = 0; i < sizeof(ULONG)*8; i++)
+ {
+ if ((buffer->ReparseTag >> i) & 1)
+ strcat( magic_dest, "." );
+ strcat( magic_dest, "/" );
+ }
+ strcat( magic_dest, unix_dest.Buffer );
+
+ /* Produce the link in a temporary location in the same folder */
+ strcpy( tmpdir, unix_src.Buffer );
+ d = dirname( tmpdir);
+ if (d != tmpdir) strcpy( tmpdir, d );
+ strcat( tmpdir, "/.winelink.XXXXXX" );
+ if (mkdtemp( tmpdir ) == NULL)
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ tempdir_created = TRUE;
+ strcpy( tmplink, tmpdir );
+ strcat( tmplink, "/tmplink" );
+ if (symlink( magic_dest, tmplink ))
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ /* Atomically move the link into position */
+ if (!renameat2( -1, tmplink, -1, unix_src.Buffer, RENAME_EXCHANGE ))
+ {
+ /* success: link and folder have switched locations */
+ rmdir( tmplink ); /* remove the folder (at link location) */
+ }
+ else if (errno == ENOSYS)
+ {
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
+ "using unsafe exchange instead.\n" );
+ if (rmdir( unix_src.Buffer ))
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ if (rename( tmplink, unix_src.Buffer ))
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
+ }
+ }
+ else
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ status = STATUS_SUCCESS;
+
+cleanup:
+ if (tempdir_created) rmdir( tmpdir );
+ if (dest_allocated) RtlFreeAnsiString( &unix_dest );
+ if (src_allocated) RtlFreeAnsiString( &unix_src );
+ if (needs_close) close( dest_fd );
+ return status;
+}
+
+
/**************************************************************************
* NtFsControlFile [NTDLL.@]
* ZwFsControlFile [NTDLL.@]
@@ -1629,6 +1729,24 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
io->Information = 0;
status = STATUS_SUCCESS;
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;
+ }
+
default:
return server_ioctl_file( handle, event, apc, apc_context, io, code,
in_buffer, in_size, out_buffer, out_size );
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 184b7cdad59..8b5ddbb0da1 100644
--- a/dlls/ntdll/tests/file.c
@ -304,6 +154,155 @@ index 184b7cdad59..8b5ddbb0da1 100644
test_flush_buffers_file();
+ test_reparse_points();
}
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index ca6899b50f5..44cb12f90ee 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -32,6 +32,7 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
+#include <libgen.h>
#include <stdarg.h>
#include <string.h>
#include <stdlib.h>
@@ -122,6 +123,7 @@
#include "ddk/wdm.h"
#define WINE_MOUNTMGR_EXTENSIONS
#include "ddk/mountmgr.h"
+#include "ntifs.h"
#include "wine/server.h"
#include "wine/list.h"
#include "wine/debug.h"
@@ -5607,6 +5609,104 @@ static void ignore_server_ioctl_struct_holes( ULONG code, const void *in_buffer,
}
+/*
+ * 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)
+{
+ BOOL src_allocated = FALSE, dest_allocated = FALSE, tempdir_created = FALSE;
+ int dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ int offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
+ WCHAR *dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
+ char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
+ ANSI_STRING unix_src, unix_dest;
+ char magic_dest[PATH_MAX];
+ int dest_fd, needs_close;
+ UNICODE_STRING nt_dest;
+ NTSTATUS status;
+ int i;
+
+ 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;
+ src_allocated = TRUE;
+ nt_dest.Buffer = dest;
+ nt_dest.Length = dest_len;
+ status = nt_to_unix_file_name( &nt_dest, &unix_dest, 0, FALSE );
+ if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
+ goto cleanup;
+ dest_allocated = TRUE;
+
+ TRACE("Linking %s to %s\n", unix_src.Buffer, unix_dest.Buffer);
+
+ /* Encode the reparse tag into the symlink */
+ strcpy( magic_dest, "/" );
+ for (i = 0; i < sizeof(ULONG)*8; i++)
+ {
+ if ((buffer->ReparseTag >> i) & 1)
+ strcat( magic_dest, "." );
+ strcat( magic_dest, "/" );
+ }
+ strcat( magic_dest, unix_dest.Buffer );
+
+ /* Produce the link in a temporary location in the same folder */
+ strcpy( tmpdir, unix_src.Buffer );
+ d = dirname( tmpdir);
+ if (d != tmpdir) strcpy( tmpdir, d );
+ strcat( tmpdir, "/.winelink.XXXXXX" );
+ if (mkdtemp( tmpdir ) == NULL)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ tempdir_created = TRUE;
+ strcpy( tmplink, tmpdir );
+ strcat( tmplink, "/tmplink" );
+ if (symlink( magic_dest, tmplink ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ /* Atomically move the link into position */
+ if (!renameat2( -1, tmplink, -1, unix_src.Buffer, RENAME_EXCHANGE ))
+ {
+ /* success: link and folder have switched locations */
+ rmdir( tmplink ); /* remove the folder (at link location) */
+ }
+ else if (errno == ENOSYS)
+ {
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
+ "using unsafe exchange instead.\n" );
+ if (rmdir( unix_src.Buffer ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if (rename( tmplink, unix_src.Buffer ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
+ }
+ }
+ else
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ status = STATUS_SUCCESS;
+
+cleanup:
+ if (tempdir_created) rmdir( tmpdir );
+ if (dest_allocated) RtlFreeAnsiString( &unix_dest );
+ if (src_allocated) RtlFreeAnsiString( &unix_src );
+ if (needs_close) close( dest_fd );
+ return status;
+}
+
+
/******************************************************************************
* NtFsControlFile (NTDLL.@)
*/
@@ -5671,6 +5771,23 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
io->Information = 0;
status = STATUS_SUCCESS;
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;
+ }
default:
return server_ioctl_file( handle, event, apc, apc_context, io, code,
in_buffer, in_size, out_buffer, out_size );
diff --git a/include/Makefile.in b/include/Makefile.in
index 9f70e72b4c7..1c5c456aa39 100644
--- a/include/Makefile.in

View File

@ -1,19 +1,53 @@
From daf6a4fc8ae19ab9f9df39f958109c09232b5426 Mon Sep 17 00:00:00 2001
From f601df88922fd3719b34376344488fe2a04afe6b 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: [PATCH] ntdll: Add support for reading junction points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 106 ++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/tests/file.c | 14 +++++-
dlls/ntdll/unix/file.c | 106 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 119 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 37dca75651c..5a05217102d 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1763,6 +1763,106 @@ cleanup:
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 8b5ddbb0da1..938ef2026e3 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5008,9 +5008,10 @@ static void test_reparse_points(void)
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags;
+ INT buffer_len, string_len;
UNICODE_STRING nameW;
- INT buffer_len;
HANDLE handle;
+ WCHAR *dest;
BOOL bret;
/* Create a temporary folder for the junction point tests */
@@ -5058,6 +5059,17 @@ static void test_reparse_points(void)
buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
bret = DeviceIoControl(handle, 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(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
+ ok(bret, "Failed to read junction point!\n");
+ string_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ 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(handle);
cleanup:
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 44cb12f90ee..52520f5f78f 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5707,6 +5707,106 @@ cleanup:
}
@ -35,7 +69,7 @@ index 37dca75651c..5a05217102d 100644
+ char *p;
+ int i;
+
+ if ((status = unix_funcs->server_get_unix_fd( handle, FILE_ANY_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
+ 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 )))
@ -47,7 +81,7 @@ index 37dca75651c..5a05217102d 100644
+ ret = readlink( unix_src.Buffer, unix_dest.Buffer, unix_dest.MaximumLength );
+ if (ret < 0)
+ {
+ status = FILE_GetNtStatus();
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ unix_dest.Length = ret;
@ -79,7 +113,7 @@ index 37dca75651c..5a05217102d 100644
+ unix_dest.Length -= (p - unix_dest.Buffer);
+ memmove(unix_dest.Buffer, p, unix_dest.Length);
+
+ if ((status = wine_unix_to_nt_file_name( &unix_dest, &nt_dest )))
+ if ((status = unix_to_nt_file_name( &unix_dest, &nt_dest )))
+ goto cleanup;
+
+ prefix_len = strlen("\\??\\");
@ -117,10 +151,10 @@ index 37dca75651c..5a05217102d 100644
+}
+
+
/**************************************************************************
* NtFsControlFile [NTDLL.@]
* ZwFsControlFile [NTDLL.@]
@@ -1848,6 +1948,12 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
/******************************************************************************
* NtFsControlFile (NTDLL.@)
*/
@@ -5772,6 +5872,12 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
status = STATUS_SUCCESS;
break;
@ -133,40 +167,6 @@ index 37dca75651c..5a05217102d 100644
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 046b49c2d2b..9197a234703 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4990,9 +4990,10 @@ static void test_reparse_points(void)
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags;
+ INT buffer_len, string_len;
UNICODE_STRING nameW;
- INT buffer_len;
HANDLE handle;
+ WCHAR *dest;
BOOL bret;
/* Create a temporary folder for the junction point tests */
@@ -5040,6 +5041,17 @@ static void test_reparse_points(void)
buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
bret = DeviceIoControl(handle, 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(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0);
+ ok(bret, "Failed to read junction point!\n");
+ string_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ 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(handle);
cleanup:
--
2.26.2
2.27.0

View File

@ -1,135 +1,20 @@
From 10508a815ca734c8a94472f82e6c0f5ebe5fbbd9 Mon Sep 17 00:00:00 2001
From 864570de933285164823fad9d6861dd018ff5a19 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: [PATCH] ntdll: Add support for deleting junction points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 97 +++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/tests/file.c | 23 +++++++++-
dlls/ntdll/unix/file.c | 97 +++++++++++++++++++++++++++++++++++++++++
include/ntifs.h | 12 +++++
3 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 5a05217102d..98f37af8793 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1863,6 +1863,87 @@ 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)
+{
+ char tmpdir[PATH_MAX], tmpfile[PATH_MAX], *d;
+ BOOL tempdir_created = FALSE;
+ int dest_fd, needs_close;
+ ANSI_STRING unix_name;
+ NTSTATUS status;
+ struct stat st;
+
+ if ((status = unix_funcs->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);
+
+ /* Produce the directory in a temporary location in the same folder */
+ if (fstat( dest_fd, &st ) == -1)
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ strcpy( tmpdir, unix_name.Buffer );
+ d = dirname( tmpdir);
+ if (d != tmpdir) strcpy( tmpdir, d );
+ strcat( tmpdir, "/.winelink.XXXXXX" );
+ if (mkdtemp( tmpdir ) == NULL)
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ tempdir_created = TRUE;
+ strcpy( tmpfile, tmpdir );
+ strcat( tmpfile, "/tmpfile" );
+ if (mkdir( tmpfile, st.st_mode ))
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ /* attemp to retain the ownership (if possible) */
+ lchown( tmpfile, st.st_uid, st.st_gid );
+ /* Atomically move the directory into position */
+ if (!renameat2( -1, tmpfile, -1, unix_name.Buffer, RENAME_EXCHANGE ))
+ {
+ /* success: link and folder have switched locations */
+ unlink( tmpfile ); /* remove the link (at folder location) */
+ }
+ else if (errno == ENOSYS)
+ {
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
+ "using unsafe exchange instead.\n" );
+ if (unlink( unix_name.Buffer ))
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ if (rename( tmpfile, unix_name.Buffer ))
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
+ }
+ }
+ else
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ status = STATUS_SUCCESS;
+
+cleanup:
+ if (tempdir_created) rmdir( tmpdir );
+ if (needs_close) close( dest_fd );
+ return status;
+}
+
+
/**************************************************************************
* NtFsControlFile [NTDLL.@]
* ZwFsControlFile [NTDLL.@]
@@ -1948,6 +2029,22 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
status = STATUS_SUCCESS;
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 9197a234703..6f6a49afd46 100644
index 938ef2026e3..80a532282c7 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4985,12 +4985,15 @@ static void test_reparse_points(void)
@@ -5003,12 +5003,15 @@ static void test_reparse_points(void)
static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0};
WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH];
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
@ -145,7 +30,7 @@ index 9197a234703..6f6a49afd46 100644
UNICODE_STRING nameW;
HANDLE handle;
WCHAR *dest;
@@ -5038,6 +5041,8 @@ static void test_reparse_points(void)
@@ -5056,6 +5059,8 @@ static void test_reparse_points(void)
win_skip("Failed to open junction point directory handle (0x%x).\n", GetLastError());
goto cleanup;
}
@ -154,7 +39,7 @@ index 9197a234703..6f6a49afd46 100644
buffer_len = build_reparse_buffer(nameW.Buffer, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
@@ -5052,6 +5057,22 @@ static void test_reparse_points(void)
@@ -5070,6 +5075,22 @@ static void test_reparse_points(void)
dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
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));
@ -177,7 +62,7 @@ index 9197a234703..6f6a49afd46 100644
CloseHandle(handle);
cleanup:
@@ -5059,7 +5080,7 @@ cleanup:
@@ -5077,7 +5098,7 @@ cleanup:
pRtlFreeUnicodeString(&nameW);
HeapFree(GetProcessHeap(), 0, buffer);
bret = RemoveDirectoryW(reparse_path);
@ -186,6 +71,121 @@ index 9197a234703..6f6a49afd46 100644
bret = RemoveDirectoryW(target_path);
ok(bret, "Failed to remove temporary target directory!\n");
RemoveDirectoryW(path);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 52520f5f78f..c65ab7de16c 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5807,6 +5807,87 @@ 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)
+{
+ char tmpdir[PATH_MAX], tmpfile[PATH_MAX], *d;
+ BOOL tempdir_created = FALSE;
+ int dest_fd, needs_close;
+ ANSI_STRING unix_name;
+ NTSTATUS status;
+ struct stat st;
+
+ 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);
+
+ /* Produce the directory in a temporary location in the same folder */
+ if (fstat( dest_fd, &st ) == -1)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ strcpy( tmpdir, unix_name.Buffer );
+ d = dirname( tmpdir);
+ if (d != tmpdir) strcpy( tmpdir, d );
+ strcat( tmpdir, "/.winelink.XXXXXX" );
+ if (mkdtemp( tmpdir ) == NULL)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ tempdir_created = TRUE;
+ strcpy( tmpfile, tmpdir );
+ strcat( tmpfile, "/tmpfile" );
+ if (mkdir( tmpfile, st.st_mode ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ /* attemp to retain the ownership (if possible) */
+ lchown( tmpfile, st.st_uid, st.st_gid );
+ /* Atomically move the directory into position */
+ if (!renameat2( -1, tmpfile, -1, unix_name.Buffer, RENAME_EXCHANGE ))
+ {
+ /* success: link and folder have switched locations */
+ unlink( tmpfile ); /* remove the link (at folder location) */
+ }
+ else if (errno == ENOSYS)
+ {
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
+ "using unsafe exchange instead.\n" );
+ if (unlink( unix_name.Buffer ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if (rename( tmpfile, unix_name.Buffer ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
+ }
+ }
+ else
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ status = STATUS_SUCCESS;
+
+cleanup:
+ if (tempdir_created) rmdir( tmpdir );
+ if (needs_close) close( dest_fd );
+ return status;
+}
+
+
/******************************************************************************
* NtFsControlFile (NTDLL.@)
*/
@@ -5872,6 +5953,22 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
status = STATUS_SUCCESS;
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/include/ntifs.h b/include/ntifs.h
index 21d42e17325..4539b89d583 100644
--- a/include/ntifs.h
@ -208,5 +208,5 @@ index 21d42e17325..4539b89d583 100644
+
#endif /* __WINE_NTIFS_H */
--
2.26.2
2.27.0

View File

@ -1,88 +1,20 @@
From d1024118fbb0a73abd19ef937d13d4378a61992b Mon Sep 17 00:00:00 2001
From 3ef1ecf4b3b6db13e96d6440e51c9407f8b5dcda 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: [PATCH] ntdll: Add support for absolute symlink creation.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 35 ++++++++++--
dlls/ntdll/tests/file.c | 117 ++++++++++++++++++++++++++++++++++------
dlls/ntdll/unix/file.c | 35 ++++++++++--
include/ntifs.h | 10 ++++
3 files changed, 143 insertions(+), 19 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 98f37af8793..825344dab86 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1672,17 +1672,33 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
{
BOOL src_allocated = FALSE, dest_allocated = FALSE, tempdir_created = FALSE;
- int dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
- int offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
- WCHAR *dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
ANSI_STRING unix_src, unix_dest;
char magic_dest[PATH_MAX];
int dest_fd, needs_close;
UNICODE_STRING nt_dest;
+ int dest_len, offset;
NTSTATUS status;
+ struct stat st;
+ WCHAR *dest;
int i;
+ switch(buffer->ReparseTag)
+ {
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
+ break;
+ case IO_REPARSE_TAG_SYMLINK:
+ dest_len = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+ offset = buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset;
+ dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[offset];
+ break;
+ default:
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
if ((status = unix_funcs->server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
return status;
@@ -1706,6 +1722,18 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
strcat( magic_dest, "." );
strcat( magic_dest, "/" );
}
+ /* Encode the type (file or directory) if NT symlink */
+ if (buffer->ReparseTag == IO_REPARSE_TAG_SYMLINK)
+ {
+ if (fstat( dest_fd, &st ) == -1)
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ if (S_ISDIR(st.st_mode))
+ strcat( magic_dest, "." );
+ strcat( magic_dest, "/" );
+ }
strcat( magic_dest, unix_dest.Buffer );
/* Produce the link in a temporary location in the same folder */
@@ -2058,6 +2086,7 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
+ case IO_REPARSE_TAG_SYMLINK:
status = FILE_CreateSymlink( handle, buffer );
break;
default:
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 89f291536b2..92f03ab3d34 100644
index 541572c27ce..f91bb40a133 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4954,26 +4954,50 @@ static void test_file_readonly_access(void)
@@ -4972,26 +4972,50 @@ static void test_file_readonly_access(void)
DeleteFileW(path);
}
@ -141,7 +73,7 @@ index 89f291536b2..92f03ab3d34 100644
lstrcpyW(subst_dest, filename);
lstrcpyW(print_dest, &filename[prefix_len]);
*pbuffer = buffer;
@@ -4993,10 +5017,12 @@ static void test_reparse_points(void)
@@ -5011,10 +5035,12 @@ static void test_reparse_points(void)
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
INT buffer_len, string_len;
@ -155,7 +87,7 @@ index 89f291536b2..92f03ab3d34 100644
BOOL bret;
/* Create a temporary folder for the junction point tests */
@@ -5043,7 +5069,7 @@ static void test_reparse_points(void)
@@ -5061,7 +5087,7 @@ static void test_reparse_points(void)
}
dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%x).\n", dwret);
@ -164,7 +96,7 @@ index 89f291536b2..92f03ab3d34 100644
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
@@ -5084,7 +5110,7 @@ static void test_reparse_points(void)
@@ -5102,7 +5128,7 @@ static void test_reparse_points(void)
HeapFree(GetProcessHeap(), 0, buffer);
handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
@ -173,7 +105,7 @@ index 89f291536b2..92f03ab3d34 100644
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
CloseHandle(handle);
@@ -5099,7 +5125,7 @@ static void test_reparse_points(void)
@@ -5117,7 +5143,7 @@ static void test_reparse_points(void)
ok(bret, "Failed to create junction point target directory.\n");
handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
@ -182,7 +114,7 @@ index 89f291536b2..92f03ab3d34 100644
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
CloseHandle(handle);
@@ -5112,14 +5138,73 @@ static void test_reparse_points(void)
@@ -5130,14 +5156,73 @@ static void test_reparse_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);
@ -260,6 +192,74 @@ index 89f291536b2..92f03ab3d34 100644
RemoveDirectoryW(path);
}
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index c65ab7de16c..15f6a006145 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5616,17 +5616,33 @@ static void ignore_server_ioctl_struct_holes( ULONG code, const void *in_buffer,
NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
{
BOOL src_allocated = FALSE, dest_allocated = FALSE, tempdir_created = FALSE;
- int dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
- int offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
- WCHAR *dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
ANSI_STRING unix_src, unix_dest;
char magic_dest[PATH_MAX];
int dest_fd, needs_close;
UNICODE_STRING nt_dest;
+ int dest_len, offset;
NTSTATUS status;
+ struct stat st;
+ WCHAR *dest;
int i;
+ switch(buffer->ReparseTag)
+ {
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
+ offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
+ dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
+ break;
+ case IO_REPARSE_TAG_SYMLINK:
+ dest_len = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
+ offset = buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset;
+ dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[offset];
+ break;
+ default:
+ return STATUS_NOT_IMPLEMENTED;
+ }
+
if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
return status;
@@ -5650,6 +5666,18 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
strcat( magic_dest, "." );
strcat( magic_dest, "/" );
}
+ /* Encode the type (file or directory) if NT symlink */
+ if (buffer->ReparseTag == IO_REPARSE_TAG_SYMLINK)
+ {
+ if (fstat( dest_fd, &st ) == -1)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if (S_ISDIR(st.st_mode))
+ strcat( magic_dest, "." );
+ strcat( magic_dest, "/" );
+ }
strcat( magic_dest, unix_dest.Buffer );
/* Produce the link in a temporary location in the same folder */
@@ -5982,6 +6010,7 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
+ case IO_REPARSE_TAG_SYMLINK:
status = FILE_CreateSymlink( handle, buffer );
break;
default:
diff --git a/include/ntifs.h b/include/ntifs.h
index 4539b89d583..ab3273d3f81 100644
--- a/include/ntifs.h
@ -294,5 +294,5 @@ index 4539b89d583..ab3273d3f81 100644
typedef struct _REPARSE_GUID_DATA_BUFFER {
DWORD ReparseTag;
--
2.26.2
2.27.0

View File

@ -1,66 +1,19 @@
From b4c166f821e7254737bf0920c3f0ea62e0646846 Mon Sep 17 00:00:00 2001
From 58371a3c2d5fed81abc2b1ae6f79133dd57a873d Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 13 Mar 2019 12:55:20 -0600
Subject: ntdll: Add support for reading absolute symlinks.
Subject: [PATCH] ntdll: Add support for reading absolute symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 22 ++++++++++++++++++++++
dlls/ntdll/tests/file.c | 13 ++++++++++++-
dlls/ntdll/unix/file.c | 22 ++++++++++++++++++++++
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 62941774ec..84da022325 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1780,6 +1780,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
UNICODE_STRING nt_dest;
DWORD max_length;
NTSTATUS status;
+ ULONG flags = 0;
INT prefix_len;
ssize_t ret;
char *p;
@@ -1826,6 +1827,17 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
}
buffer->ReparseTag |= (val << i);
}
+ /* skip past the directory/file flag */
+ if (buffer->ReparseTag == IO_REPARSE_TAG_SYMLINK)
+ {
+ char c = *p++;
+
+ if ((c != '/' && c != '.') || (c == '.' && *p++ != '/'))
+ {
+ status = STATUS_NOT_IMPLEMENTED;
+ goto cleanup;
+ }
+ }
unix_dest.Length -= (p - unix_dest.Buffer);
memmove(unix_dest.Buffer, p, unix_dest.Length);
@@ -1844,6 +1856,16 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
buffer->MountPointReparseBuffer.PrintNameLength = nt_dest.Length - prefix_len*sizeof(WCHAR);
print_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
break;
+ case IO_REPARSE_TAG_SYMLINK:
+ max_length = out_size-FIELD_OFFSET(typeof(*buffer), SymbolicLinkReparseBuffer.PathBuffer[1]);
+ buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
+ buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = nt_dest.Length;
+ subst_name = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ buffer->SymbolicLinkReparseBuffer.PrintNameOffset = nt_dest.Length + sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameLength = nt_dest.Length - prefix_len*sizeof(WCHAR);
+ print_name = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
+ buffer->SymbolicLinkReparseBuffer.Flags = flags;
+ break;
default:
/* unrecognized (regular) files should probably be treated as symlinks */
WARN("unrecognized symbolic link\n");
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 05ba0fc57e..526bd8a85a 100644
index f91bb40a133..5d3411d242e 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5067,7 +5067,6 @@ static void test_reparse_points(void)
@@ -5207,7 +5207,6 @@ static void test_reparse_points(void)
ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%x).\n", dwret);
buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_SYMLINK, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
@ -68,7 +21,7 @@ index 05ba0fc57e..526bd8a85a 100644
ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
/* Check the file attributes of the symlink */
@@ -5075,6 +5074,18 @@ static void test_reparse_points(void)
@@ -5215,6 +5214,18 @@ static void test_reparse_points(void)
ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%x)!\n", dwret);
ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a symlink! (attributes: %d)\n", dwret);
@ -87,6 +40,53 @@ index 05ba0fc57e..526bd8a85a 100644
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 15f6a006145..9cecf44db82 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5748,6 +5748,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
UNICODE_STRING nt_dest;
DWORD max_length;
NTSTATUS status;
+ ULONG flags = 0;
INT prefix_len;
ssize_t ret;
char *p;
@@ -5794,6 +5795,17 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
}
buffer->ReparseTag |= (val << i);
}
+ /* skip past the directory/file flag */
+ if (buffer->ReparseTag == IO_REPARSE_TAG_SYMLINK)
+ {
+ char c = *p++;
+
+ if ((c != '/' && c != '.') || (c == '.' && *p++ != '/'))
+ {
+ status = STATUS_NOT_IMPLEMENTED;
+ goto cleanup;
+ }
+ }
unix_dest.Length -= (p - unix_dest.Buffer);
memmove(unix_dest.Buffer, p, unix_dest.Length);
@@ -5812,6 +5824,16 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
buffer->MountPointReparseBuffer.PrintNameLength = nt_dest.Length - prefix_len*sizeof(WCHAR);
print_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
break;
+ case IO_REPARSE_TAG_SYMLINK:
+ max_length = out_size-FIELD_OFFSET(typeof(*buffer), SymbolicLinkReparseBuffer.PathBuffer[1]);
+ buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset = 0;
+ buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = nt_dest.Length;
+ subst_name = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ buffer->SymbolicLinkReparseBuffer.PrintNameOffset = nt_dest.Length + sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameLength = nt_dest.Length - prefix_len*sizeof(WCHAR);
+ print_name = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
+ buffer->SymbolicLinkReparseBuffer.Flags = flags;
+ break;
default:
/* unrecognized (regular) files should probably be treated as symlinks */
WARN("unrecognized symbolic link\n");
--
2.17.1
2.27.0

View File

@ -1,31 +1,19 @@
From 2ee26355e8261f4065b3e5e933a81ce0bfd1a1c6 Mon Sep 17 00:00:00 2001
From 478bca2da5a745e14d4fd16a3d4415cf08855308 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 13 Mar 2019 13:02:22 -0600
Subject: ntdll: Add support for deleting symlinks.
Subject: [PATCH] ntdll: Add support for deleting symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 1 +
dlls/ntdll/tests/file.c | 16 ++++++++++++++++
dlls/ntdll/unix/file.c | 1 +
2 files changed, 17 insertions(+)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 84da022325..c3e171ab19 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -2062,6 +2062,7 @@ NTSTATUS WINAPI NtFsControlFile(HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
+ case IO_REPARSE_TAG_SYMLINK:
status = FILE_RemoveSymlink( handle, buffer );
break;
default:
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 526bd8a85a..f0545feb5c 100644
index 5d3411d242e..df912e18496 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5084,6 +5084,22 @@ static void test_reparse_points(void)
@@ -5224,6 +5224,22 @@ static void test_reparse_points(void)
ok(bret, "Failed to read symlink!\n");
ok((memcmp(dest, nameW.Buffer, string_len) == 0), "Symlink destination does not match ('%s' != '%s')!\n",
wine_dbgstr_w(dest), wine_dbgstr_w(nameW.Buffer));
@ -48,6 +36,18 @@ index 526bd8a85a..f0545feb5c 100644
CloseHandle(handle);
cleanup:
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 9cecf44db82..e35ea49d17f 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -6010,6 +6010,7 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
+ case IO_REPARSE_TAG_SYMLINK:
status = FILE_RemoveSymlink( handle, buffer );
break;
default:
--
2.17.1
2.27.0

View File

@ -1,20 +1,110 @@
From cea567a0f38794b66e8da0f252d1f4864c299987 Mon Sep 17 00:00:00 2001
From 6a13b364b9b8a92d706b8ee2f4e69743ab3bee5a Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 11 Apr 2019 12:16:49 -0600
Subject: [PATCH] ntdll: Add support for relative symlink creation.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 58 ++++++++++++++++++++++++++++++++++++-----
dlls/ntdll/tests/file.c | 30 ++++++++++++++++-----
dlls/ntdll/unix/file.c | 58 ++++++++++++++++++++++++++++++++++++-----
include/ntifs.h | 2 ++
3 files changed, 77 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 3d2b874e2ee..ec8050982b0 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1671,16 +1671,19 @@ NTSTATUS WINAPI NtDeviceIoControlFile(HANDLE handle, HANDLE event,
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index df912e18496..515a84da4d6 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4972,7 +4972,8 @@ static void test_file_readonly_access(void)
DeleteFileW(path);
}
-static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_BUFFER **pbuffer)
+static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags,
+ REPARSE_DATA_BUFFER **pbuffer)
{
static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer);
INT buffer_size, struct_size, data_size, string_len, prefix_len;
@@ -4990,7 +4991,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_B
default:
return 0;
}
- prefix_len = strlen("\\??\\");
+ prefix_len = (flags == SYMLINK_FLAG_RELATIVE) ? 0 : strlen("\\??\\");
string_len = lstrlenW(&filename[prefix_len]);
data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
buffer_size = struct_size + data_size;
@@ -5010,6 +5011,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_B
buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
buffer->SymbolicLinkReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
buffer->SymbolicLinkReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.Flags = flags;
subst_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[0];
print_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[prefix_len + string_len + 1];
break;
@@ -5087,7 +5089,7 @@ static void test_reparse_points(void)
}
dwret = NtQueryInformationFile(handle, &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, IO_REPARSE_TAG_MOUNT_POINT, &buffer);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
@@ -5128,7 +5130,7 @@ static void test_reparse_points(void)
HeapFree(GetProcessHeap(), 0, buffer);
handle = CreateFileW(reparse_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, IO_REPARSE_TAG_MOUNT_POINT, &buffer);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
CloseHandle(handle);
@@ -5143,7 +5145,7 @@ static void test_reparse_points(void)
ok(bret, "Failed to create junction point target directory.\n");
handle = CreateFileW(reparse_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, IO_REPARSE_TAG_MOUNT_POINT, &buffer);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
CloseHandle(handle);
@@ -5205,7 +5207,7 @@ static void test_reparse_points(void)
}
dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%x).\n", dwret);
- buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_SYMLINK, &buffer);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_SYMLINK, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
@@ -5242,6 +5244,22 @@ static void test_reparse_points(void)
"Symlink folder's access time does not match.\n");
CloseHandle(handle);
+ /* Create a relative directory symlink */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open symlink directory handle (0x%x).\n", GetLastError());
+ goto cleanup;
+ }
+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%x).\n", dwret);
+ buffer_len = build_reparse_buffer(targetW, IO_REPARSE_TAG_SYMLINK, SYMLINK_FLAG_RELATIVE, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ CloseHandle(handle);
+ ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index e35ea49d17f..eb39dc0873b 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5615,16 +5615,19 @@ static void ignore_server_ioctl_struct_holes( ULONG code, const void *in_buffer,
*/
NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
{
@ -36,7 +126,7 @@ index 3d2b874e2ee..ec8050982b0 100644
int i;
switch(buffer->ReparseTag)
@@ -1689,11 +1692,13 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5633,11 +5636,13 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
@ -50,7 +140,7 @@ index 3d2b874e2ee..ec8050982b0 100644
break;
default:
return STATUS_NOT_IMPLEMENTED;
@@ -1705,17 +1710,54 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5649,17 +5654,54 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
if ((status = server_get_unix_name( handle, &unix_src )))
goto cleanup;
src_allocated = TRUE;
@ -68,7 +158,7 @@ index 3d2b874e2ee..ec8050982b0 100644
+ if (d != unix_path.Buffer) strcpy( unix_path.Buffer, d );
+ strcat( unix_path.Buffer, "/");
+ unix_path.Length = strlen( unix_path.Buffer );
+ if ((status = wine_unix_to_nt_file_name( &unix_path, &nt_path )))
+ if ((status = unix_to_nt_file_name( &unix_path, &nt_path )))
+ goto cleanup;
+ nt_dest.MaximumLength = dest_len + (wcslen( nt_path.Buffer ) + 1) * sizeof(WCHAR);
+ nt_dest.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_dest.MaximumLength );
@ -83,7 +173,7 @@ index 3d2b874e2ee..ec8050982b0 100644
+ nt_dest.Length = dest_len;
+ }
+ nt_dest_allocated = TRUE;
status = wine_nt_to_unix_file_name( &nt_dest, &unix_dest, 0, FALSE );
status = nt_to_unix_file_name( &nt_dest, &unix_dest, 0, FALSE );
if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
goto cleanup;
dest_allocated = TRUE;
@ -109,7 +199,7 @@ index 3d2b874e2ee..ec8050982b0 100644
for (i = 0; i < sizeof(ULONG)*8; i++)
{
if ((buffer->ReparseTag >> i) & 1)
@@ -1734,7 +1776,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5678,7 +5720,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
strcat( magic_dest, "." );
strcat( magic_dest, "/" );
}
@ -118,7 +208,7 @@ index 3d2b874e2ee..ec8050982b0 100644
/* Produce the link in a temporary location in the same folder */
strcpy( tmpdir, unix_src.Buffer );
@@ -1784,7 +1826,9 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5728,7 +5770,9 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
cleanup:
if (tempdir_created) rmdir( tmpdir );
@ -128,96 +218,6 @@ index 3d2b874e2ee..ec8050982b0 100644
if (src_allocated) RtlFreeAnsiString( &unix_src );
if (needs_close) close( dest_fd );
return status;
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index dc273734719..4d67a46fea6 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4955,7 +4955,8 @@ static void test_file_readonly_access(void)
DeleteFileW(path);
}
-static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_BUFFER **pbuffer)
+static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags,
+ REPARSE_DATA_BUFFER **pbuffer)
{
static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer);
INT buffer_size, struct_size, data_size, string_len, prefix_len;
@@ -4973,7 +4974,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_B
default:
return 0;
}
- prefix_len = strlen("\\??\\");
+ prefix_len = (flags == SYMLINK_FLAG_RELATIVE) ? 0 : strlen("\\??\\");
string_len = lstrlenW(&filename[prefix_len]);
data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
buffer_size = struct_size + data_size;
@@ -4993,6 +4994,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_B
buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
buffer->SymbolicLinkReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
buffer->SymbolicLinkReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.Flags = flags;
subst_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[0];
print_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[prefix_len + string_len + 1];
break;
@@ -5070,7 +5072,7 @@ static void test_reparse_points(void)
}
dwret = NtQueryInformationFile(handle, &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, IO_REPARSE_TAG_MOUNT_POINT, &buffer);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
@@ -5111,7 +5113,7 @@ static void test_reparse_points(void)
HeapFree(GetProcessHeap(), 0, buffer);
handle = CreateFileW(reparse_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, IO_REPARSE_TAG_MOUNT_POINT, &buffer);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
CloseHandle(handle);
@@ -5126,7 +5128,7 @@ static void test_reparse_points(void)
ok(bret, "Failed to create junction point target directory.\n");
handle = CreateFileW(reparse_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, IO_REPARSE_TAG_MOUNT_POINT, &buffer);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create junction point! (0x%x)\n", GetLastError());
CloseHandle(handle);
@@ -5188,7 +5190,7 @@ static void test_reparse_points(void)
}
dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%x).\n", dwret);
- buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_SYMLINK, &buffer);
+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_SYMLINK, 0, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
@@ -5225,6 +5227,22 @@ static void test_reparse_points(void)
"Symlink folder's access time does not match.\n");
CloseHandle(handle);
+ /* Create a relative directory symlink */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (handle == INVALID_HANDLE_VALUE)
+ {
+ win_skip("Failed to open symlink directory handle (0x%x).\n", GetLastError());
+ goto cleanup;
+ }
+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation);
+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%x).\n", dwret);
+ buffer_len = build_reparse_buffer(targetW, IO_REPARSE_TAG_SYMLINK, SYMLINK_FLAG_RELATIVE, &buffer);
+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
+ CloseHandle(handle);
+ ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/include/ntifs.h b/include/ntifs.h
index ab3273d3f81..0d02225bc4f 100644
--- a/include/ntifs.h
@ -230,5 +230,5 @@ index ab3273d3f81..0d02225bc4f 100644
+
#endif /* __WINE_NTIFS_H */
--
2.25.1
2.27.0

View File

@ -1,91 +1,19 @@
From 6e8b35c8a5c0d0dd1bd55d21c156b3ced65d376c Mon Sep 17 00:00:00 2001
From af4840c79a9958609575553aaf8bdf13dabe68ef Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 11 Apr 2019 12:31:16 -0600
Subject: [PATCH] ntdll: Add support for reading relative symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 44 ++++++++++++++++++++++++++++++++++++++++-
dlls/ntdll/tests/file.c | 13 +++++++++++-
dlls/ntdll/unix/file.c | 44 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 55 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 3001b22ff30..780d65c0e96 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1846,6 +1846,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
BOOL dest_allocated = FALSE;
int dest_fd, needs_close;
UNICODE_STRING nt_dest;
+ int path_len = 0;
DWORD max_length;
NTSTATUS status;
ULONG flags = 0;
@@ -1873,6 +1874,11 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
/* Decode the reparse tag from the symlink */
p = unix_dest.Buffer;
+ if (*p == '.')
+ {
+ flags = SYMLINK_FLAG_RELATIVE;
+ p++;
+ }
if (*p++ != '/')
{
status = STATUS_NOT_IMPLEMENTED;
@@ -1909,10 +1915,46 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
unix_dest.Length -= (p - unix_dest.Buffer);
memmove(unix_dest.Buffer, p, unix_dest.Length);
+ /* convert the relative path into an absolute path */
+ if (flags == SYMLINK_FLAG_RELATIVE)
+ {
+ int offset = unix_src.Length + 2;
+ char *d;
+ memcpy( &unix_dest.Buffer[offset], unix_dest.Buffer, unix_dest.Length );
+ unix_dest.Buffer[offset+unix_dest.Length] = 0;
+ memcpy( unix_dest.Buffer, unix_src.Buffer, unix_src.Length );
+ unix_dest.Buffer[unix_src.Length] = 0;
+ d = dirname( unix_dest.Buffer );
+ if (d != unix_dest.Buffer) strcpy( unix_dest.Buffer, d );
+ strcat( unix_dest.Buffer, "/" );
+ path_len = strlen( unix_dest.Buffer );
+ memmove( &unix_dest.Buffer[path_len], &unix_dest.Buffer[offset], unix_dest.Length + 1 );
+ unix_dest.Length = strlen( unix_dest.Buffer );
+ }
if ((status = wine_unix_to_nt_file_name( &unix_dest, &nt_dest )))
goto cleanup;
+ /* remove the relative path from the NT path */
+ if (flags == SYMLINK_FLAG_RELATIVE)
+ {
+ UNICODE_STRING nt_path;
+ int relative_offset;
+
+ unix_dest.Length = path_len;
+ if ((status = wine_unix_to_nt_file_name( &unix_dest, &nt_path )))
+ goto cleanup;
+ relative_offset = wcslen( nt_path.Buffer );
+ if (wcsncmp( nt_path.Buffer, nt_dest.Buffer, relative_offset ) != 0)
+ {
+ RtlFreeUnicodeString( &nt_path );
+ status = STATUS_IO_REPARSE_DATA_INVALID;
+ goto cleanup;
+ }
+ RtlFreeUnicodeString( &nt_path );
+ nt_dest.Length = wcslen( &nt_dest.Buffer[relative_offset] ) * sizeof(WCHAR);
+ memmove( nt_dest.Buffer, &nt_dest.Buffer[relative_offset], nt_dest.Length + sizeof(WCHAR) );
+ }
- prefix_len = strlen("\\??\\");
+ prefix_len = (flags == SYMLINK_FLAG_RELATIVE) ? 0 : strlen("\\??\\");
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 4d67a46fea6..35e674e817c 100644
index 515a84da4d6..30ab4110105 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5240,9 +5240,20 @@ static void test_reparse_points(void)
@@ -5257,9 +5257,20 @@ static void test_reparse_points(void)
ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%x).\n", dwret);
buffer_len = build_reparse_buffer(targetW, IO_REPARSE_TAG_SYMLINK, SYMLINK_FLAG_RELATIVE, &buffer);
bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0);
@ -107,6 +35,78 @@ index 4d67a46fea6..35e674e817c 100644
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index eb39dc0873b..d19b48d4224 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5790,6 +5790,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
BOOL dest_allocated = FALSE;
int dest_fd, needs_close;
UNICODE_STRING nt_dest;
+ int path_len = 0;
DWORD max_length;
NTSTATUS status;
ULONG flags = 0;
@@ -5817,6 +5818,11 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
/* Decode the reparse tag from the symlink */
p = unix_dest.Buffer;
+ if (*p == '.')
+ {
+ flags = SYMLINK_FLAG_RELATIVE;
+ p++;
+ }
if (*p++ != '/')
{
status = STATUS_NOT_IMPLEMENTED;
@@ -5853,10 +5859,46 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
unix_dest.Length -= (p - unix_dest.Buffer);
memmove(unix_dest.Buffer, p, unix_dest.Length);
+ /* convert the relative path into an absolute path */
+ if (flags == SYMLINK_FLAG_RELATIVE)
+ {
+ int offset = unix_src.Length + 2;
+ char *d;
+ memcpy( &unix_dest.Buffer[offset], unix_dest.Buffer, unix_dest.Length );
+ unix_dest.Buffer[offset+unix_dest.Length] = 0;
+ memcpy( unix_dest.Buffer, unix_src.Buffer, unix_src.Length );
+ unix_dest.Buffer[unix_src.Length] = 0;
+ d = dirname( unix_dest.Buffer );
+ if (d != unix_dest.Buffer) strcpy( unix_dest.Buffer, d );
+ strcat( unix_dest.Buffer, "/" );
+ path_len = strlen( unix_dest.Buffer );
+ memmove( &unix_dest.Buffer[path_len], &unix_dest.Buffer[offset], unix_dest.Length + 1 );
+ unix_dest.Length = strlen( unix_dest.Buffer );
+ }
if ((status = unix_to_nt_file_name( &unix_dest, &nt_dest )))
goto cleanup;
+ /* remove the relative path from the NT path */
+ if (flags == SYMLINK_FLAG_RELATIVE)
+ {
+ UNICODE_STRING nt_path;
+ int relative_offset;
+
+ unix_dest.Length = path_len;
+ if ((status = unix_to_nt_file_name( &unix_dest, &nt_path )))
+ goto cleanup;
+ relative_offset = wcslen( nt_path.Buffer );
+ if (wcsncmp( nt_path.Buffer, nt_dest.Buffer, relative_offset ) != 0)
+ {
+ RtlFreeUnicodeString( &nt_path );
+ status = STATUS_IO_REPARSE_DATA_INVALID;
+ goto cleanup;
+ }
+ RtlFreeUnicodeString( &nt_path );
+ nt_dest.Length = wcslen( &nt_dest.Buffer[relative_offset] ) * sizeof(WCHAR);
+ memmove( nt_dest.Buffer, &nt_dest.Buffer[relative_offset], nt_dest.Length + sizeof(WCHAR) );
+ }
- prefix_len = strlen("\\??\\");
+ prefix_len = (flags == SYMLINK_FLAG_RELATIVE) ? 0 : strlen("\\??\\");
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
--
2.25.1
2.27.0

View File

@ -1,101 +1,19 @@
From 824e8fa59621da5b509297d25a95cad8d4562e68 Mon Sep 17 00:00:00 2001
From 13ccfb68becff81e4a9cd94654ed51facbe96bb9 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 11 Apr 2019 17:57:53 -0600
Subject: ntdll: Add support for file symlinks.
Subject: [PATCH] ntdll: Add support for file symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 27 ++++++++++++++++++++++-----
dlls/ntdll/tests/file.c | 29 +++++++++++++++++++++++++++++
dlls/ntdll/unix/file.c | 27 ++++++++++++++++++++++-----
2 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 7af9c6635a..2f10472eeb 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1656,6 +1656,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
int relative_offset = 0;
UNICODE_STRING nt_dest;
int dest_len, offset;
+ BOOL is_dir = TRUE;
NTSTATUS status;
struct stat st;
WCHAR *dest;
@@ -1748,7 +1749,8 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
status = FILE_GetNtStatus();
goto cleanup;
}
- if (S_ISDIR(st.st_mode))
+ is_dir = S_ISDIR(st.st_mode);
+ if (is_dir)
strcat( magic_dest, "." );
strcat( magic_dest, "/" );
}
@@ -1775,8 +1777,11 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
/* Atomically move the link into position */
if (!renameat2( -1, tmplink, -1, unix_src.Buffer, RENAME_EXCHANGE ))
{
- /* success: link and folder have switched locations */
- rmdir( tmplink ); /* remove the folder (at link location) */
+ /* success: link and folder/file have switched locations */
+ if (is_dir)
+ rmdir( tmplink ); /* remove the folder (at link location) */
+ else
+ unlink( tmplink ); /* remove the file (at link location) */
}
else if (errno == ENOSYS)
{
@@ -1985,6 +1990,7 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
BOOL tempdir_created = FALSE;
int dest_fd, needs_close;
ANSI_STRING unix_name;
+ BOOL is_dir = TRUE;
NTSTATUS status;
struct stat st;
@@ -1996,12 +2002,13 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
TRACE("Deleting symlink %s\n", unix_name.Buffer);
- /* Produce the directory in a temporary location in the same folder */
+ /* Produce the file/directory in a temporary location in the same folder */
if (fstat( dest_fd, &st ) == -1)
{
status = FILE_GetNtStatus();
goto cleanup;
}
+ is_dir = S_ISDIR(st.st_mode);
strcpy( tmpdir, unix_name.Buffer );
d = dirname( tmpdir);
if (d != tmpdir) strcpy( tmpdir, d );
@@ -2014,11 +2021,21 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
tempdir_created = TRUE;
strcpy( tmpfile, tmpdir );
strcat( tmpfile, "/tmpfile" );
- if (mkdir( tmpfile, st.st_mode ))
+ if (is_dir && mkdir( tmpfile, st.st_mode ))
{
status = FILE_GetNtStatus();
goto cleanup;
}
+ else if (!is_dir)
+ {
+ int fd = open( tmpfile, O_CREAT|O_WRONLY|O_TRUNC, st.st_mode );
+ if (fd < 0)
+ {
+ status = FILE_GetNtStatus();
+ goto cleanup;
+ }
+ close( fd );
+ }
/* attemp to retain the ownership (if possible) */
lchown( tmpfile, st.st_uid, st.st_gid );
/* Atomically move the directory into position */
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index a17e792ae0..b904bc1f2d 100644
index 30ab4110105..ebeb1ec7713 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5050,6 +5050,35 @@ static void test_reparse_points(void)
@@ -5190,6 +5190,35 @@ static void test_reparse_points(void)
/* Delete the junction point directory and create a blank slate for symlink tests */
bret = RemoveDirectoryW(reparse_path);
ok(bret, "Failed to delete junction point!\n");
@ -131,6 +49,88 @@ index a17e792ae0..b904bc1f2d 100644
bret = CreateDirectoryW(reparse_path, NULL);
ok(bret, "Failed to create junction point directory.\n");
dwret = GetFileAttributesW(reparse_path);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index d19b48d4224..fb1e6bd3c1c 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5624,6 +5624,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
int relative_offset = 0;
UNICODE_STRING nt_dest;
int dest_len, offset;
+ BOOL is_dir = TRUE;
NTSTATUS status;
struct stat st;
WCHAR *dest;
@@ -5716,7 +5717,8 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
status = errno_to_status( errno );
goto cleanup;
}
- if (S_ISDIR(st.st_mode))
+ is_dir = S_ISDIR(st.st_mode);
+ if (is_dir)
strcat( magic_dest, "." );
strcat( magic_dest, "/" );
}
@@ -5743,8 +5745,11 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
/* Atomically move the link into position */
if (!renameat2( -1, tmplink, -1, unix_src.Buffer, RENAME_EXCHANGE ))
{
- /* success: link and folder have switched locations */
- rmdir( tmplink ); /* remove the folder (at link location) */
+ /* success: link and folder/file have switched locations */
+ if (is_dir)
+ rmdir( tmplink ); /* remove the folder (at link location) */
+ else
+ unlink( tmplink ); /* remove the file (at link location) */
}
else if (errno == ENOSYS)
{
@@ -5953,6 +5958,7 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
BOOL tempdir_created = FALSE;
int dest_fd, needs_close;
ANSI_STRING unix_name;
+ BOOL is_dir = TRUE;
NTSTATUS status;
struct stat st;
@@ -5964,12 +5970,13 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
TRACE("Deleting symlink %s\n", unix_name.Buffer);
- /* Produce the directory in a temporary location in the same folder */
+ /* Produce the file/directory in a temporary location in the same folder */
if (fstat( dest_fd, &st ) == -1)
{
status = errno_to_status( errno );
goto cleanup;
}
+ is_dir = S_ISDIR(st.st_mode);
strcpy( tmpdir, unix_name.Buffer );
d = dirname( tmpdir);
if (d != tmpdir) strcpy( tmpdir, d );
@@ -5982,11 +5989,21 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
tempdir_created = TRUE;
strcpy( tmpfile, tmpdir );
strcat( tmpfile, "/tmpfile" );
- if (mkdir( tmpfile, st.st_mode ))
+ if (is_dir && mkdir( tmpfile, st.st_mode ))
{
status = errno_to_status( errno );
goto cleanup;
}
+ else if (!is_dir)
+ {
+ int fd = open( tmpfile, O_CREAT|O_WRONLY|O_TRUNC, st.st_mode );
+ if (fd < 0)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ close( fd );
+ }
/* attemp to retain the ownership (if possible) */
lchown( tmpfile, st.st_uid, st.st_gid );
/* Atomically move the directory into position */
--
2.17.1
2.27.0

View File

@ -1,4 +1,4 @@
From 804bc6397bcf91a50ec6d13ca296e564ee19d689 Mon Sep 17 00:00:00 2001
From 1f399151685c3d7827d39b7039abe7b3b941a3bc Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Tue, 30 Apr 2019 16:24:54 -0600
Subject: [PATCH] ntdll: Allow creation of dangling reparse points to
@ -6,31 +6,15 @@ Subject: [PATCH] ntdll: Allow creation of dangling reparse points to
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 3 ++-
dlls/ntdll/unix/file.c | 13 +++++++++++++
dlls/ntdll/unix/file.c | 15 ++++++++++++++-
include/winternl.h | 1 +
3 files changed, 16 insertions(+), 1 deletion(-)
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 6c5da524aad..aad4ba5615b 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -1619,8 +1619,9 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
RtlCreateUnicodeString( &nt_dest, dest );
nt_dest.Length = dest_len;
}
+
nt_dest_allocated = TRUE;
- status = wine_nt_to_unix_file_name( &nt_dest, &unix_dest, 0, FALSE );
+ status = wine_nt_to_unix_file_name( &nt_dest, &unix_dest, FILE_WINE_PATH, FALSE );
if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
goto cleanup;
dest_allocated = TRUE;
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 13096e085e8..a2fc2a6425b 100644
index fb1e6bd3c1c..c47aea62a38 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -2726,6 +2726,19 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
@@ -3218,6 +3218,19 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
status = STATUS_OBJECT_NAME_COLLISION;
}
}
@ -50,8 +34,17 @@ index 13096e085e8..a2fc2a6425b 100644
if (status != STATUS_SUCCESS) break;
@@ -5682,7 +5695,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
nt_dest.Length = dest_len;
}
nt_dest_allocated = TRUE;
- status = nt_to_unix_file_name( &nt_dest, &unix_dest, 0, FALSE );
+ status = nt_to_unix_file_name( &nt_dest, &unix_dest, FILE_WINE_PATH, FALSE );
if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
goto cleanup;
dest_allocated = TRUE;
diff --git a/include/winternl.h b/include/winternl.h
index 39776d36f92..2e8c3866a3a 100644
index 0957561063a..0af566f518d 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1839,6 +1839,7 @@ typedef struct _RTL_HANDLE_TABLE

View File

@ -1,21 +1,54 @@
From 22a440051f4dd3b63977a384735cf60fad7f28f5 Mon Sep 17 00:00:00 2001
From 6ab64d5c26ab8713b2e55911540538a700580017 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 30 Mar 2019 12:00:51 -0600
Subject: [PATCH] ntdll: Correctly report file symbolic links as files.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 120 ++++++++++++++++++++++++++--------------
dlls/ntdll/tests/file.c | 8 +--
dlls/ntdll/unix/file.c | 120 ++++++++++++++++++++++++++--------------
2 files changed, 84 insertions(+), 44 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index 74df2aed687..7483c71a8db 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -123,6 +123,9 @@ mode_t FILE_umask = 0;
#define FILE_WRITE_TO_END_OF_FILE ((LONGLONG)-1)
#define FILE_USE_FILE_POINTER_POSITION ((LONGLONG)-2)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 9530adb2a84..45cffce68ee 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5205,13 +5205,13 @@ static void test_reparse_points(void)
/* Check deleting a file symlink as if it were a directory */
bret = RemoveDirectoryW(reparse_path);
- todo_wine ok(!bret, "Succeeded in deleting file symlink as a directory!\n");
+ ok(!bret, "Succeeded in deleting file symlink as a directory!\n");
err = GetLastError();
todo_wine ok(err == ERROR_DIRECTORY,
"Expected last error 0x%x for RemoveDirectory on file symlink (actually 0x%x)!\n",
ERROR_DIRECTORY, err);
dwret = GetFileAttributesW(reparse_path);
- todo_wine ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%x)!\n", dwret);
+ ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%x)!\n", dwret);
ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a symlink! (attributes: 0x%x)\n", dwret);
/* Delete the symlink as a file */
@@ -5220,10 +5220,10 @@ static void test_reparse_points(void)
/* Create a blank slate for directory symlink tests */
bret = CreateDirectoryW(reparse_path, NULL);
- ok(bret, "Failed to create junction point directory.\n");
+ todo_wine ok(bret, "Failed to create junction point directory.\n");
dwret = GetFileAttributesW(reparse_path);
ok(dwret != (DWORD)~0, "Path doesn't exist (attributes: 0x%x)!\n", dwret);
- ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %d)\n", dwret);
+ todo_wine ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %d)\n", dwret);
/* Create the directory symlink */
HeapFree(GetProcessHeap(), 0, buffer);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index d77a788e0fb..9656f1eb14c 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -1470,6 +1470,9 @@ static inline int get_file_xattr( char *hexattr, int attrlen )
return 0;
}
+NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, USHORT *unix_dest_len,
+ DWORD *tag, ULONG *flags, BOOL *is_dir);
@ -23,7 +56,7 @@ index 74df2aed687..7483c71a8db 100644
/* fetch the attributes of a file */
static inline ULONG get_file_attributes( const struct stat *st )
{
@@ -170,10 +173,15 @@ int get_file_info( const char *path, struct stat *st, ULONG *attr )
@@ -1554,10 +1557,15 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr )
if (ret == -1) return ret;
if (S_ISLNK( st->st_mode ))
{
@ -43,7 +76,7 @@ index 74df2aed687..7483c71a8db 100644
}
else if (S_ISDIR( st->st_mode ) && (parent_path = RtlAllocateHeap( GetProcessHeap(), 0, strlen(path) + 4 )))
{
@@ -1841,48 +1849,33 @@ cleanup:
@@ -5851,48 +5859,33 @@ cleanup:
}
@ -73,7 +106,7 @@ index 74df2aed687..7483c71a8db 100644
- char *p;
int i;
- if ((status = unix_funcs->server_get_unix_fd( handle, FILE_ANY_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
- 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 )))
@ -91,7 +124,7 @@ index 74df2aed687..7483c71a8db 100644
+ tmp = unix_dest;
+ if ((ret = readlink( unix_src, tmp, len )) < 0)
{
status = FILE_GetNtStatus();
status = errno_to_status( errno );
goto cleanup;
}
- unix_dest.Length = ret;
@ -107,7 +140,7 @@ index 74df2aed687..7483c71a8db 100644
p++;
}
if (*p++ != '/')
@@ -1890,7 +1883,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
@@ -5900,7 +5893,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
@ -116,7 +149,7 @@ index 74df2aed687..7483c71a8db 100644
for (i = 0; i < sizeof(ULONG)*8; i++)
{
char c = *p++;
@@ -1905,21 +1898,68 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
@@ -5915,21 +5908,68 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
@ -174,7 +207,7 @@ index 74df2aed687..7483c71a8db 100644
+ ULONG flags = 0;
+ INT prefix_len;
+
+ if ((status = unix_funcs->server_get_unix_fd( handle, FILE_ANY_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
+ 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 )))
@ -190,39 +223,6 @@ index 74df2aed687..7483c71a8db 100644
/* convert the relative path into an absolute path */
if (flags == SYMLINK_FLAG_RELATIVE)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index e0116491eee..7f983583268 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5187,13 +5187,13 @@ static void test_reparse_points(void)
/* Check deleting a file symlink as if it were a directory */
bret = RemoveDirectoryW(reparse_path);
- todo_wine ok(!bret, "Succeeded in deleting file symlink as a directory!\n");
+ ok(!bret, "Succeeded in deleting file symlink as a directory!\n");
err = GetLastError();
todo_wine ok(err == ERROR_DIRECTORY,
"Expected last error 0x%x for RemoveDirectory on file symlink (actually 0x%x)!\n",
ERROR_DIRECTORY, err);
dwret = GetFileAttributesW(reparse_path);
- todo_wine ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%x)!\n", dwret);
+ ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%x)!\n", dwret);
ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a symlink! (attributes: 0x%x)\n", dwret);
/* Delete the symlink as a file */
@@ -5202,10 +5202,10 @@ static void test_reparse_points(void)
/* Create a blank slate for directory symlink tests */
bret = CreateDirectoryW(reparse_path, NULL);
- ok(bret, "Failed to create junction point directory.\n");
+ todo_wine ok(bret, "Failed to create junction point directory.\n");
dwret = GetFileAttributesW(reparse_path);
ok(dwret != (DWORD)~0, "Path doesn't exist (attributes: 0x%x)!\n", dwret);
- ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %d)\n", dwret);
+ todo_wine ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %d)\n", dwret);
/* Create the directory symlink */
HeapFree(GetProcessHeap(), 0, buffer);
--
2.26.2
2.27.0

View File

@ -1,32 +1,19 @@
From 4df537eadbf20772213e02eb65d51fc1c016981e Mon Sep 17 00:00:00 2001
From 3c058e77263895ea58b25f652b82d443bcde9dcc Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 1 May 2019 12:06:20 -0600
Subject: ntdll: Always report symbolic links as containing zero bytes.
Subject: [PATCH] ntdll: Always report symbolic links as containing zero bytes.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/file.c | 2 ++
dlls/ntdll/tests/file.c | 46 +++++++++++++++++++++++++++++++++++++++--
dlls/ntdll/unix/file.c | 2 ++
2 files changed, 46 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/file.c b/dlls/ntdll/file.c
index be594ea517..6bb45f34f3 100644
--- a/dlls/ntdll/file.c
+++ b/dlls/ntdll/file.c
@@ -167,6 +167,8 @@ int get_file_info( const char *path, struct stat *st, ULONG *attr )
/* return information about the destination (unless this is a dangling symlink) */
stat( path, st );
+ /* symbolic links always report size 0 */
+ st->st_size = 0;
/* symbolic links (either junction points or NT symlinks) are "reparse points" */
*attr |= FILE_ATTRIBUTE_REPARSE_POINT;
/* whether a reparse point is a file or a directory is stored inside the link target */
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index f2c273e901..d776d12329 100644
index cd2b294bceb..67d54c81fb0 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4896,7 +4896,9 @@ static void test_reparse_points(void)
@@ -5036,7 +5036,9 @@ static void test_reparse_points(void)
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
@ -36,7 +23,7 @@ index f2c273e901..d776d12329 100644
HANDLE handle, token;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
@@ -5024,8 +5026,6 @@ static void test_reparse_points(void)
@@ -5164,8 +5166,6 @@ static void test_reparse_points(void)
"Unexpected junction point attributes (0x%x != 0x410)!\n", dwret);
bret = RemoveDirectoryW(target_path);
ok(bret, "Failed to delete junction point target!\n");
@ -45,7 +32,7 @@ index f2c273e901..d776d12329 100644
/* Establish permissions for symlink creation */
bret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
@@ -5050,6 +5050,13 @@ static void test_reparse_points(void)
@@ -5190,6 +5190,13 @@ static void test_reparse_points(void)
/* Delete the junction point directory and create a blank slate for symlink tests */
bret = RemoveDirectoryW(reparse_path);
ok(bret, "Failed to delete junction point!\n");
@ -59,7 +46,7 @@ index f2c273e901..d776d12329 100644
/* Create the file symlink */
HeapFree(GetProcessHeap(), 0, buffer);
@@ -5063,6 +5070,37 @@ static void test_reparse_points(void)
@@ -5203,6 +5210,37 @@ static void test_reparse_points(void)
ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
CloseHandle(handle);
@ -97,7 +84,7 @@ index f2c273e901..d776d12329 100644
/* Check deleting a file symlink as if it were a directory */
bret = RemoveDirectoryW(reparse_path);
ok(!bret, "Succeeded in deleting file symlink as a directory!\n");
@@ -5084,6 +5122,10 @@ static void test_reparse_points(void)
@@ -5224,6 +5262,10 @@ static void test_reparse_points(void)
dwret = GetFileAttributesW(reparse_path);
ok(dwret != (DWORD)~0, "Path doesn't exist (attributes: 0x%x)!\n", dwret);
ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %d)\n", dwret);
@ -108,6 +95,19 @@ index f2c273e901..d776d12329 100644
/* Create the directory symlink */
HeapFree(GetProcessHeap(), 0, buffer);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 7b32bac7fa3..ac4e09fc732 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -1511,6 +1511,8 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr )
/* return information about the destination (unless this is a dangling symlink) */
stat( path, st );
+ /* symbolic links always report size 0 */
+ st->st_size = 0;
/* symbolic links (either junction points or NT symlinks) are "reparse points" */
*attr |= FILE_ATTRIBUTE_REPARSE_POINT;
/* whether a reparse point is a file or a directory is stored inside the link target */
--
2.17.1
2.27.0

View File

@ -2,5 +2,4 @@ Fixes: [12401] NET Framework 2.0, 3.0, 4.0 installers and other apps that make u
Fixes: [44948] Multiple apps (Spine (Mod starter for Gothic), MS Office 365 installer) need CreateSymbolicLinkW implementation
# FIXME: patch 0006 was broken by e36a9c459d. We really want to get that information from ntdll instead, but the how is not trivial...
# FIXME 2: patch 0019 needs to call RemoveDirectoryW() from kernelbase, but it's stuck in kernel32 for now...
# As with other patch sets, temporarily disabled while it's awkwardly split between ntdll.dll and ntdll.so.
Disabled: true
Depends: ntdll-DOS_Attributes

View File

@ -1,5 +1,3 @@
Fixes: Improve stub for NtQueryEaFile
# Depends: ntdll-Syscall_Wrappers
Depends: ntdll-Junction_Points
# Re-enable me when ntdll-Junction_Points gets re-enabled!
Disabled: true

View File

@ -179,9 +179,11 @@ patch_enable_all ()
enable_ntdll_HashLinks="$1"
enable_ntdll_Heap_Improvements="$1"
enable_ntdll_Interrupt_0x2e="$1"
enable_ntdll_Junction_Points="$1"
enable_ntdll_Manifest_Range="$1"
enable_ntdll_NtAccessCheck="$1"
enable_ntdll_NtDevicePath="$1"
enable_ntdll_NtQueryEaFile="$1"
enable_ntdll_NtQuerySection="$1"
enable_ntdll_NtSetLdtEntries="$1"
enable_ntdll_Pipe_SpecialCharacters="$1"
@ -223,11 +225,14 @@ patch_enable_all ()
enable_riched20_IText_Interface="$1"
enable_server_Desktop_Refcount="$1"
enable_server_FileEndOfFileInformation="$1"
enable_server_File_Permissions="$1"
enable_server_Inherited_ACLs="$1"
enable_server_Key_State="$1"
enable_server_Object_Types="$1"
enable_server_PeekMessage="$1"
enable_server_Registry_Notifications="$1"
enable_server_Signal_Thread="$1"
enable_server_Stored_ACLs="$1"
enable_setupapi_DiskSpaceList="$1"
enable_setupapi_SPFILENOTIFY_FILEINCABINET="$1"
enable_shdocvw_ParseURLFromOutsideSource_Tests="$1"
@ -627,6 +632,9 @@ patch_enable ()
ntdll-Interrupt-0x2e)
enable_ntdll_Interrupt_0x2e="$2"
;;
ntdll-Junction_Points)
enable_ntdll_Junction_Points="$2"
;;
ntdll-Manifest_Range)
enable_ntdll_Manifest_Range="$2"
;;
@ -636,6 +644,9 @@ patch_enable ()
ntdll-NtDevicePath)
enable_ntdll_NtDevicePath="$2"
;;
ntdll-NtQueryEaFile)
enable_ntdll_NtQueryEaFile="$2"
;;
ntdll-NtQuerySection)
enable_ntdll_NtQuerySection="$2"
;;
@ -759,6 +770,12 @@ patch_enable ()
server-FileEndOfFileInformation)
enable_server_FileEndOfFileInformation="$2"
;;
server-File_Permissions)
enable_server_File_Permissions="$2"
;;
server-Inherited_ACLs)
enable_server_Inherited_ACLs="$2"
;;
server-Key_State)
enable_server_Key_State="$2"
;;
@ -774,6 +791,9 @@ patch_enable ()
server-Signal_Thread)
enable_server_Signal_Thread="$2"
;;
server-Stored_ACLs)
enable_server_Stored_ACLs="$2"
;;
setupapi-DiskSpaceList)
enable_setupapi_DiskSpaceList="$2"
;;
@ -1569,6 +1589,31 @@ if test "$enable_shell32_Progress_Dialog" -eq 1; then
enable_shell32_SHFileOperation_Move=1
fi
if test "$enable_server_Inherited_ACLs" -eq 1; then
if test "$enable_server_Stored_ACLs" -gt 1; then
abort "Patchset server-Stored_ACLs disabled, but server-Inherited_ACLs depends on that."
fi
enable_server_Stored_ACLs=1
fi
if test "$enable_server_Stored_ACLs" -eq 1; then
if test "$enable_ntdll_DOS_Attributes" -gt 1; then
abort "Patchset ntdll-DOS_Attributes disabled, but server-Stored_ACLs depends on that."
fi
if test "$enable_server_File_Permissions" -gt 1; then
abort "Patchset server-File_Permissions disabled, but server-Stored_ACLs depends on that."
fi
enable_ntdll_DOS_Attributes=1
enable_server_File_Permissions=1
fi
if test "$enable_server_File_Permissions" -eq 1; then
if test "$enable_ntdll_Junction_Points" -gt 1; then
abort "Patchset ntdll-Junction_Points disabled, but server-File_Permissions depends on that."
fi
enable_ntdll_Junction_Points=1
fi
if test "$enable_server_Desktop_Refcount" -eq 1; then
if test "$enable_ws2_32_WSACleanup" -gt 1; then
abort "Patchset ws2_32-WSACleanup disabled, but server-Desktop_Refcount depends on that."
@ -1622,6 +1667,13 @@ if test "$enable_winebuild_Fake_Dlls" -eq 1; then
enable_ws2_32_WSACleanup=1
fi
if test "$enable_ntdll_NtQueryEaFile" -eq 1; then
if test "$enable_ntdll_Junction_Points" -gt 1; then
abort "Patchset ntdll-Junction_Points disabled, but ntdll-NtQueryEaFile depends on that."
fi
enable_ntdll_Junction_Points=1
fi
if test "$enable_ntdll_NtDevicePath" -eq 1; then
if test "$enable_ntdll_Pipe_SpecialCharacters" -gt 1; then
abort "Patchset ntdll-Pipe_SpecialCharacters disabled, but ntdll-NtDevicePath depends on that."
@ -1629,6 +1681,13 @@ if test "$enable_ntdll_NtDevicePath" -eq 1; then
enable_ntdll_Pipe_SpecialCharacters=1
fi
if test "$enable_ntdll_Junction_Points" -eq 1; then
if test "$enable_ntdll_DOS_Attributes" -gt 1; then
abort "Patchset ntdll-DOS_Attributes disabled, but ntdll-Junction_Points depends on that."
fi
enable_ntdll_DOS_Attributes=1
fi
if test "$enable_ntdll_Builtin_Prot" -eq 1; then
if test "$enable_ntdll_WRITECOPY" -gt 1; then
abort "Patchset ntdll-WRITECOPY disabled, but ntdll-Builtin_Prot depends on that."
@ -3685,6 +3744,60 @@ if test "$enable_ntdll_Interrupt_0x2e" -eq 1; then
) >> "$patchlist"
fi
# Patchset ntdll-Junction_Points
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes
# |
# | This patchset fixes the following Wine bugs:
# | * [#12401] NET Framework 2.0, 3.0, 4.0 installers and other apps that make use of GAC API for managed assembly
# | installation on NTFS filesystems need reparse point/junction API support
# | (FSCTL_SET_REPARSE_POINT/FSCTL_GET_REPARSE_POINT)
# | * [#44948] Multiple apps (Spine (Mod starter for Gothic), MS Office 365 installer) need CreateSymbolicLinkW implementation
# |
# | Modified files:
# | * configure.ac, dlls/kernel32/path.c, dlls/ntdll/tests/file.c, dlls/ntdll/unix/file.c, include/Makefile.in,
# | include/ntifs.h, include/wine/port.h, include/winternl.h, libs/port/Makefile.in, libs/port/renameat2.c, server/fd.c
# |
if test "$enable_ntdll_Junction_Points" -eq 1; then
patch_apply ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch
patch_apply ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch
patch_apply ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch
patch_apply ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch
patch_apply ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch
patch_apply ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch
patch_apply ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch
patch_apply ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch
patch_apply ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch
patch_apply ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch
patch_apply ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch
patch_apply ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch
patch_apply ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch
patch_apply ntdll-Junction_Points/0015-kernel32-Set-error-code-when-attempting-to-delete-fi.patch
patch_apply ntdll-Junction_Points/0016-server-Properly-handle-file-symlink-deletion.patch
patch_apply ntdll-Junction_Points/0017-ntdll-Always-report-symbolic-links-as-containing-zer.patch
patch_apply ntdll-Junction_Points/0018-ntdll-Find-dangling-symlinks-quickly.patch
(
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for junction point creation.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for reading junction points.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for deleting junction points.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add a test for junction point advertisement.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "kernel32,ntdll: Add support for deleting junction points with RemoveDirectory.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for absolute symlink creation.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for reading absolute symlinks.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for deleting symlinks.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for relative symlink creation.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for reading relative symlinks.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Add support for file symlinks.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Allow creation of dangling reparse points to non-existent paths.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Correctly report file symbolic links as files.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "kernel32: Set error code when attempting to delete file symlinks as directories.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "server: Properly handle file symlink deletion.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Always report symbolic links as containing zero bytes.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "ntdll: Find dangling symlinks quickly.", 1 },';
) >> "$patchlist"
fi
# Patchset ntdll-Manifest_Range
# |
# | This patchset fixes the following Wine bugs:
@ -3745,6 +3858,21 @@ if test "$enable_ntdll_NtDevicePath" -eq 1; then
) >> "$patchlist"
fi
# Patchset ntdll-NtQueryEaFile
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes, ntdll-Junction_Points
# |
# | Modified files:
# | * dlls/ntdll/file.c, dlls/ntdll/tests/file.c
# |
if test "$enable_ntdll_NtQueryEaFile" -eq 1; then
patch_apply ntdll-NtQueryEaFile/0001-ntdll-Improve-stub-of-NtQueryEaFile.patch
(
printf '%s\n' '+ { "Sebastian Lackner", "ntdll: Improve stub of NtQueryEaFile.", 1 },';
) >> "$patchlist"
fi
# Patchset ntdll-NtQuerySection
# |
# | Modified files:
@ -4408,6 +4536,84 @@ if test "$enable_server_FileEndOfFileInformation" -eq 1; then
) >> "$patchlist"
fi
# Patchset server-File_Permissions
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes, ntdll-Junction_Points
# |
# | This patchset fixes the following Wine bugs:
# | * [#44691] Improve mapping of DACL to file permissions
# |
# | Modified files:
# | * dlls/advapi32/tests/security.c, dlls/ntdll/tests/file.c, server/fd.c, server/file.c
# |
if test "$enable_server_File_Permissions" -eq 1; then
patch_apply server-File_Permissions/0001-server-Improve-STATUS_CANNOT_DELETE-checks-for-direc.patch
patch_apply server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch
patch_apply server-File_Permissions/0003-server-When-creating-new-directories-temporarily-giv.patch
patch_apply server-File_Permissions/0004-advapi32-tests-Add-tests-for-ACL-inheritance-in-Crea.patch
patch_apply server-File_Permissions/0005-advapi32-tests-Add-ACL-inheritance-tests-for-creatin.patch
patch_apply server-File_Permissions/0006-ntdll-tests-Added-tests-for-open-behaviour-on-readon.patch
patch_apply server-File_Permissions/0007-server-FILE_WRITE_ATTRIBUTES-should-succeed-for-read.patch
patch_apply server-File_Permissions/0008-server-Improve-mapping-of-DACL-to-file-permissions.patch
(
printf '%s\n' '+ { "Sebastian Lackner", "server: Improve STATUS_CANNOT_DELETE checks for directory case.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "server: Allow to open files without any permission bits.", 2 },';
printf '%s\n' '+ { "Sebastian Lackner", "server: When creating new directories temporarily give read-permissions until they are opened.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "advapi32/tests: Add tests for ACL inheritance in CreateDirectoryA.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "advapi32/tests: Add ACL inheritance tests for creating subdirectories with NtCreateFile.", 1 },';
printf '%s\n' '+ { "Qian Hong", "ntdll/tests: Added tests for open behaviour on readonly files.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "server: FILE_WRITE_ATTRIBUTES should succeed for readonly files.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "server: Improve mapping of DACL to file permissions.", 1 },';
) >> "$patchlist"
fi
# Patchset server-Stored_ACLs
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes, ntdll-Junction_Points, server-File_Permissions
# |
# | This patchset fixes the following Wine bugs:
# | * [#33576] Support for stored file ACLs
# |
# | Modified files:
# | * dlls/advapi32/tests/security.c, include/wine/port.h, server/change.c, server/file.c, server/file.h, server/object.c,
# | server/object.h
# |
if test "$enable_server_Stored_ACLs" -eq 1; then
patch_apply server-Stored_ACLs/0001-server-Unify-the-storage-of-security-attributes-for-.patch
patch_apply server-Stored_ACLs/0002-server-Unify-the-retrieval-of-security-attributes-fo.patch
patch_apply server-Stored_ACLs/0003-server-Add-a-helper-function-set_sd_from_token_inter.patch
patch_apply server-Stored_ACLs/0004-server-Temporarily-store-the-full-security-descripto.patch
patch_apply server-Stored_ACLs/0005-server-Store-file-security-attributes-with-extended-.patch
patch_apply server-Stored_ACLs/0006-server-Convert-return-of-file-security-masks-with-ge.patch
patch_apply server-Stored_ACLs/0007-server-Retrieve-file-security-attributes-with-extend.patch
(
printf '%s\n' '+ { "Erich E. Hoover", "server: Unify the storage of security attributes for files and directories.", 7 },';
printf '%s\n' '+ { "Erich E. Hoover", "server: Unify the retrieval of security attributes for files and directories.", 7 },';
printf '%s\n' '+ { "Sebastian Lackner", "server: Add a helper function set_sd_from_token_internal to merge two security descriptors.", 1 },';
printf '%s\n' '+ { "Sebastian Lackner", "server: Temporarily store the full security descriptor for file objects.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "server: Store file security attributes with extended file attributes.", 8 },';
printf '%s\n' '+ { "Erich E. Hoover", "server: Convert return of file security masks with generic access mappings.", 7 },';
printf '%s\n' '+ { "Erich E. Hoover", "server: Retrieve file security attributes with extended file attributes.", 7 },';
) >> "$patchlist"
fi
# Patchset server-Inherited_ACLs
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes, ntdll-Junction_Points, server-File_Permissions, server-Stored_ACLs
# |
# | Modified files:
# | * dlls/advapi32/tests/security.c, server/file.c
# |
if test "$enable_server_Inherited_ACLs" -eq 1; then
patch_apply server-Inherited_ACLs/0001-server-Inherit-security-attributes-from-parent-direc.patch
(
printf '%s\n' '+ { "Erich E. Hoover", "server: Inherit security attributes from parent directories on creation.", 7 },';
) >> "$patchlist"
fi
# Patchset server-Key_State
# |
# | This patchset fixes the following Wine bugs:

View File

@ -1,5 +1,3 @@
Fixes: Allow to open files/directories without any access rights in order to query attributes
Fixes: [44691] Improve mapping of DACL to file permissions
Depends: ntdll-Junction_Points
# Re-enable me when ntdll-Junction_Points gets re-enabled!
Disabled: true

View File

@ -1,4 +1,2 @@
Depends: server-Stored_ACLs
Fixes: Support for inherited file ACLs
# Re-enable me when ntdll-Junction_Points gets re-enabled!
Disabled: true

View File

@ -1,5 +1,3 @@
Depends: ntdll-DOS_Attributes
Depends: server-File_Permissions
Fixes: [33576] Support for stored file ACLs
# Re-enable me when ntdll-Junction_Points gets re-enabled!
Disabled: true