mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-09-13 09:17:20 -07:00
ntdll-Junction_Points: Rebase and re-enable.
This commit is contained in:
parent
d799e8fd82
commit
8e5546184f
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user