From 4ffe305c90f9e15141f2c1b10e86a15a5b9b7e3f Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Sat, 18 Jul 2020 11:41:56 -0500 Subject: [PATCH] ntdll-Junction_Points: Update with rebased patch set from Erich E. Hoover. --- ...-support-for-junction-point-creation.patch | 102 ++++++----- ...-support-for-reading-junction-points.patch | 75 ++++---- ...support-for-deleting-junction-points.patch | 36 ++-- ...est-for-junction-point-advertisement.patch | 6 +- ...dd-support-for-deleting-junction-poi.patch | 66 ------- ...rt-for-deleting-junction-points-with.patch | 161 ++++++++++++++++++ ...upport-for-absolute-symlink-creation.patch | 33 ++-- ...upport-for-reading-absolute-symlinks.patch | 36 ++-- ...ll-Add-support-for-deleting-symlinks.patch | 14 +- ...upport-for-relative-symlink-creation.patch | 134 +++++++++------ ...upport-for-reading-relative-symlinks.patch | 101 ++++++----- ...-ntdll-Add-support-for-file-symlinks.patch | 34 ++-- ...tion-of-dangling-reparse-points-to-n.patch | 30 ++-- ...-report-file-symbolic-links-as-files.patch | 100 ++++------- ...or-code-when-attempting-to-delete-fi.patch | 31 ++++ ...roperly-handle-file-symlink-deletion.patch | 77 ++++----- ...ort-symbolic-links-as-containing-zer.patch | 46 +++-- ...ntdll-Find-dangling-symlinks-quickly.patch | 14 +- ...nt-CreateSymbolicLink-A-W-with-ntdll.patch | 102 ++++------- ...-Add-reparse-support-to-FindNextFile.patch | 45 +++++ ...arse-point-type-in-directory-listing.patch | 50 ++++++ ...se-point-target-in-directory-listing.patch | 72 ++++++++ ...Add-junction-point-support-to-mklink.patch | 86 ++++++++++ ...btaining-information-about-a-symlink.patch | 140 +++++++++++++++ patches/ntdll-Junction_Points/definition | 5 +- ...l32-Advertise-junction-point-support.patch | 45 ++--- ...NtQueryVirtualMemory-MemorySectionNa.patch | 28 +-- patches/ntdll-NtQueryVirtualMemory/definition | 1 + patches/patchinstall.sh | 128 ++++++++++++-- ...open-files-without-any-permission-bi.patch | 18 +- patches/server-File_Permissions/definition | 1 + 31 files changed, 1214 insertions(+), 603 deletions(-) delete mode 100644 patches/ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch create mode 100644 patches/ntdll-Junction_Points/0005-server-Add-support-for-deleting-junction-points-with.patch create mode 100644 patches/ntdll-Junction_Points/0015-kernel32-Set-error-code-when-attempting-to-delete-fi.patch create mode 100644 patches/ntdll-Junction_Points/0020-kernel32-Add-reparse-support-to-FindNextFile.patch create mode 100644 patches/ntdll-Junction_Points/0021-wcmd-Display-reparse-point-type-in-directory-listing.patch create mode 100644 patches/ntdll-Junction_Points/0022-wcmd-Show-reparse-point-target-in-directory-listing.patch create mode 100644 patches/ntdll-Junction_Points/0023-wcmd-Add-junction-point-support-to-mklink.patch create mode 100644 patches/ntdll-Junction_Points/0024-server-Fix-obtaining-information-about-a-symlink.patch diff --git a/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch b/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch index 97ec03a3..96bf0bb4 100644 --- a/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch +++ b/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch @@ -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" 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 --- 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 - #include - #include -+#include - #include +@@ -36,6 +36,7 @@ #include #include -@@ -122,6 +123,7 @@ - #include "ddk/wdm.h" - #define WINE_MOUNTMGR_EXTENSIONS - #include "ddk/mountmgr.h" -+#include "ntifs.h" - #include "wine/server.h" + #include ++#include + #include + #ifdef HAVE_MNTENT_H + #include +@@ -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 diff --git a/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch b/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch index c03364e8..7e7cdee5 100644 --- a/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch +++ b/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-junction-points.patch @@ -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" 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 --- - 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 diff --git a/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch b/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch index 2289a24e..262b29ba 100644 --- a/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch +++ b/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-junction-points.patch @@ -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" 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 --- @@ -11,10 +11,10 @@ Signed-off-by: Erich E. Hoover 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 diff --git a/patches/ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch b/patches/ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch index 9767741c..d01defda 100644 --- a/patches/ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch +++ b/patches/ntdll-Junction_Points/0004-ntdll-Add-a-test-for-junction-point-advertisement.patch @@ -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" 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 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()); diff --git a/patches/ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch b/patches/ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch deleted file mode 100644 index 59e6b7d4..00000000 --- a/patches/ntdll-Junction_Points/0005-kernel32-ntdll-Add-support-for-deleting-junction-poi.patch +++ /dev/null @@ -1,66 +0,0 @@ -From 3473ccddec5c67bbfe1d477ce36f537493fae54b Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -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 ---- - 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 - diff --git a/patches/ntdll-Junction_Points/0005-server-Add-support-for-deleting-junction-points-with.patch b/patches/ntdll-Junction_Points/0005-server-Add-support-for-deleting-junction-points-with.patch new file mode 100644 index 00000000..3471016b --- /dev/null +++ b/patches/ntdll-Junction_Points/0005-server-Add-support-for-deleting-junction-points-with.patch @@ -0,0 +1,161 @@ +From 398754456f977e063aa1c180301ce44fd5fdaf84 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 +--- + 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 + diff --git a/patches/ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch b/patches/ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch index 8998fb07..5596ede5 100644 --- a/patches/ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch +++ b/patches/ntdll-Junction_Points/0007-ntdll-Add-support-for-absolute-symlink-creation.patch @@ -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" 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 --- @@ -11,10 +11,10 @@ Signed-off-by: Erich E. Hoover 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 diff --git a/patches/ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch b/patches/ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch index 26aa069d..55244146 100644 --- a/patches/ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch +++ b/patches/ntdll-Junction_Points/0008-ntdll-Add-support-for-reading-absolute-symlinks.patch @@ -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" 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 --- @@ -10,10 +10,10 @@ Signed-off-by: Erich E. Hoover 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 diff --git a/patches/ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch b/patches/ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch index f8641062..2aa197c1 100644 --- a/patches/ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch +++ b/patches/ntdll-Junction_Points/0009-ntdll-Add-support-for-deleting-symlinks.patch @@ -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" 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 --- @@ -10,10 +10,10 @@ Signed-off-by: Erich E. Hoover 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 diff --git a/patches/ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch b/patches/ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch index 5804ab70..60397a19 100644 --- a/patches/ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch +++ b/patches/ntdll-Junction_Points/0010-ntdll-Add-support-for-relative-symlink-creation.patch @@ -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" 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 --- - 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 diff --git a/patches/ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch b/patches/ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch index 9a8ac7f0..7afe8a5b 100644 --- a/patches/ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch +++ b/patches/ntdll-Junction_Points/0011-ntdll-Add-support-for-reading-relative-symlinks.patch @@ -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" 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 --- - 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 diff --git a/patches/ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch b/patches/ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch index 185e13e8..5b6dd9e4 100644 --- a/patches/ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch +++ b/patches/ntdll-Junction_Points/0012-ntdll-Add-support-for-file-symlinks.patch @@ -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" 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 --- @@ -10,10 +10,10 @@ Signed-off-by: Erich E. Hoover 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 diff --git a/patches/ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch b/patches/ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch index dc72ebb7..9555993b 100644 --- a/patches/ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch +++ b/patches/ntdll-Junction_Points/0013-ntdll-Allow-creation-of-dangling-reparse-points-to-n.patch @@ -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" 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 --- @@ -11,10 +11,10 @@ Signed-off-by: Erich E. Hoover 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 diff --git a/patches/ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch b/patches/ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch index c29c8ee2..d50713c0 100644 --- a/patches/ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch +++ b/patches/ntdll-Junction_Points/0014-ntdll-Correctly-report-file-symbolic-links-as-files.patch @@ -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" 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 --- - 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 */ diff --git a/patches/ntdll-Junction_Points/0015-kernel32-Set-error-code-when-attempting-to-delete-fi.patch b/patches/ntdll-Junction_Points/0015-kernel32-Set-error-code-when-attempting-to-delete-fi.patch new file mode 100644 index 00000000..0cd169ae --- /dev/null +++ b/patches/ntdll-Junction_Points/0015-kernel32-Set-error-code-when-attempting-to-delete-fi.patch @@ -0,0 +1,31 @@ +From 3a96350814cd7fd9d620352e252b02aede20d1cf Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +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 +--- + 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 + diff --git a/patches/ntdll-Junction_Points/0016-server-Properly-handle-file-symlink-deletion.patch b/patches/ntdll-Junction_Points/0016-server-Properly-handle-file-symlink-deletion.patch index 63221ab4..729694ed 100644 --- a/patches/ntdll-Junction_Points/0016-server-Properly-handle-file-symlink-deletion.patch +++ b/patches/ntdll-Junction_Points/0016-server-Properly-handle-file-symlink-deletion.patch @@ -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" 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 --- 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 # 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 diff --git a/patches/ntdll-Junction_Points/0017-ntdll-Always-report-symbolic-links-as-containing-zer.patch b/patches/ntdll-Junction_Points/0017-ntdll-Always-report-symbolic-links-as-containing-zer.patch index ebf06d75..c2179c6e 100644 --- a/patches/ntdll-Junction_Points/0017-ntdll-Always-report-symbolic-links-as-containing-zer.patch +++ b/patches/ntdll-Junction_Points/0017-ntdll-Always-report-symbolic-links-as-containing-zer.patch @@ -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" 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 --- 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 diff --git a/patches/ntdll-Junction_Points/0018-ntdll-Find-dangling-symlinks-quickly.patch b/patches/ntdll-Junction_Points/0018-ntdll-Find-dangling-symlinks-quickly.patch index 62f3d21e..b520ff45 100644 --- a/patches/ntdll-Junction_Points/0018-ntdll-Find-dangling-symlinks-quickly.patch +++ b/patches/ntdll-Junction_Points/0018-ntdll-Find-dangling-symlinks-quickly.patch @@ -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" 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 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 diff --git a/patches/ntdll-Junction_Points/0019-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch b/patches/ntdll-Junction_Points/0019-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch index 3209c695..eae76c42 100644 --- a/patches/ntdll-Junction_Points/0019-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch +++ b/patches/ntdll-Junction_Points/0019-kernel32-Implement-CreateSymbolicLink-A-W-with-ntdll.patch @@ -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" 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 --- - 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 diff --git a/patches/ntdll-Junction_Points/0020-kernel32-Add-reparse-support-to-FindNextFile.patch b/patches/ntdll-Junction_Points/0020-kernel32-Add-reparse-support-to-FindNextFile.patch new file mode 100644 index 00000000..c448f906 --- /dev/null +++ b/patches/ntdll-Junction_Points/0020-kernel32-Add-reparse-support-to-FindNextFile.patch @@ -0,0 +1,45 @@ +From 87cc49c8ae73e17bc953b66f25be76d5c0eff153 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Wed, 29 May 2019 15:11:42 -0600 +Subject: kernel32: Add reparse support to FindNextFile. + +Signed-off-by: Erich E. Hoover +--- + 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 + diff --git a/patches/ntdll-Junction_Points/0021-wcmd-Display-reparse-point-type-in-directory-listing.patch b/patches/ntdll-Junction_Points/0021-wcmd-Display-reparse-point-type-in-directory-listing.patch new file mode 100644 index 00000000..7790e720 --- /dev/null +++ b/patches/ntdll-Junction_Points/0021-wcmd-Display-reparse-point-type-in-directory-listing.patch @@ -0,0 +1,50 @@ +From 6eed7c952dbb0e7151723881dc26e955b9d9595d Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Wed, 29 May 2019 15:18:50 -0600 +Subject: wcmd: Display reparse point type in directory listings. + +Signed-off-by: Erich E. Hoover +--- + 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""; ++ break; ++ case IO_REPARSE_TAG_SYMLINK: ++ default: ++ type = (fd[i].dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ? L"" : L""; ++ 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 + diff --git a/patches/ntdll-Junction_Points/0022-wcmd-Show-reparse-point-target-in-directory-listing.patch b/patches/ntdll-Junction_Points/0022-wcmd-Show-reparse-point-target-in-directory-listing.patch new file mode 100644 index 00000000..18d4980e --- /dev/null +++ b/patches/ntdll-Junction_Points/0022-wcmd-Show-reparse-point-target-in-directory-listing.patch @@ -0,0 +1,72 @@ +From 508f77e1653e67bfa8ed54eeb25251684b495115 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Wed, 29 May 2019 15:38:30 -0600 +Subject: wcmd: Show reparse point target in directory listing. + +Signed-off-by: Erich E. Hoover +--- + 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 + diff --git a/patches/ntdll-Junction_Points/0023-wcmd-Add-junction-point-support-to-mklink.patch b/patches/ntdll-Junction_Points/0023-wcmd-Add-junction-point-support-to-mklink.patch new file mode 100644 index 00000000..bad07c10 --- /dev/null +++ b/patches/ntdll-Junction_Points/0023-wcmd-Add-junction-point-support-to-mklink.patch @@ -0,0 +1,86 @@ +From c146d5ab24640039bd143ebe501755701c126a9e Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Wed, 29 May 2019 16:01:45 -0600 +Subject: wcmd: Add junction point support to mklink. + +Signed-off-by: Erich E. Hoover +--- + 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 + #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 + diff --git a/patches/ntdll-Junction_Points/0024-server-Fix-obtaining-information-about-a-symlink.patch b/patches/ntdll-Junction_Points/0024-server-Fix-obtaining-information-about-a-symlink.patch new file mode 100644 index 00000000..9d6021c5 --- /dev/null +++ b/patches/ntdll-Junction_Points/0024-server-Fix-obtaining-information-about-a-symlink.patch @@ -0,0 +1,140 @@ +From 7a25fabadf15c7514dec080502df19595249a3f6 Mon Sep 17 00:00:00 2001 +From: "Erich E. Hoover" +Date: Sat, 18 Jul 2020 09:13:29 -0600 +Subject: server: Fix obtaining information about a symlink. + +Signed-off-by: Erich E. Hoover +--- + 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 + diff --git a/patches/ntdll-Junction_Points/definition b/patches/ntdll-Junction_Points/definition index 716aac06..b8768439 100644 --- a/patches/ntdll-Junction_Points/definition +++ b/patches/ntdll-Junction_Points/definition @@ -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 diff --git a/patches/ntdll-Junction_Points/xx06-kernel32-Advertise-junction-point-support.patch b/patches/ntdll-Junction_Points/xx06-kernel32-Advertise-junction-point-support.patch index cd0824bc..d91b1c9d 100644 --- a/patches/ntdll-Junction_Points/xx06-kernel32-Advertise-junction-point-support.patch +++ b/patches/ntdll-Junction_Points/xx06-kernel32-Advertise-junction-point-support.patch @@ -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" 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 --- - 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 -+#endif -+#ifdef HAVE_SYS_STATFS_H -+# include -+#endif -+#ifdef HAVE_SYS_SYSCALL_H -+# include -+#endif -+#ifdef HAVE_SYS_VFS_H -+# include -+#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 diff --git a/patches/ntdll-NtQueryVirtualMemory/0003-ntdll-Implement-NtQueryVirtualMemory-MemorySectionNa.patch b/patches/ntdll-NtQueryVirtualMemory/0003-ntdll-Implement-NtQueryVirtualMemory-MemorySectionNa.patch index 0652bbcb..e09b08f8 100644 --- a/patches/ntdll-NtQueryVirtualMemory/0003-ntdll-Implement-NtQueryVirtualMemory-MemorySectionNa.patch +++ b/patches/ntdll-NtQueryVirtualMemory/0003-ntdll-Implement-NtQueryVirtualMemory-MemorySectionNa.patch @@ -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 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 . 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 diff --git a/patches/ntdll-NtQueryVirtualMemory/definition b/patches/ntdll-NtQueryVirtualMemory/definition index 8ee7f1df..45dd735c 100644 --- a/patches/ntdll-NtQueryVirtualMemory/definition +++ b/patches/ntdll-NtQueryVirtualMemory/definition @@ -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. \ No newline at end of file diff --git a/patches/patchinstall.sh b/patches/patchinstall.sh index f9d2b82e..6d87e75d 100755 --- a/patches/patchinstall.sh +++ b/patches/patchinstall.sh @@ -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 diff --git a/patches/server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch b/patches/server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch index b8580e80..703c81c7 100644 --- a/patches/server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch +++ b/patches/server-File_Permissions/0002-server-Allow-to-open-files-without-any-permission-bi.patch @@ -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 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; -- diff --git a/patches/server-File_Permissions/definition b/patches/server-File_Permissions/definition index 0ebcf3ac..a699a6fd 100644 --- a/patches/server-File_Permissions/definition +++ b/patches/server-File_Permissions/definition @@ -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