ntdll-Junction_Points: Update with rebased patch set from Erich E. Hoover.

This commit is contained in:
Zebediah Figura 2020-07-18 11:41:56 -05:00
parent 1a87edb76b
commit 4ffe305c90
31 changed files with 1214 additions and 603 deletions

View File

@ -1,4 +1,4 @@
From e043e7d570fcdc0f7bc662d794d111baaa15b015 Mon Sep 17 00:00:00 2001
From 40fcca0f7bf71d2675bf44cdfd8f5a178d4275c3 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/tests/file.c | 101 ++++++++++++++++++++++++++++++++++
dlls/ntdll/unix/file.c | 117 ++++++++++++++++++++++++++++++++++++++++
dlls/ntdll/tests/file.c | 101 +++++++++++++++++++++++++++++++
dlls/ntdll/unix/file.c | 129 ++++++++++++++++++++++++++++++++++++++++
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, 328 insertions(+)
libs/port/renameat2.c | 55 +++++++++++++++++
8 files changed, 340 insertions(+)
create mode 100644 include/ntifs.h
create mode 100644 libs/port/renameat2.c
diff --git a/configure.ac b/configure.ac
index a403c9436ca..dbd07791de7 100644
index f3e93b3fdb8..918f4a5253c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2218,6 +2218,8 @@ AC_CHECK_FUNCS(\
@ -31,7 +31,7 @@ index a403c9436ca..dbd07791de7 100644
select \
setproctitle \
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index a502a8eec75..bce34f03920 100644
index 5ca9742f0b6..1bc1af363e4 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -38,6 +38,7 @@
@ -42,7 +42,7 @@ index a502a8eec75..bce34f03920 100644
#ifndef IO_COMPLETION_ALL_ACCESS
#define IO_COMPLETION_ALL_ACCESS 0x001F0003
@@ -4971,6 +4972,105 @@ static void test_file_readonly_access(void)
@@ -5053,6 +5054,105 @@ static void test_file_readonly_access(void)
DeleteFileW(path);
}
@ -148,39 +148,39 @@ index a502a8eec75..bce34f03920 100644
START_TEST(file)
{
HMODULE hkernel32 = GetModuleHandleA("kernel32.dll");
@@ -5041,4 +5141,5 @@ START_TEST(file)
test_query_attribute_information_file();
@@ -5125,4 +5225,5 @@ START_TEST(file)
test_ioctl();
test_query_ea();
test_flush_buffers_file();
+ test_reparse_points();
}
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index b76d07a8175..271151ed1be 100644
index 372a8ec1248..cfa1ec0fe9c 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>
@@ -36,6 +36,7 @@
#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 <stdio.h>
+#include <libgen.h>
#include <limits.h>
#ifdef HAVE_MNTENT_H
#include <mntent.h>
@@ -126,6 +127,7 @@
#include "wine/list.h"
#include "wine/debug.h"
@@ -5661,6 +5663,104 @@ static void ignore_server_ioctl_struct_holes( ULONG code, const void *in_buffer,
#include "unix_private.h"
+#include "ntifs.h"
WINE_DEFAULT_DEBUG_CHANNEL(file);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
@@ -5645,6 +5647,116 @@ 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.
+ * 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)
+{
@ -189,7 +189,8 @@ index b76d07a8175..271151ed1be 100644
+ 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;
+ SIZE_T unix_dest_len = PATH_MAX;
+ char *unix_src, *unix_dest;
+ char magic_dest[PATH_MAX];
+ int dest_fd, needs_close;
+ UNICODE_STRING nt_dest;
@ -204,12 +205,23 @@ index b76d07a8175..271151ed1be 100644
+ src_allocated = TRUE;
+ nt_dest.Buffer = dest;
+ nt_dest.Length = dest_len;
+ status = nt_to_unix_file_name( &nt_dest, &unix_dest, 0 );
+ for (;;)
+ {
+ unix_dest = malloc( unix_dest_len );
+ if (!unix_dest)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ status = wine_nt_to_unix_file_name( &nt_dest, unix_dest, &unix_dest_len, FALSE );
+ if (status != STATUS_BUFFER_TOO_SMALL) break;
+ free( unix_dest );
+ }
+ 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);
+ TRACE( "Linking %s to %s\n", unix_src, unix_dest );
+
+ /* Encode the reparse tag into the symlink */
+ strcpy( magic_dest, "/" );
@ -219,10 +231,10 @@ index b76d07a8175..271151ed1be 100644
+ strcat( magic_dest, "." );
+ strcat( magic_dest, "/" );
+ }
+ strcat( magic_dest, unix_dest.Buffer );
+ strcat( magic_dest, unix_dest );
+
+ /* Produce the link in a temporary location in the same folder */
+ strcpy( tmpdir, unix_src.Buffer );
+ strcpy( tmpdir, unix_src );
+ d = dirname( tmpdir);
+ if (d != tmpdir) strcpy( tmpdir, d );
+ strcat( tmpdir, "/.winelink.XXXXXX" );
@ -240,7 +252,7 @@ index b76d07a8175..271151ed1be 100644
+ goto cleanup;
+ }
+ /* Atomically move the link into position */
+ if (!renameat2( -1, tmplink, -1, unix_src.Buffer, RENAME_EXCHANGE ))
+ if (!renameat2( -1, tmplink, -1, unix_src, RENAME_EXCHANGE ))
+ {
+ /* success: link and folder have switched locations */
+ rmdir( tmplink ); /* remove the folder (at link location) */
@ -249,12 +261,12 @@ index b76d07a8175..271151ed1be 100644
+ {
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
+ "using unsafe exchange instead.\n" );
+ if (rmdir( unix_src.Buffer ))
+ if (rmdir( unix_src ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if (rename( tmplink, unix_src.Buffer ))
+ if (rename( tmplink, unix_src ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
@ -269,8 +281,8 @@ index b76d07a8175..271151ed1be 100644
+
+cleanup:
+ if (tempdir_created) rmdir( tmpdir );
+ if (dest_allocated) RtlFreeAnsiString( &unix_dest );
+ if (src_allocated) RtlFreeAnsiString( &unix_src );
+ if (dest_allocated) free( unix_dest );
+ if (src_allocated) free( unix_src );
+ if (needs_close) close( dest_fd );
+ return status;
+}
@ -279,11 +291,10 @@ index b76d07a8175..271151ed1be 100644
/******************************************************************************
* NtFsControlFile (NTDLL.@)
*/
@@ -5748,6 +5848,23 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
io->Information = 0;
status = STATUS_SUCCESS;
@@ -5727,6 +5839,23 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
break;
+
}
+ case FSCTL_SET_REPARSE_POINT:
+ {
+ REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
@ -300,9 +311,10 @@ index b76d07a8175..271151ed1be 100644
+ }
+ break;
+ }
default:
return server_ioctl_file( handle, event, apc, apc_context, io, code,
in_buffer, in_size, out_buffer, out_size );
+
case FSCTL_SET_SPARSE:
TRACE("FSCTL_SET_SPARSE: Ignoring request\n");
io->Information = 0;
diff --git a/include/Makefile.in b/include/Makefile.in
index 216adf0d7ae..7dc16c230b6 100644
--- a/include/Makefile.in

View File

@ -1,19 +1,19 @@
From f601df88922fd3719b34376344488fe2a04afe6b Mon Sep 17 00:00:00 2001
From 1c6eed5d7c8a60fb7f6a9ada5345ef2dc0c6e9ad 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.
Subject: ntdll: Add support for reading junction points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 14 +++++-
dlls/ntdll/unix/file.c | 106 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 119 insertions(+), 1 deletion(-)
dlls/ntdll/tests/file.c | 14 ++++-
dlls/ntdll/unix/file.c | 119 ++++++++++++++++++++++++++++++++++++++++
2 files changed, 132 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 8b5ddbb0da1..938ef2026e3 100644
index 43cf99e8e74..4fe94f58bf1 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5008,9 +5008,10 @@ static void test_reparse_points(void)
@@ -5009,9 +5009,10 @@ static void test_reparse_points(void)
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags;
@ -25,7 +25,7 @@ index 8b5ddbb0da1..938ef2026e3 100644
BOOL bret;
/* Create a temporary folder for the junction point tests */
@@ -5058,6 +5059,17 @@ static void test_reparse_points(void)
@@ -5059,6 +5060,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());
@ -44,10 +44,10 @@ index 8b5ddbb0da1..938ef2026e3 100644
cleanup:
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 44cb12f90ee..52520f5f78f 100644
index 48e4c38b7ba..cd523dcd313 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5707,6 +5707,106 @@ cleanup:
@@ -5704,6 +5704,119 @@ cleanup:
}
@ -57,13 +57,15 @@ index 44cb12f90ee..52520f5f78f 100644
+ */
+NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_size)
+{
+ ANSI_STRING unix_src, unix_dest;
+ char *unix_src, unix_dest[PATH_MAX];
+ VOID *subst_name, *print_name;
+ SIZE_T nt_dest_len = PATH_MAX;
+ BOOL dest_allocated = FALSE;
+ int dest_fd, needs_close;
+ UNICODE_STRING nt_dest;
+ int unix_dest_len;
+ DWORD max_length;
+ NTSTATUS status;
+ WCHAR *nt_dest;
+ INT prefix_len;
+ ssize_t ret;
+ char *p;
@ -75,19 +77,16 @@ index 44cb12f90ee..52520f5f78f 100644
+ if ((status = server_get_unix_name( handle, &unix_src )))
+ goto cleanup;
+
+ unix_dest.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, PATH_MAX );
+ unix_dest.MaximumLength = PATH_MAX;
+ dest_allocated = TRUE;
+ ret = readlink( unix_src.Buffer, unix_dest.Buffer, unix_dest.MaximumLength );
+ ret = readlink( unix_src, unix_dest, sizeof(unix_dest) );
+ if (ret < 0)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ unix_dest.Length = ret;
+ unix_dest_len = ret;
+
+ /* Decode the reparse tag from the symlink */
+ p = unix_dest.Buffer;
+ p = unix_dest;
+ if (*p++ != '/')
+ {
+ status = STATUS_NOT_IMPLEMENTED;
@ -110,11 +109,25 @@ index 44cb12f90ee..52520f5f78f 100644
+ }
+ buffer->ReparseTag |= (val << i);
+ }
+ unix_dest.Length -= (p - unix_dest.Buffer);
+ memmove(unix_dest.Buffer, p, unix_dest.Length);
+ unix_dest_len -= (p - unix_dest);
+ memmove(unix_dest, p, unix_dest_len);
+
+ if ((status = unix_to_nt_file_name( &unix_dest, &nt_dest )))
+ for (;;)
+ {
+ nt_dest = malloc( nt_dest_len * sizeof(WCHAR) );
+ if (!nt_dest)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ status = wine_unix_to_nt_file_name( unix_dest, nt_dest, &nt_dest_len );
+ if (status != STATUS_BUFFER_TOO_SMALL) break;
+ free( nt_dest );
+ }
+ dest_allocated = TRUE;
+ if (status != STATUS_SUCCESS)
+ goto cleanup;
+ nt_dest_len *= sizeof(WCHAR);
+
+ prefix_len = strlen("\\??\\");
+ switch(buffer->ReparseTag)
@ -122,10 +135,10 @@ index 44cb12f90ee..52520f5f78f 100644
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ max_length = out_size-FIELD_OFFSET(typeof(*buffer), MountPointReparseBuffer.PathBuffer[1]);
+ buffer->MountPointReparseBuffer.SubstituteNameOffset = 0;
+ buffer->MountPointReparseBuffer.SubstituteNameLength = nt_dest.Length;
+ buffer->MountPointReparseBuffer.SubstituteNameLength = nt_dest_len;
+ subst_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)];
+ buffer->MountPointReparseBuffer.PrintNameOffset = nt_dest.Length + sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = nt_dest.Length - prefix_len*sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameOffset = nt_dest_len + sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = nt_dest_len - prefix_len*sizeof(WCHAR);
+ print_name = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
+ break;
+ default:
@ -134,18 +147,18 @@ index 44cb12f90ee..52520f5f78f 100644
+ status = STATUS_NOT_IMPLEMENTED;
+ goto cleanup;
+ }
+ if (nt_dest.Length > max_length)
+ if (nt_dest_len > max_length)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ goto cleanup;
+ }
+
+ memcpy( subst_name, nt_dest.Buffer, nt_dest.Length );
+ memcpy( print_name, &nt_dest.Buffer[prefix_len], nt_dest.Length - prefix_len*sizeof(WCHAR) );
+ memcpy( subst_name, nt_dest, nt_dest_len );
+ memcpy( print_name, &nt_dest[prefix_len], nt_dest_len - prefix_len*sizeof(WCHAR) );
+ status = STATUS_SUCCESS;
+
+cleanup:
+ if (dest_allocated) RtlFreeAnsiString( &unix_dest );
+ if (dest_allocated) free( nt_dest );
+ if (needs_close) close( dest_fd );
+ return status;
+}
@ -154,9 +167,9 @@ index 44cb12f90ee..52520f5f78f 100644
/******************************************************************************
* NtFsControlFile (NTDLL.@)
*/
@@ -5772,6 +5872,12 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
status = STATUS_SUCCESS;
@@ -5786,6 +5899,12 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
break;
}
+ case FSCTL_GET_REPARSE_POINT:
+ {
@ -168,5 +181,5 @@ index 44cb12f90ee..52520f5f78f 100644
{
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
--
2.27.0
2.17.1

View File

@ -1,7 +1,7 @@
From 864570de933285164823fad9d6861dd018ff5a19 Mon Sep 17 00:00:00 2001
From 17713b3abdd15d7a76ffec8e6376f2424829ecfa 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.
Subject: ntdll: Add support for deleting junction points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
@ -11,10 +11,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
3 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 938ef2026e3..80a532282c7 100644
index 4fe94f58bf1..9da353bbbd2 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5003,12 +5003,15 @@ static void test_reparse_points(void)
@@ -5004,12 +5004,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};
@ -30,7 +30,7 @@ index 938ef2026e3..80a532282c7 100644
UNICODE_STRING nameW;
HANDLE handle;
WCHAR *dest;
@@ -5056,6 +5059,8 @@ static void test_reparse_points(void)
@@ -5057,6 +5060,8 @@ static void test_reparse_points(void)
win_skip("Failed to open junction point directory handle (0x%x).\n", GetLastError());
goto cleanup;
}
@ -39,7 +39,7 @@ index 938ef2026e3..80a532282c7 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());
@@ -5070,6 +5075,22 @@ static void test_reparse_points(void)
@@ -5071,6 +5076,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));
@ -62,7 +62,7 @@ index 938ef2026e3..80a532282c7 100644
CloseHandle(handle);
cleanup:
@@ -5077,7 +5098,7 @@ cleanup:
@@ -5078,7 +5099,7 @@ cleanup:
pRtlFreeUnicodeString(&nameW);
HeapFree(GetProcessHeap(), 0, buffer);
bret = RemoveDirectoryW(reparse_path);
@ -72,10 +72,10 @@ index 938ef2026e3..80a532282c7 100644
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
index cd523dcd313..3f6dcc6ab41 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5807,6 +5807,87 @@ cleanup:
@@ -5817,6 +5817,87 @@ cleanup:
}
@ -88,8 +88,8 @@ index 52520f5f78f..c65ab7de16c 100644
+ char tmpdir[PATH_MAX], tmpfile[PATH_MAX], *d;
+ BOOL tempdir_created = FALSE;
+ int dest_fd, needs_close;
+ ANSI_STRING unix_name;
+ NTSTATUS status;
+ char *unix_name;
+ struct stat st;
+
+ if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
@ -98,7 +98,7 @@ index 52520f5f78f..c65ab7de16c 100644
+ if ((status = server_get_unix_name( handle, &unix_name )))
+ goto cleanup;
+
+ TRACE("Deleting symlink %s\n", unix_name.Buffer);
+ TRACE( "Deleting symlink %s\n", unix_name );
+
+ /* Produce the directory in a temporary location in the same folder */
+ if (fstat( dest_fd, &st ) == -1)
@ -106,7 +106,7 @@ index 52520f5f78f..c65ab7de16c 100644
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ strcpy( tmpdir, unix_name.Buffer );
+ strcpy( tmpdir, unix_name );
+ d = dirname( tmpdir);
+ if (d != tmpdir) strcpy( tmpdir, d );
+ strcat( tmpdir, "/.winelink.XXXXXX" );
@ -126,7 +126,7 @@ index 52520f5f78f..c65ab7de16c 100644
+ /* 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 ))
+ if (!renameat2( -1, tmpfile, -1, unix_name, RENAME_EXCHANGE ))
+ {
+ /* success: link and folder have switched locations */
+ unlink( tmpfile ); /* remove the link (at folder location) */
@ -135,12 +135,12 @@ index 52520f5f78f..c65ab7de16c 100644
+ {
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
+ "using unsafe exchange instead.\n" );
+ if (unlink( unix_name.Buffer ))
+ if (unlink( unix_name ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if (rename( tmpfile, unix_name.Buffer ))
+ if (rename( tmpfile, unix_name ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
@ -163,9 +163,9 @@ index 52520f5f78f..c65ab7de16c 100644
/******************************************************************************
* NtFsControlFile (NTDLL.@)
*/
@@ -5872,6 +5953,22 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
status = STATUS_SUCCESS;
@@ -5899,6 +5980,22 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
break;
}
+ case FSCTL_DELETE_REPARSE_POINT:
+ {
@ -208,5 +208,5 @@ index 21d42e17325..4539b89d583 100644
+
#endif /* __WINE_NTIFS_H */
--
2.27.0
2.17.1

View File

@ -1,4 +1,4 @@
From c86d6453694ed2723e5eaa1c55f9e53e1b9946d8 Mon Sep 17 00:00:00 2001
From 4b5123561e8260ed4b1421b0cf127468ac7c131f Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:01:25 -0700
Subject: ntdll: Add a test for junction point advertisement.
@ -9,10 +9,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
1 file changed, 5 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index bc6961bc61..e1f216370d 100644
index 9da353bbbd2..051237dd494 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4925,6 +4925,11 @@ static void test_reparse_points(void)
@@ -5066,6 +5066,11 @@ static void test_reparse_points(void)
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());

View File

@ -1,66 +0,0 @@
From 3473ccddec5c67bbfe1d477ce36f537493fae54b Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:02:11 -0700
Subject: [PATCH] kernel32,ntdll: Add support for deleting junction points with
RemoveDirectory.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 34 +++++++++++++++++++++++++++++++++-
1 file changed, 33 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 6b3071f4095..1d5e0ce95b0 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5010,7 +5010,7 @@ static void test_reparse_points(void)
REPARSE_GUID_DATA_BUFFER guid_buffer;
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
- DWORD dwret, dwLen, dwFlags;
+ DWORD dwret, dwLen, dwFlags, err;
INT buffer_len, string_len;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
@@ -5099,6 +5099,38 @@ static void test_reparse_points(void)
"Junction point folder's access time does not match.\n");
CloseHandle(handle);
+ /* Check deleting a junction point as if it were a directory */
+ 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, &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);
+ bret = RemoveDirectoryW(reparse_path);
+ ok(bret, "Failed to delete junction point as directory!\n");
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret == (DWORD)~0, "Junction point still exists (attributes: 0x%x)!\n", dwret);
+
+ /* Check deleting a junction point as if it were a file */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ bret = CreateDirectoryW(reparse_path, NULL);
+ 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, &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);
+ bret = DeleteFileW(reparse_path);
+ ok(!bret, "Succeeded in deleting junction point as file!\n");
+ err = GetLastError();
+ ok(err == ERROR_ACCESS_DENIED, "Expected last error 0x%x for DeleteFile on junction point (actually 0x%x)!\n",
+ ERROR_ACCESS_DENIED, err);
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%x)\n", dwret);
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
--
2.27.0

