From d102a32693eb2b5b91d8cd02626292d2579328b2 Mon Sep 17 00:00:00 2001 From: Alistair Leslie-Hughes Date: Wed, 9 Jul 2025 09:35:33 +1000 Subject: [PATCH] Rebase against 177848adf54f6871e558be6b42ee2478a522c3d2. --- ...-support-for-creating-reparse-points.patch | 184 ---------- ...d-support-for-reading-reparse-points.patch | 46 --- ...-support-for-deleting-reparse-points.patch | 62 ---- ...t-for-testing-for-reparse-points-wit.patch | 17 - ...upport-for-deleting-reparse-points-w.patch | 58 ---- ...upport-for-deleting-reparse-points-w.patch | 30 -- ...-tests-for-NT-symlink-reparse-points.patch | 323 ------------------ ...upport-for-moving-reparse-points-wit.patch | 61 ++-- ...test-for-reparse-point-copy-behavior.patch | 30 -- ...eparse-points-during-path-resolution.patch | 35 -- ...rse-points-to-target-the-applicable-.patch | 27 +- ...ort-symbolic-links-as-containing-zer.patch | 51 --- ...th-no-data-for-NtReadFile-on-reparse.patch | 14 - ...port-for-FileAttributeTagInformation.patch | 32 -- ...ort-for-creating-Unix-Linux-symlinks.patch | 54 --- ...ular-Unix-symlinks-as-WSL-Linux-Unix.patch | 30 -- staging/upstream-commit | 2 +- 17 files changed, 28 insertions(+), 1028 deletions(-) delete mode 100644 patches/ntdll-Junction_Points/0008-ntdll-Add-tests-for-NT-symlink-reparse-points.patch delete mode 100644 patches/ntdll-Junction_Points/0010-kernelbase-Add-test-for-reparse-point-copy-behavior.patch diff --git a/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-creating-reparse-points.patch b/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-creating-reparse-points.patch index 6d0543e7..1599bb7d 100644 --- a/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-creating-reparse-points.patch +++ b/patches/ntdll-Junction_Points/0001-ntdll-Add-support-for-creating-reparse-points.patch @@ -38,190 +38,6 @@ index f7558bb5d86..aad14d17e61 100644 EXTRADLLFLAGS = -nodefaultlibs i386_EXTRADLLFLAGS = -Wl,--image-base,0x7bc00000 -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index a2ccf3f5332..121ebe5d62a 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -38,6 +38,7 @@ - #include "winuser.h" - #include "winioctl.h" - #include "winnls.h" -+#include "ddk/ntifs.h" - - #ifndef IO_COMPLETION_ALL_ACCESS - #define IO_COMPLETION_ALL_ACCESS 0x001F0003 -@@ -5970,32 +5971,154 @@ static void test_mailslot_name(void) - CloseHandle( device ); - } - -+static INT build_reparse_buffer(const WCHAR *filename, REPARSE_DATA_BUFFER **pbuffer) -+{ -+ static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer); -+ INT buffer_size, struct_size, data_size, string_len, prefix_len; -+ WCHAR *subst_dest, *print_dest; -+ REPARSE_DATA_BUFFER *buffer; -+ -+ struct_size = offsetof(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]); -+ prefix_len = strlen("\\??\\"); -+ string_len = lstrlenW(&filename[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, filename); -+ lstrcpyW(print_dest, &filename[prefix_len]); -+ *pbuffer = buffer; -+ return buffer_size; -+} -+ - static void test_reparse_points(void) - { -- OBJECT_ATTRIBUTES attr; -- HANDLE handle; -- IO_STATUS_BLOCK io; -- NTSTATUS status; -+ WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH]; -+ static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0}; -+ static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0}; -+ static const WCHAR parentW[] = {'\\','.','.','\\',0}; -+ static const WCHAR fooW[] = {'f','o','o',0}; -+ static WCHAR volW[] = {'c',':','\\',0}; -+ static const WCHAR dotW[] = {'.',0}; -+ REPARSE_DATA_BUFFER *buffer = NULL; -+ DWORD dwret, dwLen, dwFlags; - UNICODE_STRING nameW; -- unsigned char reparse_data[1]; -+ WCHAR *long_path; -+ INT buffer_len; -+ HANDLE handle; -+ BOOL bret; -+ -+ /* Create a temporary folder for the junction point tests */ -+ GetTempFileNameW(dotW, fooW, 0, path); -+ DeleteFileW(path); -+ if (!CreateDirectoryW(path, NULL)) -+ { -+ win_skip("Unable to create a temporary junction point directory.\n"); -+ return; -+ } -+ -+ /* Check that the volume this folder is located on supports junction points */ -+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL); -+ volW[0] = nameW.Buffer[4]; -+ pRtlFreeUnicodeString( &nameW ); -+ if (!GetVolumeNameForVolumeMountPointW(volW, volnameW, MAX_PATH)) -+ { -+ win_skip("Failed to obtain volume name for current volume.\n"); -+ return; -+ } -+ GetVolumeInformationW(volnameW, 0, 0, 0, &dwLen, &dwFlags, 0, 0); -+ if (!(dwFlags & FILE_SUPPORTS_REPARSE_POINTS)) -+ { -+ skip("File system does not support reparse points.\n"); -+ RemoveDirectoryW(path); -+ return; -+ } - -- pRtlInitUnicodeString( &nameW, L"\\??\\C:\\" ); -- InitializeObjectAttributes( &attr, &nameW, 0, NULL, NULL ); -+ /* Create the folder to be replaced by a junction point */ -+ lstrcpyW(reparse_path, path); -+ lstrcatW(reparse_path, reparseW); -+ bret = CreateDirectoryW(reparse_path, NULL); -+ ok(bret, "Failed to create junction point directory.\n"); - -- status = pNtOpenFile( &handle, READ_CONTROL, &attr, &io, 0, 0 ); -- ok( !status, "open %s failed %#lx\n", wine_dbgstr_w(nameW.Buffer), status ); -+ /* Create a destination folder for the junction point to target */ -+ lstrcpyW(target_path, path); -+ for (int i=0; i<1; i++) -+ { -+ lstrcatW(target_path, parentW); -+ lstrcatW(target_path, path); -+ } -+ lstrcatW(target_path, targetW); -+ bret = CreateDirectoryW(target_path, NULL); -+ ok(bret, "Failed to create junction point target directory.\n"); -+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL); - -- status = pNtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, NULL, 0 ); -- ok( status == STATUS_INVALID_USER_BUFFER, "expected %#lx, got %#lx\n", STATUS_INVALID_USER_BUFFER, status ); -+ /* construct a too long pathname (resulting reparse buffer over 16 kiB limit) */ -+ long_path = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 32767); -+ lstrcpyW(long_path, nameW.Buffer); -+ for (int i=0; i<250; i++) -+ { -+ lstrcatW(long_path, parentW); -+ lstrcatW(long_path, path); -+ } -+ lstrcatW(long_path, targetW); - -- status = pNtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse_data, 0 ); -- ok( status == STATUS_INVALID_USER_BUFFER, "expected %#lx, got %#lx\n", STATUS_INVALID_USER_BUFFER, status ); -+ /* Create the junction point */ -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ if (handle == INVALID_HANDLE_VALUE) -+ { -+ win_skip("Failed to open junction point directory handle (0x%lx).\n", GetLastError()); -+ goto cleanup; -+ } -+ buffer_len = build_reparse_buffer(long_path, &buffer); -+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); -+ ok(!bret && GetLastError()==ERROR_INVALID_REPARSE_DATA, "Unexpected error (0x%lx)\n", GetLastError()); -+ HeapFree(GetProcessHeap(), 0, buffer); -+ CloseHandle(handle); - -- /* a volume cannot be a reparse point by definition */ -- status = pNtFsControlFile( handle, NULL, NULL, NULL, &io, FSCTL_GET_REPARSE_POINT, NULL, 0, reparse_data, 1 ); -- ok( status == STATUS_NOT_A_REPARSE_POINT, "expected %#lx, got %#lx\n", STATUS_NOT_A_REPARSE_POINT, status ); -+ /* construct a long pathname to demonstrate correct behavior with very large reparse points */ -+ pRtlDosPathNameToNtPathName_U(path, &nameW, NULL, NULL); -+ lstrcpyW(long_path, nameW.Buffer); -+ for (int i=0; i<200; i++) -+ { -+ lstrcatW(long_path, parentW); -+ lstrcatW(long_path, path); -+ } -+ lstrcatW(long_path, targetW); - -- CloseHandle( handle ); -+ /* use a sane (not obscenely long) target for the rest of testing */ -+ pRtlFreeUnicodeString(&nameW); -+ pRtlDosPathNameToNtPathName_U(target_path, &nameW, NULL, NULL); -+ -+ /* Create the junction point */ -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ if (handle == INVALID_HANDLE_VALUE) -+ { -+ win_skip("Failed to open junction point directory handle (0x%lx).\n", GetLastError()); -+ goto cleanup; -+ } -+ buffer_len = build_reparse_buffer(long_path, &buffer); -+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError()); -+ CloseHandle(handle); -+ -+cleanup: -+ /* Cleanup */ -+ pRtlFreeUnicodeString(&nameW); -+ HeapFree(GetProcessHeap(), 0, long_path); -+ HeapFree(GetProcessHeap(), 0, buffer); -+ bret = RemoveDirectoryW(reparse_path); -+ todo_wine ok(bret, "Failed to remove temporary reparse point directory!\n"); -+ bret = RemoveDirectoryW(target_path); -+ ok(bret, "Failed to remove temporary target directory!\n"); -+ RemoveDirectoryW(path); - } - - static void test_set_io_completion_ex(void) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 8d2809ca193..672a1d1fa27 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-reparse-points.patch b/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-reparse-points.patch index bd692c62..0ba37018 100644 --- a/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-reparse-points.patch +++ b/patches/ntdll-Junction_Points/0002-ntdll-Add-support-for-reading-reparse-points.patch @@ -5,55 +5,9 @@ Subject: [PATCH] ntdll: Add support for reading reparse points. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 21 +++- dlls/ntdll/unix/file.c | 221 ++++++++++++++++++++++++++++++++++++++-- 2 files changed, 231 insertions(+), 11 deletions(-) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 148b6058cee..441bb69adcb 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5896,14 +5896,14 @@ static void test_reparse_points(void) - static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0}; - static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0}; - static const WCHAR parentW[] = {'\\','.','.','\\',0}; -+ INT buffer_len, string_len, path_len, total_len; - static const WCHAR fooW[] = {'f','o','o',0}; - static WCHAR volW[] = {'c',':','\\',0}; - static const WCHAR dotW[] = {'.',0}; - REPARSE_DATA_BUFFER *buffer = NULL; - DWORD dwret, dwLen, dwFlags; -+ WCHAR *dest, *long_path; - UNICODE_STRING nameW; -- WCHAR *long_path; -- INT buffer_len; - HANDLE handle; - BOOL bret; - -@@ -6000,6 +6000,23 @@ static void test_reparse_points(void) - buffer_len = build_reparse_buffer(long_path, &buffer); - bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); - ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError()); -+ -+ /* Read back the junction point */ -+ HeapFree(GetProcessHeap(), 0, buffer); -+ buffer_len = sizeof(*buffer) + 2*32767; -+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len); -+ bret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0); -+ ok(bret, "Failed to read junction point! (last error=0x%lx)\n", GetLastError()); -+ string_len = buffer->MountPointReparseBuffer.SubstituteNameLength; -+ dest = &buffer->MountPointReparseBuffer.PathBuffer[buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)]; -+ ok((memcmp(dest, long_path, string_len) == 0), "Junction point destination does not match ('%s' != '%s')!\n", -+ wine_dbgstr_w(dest), wine_dbgstr_w(long_path)); -+ path_len = buffer->MountPointReparseBuffer.PrintNameOffset/sizeof(WCHAR); -+ path_len += buffer->MountPointReparseBuffer.PrintNameLength/sizeof(WCHAR); -+ total_len = FIELD_OFFSET(typeof(*buffer), MountPointReparseBuffer.PathBuffer[path_len+1]) -+ - FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer); -+ ok(buffer->ReparseDataLength == total_len, "ReparseDataLength has unexpected value (%d != %d)\n", -+ buffer->ReparseDataLength, total_len); - CloseHandle(handle); - - cleanup: diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 0d58abbfa84..3e160fb1e5c 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-reparse-points.patch b/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-reparse-points.patch index 9b424731..142475ae 100644 --- a/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-reparse-points.patch +++ b/patches/ntdll-Junction_Points/0003-ntdll-Add-support-for-deleting-reparse-points.patch @@ -5,71 +5,9 @@ Subject: [PATCH] ntdll: Add support for deleting reparse points. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 23 +++++++++- dlls/ntdll/unix/file.c | 99 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+), 1 deletion(-) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index b9ec79e37e0..f90509d62a1 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5388,12 +5388,15 @@ static void test_reparse_points(void) - static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0}; - static const WCHAR parentW[] = {'\\','.','.','\\',0}; - INT buffer_len, string_len, path_len, total_len; -+ FILE_BASIC_INFORMATION old_attrib, new_attrib; - static const WCHAR fooW[] = {'f','o','o',0}; - static WCHAR volW[] = {'c',':','\\',0}; -+ REPARSE_GUID_DATA_BUFFER guid_buffer; - static const WCHAR dotW[] = {'.',0}; - REPARSE_DATA_BUFFER *buffer = NULL; - DWORD dwret, dwLen, dwFlags; - WCHAR *dest, *long_path; -+ IO_STATUS_BLOCK iosb; - UNICODE_STRING nameW; - HANDLE handle; - BOOL bret; -@@ -5488,6 +5491,8 @@ static void test_reparse_points(void) - win_skip("Failed to open junction point directory handle (0x%lx).\n", GetLastError()); - goto cleanup; - } -+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%lx).\n", dwret); - buffer_len = build_reparse_buffer(long_path, &buffer); - bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); - ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError()); -@@ -5508,6 +5513,22 @@ static void test_reparse_points(void) - - FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer); - ok(buffer->ReparseDataLength == total_len, "ReparseDataLength has unexpected value (%d != %d)\n", - buffer->ReparseDataLength, total_len); -+ -+ /* Delete the junction point */ -+ memset(&old_attrib, 0x00, sizeof(old_attrib)); -+ old_attrib.LastAccessTime.QuadPart = 0x200deadcafebeef; -+ dwret = NtSetInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to set junction point folder's attributes (0x%lx).\n", dwret); -+ memset(&guid_buffer, 0x00, sizeof(guid_buffer)); -+ guid_buffer.ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; -+ bret = DeviceIoControl(handle, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer, -+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to delete junction point! (0x%lx)\n", GetLastError()); -+ memset(&new_attrib, 0x00, sizeof(new_attrib)); -+ dwret = NtQueryInformationFile(handle, &iosb, &new_attrib, sizeof(new_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to get junction point folder's attributes (0x%lx).\n", dwret); -+ ok(old_attrib.LastAccessTime.QuadPart == new_attrib.LastAccessTime.QuadPart, -+ "Junction point folder's access time does not match.\n"); - CloseHandle(handle); - - cleanup: -@@ -5516,7 +5537,7 @@ cleanup: - HeapFree(GetProcessHeap(), 0, long_path); - HeapFree(GetProcessHeap(), 0, buffer); - bret = RemoveDirectoryW(reparse_path); -- todo_wine ok(bret, "Failed to remove temporary reparse point directory!\n"); -+ ok(bret, "Failed to remove temporary reparse point directory!\n"); - bret = RemoveDirectoryW(target_path); - ok(bret, "Failed to remove temporary target directory!\n"); - RemoveDirectoryW(path); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 92ce83b685e..ba77aab61b7 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0004-ntdll-Add-support-for-testing-for-reparse-points-wit.patch b/patches/ntdll-Junction_Points/0004-ntdll-Add-support-for-testing-for-reparse-points-wit.patch index 3fc16baf..540ea059 100644 --- a/patches/ntdll-Junction_Points/0004-ntdll-Add-support-for-testing-for-reparse-points-wit.patch +++ b/patches/ntdll-Junction_Points/0004-ntdll-Add-support-for-testing-for-reparse-points-wit.patch @@ -6,26 +6,9 @@ Subject: ntdll: Add support for testing for reparse points with Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 5 +++++ dlls/ntdll/unix/file.c | 23 +++++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index a127a2f4f88..ffc4ca44e32 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5469,6 +5469,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%lx)\n", GetLastError()); - -+ /* Check the file attributes of the junction point */ -+ dwret = GetFileAttributesW(reparse_path); -+ ok(dwret != (DWORD)~0, "Reparse point doesn't exist (attributes: 0x%lx)!\n", dwret); -+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a reparse point! (attributes: 0x%lx)\n", dwret); -+ - /* Read back the junction point */ - HeapFree(GetProcessHeap(), 0, buffer); - buffer_len = sizeof(*buffer) + 2*32767; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index 4c221f53bfd..948074b35ec 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0006-kernelbase-Add-support-for-deleting-reparse-points-w.patch b/patches/ntdll-Junction_Points/0006-kernelbase-Add-support-for-deleting-reparse-points-w.patch index fb7d48b5..c25e89b7 100644 --- a/patches/ntdll-Junction_Points/0006-kernelbase-Add-support-for-deleting-reparse-points-w.patch +++ b/patches/ntdll-Junction_Points/0006-kernelbase-Add-support-for-deleting-reparse-points-w.patch @@ -7,7 +7,6 @@ Subject: kernelbase: Add support for deleting reparse points with Signed-off-by: Erich E. Hoover --- dlls/kernelbase/file.c | 2 +- - dlls/ntdll/tests/file.c | 28 +++++++++++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c @@ -23,63 +22,6 @@ index bfb291fa925..6214f549406 100644 RtlFreeUnicodeString( &nt_name ); if (!status) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index ffc4ca44e32..f3aad01ee93 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5363,11 +5363,11 @@ static void test_reparse_points(void) - FILE_BASIC_INFORMATION old_attrib, new_attrib; - static const WCHAR fooW[] = {'f','o','o',0}; - static WCHAR volW[] = {'c',':','\\',0}; -+ WCHAR *dest, *long_path, *abs_target; - REPARSE_GUID_DATA_BUFFER guid_buffer; - static const WCHAR dotW[] = {'.',0}; - REPARSE_DATA_BUFFER *buffer = NULL; - DWORD dwret, dwLen, dwFlags; -- WCHAR *dest, *long_path; - IO_STATUS_BLOCK iosb; - UNICODE_STRING nameW; - HANDLE handle; -@@ -5454,6 +5454,7 @@ static void test_reparse_points(void) - /* use a sane (not obscenely long) target for the rest of testing */ - pRtlFreeUnicodeString(&nameW); - pRtlDosPathNameToNtPathName_U(target_path, &nameW, NULL, NULL); -+ abs_target = nameW.Buffer; - - /* Create the junction point */ - handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -@@ -5508,6 +5509,31 @@ 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(abs_target, &buffer); -+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to create junction point! (0x%lx)\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%lx)!\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(abs_target, &buffer); -+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError()); -+ CloseHandle(handle); -+ /* TODO: use DeleteFile on reparse point */ -+ - cleanup: - /* Cleanup */ - pRtlFreeUnicodeString(&nameW); -- 2.17.1 diff --git a/patches/ntdll-Junction_Points/0007-kernelbase-Add-support-for-deleting-reparse-points-w.patch b/patches/ntdll-Junction_Points/0007-kernelbase-Add-support-for-deleting-reparse-points-w.patch index 7d0d122d..aff615be 100644 --- a/patches/ntdll-Junction_Points/0007-kernelbase-Add-support-for-deleting-reparse-points-w.patch +++ b/patches/ntdll-Junction_Points/0007-kernelbase-Add-support-for-deleting-reparse-points-w.patch @@ -7,7 +7,6 @@ Subject: [PATCH] kernelbase: Add support for deleting reparse points with Signed-off-by: Erich E. Hoover --- dlls/kernelbase/file.c | 3 ++- - dlls/ntdll/tests/file.c | 11 +++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c @@ -24,35 +23,6 @@ index 36b43d345d6..b7d16410d75 100644 if (status == STATUS_SUCCESS) status = NtClose(hFile); RtlFreeUnicodeString( &nameW ); -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index d4833d84906..598fdc77830 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -6007,7 +6007,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; - IO_STATUS_BLOCK iosb; - UNICODE_STRING nameW; - HANDLE handle; -@@ -6172,7 +6172,14 @@ 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%lx)\n", GetLastError()); - CloseHandle(handle); -- /* TODO: use DeleteFile on reparse point */ -+ 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%lx)!\n", -+ ERROR_ACCESS_DENIED, err); -+ dwret = GetFileAttributesW(reparse_path); -+ ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%lx)!\n", dwret); -+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%lx)\n", dwret); - - cleanup: - /* Cleanup */ -- 2.47.2 diff --git a/patches/ntdll-Junction_Points/0008-ntdll-Add-tests-for-NT-symlink-reparse-points.patch b/patches/ntdll-Junction_Points/0008-ntdll-Add-tests-for-NT-symlink-reparse-points.patch deleted file mode 100644 index 8eab1dbf..00000000 --- a/patches/ntdll-Junction_Points/0008-ntdll-Add-tests-for-NT-symlink-reparse-points.patch +++ /dev/null @@ -1,323 +0,0 @@ -From caaa38a56b7bb5e81bb71f5a6c3489755ebaee98 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Sat, 6 Feb 2021 12:52:51 -0700 -Subject: [PATCH] ntdll: Add tests for NT symlink reparse points. - -Signed-off-by: Erich E. Hoover ---- - dlls/ntdll/tests/file.c | 239 +++++++++++++++++++++++++++++++++++++--- - 1 file changed, 225 insertions(+), 14 deletions(-) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 4e3f0f04a3e..48abcd338bb 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5327,26 +5327,52 @@ static void test_mailslot_name(void) - CloseHandle( device ); - } - --static INT build_reparse_buffer(const WCHAR *filename, REPARSE_DATA_BUFFER **pbuffer) -+static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags, -+ REPARSE_DATA_BUFFER **pbuffer) - { - static INT header_size = offsetof(REPARSE_DATA_BUFFER, GenericReparseBuffer); - INT buffer_size, struct_size, data_size, string_len, prefix_len; - WCHAR *subst_dest, *print_dest; - REPARSE_DATA_BUFFER *buffer; - -- struct_size = offsetof(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]); -- prefix_len = strlen("\\??\\"); -+ switch(tag) -+ { -+ case IO_REPARSE_TAG_MOUNT_POINT: -+ struct_size = offsetof(REPARSE_DATA_BUFFER, MountPointReparseBuffer.PathBuffer[0]); -+ break; -+ case IO_REPARSE_TAG_SYMLINK: -+ struct_size = offsetof(REPARSE_DATA_BUFFER, SymbolicLinkReparseBuffer.PathBuffer[0]); -+ break; -+ default: -+ return 0; -+ } -+ prefix_len = (flags == SYMLINK_FLAG_RELATIVE) ? 0 : strlen("\\??\\"); - string_len = lstrlenW(&filename[prefix_len]); - data_size = (prefix_len + 2 * string_len + 2) * sizeof(WCHAR); - buffer_size = struct_size + data_size; - buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_size); -- buffer->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT; -+ buffer->ReparseTag = tag; - 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]; -+ switch(tag) -+ { -+ case IO_REPARSE_TAG_MOUNT_POINT: -+ 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]; -+ break; -+ case IO_REPARSE_TAG_SYMLINK: -+ buffer->SymbolicLinkReparseBuffer.SubstituteNameLength = (prefix_len + string_len) * sizeof(WCHAR); -+ buffer->SymbolicLinkReparseBuffer.PrintNameOffset = (prefix_len + string_len + 1) * sizeof(WCHAR); -+ buffer->SymbolicLinkReparseBuffer.PrintNameLength = string_len * sizeof(WCHAR); -+ buffer->SymbolicLinkReparseBuffer.Flags = flags; -+ subst_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[0]; -+ print_dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[prefix_len + string_len + 1]; -+ break; -+ default: -+ return 0; -+ } - lstrcpyW(subst_dest, filename); - lstrcpyW(print_dest, &filename[prefix_len]); - *pbuffer = buffer; -@@ -5363,14 +5389,18 @@ static void test_reparse_points(void) - FILE_BASIC_INFORMATION old_attrib, new_attrib; - static const WCHAR fooW[] = {'f','o','o',0}; - static WCHAR volW[] = {'c',':','\\',0}; -+ const WCHAR *rel_target = &targetW[1]; - WCHAR *dest, *long_path, *abs_target; - REPARSE_GUID_DATA_BUFFER guid_buffer; - static const WCHAR dotW[] = {'.',0}; - REPARSE_DATA_BUFFER *buffer = NULL; - DWORD dwret, dwLen, dwFlags, err; -+ WCHAR buf[] = {0,0,0,0}; -+ HANDLE handle, token; - IO_STATUS_BLOCK iosb; - UNICODE_STRING nameW; -- HANDLE handle; -+ TOKEN_PRIVILEGES tp; -+ LUID luid; - BOOL bret; - - /* Create a temporary folder for the junction point tests */ -@@ -5435,7 +5465,7 @@ static void test_reparse_points(void) - win_skip("Failed to open junction point directory handle (0x%lx).\n", GetLastError()); - goto cleanup; - } -- buffer_len = build_reparse_buffer(long_path, &buffer); -+ buffer_len = build_reparse_buffer(long_path, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer); - bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); - ok(!bret && GetLastError()==ERROR_INVALID_REPARSE_DATA, "Unexpected error (0x%lx)\n", GetLastError()); - HeapFree(GetProcessHeap(), 0, buffer); -@@ -5466,7 +5496,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%lx).\n", dwret); -- buffer_len = build_reparse_buffer(long_path, &buffer); -+ buffer_len = build_reparse_buffer(long_path, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer); - bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); - ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError()); - -@@ -5513,7 +5543,7 @@ static void test_reparse_points(void) - HeapFree(GetProcessHeap(), 0, buffer); - handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -- buffer_len = build_reparse_buffer(abs_target, &buffer); -+ buffer_len = build_reparse_buffer(abs_target, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer); - bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); - ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError()); - CloseHandle(handle); -@@ -5528,7 +5558,7 @@ static void test_reparse_points(void) - ok(bret, "Failed to create junction point target directory.\n"); - handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -- buffer_len = build_reparse_buffer(abs_target, &buffer); -+ buffer_len = build_reparse_buffer(abs_target, IO_REPARSE_TAG_MOUNT_POINT, 0, &buffer); - bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); - ok(bret, "Failed to create junction point! (0x%lx)\n", GetLastError()); - CloseHandle(handle); -@@ -5541,6 +5571,187 @@ static void test_reparse_points(void) - ok(dwret != (DWORD)~0, "Junction point doesn't exist (attributes: 0x%lx)!\n", dwret); - ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a junction point! (attributes: 0x%lx)\n", dwret); - -+ /* Test deleting a junction point's target */ -+ dwret = GetFileAttributesW(reparse_path); -+ ok(dwret == 0x410 || broken(dwret == 0x430) /* win2k */ || broken(dwret == 0xc10) /* vista */, -+ "Unexpected junction point attributes (0x%lx != 0x410)!\n", dwret); -+ bret = RemoveDirectoryW(target_path); -+ ok(bret, "Failed to delete junction point target!\n"); -+ bret = CreateDirectoryW(target_path, NULL); -+ ok(bret, "Failed to create junction point target directory.\n"); -+ -+ /* Establish permissions for symlink creation */ -+ bret = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &token); -+ ok(bret, "OpenProcessToken failed: %lx\n", GetLastError()); -+ bret = LookupPrivilegeValueA(NULL, "SeCreateSymbolicLinkPrivilege", &luid); -+ todo_wine ok(bret || broken(!bret && GetLastError() == ERROR_NO_SUCH_PRIVILEGE) /* winxp */, -+ "LookupPrivilegeValue failed: %lx\n", GetLastError()); -+ if (bret) -+ { -+ tp.PrivilegeCount = 1; -+ tp.Privileges[0].Luid = luid; -+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; -+ bret = AdjustTokenPrivileges(token, FALSE, &tp, 0, NULL, NULL); -+ ok(bret, "AdjustTokenPrivileges failed: %lx\n", GetLastError()); -+ if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) -+ { -+ win_skip("Insufficient permissions to perform symlink tests.\n"); -+ goto cleanup; -+ } -+ } -+ -+ /* 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"); -+ bret = RemoveDirectoryW(target_path); -+ ok(bret, "Failed to delete junction point target!\n"); -+ handle = CreateFileW(target_path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0); -+ ok(handle != INVALID_HANDLE_VALUE, "Failed to create symlink target file.\n"); -+ bret = WriteFile(handle, fooW, sizeof(fooW), &dwLen, NULL); -+ ok(bret, "Failed to write data to the symlink target file.\n"); -+ ok(GetFileSize(handle, NULL) == sizeof(fooW), "target size is incorrect (%ld vs %d)\n", -+ GetFileSize(handle, NULL), (int)sizeof(fooW)); -+ CloseHandle(handle); -+ -+ /* Create the file symlink */ -+ HeapFree(GetProcessHeap(), 0, buffer); -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ ok(handle != INVALID_HANDLE_VALUE, "Failed to create symlink file.\n"); -+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink file's attributes (0x%lx).\n", dwret); -+ buffer_len = build_reparse_buffer(nameW.Buffer, IO_REPARSE_TAG_SYMLINK, 0, &buffer); -+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError()); -+ CloseHandle(handle); -+ -+ /* Check the size/data of the symlink target when opened with FILE_FLAG_OPEN_REPARSE_POINT */ -+ handle = CreateFileW(target_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ if (handle == INVALID_HANDLE_VALUE) -+ { -+ win_skip("Failed to open symlink file handle (0x%lx).\n", GetLastError()); -+ goto cleanup; -+ } -+ ok(GetFileSize(handle, NULL) == sizeof(fooW), "symlink target size does not match (%ld != %d)\n", -+ GetFileSize(handle, NULL), (int)sizeof(fooW)); -+ bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL); -+ ok(bret, "Failed to read data from the symlink target.\n"); -+ ok(dwLen == sizeof(fooW), "Length of symlink target data does not match (%ld != %d).\n", -+ dwLen, (int)sizeof(fooW)); -+ ok(!memcmp(fooW, &buf, sizeof(fooW)), "Symlink target data does not match (%s != %s).\n", -+ wine_dbgstr_wn(buf, dwLen), wine_dbgstr_w(fooW)); -+ CloseHandle(handle); -+ -+ /* 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"); -+ err = GetLastError(); -+ ok(err == ERROR_DIRECTORY, -+ "Expected last error 0x%x for RemoveDirectory on file symlink (actually 0x%lx)!\n", -+ ERROR_DIRECTORY, err); -+ dwret = GetFileAttributesW(reparse_path); -+ ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%lx)!\n", dwret); -+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a symlink! (attributes: 0x%lx)\n", dwret); -+ -+ /* Delete the symlink as a file */ -+ bret = DeleteFileW(reparse_path); -+ ok(bret, "Failed to delete symlink as a file!\n"); -+ -+ /* Create a blank slate for directory symlink tests */ -+ bret = CreateDirectoryW(reparse_path, NULL); -+ ok(bret, "Failed to create junction point directory.\n"); -+ dwret = GetFileAttributesW(reparse_path); -+ ok(dwret != (DWORD)~0, "Path doesn't exist (attributes: 0x%lx)!\n", dwret); -+ ok(!(dwret & FILE_ATTRIBUTE_REPARSE_POINT), "File is already a reparse point! (attributes: %lx)\n", dwret); -+ bret = DeleteFileW(target_path); -+ ok(bret, "Failed to delete symlink target!\n"); -+ bret = CreateDirectoryW(target_path, NULL); -+ ok(bret, "Failed to create symlink target directory.\n"); -+ -+ /* Create the directory symlink */ -+ HeapFree(GetProcessHeap(), 0, buffer); -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ if (handle == INVALID_HANDLE_VALUE) -+ { -+ win_skip("Failed to open symlink directory handle (0x%lx).\n", GetLastError()); -+ goto cleanup; -+ } -+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%lx).\n", dwret); -+ buffer_len = build_reparse_buffer(abs_target, IO_REPARSE_TAG_SYMLINK, 0, &buffer); -+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError()); -+ -+ /* Check the file attributes of the symlink */ -+ dwret = GetFileAttributesW(reparse_path); -+ ok(dwret != (DWORD)~0, "Symlink doesn't exist (attributes: 0x%lx)!\n", dwret); -+ ok(dwret & FILE_ATTRIBUTE_REPARSE_POINT, "File is not a symlink! (attributes: %lx)\n", dwret); -+ -+ /* Read back the symlink */ -+ HeapFree(GetProcessHeap(), 0, buffer); -+ buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR); -+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len); -+ bret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0); -+ string_len = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength; -+ dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)]; -+ 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)); -+ path_len = buffer->SymbolicLinkReparseBuffer.PrintNameOffset/sizeof(WCHAR); -+ path_len += buffer->SymbolicLinkReparseBuffer.PrintNameLength/sizeof(WCHAR); -+ total_len = FIELD_OFFSET(typeof(*buffer), SymbolicLinkReparseBuffer.PathBuffer[path_len+1]) -+ - FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer); -+ ok(buffer->ReparseDataLength == total_len, "ReparseDataLength has unexpected value (%d != %d)\n", -+ buffer->ReparseDataLength, total_len); -+ -+ /* Delete the symlink */ -+ memset(&old_attrib, 0x00, sizeof(old_attrib)); -+ old_attrib.LastAccessTime.QuadPart = 0x200deadcafebeef; -+ dwret = NtSetInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to set symlink folder's attributes (0x%lx).\n", dwret); -+ memset(&guid_buffer, 0x00, sizeof(guid_buffer)); -+ guid_buffer.ReparseTag = IO_REPARSE_TAG_SYMLINK; -+ bret = DeviceIoControl(handle, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer, -+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to delete symlink! (0x%lx)\n", GetLastError()); -+ memset(&new_attrib, 0x00, sizeof(new_attrib)); -+ dwret = NtQueryInformationFile(handle, &iosb, &new_attrib, sizeof(new_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%lx).\n", dwret); -+ ok(old_attrib.LastAccessTime.QuadPart == new_attrib.LastAccessTime.QuadPart, -+ "Symlink folder's access time does not match.\n"); -+ CloseHandle(handle); -+ -+ /* Create a relative directory symlink */ -+ HeapFree(GetProcessHeap(), 0, buffer); -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ if (handle == INVALID_HANDLE_VALUE) -+ { -+ win_skip("Failed to open symlink directory handle (0x%lx).\n", GetLastError()); -+ goto cleanup; -+ } -+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%lx).\n", dwret); -+ buffer_len = build_reparse_buffer(rel_target, IO_REPARSE_TAG_SYMLINK, SYMLINK_FLAG_RELATIVE, &buffer); -+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError()); -+ -+ /* Read back the relative symlink */ -+ HeapFree(GetProcessHeap(), 0, buffer); -+ buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR); -+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len); -+ bret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0); -+ ok(bret, "Failed to read relative symlink!\n"); -+ string_len = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength; -+ ok(string_len != lstrlenW(rel_target), "Symlink destination length does not match ('%d' != '%d')!\n", -+ string_len, lstrlenW(rel_target)); -+ dest = &buffer->SymbolicLinkReparseBuffer.PathBuffer[buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR)]; -+ ok((memcmp(dest, rel_target, string_len) == 0), "Symlink destination does not match ('%s' != '%s')!\n", -+ wine_dbgstr_w(dest), wine_dbgstr_w(rel_target)); -+ CloseHandle(handle); -+ - cleanup: - /* Cleanup */ - pRtlFreeUnicodeString(&nameW); --- -2.37.2 - diff --git a/patches/ntdll-Junction_Points/0009-kernelbase-Add-support-for-moving-reparse-points-wit.patch b/patches/ntdll-Junction_Points/0009-kernelbase-Add-support-for-moving-reparse-points-wit.patch index ee406f6e..1955518e 100644 --- a/patches/ntdll-Junction_Points/0009-kernelbase-Add-support-for-moving-reparse-points-wit.patch +++ b/patches/ntdll-Junction_Points/0009-kernelbase-Add-support-for-moving-reparse-points-wit.patch @@ -1,4 +1,4 @@ -From fea1d301c573d3410e2f7d66b21609663ee47880 Mon Sep 17 00:00:00 2001 +From 51373e0350ff1b507d7b47d6e5acd84b8af9d328 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Sat, 6 Feb 2021 12:46:30 -0700 Subject: [PATCH] kernelbase: Add support for moving reparse points with @@ -6,17 +6,16 @@ Subject: [PATCH] kernelbase: Add support for moving reparse points with Signed-off-by: Erich E. Hoover --- - dlls/kernelbase/file.c | 2 +- - dlls/ntdll/tests/file.c | 12 +++++++++++- - dlls/ntdll/unix/file.c | 23 ++++++++++++++++++++++- - server/fd.c | 6 ++++-- - 4 files changed, 38 insertions(+), 5 deletions(-) + dlls/kernelbase/file.c | 2 +- + dlls/ntdll/unix/file.c | 24 ++++++++++++++++++++++-- + server/fd.c | 6 ++++-- + 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c -index 51459402e75..d70e0fc833c 100644 +index 36045116e43..f1b1326353f 100644 --- a/dlls/kernelbase/file.c +++ b/dlls/kernelbase/file.c -@@ -2538,7 +2538,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH MoveFileWithProgressW( const WCHAR *source, const +@@ -2597,7 +2597,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH MoveFileWithProgressW( const WCHAR *source, const InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL ); status = NtOpenFile( &source_handle, DELETE | SYNCHRONIZE, &attr, &io, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, @@ -25,41 +24,11 @@ index 51459402e75..d70e0fc833c 100644 RtlFreeUnicodeString( &nt_name ); if (!set_ntstatus( status )) goto error; -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index b592036d2d0..6e2c7906644 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -6025,7 +6025,8 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags, - - static void test_reparse_points(void) - { -- WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH]; -+ WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH], new_path[MAX_PATH]; -+ static const WCHAR new_reparseW[] = {'\\','n','e','w','_','r','e','p','a','r','s','e',0}; - static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0}; - static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0}; - static const WCHAR parentW[] = {'\\','.','.','\\',0}; -@@ -6396,6 +6397,15 @@ static void test_reparse_points(void) - wine_dbgstr_w(dest), wine_dbgstr_w(rel_target)); - CloseHandle(handle); - -+ /* Check moving a reparse point to another location */ -+ lstrcpyW(new_path, path); -+ lstrcatW(new_path, parentW); -+ lstrcatW(new_path, new_reparseW); -+ bret = MoveFileW(reparse_path, new_path); -+ ok(bret, "Failed to move and rename reparse point.\n"); -+ bret = MoveFileW(new_path, reparse_path); -+ ok(bret, "Failed to move and rename reparse point.\n"); -+ - cleanup: - /* Cleanup */ - pRtlFreeUnicodeString(&nameW); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index 8e9e28269f8..6385a26bee7 100644 +index 3c341a6d702..9076da9f763 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c -@@ -5675,6 +5675,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, +@@ -5572,6 +5572,8 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, unsigned int flags; UNICODE_STRING name_str, nt_name; OBJECT_ATTRIBUTES attr; @@ -68,7 +37,7 @@ index 8e9e28269f8..6385a26bee7 100644 char *unix_name; if (class == FileRenameInformation) -@@ -5689,6 +5691,20 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, +@@ -5586,6 +5588,20 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, name_str.Length = info->FileNameLength; name_str.MaximumLength = info->FileNameLength + sizeof(WCHAR); InitializeObjectAttributes( &attr, &name_str, OBJ_CASE_INSENSITIVE, info->RootDirectory, NULL ); @@ -89,7 +58,7 @@ index 8e9e28269f8..6385a26bee7 100644 status = get_nt_and_unix_names( &attr, &nt_name, &unix_name, FILE_OPEN_IF ); if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE) { -@@ -5705,8 +5721,13 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, +@@ -5602,8 +5618,13 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, } SERVER_END_REQ; @@ -104,6 +73,14 @@ index 8e9e28269f8..6385a26bee7 100644 free( nt_name.Buffer ); } else status = STATUS_INVALID_PARAMETER_3; +@@ -5646,7 +5667,6 @@ NTSTATUS WINAPI NtSetInformationFile( HANDLE handle, IO_STATUS_BLOCK *io, + status = wine_server_call( req ); + } + SERVER_END_REQ; +- + } + free( unix_name ); + free( nt_name.Buffer ); diff --git a/server/fd.c b/server/fd.c index 466259ae567..7f88fcd6e33 100644 --- a/server/fd.c diff --git a/patches/ntdll-Junction_Points/0010-kernelbase-Add-test-for-reparse-point-copy-behavior.patch b/patches/ntdll-Junction_Points/0010-kernelbase-Add-test-for-reparse-point-copy-behavior.patch deleted file mode 100644 index 8a9bd59f..00000000 --- a/patches/ntdll-Junction_Points/0010-kernelbase-Add-test-for-reparse-point-copy-behavior.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 2cf08dad55bea4bbf5ca37ff0bf4a0553d1f6be3 Mon Sep 17 00:00:00 2001 -From: "Erich E. Hoover" -Date: Sat, 3 Sep 2022 08:57:05 -0600 -Subject: kernelbase: Add test for reparse point copy behavior. - -Signed-off-by: Erich E. Hoover ---- - dlls/ntdll/tests/file.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 808d863ea55..390768f557d 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5762,6 +5762,12 @@ static void test_reparse_points(void) - bret = MoveFileW(new_path, reparse_path); - ok(bret, "Failed to move and rename reparse point.\n"); - -+ /* Check copying a reparse point to another location */ -+ lstrcpyW(new_path, path); -+ lstrcatW(new_path, new_reparseW); -+ bret = CopyFileW(reparse_path, new_path, TRUE); -+ ok(!bret, "Reparse points cannot be copied.\n"); -+ - cleanup: - /* Cleanup */ - pRtlFreeUnicodeString(&nameW); --- -2.17.1 - diff --git a/patches/ntdll-Junction_Points/0011-ntdll-Follow-reparse-points-during-path-resolution.patch b/patches/ntdll-Junction_Points/0011-ntdll-Follow-reparse-points-during-path-resolution.patch index c905a276..9e8a169e 100644 --- a/patches/ntdll-Junction_Points/0011-ntdll-Follow-reparse-points-during-path-resolution.patch +++ b/patches/ntdll-Junction_Points/0011-ntdll-Follow-reparse-points-during-path-resolution.patch @@ -5,44 +5,9 @@ Subject: [PATCH] ntdll: Follow reparse points during path resolution. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 11 ++- dlls/ntdll/unix/file.c | 196 +++++++++++++++++++++++++++++++++++----- 2 files changed, 184 insertions(+), 23 deletions(-) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 9bd4bbdd245..84a0957b040 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -6025,7 +6025,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags, - - static void test_reparse_points(void) - { -- WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH], new_path[MAX_PATH]; -+ WCHAR path[MAX_PATH], reparse_path[MAX_PATH], target_path[MAX_PATH], volnameW[MAX_PATH], new_path[MAX_PATH], thru_path[MAX_PATH]; - static const WCHAR new_reparseW[] = {'\\','n','e','w','_','r','e','p','a','r','s','e',0}; - static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0}; - static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0}; -@@ -6412,11 +6412,20 @@ static void test_reparse_points(void) - bret = CopyFileW(reparse_path, new_path, TRUE); - ok(!bret, "Reparse points cannot be copied.\n"); - -+ /* Create a file on the other side of a reparse point */ -+ lstrcpyW(thru_path, reparse_path); -+ lstrcatW(thru_path, new_reparseW); -+ handle = CreateFileW(thru_path, GENERIC_READ | GENERIC_WRITE, 0, 0, CREATE_NEW, 0, 0); -+ ok( handle != INVALID_HANDLE_VALUE, "Failed to create file on other side of reparse point: %lx.\n", GetLastError() ); -+ CloseHandle(handle); -+ - cleanup: - /* Cleanup */ - pRtlFreeUnicodeString(&nameW); - HeapFree(GetProcessHeap(), 0, long_path); - HeapFree(GetProcessHeap(), 0, buffer); -+ bret = DeleteFileW(thru_path); -+ ok(bret, "Failed to delete file on other side of junction point!\n"); - bret = RemoveDirectoryW(reparse_path); - ok(bret, "Failed to remove temporary reparse point directory!\n"); - bret = RemoveDirectoryW(target_path); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index f3274478ae2..860e563f69d 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0013-ntdll-Allow-reparse-points-to-target-the-applicable-.patch b/patches/ntdll-Junction_Points/0013-ntdll-Allow-reparse-points-to-target-the-applicable-.patch index 78c0f943..067d8463 100644 --- a/patches/ntdll-Junction_Points/0013-ntdll-Allow-reparse-points-to-target-the-applicable-.patch +++ b/patches/ntdll-Junction_Points/0013-ntdll-Allow-reparse-points-to-target-the-applicable-.patch @@ -1,4 +1,4 @@ -From f1675a9b37980cafd0b6f76e23ef8b042b60bb1e Mon Sep 17 00:00:00 2001 +From 5b94720ada0b6f75ddff60cf19472a2685dbeaf0 Mon Sep 17 00:00:00 2001 From: "Erich E. Hoover" Date: Sun, 4 Sep 2022 13:19:16 -0600 Subject: [PATCH] ntdll: Allow reparse points to target the applicable Unix @@ -9,14 +9,14 @@ the user to follow the symlink outside of Wine. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/unix/file.c | 129 +++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 129 insertions(+) + dlls/ntdll/unix/file.c | 118 +++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 118 insertions(+) diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index f2e182d9076..63a27b89e20 100644 +index c54fd1119e1..33f26ceb89a 100644 --- a/dlls/ntdll/unix/file.c +++ b/dlls/ntdll/unix/file.c -@@ -3577,6 +3577,125 @@ static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFF +@@ -3712,6 +3712,114 @@ static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFF } @@ -50,18 +50,7 @@ index f2e182d9076..63a27b89e20 100644 + 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) -+ { -+ free( unix_path ); -+ return STATUS_NO_MEMORY; -+ } -+ status = wine_unix_to_nt_file_name( unix_path, nt_path, &nt_path_len ); -+ if (status != STATUS_BUFFER_TOO_SMALL) break; -+ free( nt_path ); -+ } ++ status = unix_to_nt_file_name( unix_path, &nt_path, FILE_OPEN ); + free( unix_path ); + if (status != STATUS_SUCCESS) + return status; @@ -142,7 +131,7 @@ index f2e182d9076..63a27b89e20 100644 /* * 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. -@@ -3710,6 +3829,16 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer) +@@ -3845,6 +3953,16 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer) link_dir_fd = fd; } @@ -160,5 +149,5 @@ index f2e182d9076..63a27b89e20 100644 if (!renameat2( -1, tmplink, -1, unix_src, RENAME_EXCHANGE )) { -- -2.43.0 +2.47.2 diff --git a/patches/ntdll-Junction_Points/0015-ntdll-Always-report-symbolic-links-as-containing-zer.patch b/patches/ntdll-Junction_Points/0015-ntdll-Always-report-symbolic-links-as-containing-zer.patch index e7bad2e3..ffa8827a 100644 --- a/patches/ntdll-Junction_Points/0015-ntdll-Always-report-symbolic-links-as-containing-zer.patch +++ b/patches/ntdll-Junction_Points/0015-ntdll-Always-report-symbolic-links-as-containing-zer.patch @@ -5,60 +5,9 @@ Subject: ntdll: Always report symbolic links as containing zero bytes. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 32 ++++++++++++++++++++++++++++++++ dlls/ntdll/unix/file.c | 4 ++++ 2 files changed, 36 insertions(+) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index a0b84849490..35ba5f03097 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5396,6 +5396,7 @@ static void test_reparse_points(void) - static const WCHAR dotW[] = {'.',0}; - REPARSE_DATA_BUFFER *buffer = NULL; - DWORD dwret, dwLen, dwFlags, err; -+ WIN32_FILE_ATTRIBUTE_DATA fad; - WCHAR buf[] = {0,0,0,0}; - HANDLE handle, token; - IO_STATUS_BLOCK iosb; -@@ -5626,6 +5627,37 @@ static void test_reparse_points(void) - ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError()); - CloseHandle(handle); - -+ /* Check the size of the symlink */ -+ bret = GetFileAttributesExW(reparse_path, GetFileExInfoStandard, &fad); -+ ok(bret, "Failed to read file attributes from the symlink target.\n"); -+ ok(fad.nFileSizeLow == 0 && fad.nFileSizeHigh == 0, "Size of symlink is not zero.\n"); -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ ok(handle != INVALID_HANDLE_VALUE, "Failed to open symlink file.\n"); -+ ok(GetFileSize(handle, NULL) == 0, "symlink size is not zero\n"); -+ bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL); -+ todo_wine ok(bret, "Failed to read data from the symlink.\n"); -+ ok(dwLen == 0, "Length of symlink data is not zero.\n"); -+ CloseHandle(handle); -+ -+ /* Check the size/data of the symlink target */ -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS, 0); -+ if (handle == INVALID_HANDLE_VALUE) -+ { -+ win_skip("Failed to open symlink file handle (0x%lx).\n", GetLastError()); -+ goto cleanup; -+ } -+ ok(GetFileSize(handle, NULL) == sizeof(fooW), "symlink target size does not match (%ld != %d)\n", -+ GetFileSize(handle, NULL), (int)sizeof(fooW)); -+ bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL); -+ ok(bret, "Failed to read data from the symlink.\n"); -+ ok(dwLen == sizeof(fooW), "Length of symlink target data does not match (%ld != %d).\n", -+ dwLen, (int)sizeof(fooW)); -+ ok(!memcmp(fooW, &buf, sizeof(fooW)), "Symlink target data does not match (%s != %s).\n", -+ wine_dbgstr_wn(buf, dwLen), wine_dbgstr_w(fooW)); -+ CloseHandle(handle); -+ - /* Check the size/data of the symlink target when opened with FILE_FLAG_OPEN_REPARSE_POINT */ - handle = CreateFileW(target_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, - FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index f298b1f7a6c..caa454c024f 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0017-ntdll-Succeed-with-no-data-for-NtReadFile-on-reparse.patch b/patches/ntdll-Junction_Points/0017-ntdll-Succeed-with-no-data-for-NtReadFile-on-reparse.patch index ba6f8d1f..6b69992a 100644 --- a/patches/ntdll-Junction_Points/0017-ntdll-Succeed-with-no-data-for-NtReadFile-on-reparse.patch +++ b/patches/ntdll-Junction_Points/0017-ntdll-Succeed-with-no-data-for-NtReadFile-on-reparse.patch @@ -5,25 +5,11 @@ Subject: ntdll: Succeed with no data for NtReadFile on reparse points. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 2 +- dlls/ntdll/unix/file.c | 5 +++++ server/file.c | 1 + server/protocol.def | 1 + 4 files changed, 8 insertions(+), 1 deletion(-) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 35ba5f03097..8508161d269 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5636,7 +5636,7 @@ static void test_reparse_points(void) - ok(handle != INVALID_HANDLE_VALUE, "Failed to open symlink file.\n"); - ok(GetFileSize(handle, NULL) == 0, "symlink size is not zero\n"); - bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL); -- todo_wine ok(bret, "Failed to read data from the symlink.\n"); -+ ok(bret, "Failed to read data from the symlink.\n"); - ok(dwLen == 0, "Length of symlink data is not zero.\n"); - CloseHandle(handle); - diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index b26b239574b..bf80708b41e 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0018-ntdll-Add-support-for-FileAttributeTagInformation.patch b/patches/ntdll-Junction_Points/0018-ntdll-Add-support-for-FileAttributeTagInformation.patch index b0b86a35..76f4940e 100644 --- a/patches/ntdll-Junction_Points/0018-ntdll-Add-support-for-FileAttributeTagInformation.patch +++ b/patches/ntdll-Junction_Points/0018-ntdll-Add-support-for-FileAttributeTagInformation.patch @@ -5,41 +5,9 @@ Subject: ntdll: Add support for FileAttributeTagInformation. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 6 ++++++ dlls/ntdll/unix/file.c | 15 ++++++++++++++- 2 files changed, 20 insertions(+), 1 deletion(-) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 8508161d269..2450e9e5b4a 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5394,6 +5394,7 @@ static void test_reparse_points(void) - WCHAR *dest, *long_path, *abs_target; - REPARSE_GUID_DATA_BUFFER guid_buffer; - static const WCHAR dotW[] = {'.',0}; -+ FILE_ATTRIBUTE_TAG_INFORMATION info; - REPARSE_DATA_BUFFER *buffer = NULL; - DWORD dwret, dwLen, dwFlags, err; - WIN32_FILE_ATTRIBUTE_DATA fad; -@@ -5402,6 +5403,7 @@ static void test_reparse_points(void) - IO_STATUS_BLOCK iosb; - UNICODE_STRING nameW; - TOKEN_PRIVILEGES tp; -+ NTSTATUS status; - LUID luid; - BOOL bret; - -@@ -5638,6 +5640,10 @@ static void test_reparse_points(void) - bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL); - ok(bret, "Failed to read data from the symlink.\n"); - ok(dwLen == 0, "Length of symlink data is not zero.\n"); -+ memset(&info, 0x0, sizeof(info)); -+ status = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), FileAttributeTagInformation); -+ ok( status == STATUS_SUCCESS, "got %#lx\n", status ); -+ ok( info.ReparseTag == IO_REPARSE_TAG_SYMLINK, "got reparse tag %#lx\n", info.ReparseTag ); - CloseHandle(handle); - - /* Check the size/data of the symlink target */ diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index bf80708b41e..51d6aed85f0 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0024-ntdll-Add-support-for-creating-Unix-Linux-symlinks.patch b/patches/ntdll-Junction_Points/0024-ntdll-Add-support-for-creating-Unix-Linux-symlinks.patch index 0064e97d..76816804 100644 --- a/patches/ntdll-Junction_Points/0024-ntdll-Add-support-for-creating-Unix-Linux-symlinks.patch +++ b/patches/ntdll-Junction_Points/0024-ntdll-Add-support-for-creating-Unix-Linux-symlinks.patch @@ -5,64 +5,10 @@ Subject: [PATCH] ntdll: Add support for creating Unix/Linux symlinks. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 35 +++++++++++++++++++++++++++++++++++ dlls/ntdll/unix/file.c | 38 ++++++++++++++++++++++++++------------ include/winnt.h | 1 + 3 files changed, 62 insertions(+), 12 deletions(-) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 2139ddd8ea2..fc08a533559 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5426,6 +5426,8 @@ static void test_reparse_points(void) - REPARSE_DATA_BUFFER *buffer = NULL; - DWORD dwret, dwLen, dwFlags, err; - WIN32_FILE_ATTRIBUTE_DATA fad; -+ char unix_target[] = "target"; -+ UCHAR *unix_dest; - WCHAR buf[] = {0,0,0,0}; - HANDLE handle, token; - IO_STATUS_BLOCK iosb; -@@ -5790,6 +5792,39 @@ static void test_reparse_points(void) - "Symlink folder's access time does not match.\n"); - CloseHandle(handle); - -+ /* Create a Unix/Linux symlink */ -+ HeapFree(GetProcessHeap(), 0, buffer); -+ RemoveDirectoryW(reparse_path); -+ bret = CreateDirectoryW(reparse_path, NULL); -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ if (handle == INVALID_HANDLE_VALUE) -+ { -+ win_skip("Failed to open symlink directory handle (0x%lx).\n", GetLastError()); -+ goto cleanup; -+ } -+ dwret = NtQueryInformationFile(handle, &iosb, &old_attrib, sizeof(old_attrib), FileBasicInformation); -+ ok(dwret == STATUS_SUCCESS, "Failed to get symlink folder's attributes (0x%lx).\n", dwret); -+ path_len = strlen(unix_target); -+ buffer_len = offsetof(REPARSE_DATA_BUFFER, LinuxSymbolicLinkReparseBuffer.PathBuffer[path_len]); -+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len); -+ buffer->ReparseTag = IO_REPARSE_TAG_LX_SYMLINK; -+ buffer->ReparseDataLength = sizeof(ULONG) + path_len; -+ memcpy(buffer->LinuxSymbolicLinkReparseBuffer.PathBuffer, unix_target, path_len); -+ bret = DeviceIoControl(handle, FSCTL_SET_REPARSE_POINT, (LPVOID)buffer, buffer_len, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to create symlink! (0x%lx)\n", GetLastError()); -+ -+ /* Delete the symlink */ -+ memset(&guid_buffer, 0x00, sizeof(guid_buffer)); -+ guid_buffer.ReparseTag = IO_REPARSE_TAG_LX_SYMLINK; -+ bret = DeviceIoControl(handle, FSCTL_DELETE_REPARSE_POINT, (LPVOID)&guid_buffer, -+ REPARSE_GUID_DATA_BUFFER_HEADER_SIZE, NULL, 0, &dwret, 0); -+ ok(bret, "Failed to delete symlink! (0x%lx)\n", GetLastError()); -+ CloseHandle(handle); -+ RemoveDirectoryW(reparse_path); -+ DeleteFileW(reparse_path); -+ CreateDirectoryW(reparse_path, NULL); -+ - /* Create a relative directory symlink */ - HeapFree(GetProcessHeap(), 0, buffer); - handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index fe1c50468a4..f87117438b8 100644 --- a/dlls/ntdll/unix/file.c diff --git a/patches/ntdll-Junction_Points/0025-ntdll-Report-regular-Unix-symlinks-as-WSL-Linux-Unix.patch b/patches/ntdll-Junction_Points/0025-ntdll-Report-regular-Unix-symlinks-as-WSL-Linux-Unix.patch index 243e9e39..8276dd4d 100644 --- a/patches/ntdll-Junction_Points/0025-ntdll-Report-regular-Unix-symlinks-as-WSL-Linux-Unix.patch +++ b/patches/ntdll-Junction_Points/0025-ntdll-Report-regular-Unix-symlinks-as-WSL-Linux-Unix.patch @@ -5,39 +5,9 @@ Subject: ntdll: Report regular Unix symlinks as WSL Linux/Unix symlinks. Signed-off-by: Erich E. Hoover --- - dlls/ntdll/tests/file.c | 18 ++++++++++++++++++ dlls/ntdll/unix/file.c | 9 ++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) -diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c -index 16a45636ebe..979988e65fd 100644 ---- a/dlls/ntdll/tests/file.c -+++ b/dlls/ntdll/tests/file.c -@@ -5786,6 +5786,24 @@ 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 symlink! (0x%lx)\n", GetLastError()); - -+ /* Read back the Unix/Linux symlink */ -+ HeapFree(GetProcessHeap(), 0, buffer); -+ handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, -+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); -+ if (handle == INVALID_HANDLE_VALUE) -+ buffer_len = sizeof(*buffer) + MAX_PATH*sizeof(WCHAR); -+ buffer = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buffer_len); -+ bret = DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, (LPVOID)buffer, buffer_len, &dwret, 0); -+ ok(bret, "Failed to read symlink!\n"); -+ string_len = buffer->ReparseDataLength - sizeof(ULONG); -+ unix_dest = &buffer->LinuxSymbolicLinkReparseBuffer.PathBuffer[0]; -+ ok((memcmp(unix_dest, unix_target, string_len) == 0), "Symlink destination does not match ('%s' != '%s')!\n", -+ unix_dest, unix_target); -+ total_len = FIELD_OFFSET(typeof(*buffer), LinuxSymbolicLinkReparseBuffer.PathBuffer[path_len]) -+ - FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer); -+ ok(buffer->ReparseDataLength == total_len, "ReparseDataLength has unexpected value (%d != %d)\n", -+ buffer->ReparseDataLength, total_len); -+ - /* Delete the symlink */ - memset(&guid_buffer, 0x00, sizeof(guid_buffer)); - guid_buffer.ReparseTag = IO_REPARSE_TAG_LX_SYMLINK; diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c index b17ee58d736..e6967a65a06 100644 --- a/dlls/ntdll/unix/file.c diff --git a/staging/upstream-commit b/staging/upstream-commit index b060ec3f..69953227 100644 --- a/staging/upstream-commit +++ b/staging/upstream-commit @@ -1 +1 @@ -cad35b3c8119f38bf2084a5a3613630cd7b2d45d +177848adf54f6871e558be6b42ee2478a522c3d2