[PATCH] ntdll: resolve drive symlink for mapped filename
Matias Zuniga
matias.nicolas.zc at gmail.com
Thu Sep 9 23:33:29 CDT 2021
Applications expect a path starting with a drive like
'\Device\Harddisk1\' instead of a drive letter.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=51687
Signed-off-by: Matias Zuniga <matias.nicolas.zc at gmail.com>
---
dlls/ntdll/unix/virtual.c | 76 ++++++++++++++++++++++++++++++++---
dlls/psapi/tests/psapi_main.c | 5 +--
2 files changed, 71 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index 8a1e35b6387..04eddf0e6f1 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -133,6 +133,8 @@ struct file_view
} \
} while (0);
+#define SYMBOLIC_LINK_QUERY 0x0001
+
/* per-page protection flags */
#define VPROT_READ 0x01
#define VPROT_WRITE 0x02
@@ -4273,34 +4275,96 @@ static NTSTATUS get_working_set_ex( HANDLE process, LPCVOID addr,
return STATUS_SUCCESS;
}
+static NTSTATUS read_nt_symlink( UNICODE_STRING *name, WCHAR *target, DWORD size )
+{
+ NTSTATUS status;
+ OBJECT_ATTRIBUTES attr;
+ HANDLE handle;
+
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = 0;
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
+ attr.ObjectName = name;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+
+ if (!(status = NtOpenSymbolicLinkObject( &handle, SYMBOLIC_LINK_QUERY, &attr )))
+ {
+ UNICODE_STRING targetW;
+ targetW.Buffer = target;
+ targetW.MaximumLength = (size - 1) * sizeof(WCHAR);
+ status = NtQuerySymbolicLinkObject( handle, &targetW, NULL );
+ if (!status) target[targetW.Length / sizeof(WCHAR)] = 0;
+ NtClose( handle );
+ }
+ return status;
+}
+
+static NTSTATUS follow_device_symlink( WCHAR *buffer, SIZE_T max_path_len, WCHAR *name, SIZE_T *current_path_len )
+{
+ WCHAR *p = buffer;
+ NTSTATUS status = STATUS_SUCCESS;
+ SIZE_T devname_len = 6; // e.g. \??\C:
+ UNICODE_STRING devname;
+ DWORD target_len;
+
+ if (*current_path_len >= devname_len * sizeof(WCHAR) && name[devname_len - 1] == ':') {
+ devname.Buffer = name;
+ devname.Length = devname_len * sizeof(WCHAR);
+ if (!(status = read_nt_symlink( &devname, p, (max_path_len - *current_path_len) / sizeof(WCHAR) + devname_len + 1 )))
+ {
+ target_len = lstrlenW(p);
+ *current_path_len -= devname_len * sizeof(WCHAR); // skip the device name
+ p += target_len;
+
+ memcpy( p, name + devname_len, *current_path_len );
+ *current_path_len += target_len * sizeof(WCHAR);
+ }
+ }
+ else memcpy( p, name, *current_path_len );
+
+ return status;
+}
+
static NTSTATUS get_memory_section_name( HANDLE process, LPCVOID addr,
MEMORY_SECTION_NAME *info, SIZE_T len, SIZE_T *ret_len )
{
+ SIZE_T current_path_len, max_path_len;
+ WCHAR *name;
NTSTATUS status;
if (!info) return STATUS_ACCESS_VIOLATION;
+ max_path_len = len - sizeof(*info) - sizeof(WCHAR); // dont count null char
+ if (!(name = malloc( max_path_len ))) return STATUS_NO_MEMORY;
SERVER_START_REQ( get_mapping_filename )
{
req->process = wine_server_obj_handle( process );
req->addr = wine_server_client_ptr( addr );
if (len > sizeof(*info) + sizeof(WCHAR))
- wine_server_set_reply( req, info + 1, len - sizeof(*info) - sizeof(WCHAR) );
+ wine_server_set_reply( req, name, max_path_len );
status = wine_server_call( req );
if (!status || status == STATUS_BUFFER_OVERFLOW)
{
- if (ret_len) *ret_len = sizeof(*info) + reply->len + sizeof(WCHAR);
- if (len < sizeof(*info)) status = STATUS_INFO_LENGTH_MISMATCH;
+ current_path_len = reply->len;
+ if (len < sizeof(*info))
+ {
+ status = STATUS_INFO_LENGTH_MISMATCH;
+ }
+ else if (!status) status = follow_device_symlink( (WCHAR *)(info + 1), max_path_len, name, ¤t_path_len);
+
+ if (ret_len) *ret_len = sizeof(*info) + current_path_len + sizeof(WCHAR);
if (!status)
{
info->SectionFileName.Buffer = (WCHAR *)(info + 1);
- info->SectionFileName.Length = reply->len;
- info->SectionFileName.MaximumLength = reply->len + sizeof(WCHAR);
- info->SectionFileName.Buffer[reply->len / sizeof(WCHAR)] = 0;
+ info->SectionFileName.Length = current_path_len;
+ info->SectionFileName.MaximumLength = current_path_len + sizeof(WCHAR);
+ info->SectionFileName.Buffer[current_path_len / sizeof(WCHAR)] = 0;
}
}
}
SERVER_END_REQ;
+ free(name);
return status;
}
diff --git a/dlls/psapi/tests/psapi_main.c b/dlls/psapi/tests/psapi_main.c
index c4a740310a4..d6fb8e69384 100644
--- a/dlls/psapi/tests/psapi_main.c
+++ b/dlls/psapi/tests/psapi_main.c
@@ -471,7 +471,6 @@ static void test_GetMappedFileName(void)
ret = GetMappedFileNameA(GetCurrentProcess(), base, map_name, sizeof(map_name));
ok(ret, "GetMappedFileName error %d\n", GetLastError());
ok(ret > strlen(device_name), "map_name should be longer than device_name\n");
- todo_wine
ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
SetLastError(0xdeadbeef);
@@ -482,7 +481,6 @@ static void test_GetMappedFileName(void)
{
ok(memcmp(map_nameW, nt_map_name, lstrlenW(map_nameW)) == 0, "map name does not start with a device name: %s\n", map_name);
WideCharToMultiByte(CP_ACP, 0, map_nameW, -1, map_name, MAX_PATH, NULL, NULL);
- todo_wine
ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
}
@@ -490,7 +488,6 @@ static void test_GetMappedFileName(void)
ret = GetMappedFileNameA(GetCurrentProcess(), base + 0x2000, map_name, sizeof(map_name));
ok(ret, "GetMappedFileName error %d\n", GetLastError());
ok(ret > strlen(device_name), "map_name should be longer than device_name\n");
- todo_wine
ok(memcmp(map_name, device_name, strlen(device_name)) == 0, "map name does not start with a device name: %s\n", map_name);
SetLastError(0xdeadbeef);
@@ -566,7 +563,7 @@ static void test_GetProcessImageFileName(void)
{
/* Windows returns 2*strlen-1 */
ok(ret >= strlen(szImgPath), "szImgPath=\"%s\" ret=%d\n", szImgPath, ret);
- todo_wine ok(!strcmp(szImgPath, szMapPath), "szImgPath=\"%s\" szMapPath=\"%s\"\n", szImgPath, szMapPath);
+ ok(!strcmp(szImgPath, szMapPath), "szImgPath=\"%s\" szMapPath=\"%s\"\n", szImgPath, szMapPath);
}
SetLastError(0xdeadbeef);
--
2.31.1
More information about the wine-devel
mailing list