View File

@ -0,0 +1,161 @@
From 398754456f977e063aa1c180301ce44fd5fdaf84 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:02:11 -0700
Subject: server: Add support for deleting junction points with
RemoveDirectory.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 34 +++++++++++++++++++++++++++++++++-
server/fd.c | 27 ++++++++++++++++++---------
2 files changed, 51 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 051237dd494..77a1be8307b 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5010,7 +5010,7 @@ static void test_reparse_points(void)
REPARSE_GUID_DATA_BUFFER guid_buffer;
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
- DWORD dwret, dwLen, dwFlags;
+ DWORD dwret, dwLen, dwFlags, err;
INT buffer_len, string_len;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
@@ -5099,6 +5099,38 @@ static void test_reparse_points(void)
"Junction point folder's access time does not match.\n");
CloseHandle(handle);
+ /* Check deleting a junction point as if it were a directory */
+ 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, &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);
+ bret = RemoveDirectoryW(reparse_path);
+ ok(bret, "Failed to delete junction point as directory!\n");
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret == (DWORD)~0, "Junction point still exists (attributes: 0x%x)!\n", dwret);
+
+ /* Check deleting a junction point as if it were a file */
+ HeapFree(GetProcessHeap(), 0, buffer);
+ bret = CreateDirectoryW(reparse_path, NULL);
+ 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, &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);
+ bret = DeleteFileW(reparse_path);
+ ok(!bret, "Succeeded in deleting junction point as file!\n");
+ err = GetLastError();
+ ok(err == ERROR_ACCESS_DENIED, "Expected last error 0x%x for DeleteFile on junction point (actually 0x%x)!\n",
+ ERROR_ACCESS_DENIED, err);
+ dwret = GetFileAttributesW(reparse_path);
+ ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%x)!\n", dwret);
+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%x)\n", dwret);
+
cleanup:
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/server/fd.c b/server/fd.c
index 7ea8ac273e5..c0d35e2fa4c 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -169,7 +169,8 @@ struct closed_fd
struct list entry; /* entry in inode closed list */
int unix_fd; /* the unix file descriptor */
int unlink; /* whether to unlink on close: -1 - implicit FILE_DELETE_ON_CLOSE, 1 - explicit disposition */
- char *unix_name; /* name to unlink on close, points to parent fd unix_name */
+ char *unlink_name; /* name to unlink on close, points to parent fd unix_name */
+ char *unix_name; /* name to real file path, points to parent fd unix_name */
};
struct fd
@@ -184,6 +185,7 @@ struct fd
unsigned int access; /* file access (FILE_READ_DATA etc.) */
unsigned int options; /* file options (FILE_DELETE_ON_CLOSE, FILE_SYNCHRONOUS...) */
unsigned int sharing; /* file sharing mode */
+ char *unlink_name; /* file name to unlink on close */
char *unix_name; /* unix file name */
int unix_fd; /* unix file descriptor */
unsigned int no_fd_status;/* status to return when unix_fd is -1 */
@@ -1113,6 +1115,7 @@ static void inode_close_pending( struct inode *inode, int keep_unlinks )
if (!keep_unlinks || !fd->unlink) /* get rid of it unless there's an unlink pending on that file */
{
list_remove( ptr );
+ free( fd->unlink_name );
free( fd->unix_name );
free( fd );
}
@@ -1147,12 +1150,13 @@ static void inode_destroy( struct object *obj )
{
/* make sure it is still the same file */
struct stat st;
- if (!stat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
+ if (!lstat( fd->unlink_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
{
- if (S_ISDIR(st.st_mode)) rmdir( fd->unix_name );
- else unlink( fd->unix_name );
+ if (S_ISDIR(st.st_mode)) rmdir( fd->unlink_name );
+ else unlink( fd->unlink_name );
}
}
+ free( fd->unlink_name );
free( fd->unix_name );
free( fd );
}
@@ -1903,18 +1907,19 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
fd->unix_name = NULL;
if ((path = dup_fd_name( root, name )))
{
+ fd->unlink_name = path;
fd->unix_name = realpath( path, NULL );
- free( path );
}
closed_fd->unix_fd = fd->unix_fd;
closed_fd->unlink = 0;
+ closed_fd->unlink_name = fd->unlink_name;
closed_fd->unix_name = fd->unix_name;
- fstat( fd->unix_fd, &st );
+ lstat( fd->unlink_name, &st );
*mode = st.st_mode;
/* only bother with an inode for normal files and directories */
- if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
+ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
{
unsigned int err;
struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd );
@@ -1932,6 +1937,9 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
list_add_head( &inode->open, &fd->inode_entry );
closed_fd = NULL;
+ fstat( fd->unix_fd, &st );
+ *mode = st.st_mode;
+
/* check directory options */
if ((options & FILE_DIRECTORY_FILE) && !S_ISDIR(st.st_mode))
{
@@ -2563,10 +2571,11 @@ static void set_fd_name( struct fd *fd, struct fd *root, const char *nameptr,
fchmod( fd->unix_fd, st.st_mode );
}
+ free( fd->unlink_name );
free( fd->unix_name );
+ fd->closed->unlink_name = fd->unlink_name = name;
fd->closed->unix_name = fd->unix_name = realpath( name, NULL );
- free( name );
- if (!fd->unix_name)
+ if (!fd->unlink_name || !fd->unix_name)
set_error( STATUS_NO_MEMORY );
return;
--
2.17.1

View File

@ -1,7 +1,7 @@
From 3ef1ecf4b3b6db13e96d6440e51c9407f8b5dcda Mon Sep 17 00:00:00 2001
From f74db8315285e44fe21d120337fe568ed9824ae1 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.
Subject: ntdll: Add support for absolute symlink creation.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
@ -11,10 +11,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
3 files changed, 143 insertions(+), 19 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 541572c27ce..f91bb40a133 100644
index 77a1be8307b..986468a1495 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4972,26 +4972,50 @@ static void test_file_readonly_access(void)
@@ -4973,26 +4973,50 @@ static void test_file_readonly_access(void)
DeleteFileW(path);
}
@ -73,7 +73,7 @@ index 541572c27ce..f91bb40a133 100644
lstrcpyW(subst_dest, filename);
lstrcpyW(print_dest, &filename[prefix_len]);
*pbuffer = buffer;
@@ -5011,10 +5035,12 @@ static void test_reparse_points(void)
@@ -5012,10 +5036,12 @@ static void test_reparse_points(void)
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
INT buffer_len, string_len;
@ -87,7 +87,7 @@ index 541572c27ce..f91bb40a133 100644
BOOL bret;
/* Create a temporary folder for the junction point tests */
@@ -5061,7 +5087,7 @@ static void test_reparse_points(void)
@@ -5062,7 +5088,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);
@ -96,7 +96,7 @@ index 541572c27ce..f91bb40a133 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());
@@ -5102,7 +5128,7 @@ static void test_reparse_points(void)
@@ -5103,7 +5129,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);
@ -105,7 +105,7 @@ index 541572c27ce..f91bb40a133 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);
@@ -5117,7 +5143,7 @@ static void test_reparse_points(void)
@@ -5118,7 +5144,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);
@ -114,7 +114,7 @@ index 541572c27ce..f91bb40a133 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);
@@ -5130,14 +5156,73 @@ static void test_reparse_points(void)
@@ -5131,14 +5157,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);
@ -193,10 +193,10 @@ index 541572c27ce..f91bb40a133 100644
}
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index c65ab7de16c..15f6a006145 100644
index 3f6dcc6ab41..b8dc02127ba 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,
@@ -5601,18 +5601,34 @@ 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;
@ -204,7 +204,8 @@ index c65ab7de16c..15f6a006145 100644
- 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;
SIZE_T unix_dest_len = PATH_MAX;
char *unix_src, *unix_dest;
char magic_dest[PATH_MAX];
int dest_fd, needs_close;
UNICODE_STRING nt_dest;
@ -233,7 +234,7 @@ index c65ab7de16c..15f6a006145 100644
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)
@@ -5647,6 +5663,18 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
strcat( magic_dest, "." );
strcat( magic_dest, "/" );
}
@ -249,10 +250,10 @@ index c65ab7de16c..15f6a006145 100644
+ strcat( magic_dest, "." );
+ strcat( magic_dest, "/" );
+ }
strcat( magic_dest, unix_dest.Buffer );
strcat( magic_dest, unix_dest );
/* 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
@@ -6009,6 +6037,7 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
@ -294,5 +295,5 @@ index 4539b89d583..ab3273d3f81 100644
typedef struct _REPARSE_GUID_DATA_BUFFER {
DWORD ReparseTag;
--
2.27.0
2.17.1

View File

@ -1,7 +1,7 @@
From 58371a3c2d5fed81abc2b1ae6f79133dd57a873d Mon Sep 17 00:00:00 2001
From 3595e892dbf4d5b123ce641b6ce72490cc3d782f 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: [PATCH] ntdll: Add support for reading absolute symlinks.
Subject: ntdll: Add support for reading absolute symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
@ -10,10 +10,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
2 files changed, 34 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index f91bb40a133..5d3411d242e 100644
index 986468a1495..5b7bdf7ddfd 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5207,7 +5207,6 @@ static void test_reparse_points(void)
@@ -5208,7 +5208,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);
@ -21,7 +21,7 @@ index f91bb40a133..5d3411d242e 100644
ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
/* Check the file attributes of the symlink */
@@ -5215,6 +5214,18 @@ static void test_reparse_points(void)
@@ -5216,6 +5215,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);
@ -41,18 +41,18 @@ index f91bb40a133..5d3411d242e 100644
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 15f6a006145..9cecf44db82 100644
index b8dc02127ba..cd14a2e24c3 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;
@@ -5746,6 +5746,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
int unix_dest_len;
DWORD max_length;
NTSTATUS status;
+ ULONG flags = 0;
WCHAR *nt_dest;
INT prefix_len;
ssize_t ret;
char *p;
@@ -5794,6 +5795,17 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
@@ -5790,6 +5791,17 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
}
buffer->ReparseTag |= (val << i);
}
@ -67,20 +67,20 @@ index 15f6a006145..9cecf44db82 100644
+ goto cleanup;
+ }
+ }
unix_dest.Length -= (p - unix_dest.Buffer);
memmove(unix_dest.Buffer, p, unix_dest.Length);
unix_dest_len -= (p - unix_dest);
memmove(unix_dest, p, unix_dest_len);
@@ -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);
@@ -5822,6 +5834,16 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
buffer->MountPointReparseBuffer.PrintNameLength = nt_dest_len - 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;
+ buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = nt_dest_len;
+ 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);
+ buffer->SymbolicLinkReparseBuffer.PrintNameOffset = nt_dest_len + sizeof(WCHAR);
+ buffer->SymbolicLinkReparseBuffer.PrintNameLength = nt_dest_len - prefix_len*sizeof(WCHAR);
+ print_name = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR)];
+ buffer->SymbolicLinkReparseBuffer.Flags = flags;
+ break;
@ -88,5 +88,5 @@ index 15f6a006145..9cecf44db82 100644
/* unrecognized (regular) files should probably be treated as symlinks */
WARN("unrecognized symbolic link\n");
--
2.27.0
2.17.1

