mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2024-11-21 16:46:54 -08:00
227 lines
8.8 KiB
Diff
227 lines
8.8 KiB
Diff
From 7bbc11e52188ec7babe97270f03e2e5015ac22ff Mon Sep 17 00:00:00 2001
|
|
From: =?UTF-8?q?Michael=20M=C3=BCller?= <michael@fds-team.de>
|
|
Date: Tue, 30 Nov 2021 16:32:34 +0300
|
|
Subject: [PATCH] ntdll: Implement opening files through nt device paths.
|
|
|
|
---
|
|
dlls/ntdll/tests/file.c | 25 +++++++-
|
|
dlls/ntdll/unix/file.c | 134 +++++++++++++++++++++++++++++++++++++++-
|
|
2 files changed, 156 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
|
|
index 640fd2d81db..e8e8652334e 100644
|
|
--- a/dlls/ntdll/tests/file.c
|
|
+++ b/dlls/ntdll/tests/file.c
|
|
@@ -137,18 +137,22 @@ static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
|
|
|
|
static void create_file_test(void)
|
|
{
|
|
+ static const WCHAR notepadW[] = {'n','o','t','e','p','a','d','.','e','x','e',0};
|
|
static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t',
|
|
'\\','f','a','i','l','i','n','g',0};
|
|
+ static const WCHAR systemrootExplorerW[] = {'\\','S','y','s','t','e','m','R','o','o','t',
|
|
+ '\\','e','x','p','l','o','r','e','r','.','e','x','e',0};
|
|
static const WCHAR questionmarkInvalidNameW[] = {'a','f','i','l','e','?',0};
|
|
static const WCHAR pipeInvalidNameW[] = {'a','|','b',0};
|
|
static const WCHAR pathInvalidNtW[] = {'\\','\\','?','\\',0};
|
|
static const WCHAR pathInvalidNt2W[] = {'\\','?','?','\\',0};
|
|
static const WCHAR pathInvalidDosW[] = {'\\','D','o','s','D','e','v','i','c','e','s','\\',0};
|
|
static const char testdata[] = "Hello World";
|
|
+ static const WCHAR sepW[] = {'\\',0};
|
|
FILE_NETWORK_OPEN_INFORMATION info;
|
|
NTSTATUS status;
|
|
HANDLE dir, file;
|
|
- WCHAR path[MAX_PATH];
|
|
+ WCHAR path[MAX_PATH], temp[MAX_PATH];
|
|
OBJECT_ATTRIBUTES attr;
|
|
IO_STATUS_BLOCK io;
|
|
UNICODE_STRING nameW;
|
|
@@ -328,6 +332,25 @@ static void create_file_test(void)
|
|
status = pNtQueryFullAttributesFile( &attr, &info );
|
|
ok( status == STATUS_OBJECT_NAME_INVALID,
|
|
"query %s failed %lx\n", wine_dbgstr_w(nameW.Buffer), status );
|
|
+
|
|
+ GetWindowsDirectoryW( path, MAX_PATH );
|
|
+ path[2] = 0;
|
|
+ ok( QueryDosDeviceW( path, temp, MAX_PATH ),
|
|
+ "QueryDosDeviceW failed with error %u\n", GetLastError() );
|
|
+ lstrcatW( temp, sepW );
|
|
+ lstrcatW( temp, path+3 );
|
|
+ lstrcatW( temp, sepW );
|
|
+ lstrcatW( temp, notepadW );
|
|
+
|
|
+ pRtlInitUnicodeString( &nameW, temp );
|
|
+ status = pNtQueryFullAttributesFile( &attr, &info );
|
|
+ ok( status == STATUS_SUCCESS,
|
|
+ "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
|
|
+
|
|
+ pRtlInitUnicodeString( &nameW, systemrootExplorerW );
|
|
+ status = pNtQueryFullAttributesFile( &attr, &info );
|
|
+ ok( status == STATUS_SUCCESS,
|
|
+ "query %s failed %x\n", wine_dbgstr_w(nameW.Buffer), status );
|
|
}
|
|
|
|
static void open_file_test(void)
|
|
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
|
index 67e0c6f0b40..25a03ef84f1 100644
|
|
--- a/dlls/ntdll/unix/file.c
|
|
+++ b/dlls/ntdll/unix/file.c
|
|
@@ -4494,7 +4494,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( FILE_OBJECT *fileobj, char **unix_
|
|
|
|
|
|
/******************************************************************************
|
|
- * nt_to_unix_file_name
|
|
+ * nt_to_unix_file_name_internal
|
|
*
|
|
* Convert a file name from NT namespace to Unix namespace.
|
|
*
|
|
@@ -4502,7 +4502,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( FILE_OBJECT *fileobj, char **unix_
|
|
* element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is
|
|
* returned, but the unix name is still filled in properly.
|
|
*/
|
|
-NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition )
|
|
+NTSTATUS nt_to_unix_file_name_internal( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition )
|
|
{
|
|
HANDLE rootdir = attr->RootDirectory;
|
|
enum server_fd_type type;
|
|
@@ -4581,6 +4581,136 @@ reparse:
|
|
}
|
|
|
|
|
|
+/* read the contents of an NT symlink object */
|
|
+static NTSTATUS read_nt_symlink( HANDLE root, UNICODE_STRING *name, WCHAR *target, size_t length )
|
|
+{
|
|
+ OBJECT_ATTRIBUTES attr;
|
|
+ UNICODE_STRING targetW;
|
|
+ NTSTATUS status;
|
|
+ HANDLE handle;
|
|
+
|
|
+ attr.Length = sizeof(attr);
|
|
+ attr.RootDirectory = root;
|
|
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
|
|
+ attr.ObjectName = name;
|
|
+ attr.SecurityDescriptor = NULL;
|
|
+ attr.SecurityQualityOfService = NULL;
|
|
+
|
|
+ if (!(status = NtOpenSymbolicLinkObject( &handle, SYMBOLIC_LINK_QUERY, &attr )))
|
|
+ {
|
|
+ targetW.Buffer = target;
|
|
+ targetW.MaximumLength = (length - 1) * sizeof(WCHAR);
|
|
+ status = NtQuerySymbolicLinkObject( handle, &targetW, NULL );
|
|
+ NtClose( handle );
|
|
+ }
|
|
+
|
|
+ return status;
|
|
+}
|
|
+
|
|
+/* try to find dos device based on nt device name */
|
|
+static NTSTATUS nt_to_dos_device( WCHAR *name, size_t length, WCHAR *device_ret )
|
|
+{
|
|
+ static const WCHAR dosdevicesW[] = {'\\','D','o','s','D','e','v','i','c','e','s',0};
|
|
+ UNICODE_STRING dosdevW = { sizeof(dosdevicesW) - sizeof(WCHAR), sizeof(dosdevicesW), (WCHAR *)dosdevicesW };
|
|
+ WCHAR symlinkW[MAX_DIR_ENTRY_LEN];
|
|
+ OBJECT_ATTRIBUTES attr;
|
|
+ NTSTATUS status;
|
|
+ char data[1024];
|
|
+ HANDLE handle;
|
|
+ ULONG ctx = 0;
|
|
+
|
|
+ DIRECTORY_BASIC_INFORMATION *info = (DIRECTORY_BASIC_INFORMATION *)data;
|
|
+
|
|
+ attr.Length = sizeof(attr);
|
|
+ attr.RootDirectory = 0;
|
|
+ attr.ObjectName = &dosdevW;
|
|
+ attr.Attributes = OBJ_CASE_INSENSITIVE;
|
|
+ attr.SecurityDescriptor = NULL;
|
|
+ attr.SecurityQualityOfService = NULL;
|
|
+
|
|
+ status = NtOpenDirectoryObject( &handle, FILE_LIST_DIRECTORY, &attr );
|
|
+ if (status) return STATUS_BAD_DEVICE_TYPE;
|
|
+
|
|
+ while (!NtQueryDirectoryObject( handle, info, sizeof(data), TRUE, FALSE, &ctx, NULL ))
|
|
+ {
|
|
+ if (read_nt_symlink( handle, &info->ObjectName, symlinkW, MAX_DIR_ENTRY_LEN )) continue;
|
|
+ if (wcsnicmp( symlinkW, name, length )) continue;
|
|
+ if (info->ObjectName.Length != 2 * sizeof(WCHAR) || info->ObjectName.Buffer[1] != ':') continue;
|
|
+
|
|
+ *device_ret = info->ObjectName.Buffer[0];
|
|
+ NtClose( handle );
|
|
+ return STATUS_SUCCESS;
|
|
+ }
|
|
+
|
|
+ NtClose( handle );
|
|
+ return STATUS_BAD_DEVICE_TYPE;
|
|
+}
|
|
+
|
|
+/******************************************************************************
|
|
+ * nt_to_unix_file_name
|
|
+ *
|
|
+ * Convert a file name from NT namespace to Unix namespace.
|
|
+ *
|
|
+ * If disposition is not FILE_OPEN or FILE_OVERWRITE, the last path
|
|
+ * element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is
|
|
+ * returned, but the unix name is still filled in properly.
|
|
+ */
|
|
+NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition )
|
|
+{
|
|
+ static const WCHAR systemrootW[] = {'\\','S','y','s','t','e','m','R','o','o','t','\\',0};
|
|
+ static const WCHAR dosprefixW[] = {'\\','?','?','\\'};
|
|
+ static const WCHAR deviceW[] = {'\\','D','e','v','i','c','e','\\',0};
|
|
+ WCHAR *name, *ptr, *prefix, buffer[3] = {'c',':',0};
|
|
+ UNICODE_STRING dospathW, *nameW;
|
|
+ OBJECT_ATTRIBUTES attr_copy;
|
|
+ size_t offset, name_len;
|
|
+ NTSTATUS status;
|
|
+
|
|
+ if (attr->RootDirectory) return nt_to_unix_file_name_internal( attr, name_ret, disposition );
|
|
+
|
|
+ nameW = attr->ObjectName;
|
|
+
|
|
+ if (nameW->Length >= sizeof(deviceW) - sizeof(WCHAR)
|
|
+ && !wcsnicmp( nameW->Buffer, deviceW, ARRAY_SIZE(deviceW) - 1 ))
|
|
+ {
|
|
+ offset = sizeof(deviceW) / sizeof(WCHAR);
|
|
+ while (offset * sizeof(WCHAR) < nameW->Length && nameW->Buffer[ offset ] != '\\') offset++;
|
|
+ if ((status = nt_to_dos_device( nameW->Buffer, offset, buffer ))) return status;
|
|
+ prefix = buffer;
|
|
+ }
|
|
+ else if (nameW->Length >= sizeof(systemrootW) - sizeof(WCHAR) &&
|
|
+ !wcsnicmp( nameW->Buffer, systemrootW, ARRAY_SIZE(systemrootW) - 1 ))
|
|
+ {
|
|
+ offset = (sizeof(systemrootW) - 1) / sizeof(WCHAR);
|
|
+ prefix = user_shared_data->NtSystemRoot;
|
|
+ }
|
|
+ else
|
|
+ return nt_to_unix_file_name_internal( attr, name_ret, disposition );
|
|
+
|
|
+ name_len = sizeof(dosprefixW) + wcslen(prefix) * sizeof(WCHAR)
|
|
+ + sizeof(WCHAR) /* '\\' */ + nameW->Length - offset * sizeof(WCHAR) + sizeof(WCHAR);
|
|
+ if (!(name = malloc( name_len )))
|
|
+ return STATUS_NO_MEMORY;
|
|
+
|
|
+ ptr = name;
|
|
+ memcpy( ptr, dosprefixW, sizeof(dosprefixW) );
|
|
+ ptr += sizeof(dosprefixW) / sizeof(WCHAR);
|
|
+ wcscpy( ptr, prefix );
|
|
+ ptr += wcslen(ptr);
|
|
+ *ptr++ = '\\';
|
|
+ memcpy( ptr, nameW->Buffer + offset, nameW->Length - offset * sizeof(WCHAR) );
|
|
+ ptr[ nameW->Length / sizeof(WCHAR) - offset ] = 0;
|
|
+
|
|
+ dospathW.Buffer = name;
|
|
+ dospathW.Length = wcslen( name ) * sizeof(WCHAR);
|
|
+ attr_copy = *attr;
|
|
+ attr_copy.ObjectName = &dospathW;
|
|
+ status = nt_to_unix_file_name_internal( &attr_copy, name_ret, disposition );
|
|
+
|
|
+ free( name );
|
|
+ return status;
|
|
+}
|
|
+
|
|
/******************************************************************************
|
|
* wine_nt_to_unix_file_name
|
|
*
|
|
--
|
|
2.38.1
|
|
|