You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-09-12 18:50:20 -07:00
Rebase against 177848adf54f6871e558be6b42ee2478a522c3d2.
This commit is contained in:
@@ -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
|
||||
|
@@ -5,55 +5,9 @@ Subject: [PATCH] ntdll: Add support for reading reparse points.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -5,71 +5,9 @@ Subject: [PATCH] ntdll: Add support for deleting reparse points.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -6,26 +6,9 @@ Subject: ntdll: Add support for testing for reparse points with
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -7,7 +7,6 @@ Subject: kernelbase: Add support for deleting reparse points with
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
||||
|
@@ -7,7 +7,6 @@ Subject: [PATCH] kernelbase: Add support for deleting reparse points with
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
||||
|
@@ -1,323 +0,0 @@
|
||||
From caaa38a56b7bb5e81bb71f5a6c3489755ebaee98 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
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 <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -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" <erich.e.hoover@wine-staging.com>
|
||||
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 <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -1,30 +0,0 @@
|
||||
From 2cf08dad55bea4bbf5ca37ff0bf4a0553d1f6be3 Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Sat, 3 Sep 2022 08:57:05 -0600
|
||||
Subject: kernelbase: Add test for reparse point copy behavior.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -5,44 +5,9 @@ Subject: [PATCH] ntdll: Follow reparse points during path resolution.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -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" <erich.e.hoover@gmail.com>
|
||||
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 <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
||||
|
@@ -5,60 +5,9 @@ Subject: ntdll: Always report symbolic links as containing zero bytes.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/tests/file.c | 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
|
||||
|
@@ -5,25 +5,11 @@ Subject: ntdll: Succeed with no data for NtReadFile on reparse points.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -5,41 +5,9 @@ Subject: ntdll: Add support for FileAttributeTagInformation.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -5,64 +5,10 @@ Subject: [PATCH] ntdll: Add support for creating Unix/Linux symlinks.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -5,39 +5,9 @@ Subject: ntdll: Report regular Unix symlinks as WSL Linux/Unix symlinks.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
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
|
||||
|
@@ -1 +1 @@
|
||||
cad35b3c8119f38bf2084a5a3613630cd7b2d45d
|
||||
177848adf54f6871e558be6b42ee2478a522c3d2
|
||||
|
Reference in New Issue
Block a user