View File

@ -1,7 +1,7 @@
From 478bca2da5a745e14d4fd16a3d4415cf08855308 Mon Sep 17 00:00:00 2001
From 248faa7fd14b6ff0028c7762edd0bb8ad564b9ca 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: [PATCH] ntdll: Add support for deleting symlinks.
Subject: ntdll: Add support for deleting symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
@ -10,10 +10,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
2 files changed, 17 insertions(+)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 5d3411d242e..df912e18496 100644
index 5b7bdf7ddfd..b6a58c3f2a7 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5224,6 +5224,22 @@ static void test_reparse_points(void)
@@ -5225,6 +5225,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));
@ -37,10 +37,10 @@ index 5d3411d242e..df912e18496 100644
cleanup:
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 9cecf44db82..e35ea49d17f 100644
index cd14a2e24c3..232cbb36f42 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
@@ -6037,6 +6037,7 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
@ -49,5 +49,5 @@ index 9cecf44db82..e35ea49d17f 100644
break;
default:
--
2.27.0
2.17.1

View File

@ -1,20 +1,20 @@
From 2fe2cb6a67925f22e9b3fbffefd20c2fe0040775 Mon Sep 17 00:00:00 2001
From 9baddd14dceb102d123a6470a12e43ffd4e1e4de 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.
Subject: ntdll: Add support for relative symlink creation.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 30 ++++++++++++++++-----
dlls/ntdll/unix/file.c | 58 ++++++++++++++++++++++++++++++++++++-----
include/ntifs.h | 2 ++
3 files changed, 77 insertions(+), 13 deletions(-)
dlls/ntdll/tests/file.c | 30 +++++++++++---
dlls/ntdll/unix/file.c | 90 +++++++++++++++++++++++++++++++++++++----
include/ntifs.h | 2 +
3 files changed, 109 insertions(+), 13 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index b93ba0e87ed..975a72e7103 100644
index b6a58c3f2a7..9b510fe9057 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -4972,7 +4972,8 @@ static void test_file_readonly_access(void)
@@ -4973,7 +4973,8 @@ static void test_file_readonly_access(void)
DeleteFileW(path);
}
@ -24,7 +24,7 @@ index b93ba0e87ed..975a72e7103 100644
{
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
@@ -4991,7 +4992,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, REPARSE_DATA_B
default:
return 0;
}
@ -33,7 +33,7 @@ index b93ba0e87ed..975a72e7103 100644
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
@@ -5011,6 +5012,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);
@ -41,7 +41,7 @@ index b93ba0e87ed..975a72e7103 100644
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)
@@ -5088,7 +5090,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);
@ -50,7 +50,7 @@ index b93ba0e87ed..975a72e7103 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());
@@ -5128,7 +5130,7 @@ static void test_reparse_points(void)
@@ -5129,7 +5131,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);
@ -59,7 +59,7 @@ index b93ba0e87ed..975a72e7103 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);
@@ -5143,7 +5145,7 @@ static void test_reparse_points(void)
@@ -5144,7 +5146,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);
@ -68,7 +68,7 @@ index b93ba0e87ed..975a72e7103 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);
@@ -5205,7 +5207,7 @@ static void test_reparse_points(void)
@@ -5206,7 +5208,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);
@ -77,7 +77,7 @@ index b93ba0e87ed..975a72e7103 100644
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)
@@ -5243,6 +5245,22 @@ static void test_reparse_points(void)
"Symlink folder's access time does not match.\n");
CloseHandle(handle);
@ -101,19 +101,20 @@ index b93ba0e87ed..975a72e7103 100644
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index fe945cef477..a1d1863133a 100644
index 232cbb36f42..3652fbb1a0d 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5669,16 +5669,19 @@ static void ignore_server_ioctl_struct_holes( ULONG code, const void *in_buffer,
@@ -5600,17 +5600,20 @@ 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;
+ BOOL src_allocated = FALSE, path_allocated = FALSE, dest_allocated = FALSE;
+ BOOL nt_dest_allocated = FALSE, tempdir_created = FALSE;
+ char *unix_src, *unix_dest, *unix_path = NULL;
char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
- ANSI_STRING unix_src, unix_dest;
+ ANSI_STRING unix_src, unix_dest, unix_path;
SIZE_T unix_dest_len = PATH_MAX;
- char *unix_src, *unix_dest;
char magic_dest[PATH_MAX];
int dest_fd, needs_close;
+ int relative_offset = 0;
@ -126,7 +127,7 @@ index fe945cef477..a1d1863133a 100644
int i;
switch(buffer->ReparseTag)
@@ -5687,11 +5690,13 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5619,11 +5622,13 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
dest_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
offset = buffer->MountPointReparseBuffer.SubstituteNameOffset;
dest = &buffer->MountPointReparseBuffer.PathBuffer[offset];
@ -140,7 +141,7 @@ index fe945cef477..a1d1863133a 100644
break;
default:
return STATUS_NOT_IMPLEMENTED;
@@ -5703,17 +5708,54 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5635,8 +5640,64 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
if ((status = server_get_unix_name( handle, &unix_src )))
goto cleanup;
src_allocated = TRUE;
@ -148,24 +149,54 @@ index fe945cef477..a1d1863133a 100644
- nt_dest.Length = dest_len;
+ if (flags == SYMLINK_FLAG_RELATIVE)
+ {
+ UNICODE_STRING nt_path;
+ SIZE_T nt_path_len = PATH_MAX, unix_path_len = PATH_MAX;
+ WCHAR *nt_path;
+
+ unix_path.MaximumLength = strlen(unix_src.Buffer) + 2;
+ unix_path.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, unix_path.MaximumLength );
+ /* resolve the NT path of the source */
+ unix_path = malloc( strlen(unix_src) + 2 );
+ path_allocated = TRUE;
+ strcpy( unix_path.Buffer, unix_src.Buffer );
+ d = dirname( unix_path.Buffer );
+ if (d != unix_path.Buffer) strcpy( unix_path.Buffer, d );
+ strcat( unix_path.Buffer, "/");
+ unix_path.Length = strlen( unix_path.Buffer );
+ if ((status = unix_to_nt_file_name( &unix_path, &nt_path )))
+ strcpy( unix_path, unix_src );
+ d = dirname( unix_path );
+ if (d != unix_path) strcpy( unix_path, d );
+ strcat( unix_path, "/");
+ for (;;)
+ {
+ nt_path = malloc( nt_path_len * sizeof(WCHAR) );
+ if (!nt_path)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ status = wine_unix_to_nt_file_name( unix_path, nt_path, &nt_path_len );
+ if (status != STATUS_BUFFER_TOO_SMALL) break;
+ free( nt_path );
+ }
+ if (status != STATUS_SUCCESS)
+ goto cleanup;
+ nt_dest.MaximumLength = dest_len + (wcslen( nt_path.Buffer ) + 1) * sizeof(WCHAR);
+ free(unix_path);
+ /* re-resolve the unix path for the source */
+ for (;;)
+ {
+ UNICODE_STRING nt_path_tmp;
+ unix_path = malloc( unix_path_len );
+ if (!unix_path)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ nt_path_tmp.Buffer = nt_path;
+ nt_path_tmp.Length = lstrlenW(nt_path) * sizeof(WCHAR);
+ status = wine_nt_to_unix_file_name( &nt_path_tmp, unix_path, &unix_path_len, FALSE );
+ if (status != STATUS_BUFFER_TOO_SMALL) break;
+ free( unix_path );
+ }
+ /* append the destination */
+ nt_dest.MaximumLength = dest_len + (lstrlenW( nt_path ) + 1) * sizeof(WCHAR);
+ nt_dest.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, nt_dest.MaximumLength );
+ wcscpy( nt_dest.Buffer, nt_path.Buffer );
+ RtlFreeUnicodeString( &nt_path );
+ memcpy( &nt_dest.Buffer[wcslen(nt_dest.Buffer)], dest, dest_len + sizeof(WCHAR));
+ nt_dest.Length = wcslen( nt_dest.Buffer ) * sizeof(WCHAR);
+ lstrcpyW( nt_dest.Buffer, nt_path );
+ free( nt_path );
+ memcpy( &nt_dest.Buffer[lstrlenW(nt_dest.Buffer)], dest, dest_len + sizeof(WCHAR));
+ nt_dest.Length = lstrlenW( nt_dest.Buffer ) * sizeof(WCHAR);
+ }
+ else
+ {
@ -173,22 +204,27 @@ index fe945cef477..a1d1863133a 100644
+ nt_dest.Length = dest_len;
+ }
+ nt_dest_allocated = TRUE;
status = nt_to_unix_file_name( &nt_dest, &unix_dest, 0 );
+ /* resolve the NT path of the destination */
for (;;)
{
unix_dest = malloc( unix_dest_len );
@@ -5652,11 +5713,24 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
if (status != STATUS_SUCCESS && status != STATUS_NO_SUCH_FILE)
goto cleanup;
dest_allocated = TRUE;
+ /* check that the source and destination paths are the same up to the relative path */
+ if (flags == SYMLINK_FLAG_RELATIVE)
+ {
+ relative_offset = strlen(unix_path.Buffer);
+ if (strncmp( unix_path.Buffer, unix_dest.Buffer, relative_offset ) != 0)
+ relative_offset = strlen(unix_path);
+ if (strncmp( unix_path, unix_dest, relative_offset ) != 0)
+ {
+ status = STATUS_IO_REPARSE_DATA_INVALID;
+ goto cleanup;
+ }
+ }
- TRACE("Linking %s to %s\n", unix_src.Buffer, unix_dest.Buffer);
+ TRACE("Linking %s to %s\n", unix_src.Buffer, &unix_dest.Buffer[relative_offset]);
- TRACE( "Linking %s to %s\n", unix_src, unix_dest );
+ TRACE( "Linking %s to %s\n", unix_src, &unix_dest[relative_offset] );
/* Encode the reparse tag into the symlink */
- strcpy( magic_dest, "/" );
@ -199,23 +235,23 @@ index fe945cef477..a1d1863133a 100644
for (i = 0; i < sizeof(ULONG)*8; i++)
{
if ((buffer->ReparseTag >> i) & 1)
@@ -5732,7 +5774,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5675,7 +5749,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
strcat( magic_dest, "." );
strcat( magic_dest, "/" );
}
- strcat( magic_dest, unix_dest.Buffer );
+ strcat( magic_dest, &unix_dest.Buffer[relative_offset] );
- strcat( magic_dest, unix_dest );
+ strcat( magic_dest, &unix_dest[relative_offset] );
/* Produce the link in a temporary location in the same folder */
strcpy( tmpdir, unix_src.Buffer );
@@ -5782,7 +5824,9 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
strcpy( tmpdir, unix_src );
@@ -5725,7 +5799,9 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
cleanup:
if (tempdir_created) rmdir( tmpdir );
+ if (path_allocated) RtlFreeAnsiString( &unix_path );
if (dest_allocated) RtlFreeAnsiString( &unix_dest );
+ if (path_allocated) free( unix_path );
if (dest_allocated) free( unix_dest );
+ if (nt_dest_allocated) RtlFreeUnicodeString( &nt_dest );
if (src_allocated) RtlFreeAnsiString( &unix_src );
if (src_allocated) free( unix_src );
if (needs_close) close( dest_fd );
return status;
diff --git a/include/ntifs.h b/include/ntifs.h
@ -230,5 +266,5 @@ index ab3273d3f81..0d02225bc4f 100644
+
#endif /* __WINE_NTIFS_H */
--
2.27.0
2.17.1

View File

@ -1,19 +1,19 @@
From af4840c79a9958609575553aaf8bdf13dabe68ef Mon Sep 17 00:00:00 2001
From 5658e73f218d01b0e11bc4575cf0502b8235ec2c 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.
Subject: ntdll: Add support for reading relative symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 13 +++++++++++-
dlls/ntdll/unix/file.c | 44 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 55 insertions(+), 2 deletions(-)
dlls/ntdll/tests/file.c | 13 ++++++++-
dlls/ntdll/unix/file.c | 61 ++++++++++++++++++++++++++++++++++++++++-
2 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 515a84da4d6..30ab4110105 100644
index 9b510fe9057..0db7372a0c8 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5257,9 +5257,20 @@ static void test_reparse_points(void)
@@ -5258,9 +5258,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);
@ -36,21 +36,21 @@ index 515a84da4d6..30ab4110105 100644
/* Cleanup */
pRtlFreeUnicodeString(&nameW);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index eb39dc0873b..d19b48d4224 100644
index 3652fbb1a0d..e62a2529bb2 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
@@ -5820,6 +5820,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 unix_dest_len;
+ 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
@@ -5845,6 +5846,11 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
/* Decode the reparse tag from the symlink */
p = unix_dest.Buffer;
p = unix_dest;
+ if (*p == '.')
+ {
+ flags = SYMLINK_FLAG_RELATIVE;
@ -59,54 +59,75 @@ index eb39dc0873b..d19b48d4224 100644
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);
@@ -5881,6 +5887,25 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
unix_dest_len -= (p - unix_dest);
memmove(unix_dest, p, unix_dest_len);
+ /* convert the relative path into an absolute path */
+ if (flags == SYMLINK_FLAG_RELATIVE)
+ {
+ int offset = unix_src.Length + 2;
+ int unix_src_len = strlen(unix_src);
+ int offset = unix_src_len + 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 );
+
+ memcpy( &unix_dest[offset], unix_dest, unix_dest_len );
+ unix_dest[offset+unix_dest_len] = 0;
+ memcpy( unix_dest, unix_src, unix_src_len );
+ unix_dest[unix_src_len] = 0;
+ d = dirname( unix_dest );
+ if (d != unix_dest) strcpy( unix_dest, d );
+ strcat( unix_dest, "/" );
+ path_len = strlen( unix_dest );
+ memmove( &unix_dest[path_len], &unix_dest[offset], unix_dest_len + 1 );
+ unix_dest_len = strlen( unix_dest );
+ }
if ((status = unix_to_nt_file_name( &unix_dest, &nt_dest )))
+ /* resolve the NT path */
for (;;)
{
nt_dest = malloc( nt_dest_len * sizeof(WCHAR) );
@@ -5898,7 +5923,41 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
goto cleanup;
nt_dest_len *= sizeof(WCHAR);
- prefix_len = strlen("\\??\\");
+ /* remove the relative path from the NT path */
+ if (flags == SYMLINK_FLAG_RELATIVE)
+ {
+ UNICODE_STRING nt_path;
+ SIZE_T nt_path_len = PATH_MAX;
+ int relative_offset;
+ WCHAR *nt_path;
+
+ 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)
+ unix_dest_len = path_len;
+ for (;;)
+ {
+ RtlFreeUnicodeString( &nt_path );
+ nt_path = malloc( nt_path_len * sizeof(WCHAR) );
+ if (!nt_path)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ status = wine_unix_to_nt_file_name( unix_dest, nt_path, &nt_path_len );
+ if (status != STATUS_BUFFER_TOO_SMALL) break;
+ free( nt_path );
+ }
+ if (status != STATUS_SUCCESS)
+ goto cleanup;
+ relative_offset = lstrlenW( nt_path );
+ if (wcsnicmp( nt_path, nt_dest, relative_offset ) != 0)
+ {
+ free( 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) );
+ free( nt_path );
+ nt_dest_len = lstrlenW( &nt_dest[relative_offset] ) * sizeof(WCHAR);
+ memmove( nt_dest, &nt_dest[relative_offset], nt_dest_len + sizeof(WCHAR) );
+ }
- prefix_len = strlen("\\??\\");
+
+ prefix_len = (flags == SYMLINK_FLAG_RELATIVE) ? 0 : strlen("\\??\\");
switch(buffer->ReparseTag)
{
case IO_REPARSE_TAG_MOUNT_POINT:
--
2.27.0
2.17.1

View File

@ -1,7 +1,7 @@
From 13ccfb68becff81e4a9cd94654ed51facbe96bb9 Mon Sep 17 00:00:00 2001
From d98202d50cdb09fe199414b8a313fcf954725e2d 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: [PATCH] ntdll: Add support for file symlinks.
Subject: ntdll: Add support for file symlinks.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
@ -10,10 +10,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
2 files changed, 51 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 30ab4110105..ebeb1ec7713 100644
index 0db7372a0c8..58fec76bec4 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5190,6 +5190,35 @@ static void test_reparse_points(void)
@@ -5191,6 +5191,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");
@ -50,10 +50,10 @@ index 30ab4110105..ebeb1ec7713 100644
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
index e62a2529bb2..242d344e1f5 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)
@@ -5610,6 +5610,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
int relative_offset = 0;
UNICODE_STRING nt_dest;
int dest_len, offset;
@ -61,7 +61,7 @@ index d19b48d4224..fb1e6bd3c1c 100644
NTSTATUS status;
struct stat st;
WCHAR *dest;
@@ -5716,7 +5717,8 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5745,7 +5746,8 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
status = errno_to_status( errno );
goto cleanup;
}
@ -71,9 +71,9 @@ index d19b48d4224..fb1e6bd3c1c 100644
strcat( magic_dest, "." );
strcat( magic_dest, "/" );
}
@@ -5743,8 +5745,11 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
@@ -5772,8 +5774,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 ))
if (!renameat2( -1, tmplink, -1, unix_src, RENAME_EXCHANGE ))
{
- /* success: link and folder have switched locations */
- rmdir( tmplink ); /* remove the folder (at link location) */
@ -85,17 +85,17 @@ index d19b48d4224..fb1e6bd3c1c 100644
}
else if (errno == ENOSYS)
{
@@ -5953,6 +5958,7 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
@@ -6011,6 +6016,7 @@ 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;
+ BOOL is_dir = TRUE;
NTSTATUS status;
char *unix_name;
struct stat st;
@@ -6023,12 +6029,13 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
@@ -5964,12 +5970,13 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
TRACE("Deleting symlink %s\n", unix_name.Buffer);
TRACE( "Deleting symlink %s\n", unix_name );
- /* Produce the directory in a temporary location in the same folder */
+ /* Produce the file/directory in a temporary location in the same folder */
@ -105,10 +105,10 @@ index d19b48d4224..fb1e6bd3c1c 100644
goto cleanup;
}
+ is_dir = S_ISDIR(st.st_mode);
strcpy( tmpdir, unix_name.Buffer );
strcpy( tmpdir, unix_name );
d = dirname( tmpdir);
if (d != tmpdir) strcpy( tmpdir, d );
@@ -5982,11 +5989,21 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
@@ -6041,11 +6048,21 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
tempdir_created = TRUE;
strcpy( tmpfile, tmpdir );
strcat( tmpfile, "/tmpfile" );
@ -132,5 +132,5 @@ index d19b48d4224..fb1e6bd3c1c 100644
lchown( tmpfile, st.st_uid, st.st_gid );
/* Atomically move the directory into position */
--
2.27.0
2.17.1

View File

@ -1,8 +1,8 @@
From c1f3ec8ecefd4488bd8f49da22deb2f4f56d489c Mon Sep 17 00:00:00 2001
From 767c81a6bb76f0f852f4ba7260dc0c1b26b45e09 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
non-existent paths.
Subject: ntdll: Allow creation of dangling reparse points to non-existent
paths.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
@ -11,10 +11,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
2 files changed, 15 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 3cfd633df86..fc79a2fa735 100644
index 242d344e1f5..248bda3d3ce 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3273,6 +3273,19 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
@@ -3154,6 +3154,19 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
status = STATUS_OBJECT_NAME_COLLISION;
}
}
@ -34,17 +34,17 @@ index 3cfd633df86..fc79a2fa735 100644
if (status != STATUS_SUCCESS) break;
@@ -5736,7 +5749,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
nt_dest.Length = dest_len;
@@ -5707,7 +5720,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
status = STATUS_NO_MEMORY;
goto cleanup;
}
- status = wine_nt_to_unix_file_name( &nt_dest, unix_dest, &unix_dest_len, FALSE );
+ status = wine_nt_to_unix_file_name( &nt_dest, unix_dest, &unix_dest_len, FILE_WINE_PATH );
if (status != STATUS_BUFFER_TOO_SMALL) break;
free( unix_dest );
}
nt_dest_allocated = TRUE;
- status = nt_to_unix_file_name( &nt_dest, &unix_dest, 0 );
+ status = nt_to_unix_file_name( &nt_dest, &unix_dest, FILE_WINE_PATH );
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 4ee32d3c9e9..3d444e7485e 100644
index b3fbb90feff..221c8e39e84 100644
--- a/include/winternl.h
+++ b/include/winternl.h
@@ -1869,6 +1869,7 @@ typedef struct _RTL_HANDLE_TABLE
@ -56,5 +56,5 @@ index 4ee32d3c9e9..3d444e7485e 100644
/* Characteristics of a File System */
#define FILE_REMOVABLE_MEDIA 0x00000001
--
2.27.0
2.17.1

View File

@ -1,62 +1,28 @@
From 6ab64d5c26ab8713b2e55911540538a700580017 Mon Sep 17 00:00:00 2001
From dcb3180f1f1569626956e51aa35b032271399390 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/tests/file.c | 8 +--
dlls/ntdll/unix/file.c | 120 ++++++++++++++++++++++++++--------------
2 files changed, 84 insertions(+), 44 deletions(-)
dlls/ntdll/unix/file.c | 115 +++++++++++++++++++++++++++--------------
1 file changed, 77 insertions(+), 38 deletions(-)
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
index af964cf1334..205adafcd8f 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 )
@@ -1466,6 +1466,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,
+NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, int *unix_dest_len,
+ DWORD *tag, ULONG *flags, BOOL *is_dir);
+
/* fetch the attributes of a file */
static inline ULONG get_file_attributes( const struct stat *st )
{
@@ -1554,10 +1557,15 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr )
@@ -1550,10 +1553,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 ))
{
@ -74,9 +40,9 @@ index d77a788e0fb..9656f1eb14c 100644
+ if (FILE_DecodeSymlink( path, NULL, NULL, NULL, NULL, &is_dir ) == STATUS_SUCCESS)
+ st->st_mode = (st->st_mode & ~S_IFMT) | (is_dir ? S_IFDIR : S_IFREG);
}
else if (S_ISDIR( st->st_mode ) && (parent_path = RtlAllocateHeap( GetProcessHeap(), 0, strlen(path) + 4 )))
else if (S_ISDIR( st->st_mode ) && (parent_path = malloc( strlen(path) + 4 )))
{
@@ -5851,48 +5859,33 @@ cleanup:
@@ -5879,47 +5887,34 @@ cleanup:
}
@ -85,20 +51,22 @@ index d77a788e0fb..9656f1eb14c 100644
- * symlink corresponding to that file handle.
- */
-NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_size)
+NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, USHORT *unix_dest_len,
+NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, int *unix_dest_len,
+ DWORD *tag, ULONG *flags, BOOL *is_dir)
{
- ANSI_STRING unix_src, unix_dest;
- char *unix_src, unix_dest[PATH_MAX];
- VOID *subst_name, *print_name;
- SIZE_T nt_dest_len = PATH_MAX;
- BOOL dest_allocated = FALSE;
- int dest_fd, needs_close;
- UNICODE_STRING nt_dest;
- int unix_dest_len;
- int path_len = 0;
- DWORD max_length;
+ USHORT len = MAX_PATH;
+ int len = MAX_PATH;
+ DWORD reparse_tag;
NTSTATUS status;
- ULONG flags = 0;
- WCHAR *nt_dest;
- INT prefix_len;
+ BOOL dir_flag;
+ char *p, *tmp;
@ -112,14 +80,11 @@ index d77a788e0fb..9656f1eb14c 100644
- if ((status = server_get_unix_name( handle, &unix_src )))
- goto cleanup;
-
- unix_dest.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, PATH_MAX );
- unix_dest.MaximumLength = PATH_MAX;
- dest_allocated = TRUE;
- ret = readlink( unix_src.Buffer, unix_dest.Buffer, unix_dest.MaximumLength );
- ret = readlink( unix_src, unix_dest, sizeof(unix_dest) );
- if (ret < 0)
+ if (unix_dest_len) len = *unix_dest_len;
+ if (!unix_dest)
+ tmp = RtlAllocateHeap( GetProcessHeap(), 0, len );
+ tmp = malloc( len );
+ else
+ tmp = unix_dest;
+ if ((ret = readlink( unix_src, tmp, len )) < 0)
@ -127,11 +92,11 @@ index d77a788e0fb..9656f1eb14c 100644
status = errno_to_status( errno );
goto cleanup;
}
- unix_dest.Length = ret;
-
- unix_dest_len = ret;
+ len = ret;
/* Decode the reparse tag from the symlink */
- p = unix_dest.Buffer;
- p = unix_dest;
+ p = tmp;
if (*p == '.')
{
@ -140,7 +105,7 @@ index d77a788e0fb..9656f1eb14c 100644
p++;
}
if (*p++ != '/')
@@ -5900,7 +5893,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
@@ -5927,7 +5922,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
@ -149,7 +114,7 @@ index d77a788e0fb..9656f1eb14c 100644
for (i = 0; i < sizeof(ULONG)*8; i++)
{
char c = *p++;
@@ -5915,21 +5908,68 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
@@ -5942,21 +5937,65 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
status = STATUS_NOT_IMPLEMENTED;
goto cleanup;
}
@ -173,19 +138,19 @@ index d77a788e0fb..9656f1eb14c 100644
goto cleanup;
}
}
- unix_dest.Length -= (p - unix_dest.Buffer);
- memmove(unix_dest.Buffer, p, unix_dest.Length);
- unix_dest_len -= (p - unix_dest);
- memmove(unix_dest, p, unix_dest_len);
+ else
+ dir_flag = TRUE;
+ len -= (p - tmp);
+ if (tag) *tag = reparse_tag;
+ if (is_dir) *is_dir = dir_flag;
+ if (unix_dest) memmove(unix_dest, p, len);
+ if (unix_dest) memmove(unix_dest, p, len + 1);
+ if (unix_dest_len) *unix_dest_len = len;
+ status = STATUS_SUCCESS;
+
+cleanup:
+ if (!unix_dest) RtlFreeHeap( GetProcessHeap(), 0, tmp );
+ if (!unix_dest) free( tmp );
+ return status;
+}
+
@ -196,15 +161,17 @@ index d77a788e0fb..9656f1eb14c 100644
+ */
+NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_size)
+{
+ ANSI_STRING unix_src, unix_dest;
+ char *unix_src, unix_dest[PATH_MAX];
+ VOID *subst_name, *print_name;
+ SIZE_T nt_dest_len = PATH_MAX;
+ int unix_dest_len = PATH_MAX;
+ 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;
+ WCHAR *nt_dest;
+ INT prefix_len;
+
+ if ((status = server_get_unix_fd( handle, FILE_ANY_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
@ -213,12 +180,7 @@ index d77a788e0fb..9656f1eb14c 100644
+ if ((status = server_get_unix_name( handle, &unix_src )))
+ goto cleanup;
+
+ unix_dest.MaximumLength = PATH_MAX;
+ unix_dest.Buffer = RtlAllocateHeap( GetProcessHeap(), 0, unix_dest.MaximumLength );
+ unix_dest.Length = unix_dest.MaximumLength;
+ dest_allocated = TRUE;
+ if ((status = FILE_DecodeSymlink( unix_src.Buffer, unix_dest.Buffer, &unix_dest.Length,
+ &buffer->ReparseTag, &flags, NULL )))
+ if ((status = FILE_DecodeSymlink( unix_src, unix_dest, &unix_dest_len, &buffer->ReparseTag, &flags, NULL )))
+ goto cleanup;
/* convert the relative path into an absolute path */

View File

@ -0,0 +1,31 @@
From 3a96350814cd7fd9d620352e252b02aede20d1cf Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 30 Mar 2019 12:01:50 -0600
Subject: kernel32: Set error code when attempting to delete file symlinks as
directories.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 58fec76bec4..7f69a9116f2 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5208,9 +5208,9 @@ static void test_reparse_points(void)
bret = RemoveDirectoryW(reparse_path);
todo_wine 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);
+ 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 & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a symlink! (attributes: 0x%x)\n", dwret);
--
2.17.1

View File

@ -1,19 +1,32 @@
From 9ac3c75b53eeeee76fcf4e1c1a5546ae5fc3b58a Mon Sep 17 00:00:00 2001
From a936bfbd369e1199723b0e5f2fa1329c084561db Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 30 Mar 2019 13:41:07 -0600
Subject: [PATCH] server: Properly handle file symlink deletion.
Subject: server: Properly handle file symlink deletion.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 6 ++--
server/fd.c | 76 ++++++++++++++++++++++++++++++++++++++---
2 files changed, 74 insertions(+), 8 deletions(-)
server/fd.c | 69 +++++++++++++++++++++++++++++++++++++++--
2 files changed, 70 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 0b7e9e230227..a6085d8de75c 100644
index 7f69a9116f2..ddd3d693659 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5198,14 +5198,14 @@ static void test_reparse_points(void)
@@ -5206,18 +5206,18 @@ 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();
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 */
bret = DeleteFileW(reparse_path);
@ -22,20 +35,11 @@ index 0b7e9e230227..a6085d8de75c 100644
/* Create a blank slate for directory symlink tests */
bret = CreateDirectoryW(reparse_path, NULL);
- todo_wine ok(bret, "Failed to create junction point directory.\n");
+ 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);
- todo_wine ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %d)\n", dwret);
+ 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/server/fd.c b/server/fd.c
index 06d1d81bdb08..df0caa483827 100644
index c0d35e2fa4c..9e087917c0d 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -106,6 +106,10 @@
@@ -107,6 +107,10 @@
#include "winioctl.h"
#include "ddk/wdm.h"
@ -46,16 +50,7 @@ index 06d1d81bdb08..df0caa483827 100644
#if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE)
# include <sys/epoll.h>
# define USE_EPOLL
@@ -1146,7 +1150,7 @@ static void inode_destroy( struct object *obj )
{
/* make sure it is still the same file */
struct stat st;
- if (!stat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
+ if (!lstat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
{
if (S_ISDIR(st.st_mode)) rmdir( fd->unix_name );
else unlink( fd->unix_name );
@@ -1824,6 +1828,53 @@ char *dup_fd_name( struct fd *root, const char *name )
@@ -1829,6 +1833,55 @@ char *dup_fd_name( struct fd *root, const char *name )
return ret;
}
@ -66,6 +61,8 @@ index 06d1d81bdb08..df0caa483827 100644
+ int len, i;
+
+ len = readlink( name, link, sizeof(link) );
+ if (len == -1)
+ return;
+ link[len] = 0;
+ p = link;
+ /* skip past relative/absolute indication */
@ -109,7 +106,7 @@ index 06d1d81bdb08..df0caa483827 100644
/* open() wrapper that returns a struct fd with no fd user set */
struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode, unsigned int access,
unsigned int sharing, unsigned int options )
@@ -1891,6 +1942,13 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
@@ -1896,6 +1949,13 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
if ((access & FILE_UNIX_WRITE_ACCESS) || (flags & O_CREAT))
fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode );
}
@ -123,17 +120,7 @@ index 06d1d81bdb08..df0caa483827 100644
if (fd->unix_fd == -1)
{
@@ -1909,14 +1967,15 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
closed_fd->unix_fd = fd->unix_fd;
closed_fd->unlink = 0;
closed_fd->unix_name = fd->unix_name;
- fstat( fd->unix_fd, &st );
+ lstat( fd->unix_name, &st );
*mode = st.st_mode;
/* only bother with an inode for normal files and directories */
- if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
+ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
@@ -1923,6 +1983,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
{
unsigned int err;
struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd );
@ -141,17 +128,17 @@ index 06d1d81bdb08..df0caa483827 100644
if (!inode)
{
@@ -1931,13 +1990,20 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
@@ -1937,16 +1998,20 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
list_add_head( &inode->open, &fd->inode_entry );
closed_fd = NULL;
+ /* decode symlink type */
+ fstat( fd->unix_fd, &st );
+ *mode = st.st_mode;
fstat( fd->unix_fd, &st );
*mode = st.st_mode;
+ is_dir = S_ISDIR(st.st_mode);
+ if (is_link)
+ decode_symlink(fd->unix_name, &is_dir);
+
+ decode_symlink(fd->unlink_name, &is_dir);
/* check directory options */
- if ((options & FILE_DIRECTORY_FILE) && !S_ISDIR(st.st_mode))
+ if ((options & FILE_DIRECTORY_FILE) && !is_dir)
@ -165,5 +152,5 @@ index 06d1d81bdb08..df0caa483827 100644
set_error( STATUS_FILE_IS_A_DIRECTORY );
goto error;
--
2.26.2
2.17.1

View File

@ -1,19 +1,20 @@
From 3c058e77263895ea58b25f652b82d443bcde9dcc Mon Sep 17 00:00:00 2001
From ceb069628acc263e5c1a9ed274f8d00eeb9c4dd8 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: [PATCH] ntdll: Always report symbolic links as containing zero bytes.
Subject: ntdll: Always report symbolic links as containing zero bytes.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 46 +++++++++++++++++++++++++++++++++++++++--
dlls/ntdll/unix/file.c | 2 ++
2 files changed, 46 insertions(+), 2 deletions(-)
server/fd.c | 3 ++-
3 files changed, 48 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index cd2b294bceb..67d54c81fb0 100644
index ddd3d693659..e0a6e3b3143 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5036,7 +5036,9 @@ static void test_reparse_points(void)
@@ -5037,7 +5037,9 @@ static void test_reparse_points(void)
static const WCHAR dotW[] = {'.',0};
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
@ -23,7 +24,7 @@ index cd2b294bceb..67d54c81fb0 100644
HANDLE handle, token;
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
@@ -5164,8 +5166,6 @@ static void test_reparse_points(void)
@@ -5165,8 +5167,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");
@ -32,7 +33,7 @@ index cd2b294bceb..67d54c81fb0 100644
/* Establish permissions for symlink creation */
bret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token);
@@ -5190,6 +5190,13 @@ static void test_reparse_points(void)
@@ -5191,6 +5191,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");
@ -46,7 +47,7 @@ index cd2b294bceb..67d54c81fb0 100644
/* Create the file symlink */
HeapFree(GetProcessHeap(), 0, buffer);
@@ -5203,6 +5210,37 @@ static void test_reparse_points(void)
@@ -5204,6 +5211,37 @@ static void test_reparse_points(void)
ok(bret, "Failed to create symlink! (0x%x)\n", GetLastError());
CloseHandle(handle);
@ -84,7 +85,7 @@ index cd2b294bceb..67d54c81fb0 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");
@@ -5224,6 +5262,10 @@ static void test_reparse_points(void)
@@ -5225,6 +5263,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);
@ -96,10 +97,10 @@ index cd2b294bceb..67d54c81fb0 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
index ca21a799231..bdc8b8c756f 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 )
@@ -1507,6 +1507,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 );
@ -108,6 +109,27 @@ index 7b32bac7fa3..ac4e09fc732 100644
/* 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/server/fd.c b/server/fd.c
index 9e087917c0d..03966cd3067 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1969,6 +1969,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
{
fd->unlink_name = path;
fd->unix_name = realpath( path, NULL );
+ if (!fd->unix_name) fd->unix_name = dup_fd_name( root, name ); /* dangling symlink */
}
closed_fd->unix_fd = fd->unix_fd;
@@ -2487,7 +2488,7 @@ static void set_fd_disposition( struct fd *fd, int unlink )
file_set_error();
return;
}
- if (S_ISREG( st.st_mode )) /* can't unlink files we don't have permission to write */
+ if (S_ISREG( st.st_mode ) || S_ISLNK( st.st_mode )) /* can't unlink files we don't have permission to write */
{
if (!(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
{
--
2.27.0
2.17.1

View File

@ -1,7 +1,7 @@
From e17d27788c8368ac1d395c6e142c42249f1e02f4 Mon Sep 17 00:00:00 2001
From bc78873be1ca0e16e7c2d5aedf15f9e09f86069c Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 1 May 2019 17:48:51 -0600
Subject: [PATCH] ntdll: Find dangling symlinks quickly.
Subject: ntdll: Find dangling symlinks quickly.
This is also necessary on systems (such as MacOS) that support
case-insensitive lookups of files.
@ -12,10 +12,10 @@ Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index a2fc2a6425b..66ce2eb5fe4 100644
index bdc8b8c756f..a7dc12f0a3e 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -2146,7 +2146,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
@@ -2501,7 +2501,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
if (ret >= 0 && ret <= MAX_DIR_ENTRY_LEN)
{
unix_name[pos + ret] = 0;
@ -24,7 +24,7 @@ index a2fc2a6425b..66ce2eb5fe4 100644
{
if (is_win_dir) *is_win_dir = is_same_file( &windir, &st );
return STATUS_SUCCESS;
@@ -2257,7 +2257,7 @@ not_found:
@@ -2606,7 +2606,7 @@ not_found:
return STATUS_OBJECT_PATH_NOT_FOUND;
success:
@ -33,7 +33,7 @@ index a2fc2a6425b..66ce2eb5fe4 100644
return STATUS_SUCCESS;
}
@@ -2662,7 +2662,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
@@ -3101,7 +3101,7 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/';
if (!name_len || !redirect || (!strstr( unix_name, "/windows/") && strncmp( unix_name, "windows/", 8 )))
{
@ -43,5 +43,5 @@ index a2fc2a6425b..66ce2eb5fe4 100644
if (disposition == FILE_CREATE)
return STATUS_OBJECT_NAME_COLLISION;
--
2.27.0
2.17.1

View File

@ -1,51 +1,19 @@
From cab7c1b99de7c594083c6fd16b728a79f16b9ac8 Mon Sep 17 00:00:00 2001
From f0eee9d4ed2009f24799a149a70e0848dda9fe14 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 13 Mar 2019 16:02:05 -0600
Subject: [PATCH] kernel32: Implement CreateSymbolicLink[A|W] with ntdll
reparse points.
Subject: kernel32: Implement CreateSymbolicLink[A|W] with ntdll reparse
points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/kernel32/path.c | 20 ++++++-
dlls/kernel32/tests/path.c | 96 ++++++++++++++++++++++++++++++
dlls/kernelbase/file.c | 105 ++++++++++++++++++++++++++++++++-
dlls/msvcp120/tests/msvcp120.c | 75 +++++++++++------------
dlls/kernel32/tests/path.c | 94 ++++++++++++++++++++++++++++++
dlls/kernelbase/file.c | 103 ++++++++++++++++++++++++++++++++-
dlls/msvcp120/tests/msvcp120.c | 75 +++++++++++-------------
dlls/msvcp140/tests/msvcp140.c | 63 +++++++++-----------
5 files changed, 277 insertions(+), 82 deletions(-)
4 files changed, 256 insertions(+), 79 deletions(-)
diff --git a/dlls/kernel32/path.c b/dlls/kernel32/path.c
index 0f075d0af1c..3d17b53a829 100644
--- a/dlls/kernel32/path.c
+++ b/dlls/kernel32/path.c
@@ -385,8 +385,24 @@ WCHAR * CDECL wine_get_dos_file_name( LPCSTR str )
*/
BOOLEAN WINAPI CreateSymbolicLinkA(LPCSTR link, LPCSTR target, DWORD flags)
{
- FIXME("(%s %s %d): stub\n", debugstr_a(link), debugstr_a(target), flags);
- return TRUE;
+ WCHAR *targetW, *linkW;
+ BOOL ret;
+
+ TRACE("(%s %s %d)\n", debugstr_a(link), debugstr_a(target), flags);
+
+ if (!(linkW = FILE_name_AtoW( link, TRUE )))
+ {
+ return FALSE;
+ }
+ if (!(targetW = FILE_name_AtoW( target, TRUE )))
+ {
+ HeapFree( GetProcessHeap(), 0, linkW );
+ return FALSE;
+ }
+ ret = CreateSymbolicLinkW( linkW, targetW, flags );
+ HeapFree( GetProcessHeap(), 0, linkW );
+ HeapFree( GetProcessHeap(), 0, targetW );
+ return ret;
}
/*************************************************************************
diff --git a/dlls/kernel32/tests/path.c b/dlls/kernel32/tests/path.c
index 0e45ad44ff3..841353dcab8 100644
index 0e45ad44ff3..0f8d94e2957 100644
--- a/dlls/kernel32/tests/path.c
+++ b/dlls/kernel32/tests/path.c
@@ -83,6 +83,9 @@ static NTSTATUS (WINAPI *pLdrGetDllPath)(LPCWSTR,ULONG,LPWSTR*,LPWSTR*);
@ -58,22 +26,15 @@ index 0e45ad44ff3..841353dcab8 100644
/* a structure to deal with wine todos somewhat cleanly */
typedef struct {
DWORD shortlen;
@@ -2147,11 +2150,14 @@ static void init_pointers(void)
@@ -2147,6 +2150,7 @@ static void init_pointers(void)
MAKEFUNC(SetDefaultDllDirectories);
MAKEFUNC(CheckNameLegalDOS8Dot3W);
MAKEFUNC(CheckNameLegalDOS8Dot3A);
+ MAKEFUNC(CreateSymbolicLinkW);
+
mod = GetModuleHandleA("ntdll.dll");
MAKEFUNC(LdrGetDllPath);
MAKEFUNC(RtlGetExePath);
MAKEFUNC(RtlGetSearchPath);
MAKEFUNC(RtlReleasePath);
+
#undef MAKEFUNC
}
@@ -2690,6 +2696,95 @@ static void test_LdrGetDllPath(void)
@@ -2690,6 +2694,95 @@ static void test_LdrGetDllPath(void)
SetEnvironmentVariableW( pathW, old_path );
}
@ -104,7 +65,7 @@ index 0e45ad44ff3..841353dcab8 100644
+ DeleteFileW( path );
+ if (!CreateDirectoryW( path, NULL ))
+ {
+ win_skip("Unable to create a temporary junction point directory.\n");
+ win_skip("Unable to create a temporary reparse point directory.\n");
+ return;
+ }
+ GetCurrentDirectoryW( sizeof(old_path)/sizeof(WCHAR), old_path );
@ -116,7 +77,7 @@ index 0e45ad44ff3..841353dcab8 100644
+ GetVolumeInformationW( volW, 0, 0, 0, &dwLen, &dwFlags, 0, 0 );
+ if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS))
+ {
+ skip("File system does not support junction points.\n");
+ skip("File system does not support reparse points.\n");
+ goto cleanup;
+ }
+
@ -169,30 +130,27 @@ index 0e45ad44ff3..841353dcab8 100644
START_TEST(path)
{
CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
@@ -2719,4 +2814,5 @@ START_TEST(path)
@@ -2719,4 +2812,5 @@ START_TEST(path)
test_RtlGetSearchPath();
test_RtlGetExePath();
test_LdrGetDllPath();
+ test_CreateSymbolicLink();
}
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
index 905029066e4..ed6ba6ae30e 100644
index d9b34408692..2e67f6eaa3e 100644
--- a/dlls/kernelbase/file.c
+++ b/dlls/kernelbase/file.c
@@ -36,6 +36,7 @@
#include "wincon.h"
#include "fileapi.h"
@@ -38,6 +38,7 @@
#include "shlwapi.h"
+#include "ntifs.h"
#include "ddk/ntddk.h"
#include "ddk/ntddser.h"
+#include "ntifs.h"
@@ -943,10 +944,108 @@ done:
/*************************************************************************
* CreateSymbolicLinkW (kernelbase.@)
#include "kernelbase.h"
#include "wine/exception.h"
@@ -926,8 +927,106 @@ done:
*/
-BOOLEAN WINAPI /* DECLSPEC_HOTPATCH */ CreateSymbolicLinkW( LPCWSTR link, LPCWSTR target, DWORD flags )
+BOOLEAN WINAPI DECLSPEC_HOTPATCH CreateSymbolicLinkW( const WCHAR *link, const WCHAR *target, DWORD flags )
BOOLEAN WINAPI /* DECLSPEC_HOTPATCH */ CreateSymbolicLinkW( LPCWSTR link, LPCWSTR target, DWORD flags )
{
- FIXME( "(%s %s %d): stub\n", debugstr_w(link), debugstr_w(target), flags );
- return TRUE;
@ -210,7 +168,7 @@ index 905029066e4..ed6ba6ae30e 100644
+ HANDLE hlink;
+ DWORD dwret;
+
+ TRACE("(%s %s %d)\n", debugstr_w(link), debugstr_w(target), flags);
+ TRACE( "(%s %s %d): stub\n", debugstr_w(link), debugstr_w(target), flags );
+
+ is_relative = (RtlDetermineDosPathNameType_U( target ) == RELATIVE_PATH);
+ is_dir = (flags & SYMBOLIC_LINK_FLAG_DIRECTORY);
@ -244,11 +202,11 @@ index 905029066e4..ed6ba6ae30e 100644
+ }
+ /* append the target to the link path */
+ target_path_len = nt_path.Length / sizeof(WCHAR);
+ len = target_path_len + (wcslen( target ) + 1);
+ len = target_path_len + (lstrlenW( target ) + 1);
+ target_path = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, len*sizeof(WCHAR) );
+ lstrcpynW( target_path, nt_path.Buffer, target_path_len+1 );
+ target_path[target_path_len+1] = 0;
+ wcscat( target_path, target );
+ lstrcatW( target_path, target );
+ RtlFreeUnicodeString( &nt_path );
+ }
+ else
@ -259,14 +217,14 @@ index 905029066e4..ed6ba6ae30e 100644
+ SetLastError( RtlNtStatusToDosError(status) );
+ goto cleanup;
+ }
+ if (is_relative && wcsncmp( target_path, nt_name.Buffer, target_path_len ))
+ if (is_relative && _wcsnicmp( target_path, nt_name.Buffer, target_path_len ) != 0)
+ {
+ SetLastError( RtlNtStatusToDosError(status) );
+ goto cleanup;
+ }
+ prefix_len = is_relative ? 0 : strlen("\\??\\");
+ string = &nt_name.Buffer[target_path_len];
+ string_len = wcslen( &string[prefix_len] );
+ string_len = lstrlenW( &string[prefix_len] );
+ data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
+ buffer_size = struct_size + data_size;
+ buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size );
@ -278,10 +236,10 @@ index 905029066e4..ed6ba6ae30e 100644
+ buffer->SymbolicLinkReparseBuffer.Flags = is_relative ? SYMLINK_FLAG_RELATIVE : 0;
+ subst_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[0];
+ print_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[prefix_len + string_len + 1];
+ wcscpy( subst_dest, string );
+ wcscpy( print_dest, &string[prefix_len] );
+ lstrcpyW( subst_dest, string );
+ lstrcpyW( print_dest, &string[prefix_len] );
+ RtlFreeUnicodeString( &nt_name );
+ bret = DeviceIoControl( hlink, FSCTL_SET_REPARSE_POINT, buffer, buffer_size, NULL, 0,
+ bret = DeviceIoControl( hlink, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_size, NULL, 0,
+ &dwret, 0 );
+ HeapFree( GetProcessHeap(), 0, buffer );
+
@ -300,7 +258,7 @@ index 905029066e4..ed6ba6ae30e 100644
diff --git a/dlls/msvcp120/tests/msvcp120.c b/dlls/msvcp120/tests/msvcp120.c
index 7a382ac6faa..9775ef5e1d8 100644
index ed632a27df2..bd2e8550d05 100644
--- a/dlls/msvcp120/tests/msvcp120.c
+++ b/dlls/msvcp120/tests/msvcp120.c
@@ -1615,15 +1615,14 @@ static void test_tr2_sys__Stat(void)
@ -552,5 +510,5 @@ index 751b1beed86..382f5732c29 100644
}
--
2.26.2
2.17.1

View File

@ -0,0 +1,45 @@
From 87cc49c8ae73e17bc953b66f25be76d5c0eff153 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 29 May 2019 15:11:42 -0600
Subject: kernel32: Add reparse support to FindNextFile.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/kernelbase/file.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
index 2e67f6eaa3e..9920b50191b 100644
--- a/dlls/kernelbase/file.c
+++ b/dlls/kernelbase/file.c
@@ -1485,6 +1485,27 @@ BOOL WINAPI DECLSPEC_HOTPATCH FindNextFileW( HANDLE handle, WIN32_FIND_DATAW *da
memcpy( data->cFileName, dir_info->FileName, dir_info->FileNameLength );
data->cFileName[dir_info->FileNameLength/sizeof(WCHAR)] = 0;
+ /* get reparse tag */
+ if (dir_info->FileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
+ {
+ REPARSE_DATA_BUFFER *buffer = NULL;
+ INT buffer_len;
+ HANDLE hlink;
+ DWORD dwret;
+ BOOL bret;
+
+ hlink = CreateFileW( data->cFileName, GENERIC_READ | GENERIC_WRITE, 0, 0,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0 );
+ buffer_len = sizeof(*buffer) + 2*MAX_PATH*sizeof(WCHAR);
+ buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len );
+ bret = DeviceIoControl( hlink, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer,
+ buffer_len, &dwret, 0 );
+ if (bret) data->dwReserved0 = buffer->ReparseTag;
+ HeapFree( GetProcessHeap(), 0, buffer );
+ CloseHandle( hlink );
+ }
+
if (info->level != FindExInfoBasic)
{
memcpy( data->cAlternateFileName, dir_info->ShortName, dir_info->ShortNameLength );
--
2.17.1

View File

@ -0,0 +1,50 @@
From 6eed7c952dbb0e7151723881dc26e955b9d9595d Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 29 May 2019 15:18:50 -0600
Subject: wcmd: Display reparse point type in directory listings.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
programs/cmd/directory.c | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c
index 2d35f8eb1d1..5b7416ce72a 100644
--- a/programs/cmd/directory.c
+++ b/programs/cmd/directory.c
@@ -400,6 +400,32 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
WCMD_output(L"%1!*s!", cur_width - tmp_width, nullW);
}
+ } else if (fd[i].dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) {
+ if (!bare) {
+ const WCHAR *type;
+
+ switch(fd[i].dwReserved0) {
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ type = L"<JUNCTION>";
+ break;
+ case IO_REPARSE_TAG_SYMLINK:
+ default:
+ type = (fd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? L"<SYMLINKD>" : L"<SYMLINK>";
+ break;
+ }
+ WCMD_output (L"%1!10s! %2!8s! %3!-14s!", datestring, timestring, type);
+ if (shortname) WCMD_output (fmt2, fd[i].cAlternateFileName);
+ if (usernames) WCMD_output (fmt3, username);
+ WCMD_output(fmt4,fd[i].cFileName);
+ } else {
+ if (!((lstrcmpW(fd[i].cFileName, dotW) == 0) ||
+ (lstrcmpW(fd[i].cFileName, dotdotW) == 0))) {
+ WCMD_output (fmt5, recurse?inputparms->dirName:nullW, fd[i].cFileName);
+ } else {
+ addNewLine = FALSE;
+ }
+ }
+
} else if (fd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
dir_count++;
--
2.17.1

View File

@ -0,0 +1,72 @@
From 508f77e1653e67bfa8ed54eeb25251684b495115 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 29 May 2019 15:38:30 -0600
Subject: wcmd: Show reparse point target in directory listing.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
programs/cmd/directory.c | 34 ++++++++++++++++++++++++++++++++++
1 file changed, 34 insertions(+)
diff --git a/programs/cmd/directory.c b/programs/cmd/directory.c
index 5b7416ce72a..87a5a310224 100644
--- a/programs/cmd/directory.c
+++ b/programs/cmd/directory.c
@@ -23,6 +23,8 @@
#include "wcmd.h"
#include "wine/debug.h"
+#include "winioctl.h"
+#include "ntifs.h"
WINE_DEFAULT_DEBUG_CHANNEL(cmd);
@@ -256,6 +258,7 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
static const WCHAR fmt3[] = {'%','1','!','-','2','3','s','!','\0'};
static const WCHAR fmt4[] = {'%','1','\0'};
static const WCHAR fmt5[] = {'%','1','%','2','\0'};
+ static const WCHAR fmt6[] = {' ','[','%','1',']','\0'};
dir_count = 0;
file_count = 0;
@@ -417,6 +420,37 @@ static DIRECTORY_STACK *WCMD_list_directory (DIRECTORY_STACK *inputparms, int le
if (shortname) WCMD_output (fmt2, fd[i].cAlternateFileName);
if (usernames) WCMD_output (fmt3, username);
WCMD_output(fmt4,fd[i].cFileName);
+ if (fd[i].dwReserved0) {
+ REPARSE_DATA_BUFFER *buffer = NULL;
+ WCHAR *target = NULL;
+ INT buffer_len;
+ HANDLE hlink;
+ DWORD dwret;
+ BOOL bret;
+
+ hlink = CreateFileW(fd[i].cFileName, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ buffer_len = sizeof(*buffer) + 2*MAX_PATH*sizeof(WCHAR);
+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len);
+ bret = DeviceIoControl(hlink, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer,
+ buffer_len, &dwret, 0);
+ if (bret) {
+ INT offset;
+ switch(buffer->ReparseTag) {
+ case IO_REPARSE_TAG_MOUNT_POINT:
+ offset = buffer->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR);
+ target = &buffer->MountPointReparseBuffer.PathBuffer[offset];
+ break;
+ case IO_REPARSE_TAG_SYMLINK:
+ offset = buffer->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR);
+ target = &buffer->SymbolicLinkReparseBuffer.PathBuffer[offset];
+ break;
+ }
+ }
+ CloseHandle(hlink);
+ if (target) WCMD_output(fmt6, target);
+ HeapFree(GetProcessHeap(), 0, buffer);
+ }
} else {
if (!((lstrcmpW(fd[i].cFileName, dotW) == 0) ||
(lstrcmpW(fd[i].cFileName, dotdotW) == 0))) {
--
2.17.1

View File

@ -0,0 +1,86 @@
From c146d5ab24640039bd143ebe501755701c126a9e Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 29 May 2019 16:01:45 -0600
Subject: wcmd: Add junction point support to mklink.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
programs/cmd/builtins.c | 48 ++++++++++++++++++++++++++++++++++++++++-
1 file changed, 47 insertions(+), 1 deletion(-)
diff --git a/programs/cmd/builtins.c b/programs/cmd/builtins.c
index 70ccddebc11..34de0486fdd 100644
--- a/programs/cmd/builtins.c
+++ b/programs/cmd/builtins.c
@@ -31,6 +31,9 @@
#include "wcmd.h"
#include <shellapi.h>
#include "wine/debug.h"
+#include "winternl.h"
+#include "winioctl.h"
+#include "ntifs.h"
WINE_DEFAULT_DEBUG_CHANNEL(cmd);
@@ -5055,6 +5058,49 @@ void WCMD_color (void) {
}
}
+BOOL WCMD_create_junction(WCHAR *link, WCHAR *target) {
+ static INT struct_size = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]);
+ static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer);
+ INT buffer_size, data_size, string_len, prefix_len;
+ WCHAR *subst_dest, *print_dest, *string;
+ REPARSE_DATA_BUFFER *buffer;
+ UNICODE_STRING nt_name;
+ NTSTATUS status;
+ HANDLE hlink;
+ DWORD dwret;
+ BOOL ret;
+
+ if (!CreateDirectoryW(link, NULL ))
+ return FALSE;
+ hlink = CreateFileW(link, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
+ if (hlink == INVALID_HANDLE_VALUE)
+ return FALSE;
+ status = RtlDosPathNameToNtPathName_U_WithStatus(target, &nt_name, NULL, NULL);
+ if (status)
+ return FALSE;
+ prefix_len = strlen("\\??\\");
+ string = nt_name.Buffer;
+ string_len = lstrlenW( &string[prefix_len] );
+ data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR);
+ buffer_size = struct_size + data_size;
+ buffer = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size );
+ buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
+ buffer->ReparseDataLength = struct_size - header_size + data_size;
+ buffer->MountPointReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR);
+ buffer->MountPointReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR);
+ subst_dest = &buffer->MountPointReparseBuffer.PathBuffer[0];
+ print_dest = &buffer->MountPointReparseBuffer.PathBuffer[prefix_len + string_len + 1];
+ lstrcpyW(subst_dest, string);
+ lstrcpyW(print_dest, &string[prefix_len]);
+ RtlFreeUnicodeString(&nt_name );
+ ret = DeviceIoControl(hlink, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_size, NULL, 0,
+ &dwret, 0 );
+ HeapFree(GetProcessHeap(), 0, buffer);
+ return ret;
+}
+
/****************************************************************************
* WCMD_mklink
*/
@@ -5106,7 +5152,7 @@ void WCMD_mklink(WCHAR *args)
else if(!junction)
ret = CreateSymbolicLinkW(file1, file2, isdir);
else
- WINE_TRACE("Juction links currently not supported.\n");
+ ret = WCMD_create_junction(file1, file2);
if(!ret)
WCMD_output_stderr(WCMD_LoadMessage(WCMD_READFAIL), file1);
--
2.17.1

View File

@ -0,0 +1,140 @@
From 7a25fabadf15c7514dec080502df19595249a3f6 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 18 Jul 2020 09:13:29 -0600
Subject: server: Fix obtaining information about a symlink.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/unix/file.c | 19 ++++++++++---------
server/fd.c | 7 ++++---
server/protocol.def | 1 +
3 files changed, 15 insertions(+), 12 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index a7dc12f0a3e..b507d575766 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -1775,7 +1775,7 @@ static NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
}
-static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name )
+static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name, BOOL nofollow )
{
data_size_t size = 1024;
NTSTATUS ret;
@@ -1788,6 +1788,7 @@ static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name )
SERVER_START_REQ( get_handle_unix_name )
{
req->handle = wine_server_obj_handle( handle );
+ req->nofollow = nofollow;
wine_server_set_reply( req, name, size );
ret = wine_server_call( req );
size = reply->name_len;
@@ -1962,7 +1963,7 @@ static NTSTATUS get_mountmgr_fs_info( HANDLE handle, int fd, struct mountmgr_uni
NTSTATUS status;
int letter;
- if ((status = server_get_unix_name( handle, &unix_name ))) return status;
+ if ((status = server_get_unix_name( handle, &unix_name, FALSE ))) return status;
letter = find_dos_device( unix_name );
free( unix_name );
@@ -3973,7 +3974,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = errno_to_status( errno );
else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
io->u.Status = STATUS_INVALID_INFO_CLASS;
- else if (!(io->u.Status = server_get_unix_name( handle, &unix_name )))
+ else if (!(io->u.Status = server_get_unix_name( handle, &unix_name, FALSE )))
{
LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
@@ -4034,7 +4035,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
FILE_NAME_INFORMATION *info = ptr;
char *unix_name;
- if (!(io->u.Status = server_get_unix_name( handle, &unix_name )))
+ if (!(io->u.Status = server_get_unix_name( handle, &unix_name, FALSE )))
{
LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
io->u.Status = fill_name_info( unix_name, info, &name_len );
@@ -4048,7 +4049,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
FILE_NETWORK_OPEN_INFORMATION *info = ptr;
char *unix_name;
- if (!(io->u.Status = server_get_unix_name( handle, &unix_name )))
+ if (!(io->u.Status = server_get_unix_name( handle, &unix_name, FALSE )))
{
ULONG attributes;
struct stat st;
@@ -5661,7 +5662,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
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 )))
+ if ((status = server_get_unix_name( handle, &unix_src, FALSE )))
goto cleanup;
src_allocated = TRUE;
if (flags == SYMLINK_FLAG_RELATIVE)
@@ -5940,7 +5941,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
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 )))
+ if ((status = server_get_unix_name( handle, &unix_src, TRUE )))
goto cleanup;
if ((status = FILE_DecodeSymlink( unix_src, unix_dest, &unix_dest_len, &buffer->ReparseTag, &flags, NULL )))
@@ -6078,7 +6079,7 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
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 )))
+ if ((status = server_get_unix_name( handle, &unix_name, TRUE )))
goto cleanup;
TRACE( "Deleting symlink %s\n", unix_name );
@@ -7104,7 +7105,7 @@ NTSTATUS WINAPI NtQueryObject( HANDLE handle, OBJECT_INFORMATION_CLASS info_clas
/* first try as a file object */
- if (!(status = server_get_unix_name( handle, &unix_name )))
+ if (!(status = server_get_unix_name( handle, &unix_name, FALSE )))
{
if (!(status = unix_to_nt_file_name( unix_name, &nt_name )))
{
diff --git a/server/fd.c b/server/fd.c
index 03966cd3067..100c3865126 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2729,11 +2729,12 @@ DECL_HANDLER(get_handle_unix_name)
if ((fd = get_handle_fd_obj( current->process, req->handle, 0 )))
{
- if (fd->unix_name)
+ char *name = (req->nofollow ? fd->unlink_name : fd->unix_name);
+ if (name)
{
- data_size_t name_len = strlen( fd->unix_name );
+ data_size_t name_len = strlen( name );
reply->name_len = name_len;
- if (name_len <= get_reply_max_size()) set_reply_data( fd->unix_name, name_len );
+ if (name_len <= get_reply_max_size()) set_reply_data( name, name_len );
else set_error( STATUS_BUFFER_OVERFLOW );
}
else set_error( STATUS_OBJECT_TYPE_MISMATCH );
diff --git a/server/protocol.def b/server/protocol.def
index a121c371c19..faf4891a01e 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1297,6 +1297,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
/* Get the Unix name from a file handle */
@REQ(get_handle_unix_name)
obj_handle_t handle; /* file handle */
+ int nofollow; /* do not follow symlinks (return the link) */
@REPLY
data_size_t name_len; /* unix name length */
VARARG(name,string); /* unix name */
--
2.17.1

View File

@ -1,8 +1,5 @@
Fixes: [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)
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...
# FIXME 3: RemoveDirectory() doesn't work anymore, I think.
Depends: ntdll-DOS_Attributes
# Someone needs to rewrite all of this string arithmetic.
Disabled: true
Depends: ntdll-NtQueryEaFile

View File

@ -1,38 +1,21 @@
From 5028b688bbe434ce83811da8251d920c7e2dba8a Mon Sep 17 00:00:00 2001
From a796dda4d4b7676ef758245f712ed4891902043c Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:03:47 -0700
Subject: kernel32: Advertise junction point support.
TODO: this patch requires an update that is dependent upon obtaining
volume information through mountmgr.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/kernel32/volume.c | 85 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 1 deletion(-)
dlls/kernelbase/volume.c | 72 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/dlls/kernel32/volume.c b/dlls/kernel32/volume.c
index 4fd913aa22..437832e5c9 100644
--- a/dlls/kernel32/volume.c
+++ b/dlls/kernel32/volume.c
@@ -44,6 +44,19 @@
#include "wine/unicode.h"
#include "wine/debug.h"
+#ifdef HAVE_SYS_MOUNT_H
+# include <sys/mount.h>
+#endif
+#ifdef HAVE_SYS_STATFS_H
+# include <sys/statfs.h>
+#endif
+#ifdef HAVE_SYS_SYSCALL_H
+# include <sys/syscall.h>
+#endif
+#ifdef HAVE_SYS_VFS_H
+# include <sys/vfs.h>
+#endif
+
WINE_DEFAULT_DEBUG_CHANNEL(volume);
#define BLOCK_SIZE 2048
@@ -680,6 +693,75 @@ static DWORD VOLUME_GetAudioCDSerial( const CDROM_TOC *toc )
diff --git a/dlls/kernelbase/volume.c b/dlls/kernelbase/volume.c
index 53cc0d49b65..f58909d321d 100644
--- a/dlls/kernelbase/volume.c
+++ b/dlls/kernelbase/volume.c
@@ -646,6 +646,75 @@ static DWORD get_audiocd_serial( const CDROM_TOC *toc )
}
@ -106,11 +89,11 @@ index 4fd913aa22..437832e5c9 100644
+
+
/***********************************************************************
* GetVolumeInformationW (KERNEL32.@)
* GetVolumeInformationW (kernelbase.@)
*/
@@ -824,7 +906,8 @@ fill_fs_info: /* now fill in the information that depends on the file system ty
@@ -781,7 +850,8 @@ fill_fs_info: /* now fill in the information that depends on the file system ty
default:
if (fsname) lstrcpynW( fsname, ntfsW, fsname_len );
if (fsname) lstrcpynW( fsname, L"NTFS", fsname_len );
if (filename_len) *filename_len = 255;
- if (flags) *flags = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS;
+ if (flags) *flags = FILE_CASE_PRESERVED_NAMES | FILE_PERSISTENT_ACLS

View File

@ -1,4 +1,4 @@
From 2de64a6d61d01b9409ab6b61176c0a88a4838937 Mon Sep 17 00:00:00 2001
From 4ad7e0d2a51606b323cbe2f33c64a99c3666a072 Mon Sep 17 00:00:00 2001
From: Dmitry Timoshkov <dmitry@baikal.ru>
Date: Sun, 28 May 2017 05:19:30 +0200
Subject: [PATCH] ntdll: Implement NtQueryVirtualMemory(MemorySectionName).
@ -15,35 +15,35 @@ Contains several improvements by Sebastian Lackner <sebastian@fds-team.de>.
6 files changed, 136 insertions(+), 9 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index b404bceb427..dcc76846c1e 100644
index a41deb0881d..06ab827836d 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -1763,7 +1763,7 @@ static NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
@@ -1835,7 +1835,7 @@ static NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
}
-static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name )
+NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name )
-static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name, BOOL nofollow )
+NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name, BOOL nofollow )
{
data_size_t size = 1024;
NTSTATUS ret;
diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
index 3d56ea5d408..f24ca578ce1 100644
index 3cf9ca66736..a9ce3be82b2 100644
--- a/dlls/ntdll/unix/unix_private.h
+++ b/dlls/ntdll/unix/unix_private.h
@@ -170,6 +170,7 @@ extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *
@@ -171,6 +171,7 @@ extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *
apc_result_t *result ) DECLSPEC_HIDDEN;
extern int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd,
int *needs_close, enum server_fd_type *type, unsigned int *options ) DECLSPEC_HIDDEN;
+extern NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name ) DECLSPEC_HIDDEN;
+extern NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name, BOOL nofollow ) DECLSPEC_HIDDEN;
extern void server_init_process(void) DECLSPEC_HIDDEN;
extern size_t server_init_thread( void *entry_point, BOOL *suspend ) DECLSPEC_HIDDEN;
extern int server_pipe( int fd[2] ) DECLSPEC_HIDDEN;
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 91989bd569e..d1c63bdb215 100644
index 9d19a621666..9758b11de74 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -4009,6 +4009,98 @@ static NTSTATUS get_working_set_ex( HANDLE process, LPCVOID addr,
@@ -4060,6 +4060,98 @@ static NTSTATUS get_working_set_ex( HANDLE process, LPCVOID addr,
return STATUS_SUCCESS;
}
@ -73,7 +73,7 @@ index 91989bd569e..d1c63bdb215 100644
+
+ if (!status && mapping)
+ {
+ status = server_get_unix_name( mapping, &unix_name );
+ status = server_get_unix_name( mapping, &unix_name, FALSE );
+ NtClose( mapping );
+ if (!status)
+ {
@ -142,7 +142,7 @@ index 91989bd569e..d1c63bdb215 100644
#define UNIMPLEMENTED_INFO_CLASS(c) \
case c: \
FIXME("(process=%p,addr=%p) Unimplemented information class: " #c "\n", process, addr); \
@@ -4033,8 +4125,10 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
@@ -4084,8 +4176,10 @@ NTSTATUS WINAPI NtQueryVirtualMemory( HANDLE process, LPCVOID addr,
case MemoryWorkingSetExInformation:
return get_working_set_ex( process, addr, buffer, len, res_len );
@ -222,10 +222,10 @@ index db0debe0af5..6e74f5b770f 100644
DECL_HANDLER(get_mapping_committed_range)
{
diff --git a/server/protocol.def b/server/protocol.def
index 03e567c3dd4..3f0a68ccdcc 100644
index faf4891a01e..0d98d9413e4 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1686,6 +1686,15 @@ enum char_info_mode
@@ -1691,6 +1691,15 @@ enum char_info_mode
@END

View File

@ -2,6 +2,7 @@ Fixes: [23999] Implement MemorySectionName class in NtQueryVirtualMemory
Fixes: [27248] Implement K32GetMappedFileName
Depends: ntdll-NtDevicePath
Depends: ntdll-ForceBottomUpAlloc
Depends: ntdll-Junction_Points
# This uses RtlDosPathNameToNtPathName_U (and RtlInitUnicodeString) from
# ntdll.so, and needs to stop. Defer this until after we have a conversation
# about volumes.

View File

@ -176,6 +176,7 @@ patch_enable_all ()
enable_ntdll_Heap_Improvements="$1"
enable_ntdll_Hide_Wine_Exports="$1"
enable_ntdll_Interrupt_0x2e="$1"
enable_ntdll_Junction_Points="$1"
enable_ntdll_Manifest_Range="$1"
enable_ntdll_NtAccessCheck="$1"
enable_ntdll_NtDevicePath="$1"
@ -618,6 +619,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"
;;
@ -1575,6 +1579,13 @@ if test "$enable_server_Stored_ACLs" -eq 1; then
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."
@ -1621,10 +1632,14 @@ if test "$enable_ntdll_NtQueryVirtualMemory" -eq 1; then
if test "$enable_ntdll_ForceBottomUpAlloc" -gt 1; then
abort "Patchset ntdll-ForceBottomUpAlloc disabled, but ntdll-NtQueryVirtualMemory depends on that."
fi
if test "$enable_ntdll_Junction_Points" -gt 1; then
abort "Patchset ntdll-Junction_Points disabled, but ntdll-NtQueryVirtualMemory depends on that."
fi
if test "$enable_ntdll_NtDevicePath" -gt 1; then
abort "Patchset ntdll-NtDevicePath disabled, but ntdll-NtQueryVirtualMemory depends on that."
fi
enable_ntdll_ForceBottomUpAlloc=1
enable_ntdll_Junction_Points=1
enable_ntdll_NtDevicePath=1
fi
@ -1635,6 +1650,17 @@ 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
if test "$enable_ntdll_NtQueryEaFile" -gt 1; then
abort "Patchset ntdll-NtQueryEaFile disabled, but ntdll-Junction_Points depends on that."
fi
enable_ntdll_DOS_Attributes=1
enable_ntdll_NtQueryEaFile=1
fi
if test "$enable_ntdll_Hide_Wine_Exports" -eq 1; then
if test "$enable_advapi32_Token_Integrity_Level" -gt 1; then
abort "Patchset advapi32-Token_Integrity_Level disabled, but ntdll-Hide_Wine_Exports depends on that."
@ -3631,6 +3657,86 @@ if test "$enable_ntdll_Interrupt_0x2e" -eq 1; then
) >> "$patchlist"
fi
# Patchset ntdll-NtQueryEaFile
# |
# | Modified files:
# | * dlls/ntdll/tests/file.c, dlls/ntdll/unix/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-Junction_Points
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes, ntdll-NtQueryEaFile
# |
# | 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/tests/path.c, dlls/kernelbase/file.c, dlls/msvcp120/tests/msvcp120.c,
# | dlls/msvcp140/tests/msvcp140.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, programs/cmd/builtins.c,
# | programs/cmd/directory.c, server/fd.c, server/protocol.def
# |
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-server-Add-support-for-deleting-junction-points-with.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
patch_apply ntdll-Junction_Points/0019-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch
patch_apply ntdll-Junction_Points/0020-kernel32-Add-reparse-support-to-FindNextFile.patch
patch_apply ntdll-Junction_Points/0021-wcmd-Display-reparse-point-type-in-directory-listing.patch
patch_apply ntdll-Junction_Points/0022-wcmd-Show-reparse-point-target-in-directory-listing.patch
patch_apply ntdll-Junction_Points/0023-wcmd-Add-junction-point-support-to-mklink.patch
patch_apply ntdll-Junction_Points/0024-server-Fix-obtaining-information-about-a-symlink.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", "server: 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 },';
printf '%s\n' '+ { "Erich E. Hoover", "kernel32: Implement CreateSymbolicLink[A|W] with ntdll reparse points.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "kernel32: Add reparse support to FindNextFile.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "wcmd: Display reparse point type in directory listings.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "wcmd: Show reparse point target in directory listing.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "wcmd: Add junction point support to mklink.", 1 },';
printf '%s\n' '+ { "Erich E. Hoover", "server: Fix obtaining information about a symlink.", 1 },';
) >> "$patchlist"
fi
# Patchset ntdll-Manifest_Range
# |
# | This patchset fixes the following Wine bugs:
@ -3691,18 +3797,6 @@ if test "$enable_ntdll_NtDevicePath" -eq 1; then
) >> "$patchlist"
fi
# Patchset ntdll-NtQueryEaFile
# |
# | Modified files:
# | * dlls/ntdll/tests/file.c, dlls/ntdll/unix/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:
@ -3718,7 +3812,8 @@ fi
# Patchset ntdll-NtQueryVirtualMemory
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-ForceBottomUpAlloc, ntdll-Pipe_SpecialCharacters, ntdll-NtDevicePath
# | * ntdll-ForceBottomUpAlloc, ntdll-DOS_Attributes, ntdll-NtQueryEaFile, ntdll-Junction_Points, ntdll-
# | Pipe_SpecialCharacters, ntdll-NtDevicePath
# |
# | This patchset fixes the following Wine bugs:
# | * [#23999] Implement MemorySectionName class in NtQueryVirtualMemory
@ -4326,6 +4421,9 @@ fi
# Patchset server-File_Permissions
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes, ntdll-NtQueryEaFile, ntdll-Junction_Points
# |
# | This patchset fixes the following Wine bugs:
# | * [#44691] Improve mapping of DACL to file permissions
# |
@ -4356,7 +4454,7 @@ fi
# Patchset server-Stored_ACLs
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes, server-File_Permissions
# | * ntdll-DOS_Attributes, ntdll-NtQueryEaFile, ntdll-Junction_Points, server-File_Permissions
# |
# | This patchset fixes the following Wine bugs:
# | * [#33576] Support for stored file ACLs
@ -4387,7 +4485,7 @@ fi
# Patchset server-Inherited_ACLs
# |
# | This patchset has the following (direct or indirect) dependencies:
# | * ntdll-DOS_Attributes, server-File_Permissions, server-Stored_ACLs
# | * ntdll-DOS_Attributes, ntdll-NtQueryEaFile, ntdll-Junction_Points, server-File_Permissions, server-Stored_ACLs
# |
# | Modified files:
# | * dlls/advapi32/tests/security.c, server/file.c

View File

@ -1,4 +1,4 @@
From b1dcc9759921e696a554c46d7aee2c4c29d3c7ae Mon Sep 17 00:00:00 2001
From 7f1169fde63549646dcd24d60ea648db3a11765c Mon Sep 17 00:00:00 2001
From: Sebastian Lackner <sebastian@fds-team.de>
Date: Fri, 3 Apr 2015 03:58:47 +0200
Subject: [PATCH] server: Allow to open files without any permission bits. (try
@ -65,10 +65,10 @@ index 825f8451904..948c257cea2 100644
done:
diff --git a/server/fd.c b/server/fd.c
index e5e1fdbbf32..188a632575f 100644
index 819f77d041e..c1401acc1aa 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1835,6 +1835,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
@@ -1892,6 +1892,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
int root_fd = -1;
int rw_mode;
char *path;
@ -76,10 +76,10 @@ index e5e1fdbbf32..188a632575f 100644
int created = (flags & O_CREAT);
if (((options & FILE_DELETE_ON_CLOSE) && !(access & DELETE)) ||
@@ -1894,10 +1895,28 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
if ((access & FILE_UNIX_WRITE_ACCESS) || (flags & O_CREAT))
fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode );
@@ -1958,10 +1959,28 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
fd->unix_fd = open( name, rw_mode | O_SYMLINK | (flags & ~O_TRUNC), *mode );
}
#endif
+ else if (errno == EACCES)
+ {
+ /* try to change permissions temporarily to open a file descriptor */
@ -105,12 +105,12 @@ index e5e1fdbbf32..188a632575f 100644
goto error;
}
}
@@ -1912,6 +1931,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
closed_fd->unix_fd = fd->unix_fd;
@@ -1978,6 +1997,7 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
closed_fd->unlink = 0;
closed_fd->unlink_name = fd->unlink_name;
closed_fd->unix_name = fd->unix_name;
+ if (do_chmod) chmod( name, *mode );
fstat( fd->unix_fd, &st );
lstat( fd->unlink_name, &st );
*mode = st.st_mode;
--

View File

@ -1,2 +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