You've already forked wine-staging
mirror of
https://gitlab.winehq.org/wine/wine-staging.git
synced 2025-12-15 08:03:15 -08:00
Rebase against fe1175af410d04f806dda770502d0476a8ccbef6.
This commit is contained in:
@@ -1,27 +0,0 @@
|
||||
From 0423cf43baf2938b4b1e7d705c20af11fb13f82c Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
|
||||
Date: Sat, 12 Dec 2020 17:35:21 -0700
|
||||
Subject: kernelbase: Add support for deleting reparse points with
|
||||
RemoveDirectory.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/kernelbase/file.c | 2 +-
|
||||
2 files changed, 28 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
|
||||
index bfb291fa925..6214f549406 100644
|
||||
--- a/dlls/kernelbase/file.c
|
||||
+++ b/dlls/kernelbase/file.c
|
||||
@@ -3493,7 +3493,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH RemoveDirectoryW( LPCWSTR path )
|
||||
InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||
status = NtOpenFile( &handle, DELETE | SYNCHRONIZE, &attr, &io,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
- FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
|
||||
+ FILE_OPEN_REPARSE_POINT | FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT );
|
||||
RtlFreeUnicodeString( &nt_name );
|
||||
|
||||
if (!status)
|
||||
--
|
||||
2.17.1
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
From afd4ad0f6725f49daaa0fe2351c98faa6a57519a 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] kernelbase: Add support for deleting reparse points with
|
||||
DeleteFile.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/kernelbase/file.c | 3 ++-
|
||||
2 files changed, 11 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
|
||||
index 36b43d345d6..b7d16410d75 100644
|
||||
--- a/dlls/kernelbase/file.c
|
||||
+++ b/dlls/kernelbase/file.c
|
||||
@@ -1002,7 +1002,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH DeleteFileW( LPCWSTR path )
|
||||
InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
|
||||
status = NtCreateFile(&hFile, SYNCHRONIZE | DELETE, &attr, &io, NULL, 0,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
- FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE, NULL, 0);
|
||||
+ FILE_OPEN, FILE_DELETE_ON_CLOSE | FILE_NON_DIRECTORY_FILE | FILE_OPEN_REPARSE_POINT,
|
||||
+ NULL, 0);
|
||||
if (status == STATUS_SUCCESS) status = NtClose(hFile);
|
||||
|
||||
RtlFreeUnicodeString( &nameW );
|
||||
--
|
||||
2.47.2
|
||||
|
||||
@@ -1,349 +0,0 @@
|
||||
From a9773394980e77b017dcb797766ec422b384a5cc Mon Sep 17 00:00:00 2001
|
||||
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
|
||||
Date: Sat, 3 Sep 2022 11:23:31 -0600
|
||||
Subject: [PATCH] ntdll: Follow reparse points during path resolution.
|
||||
|
||||
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
|
||||
---
|
||||
dlls/ntdll/unix/file.c | 196 +++++++++++++++++++++++++++++++++++-----
|
||||
2 files changed, 184 insertions(+), 23 deletions(-)
|
||||
|
||||
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
|
||||
index f3274478ae2..860e563f69d 100644
|
||||
--- a/dlls/ntdll/unix/file.c
|
||||
+++ b/dlls/ntdll/unix/file.c
|
||||
@@ -3741,6 +3741,35 @@ done:
|
||||
}
|
||||
|
||||
|
||||
+static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFFER *buffer,
|
||||
+ int *is_relative )
|
||||
+{
|
||||
+ int target_len, offset;
|
||||
+ WCHAR *target;
|
||||
+
|
||||
+ switch( buffer->ReparseTag )
|
||||
+ {
|
||||
+ case IO_REPARSE_TAG_MOUNT_POINT:
|
||||
+ offset = buffer->MountPointReparseBuffer.SubstituteNameOffset/sizeof(WCHAR);
|
||||
+ target = &buffer->MountPointReparseBuffer.PathBuffer[offset];
|
||||
+ target_len = buffer->MountPointReparseBuffer.SubstituteNameLength;
|
||||
+ *is_relative = FALSE;
|
||||
+ break;
|
||||
+ case IO_REPARSE_TAG_SYMLINK:
|
||||
+ offset = buffer->SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof(WCHAR);
|
||||
+ target = &buffer->SymbolicLinkReparseBuffer.PathBuffer[offset];
|
||||
+ target_len = buffer->SymbolicLinkReparseBuffer.SubstituteNameLength;
|
||||
+ *is_relative = (buffer->SymbolicLinkReparseBuffer.Flags & SYMLINK_FLAG_RELATIVE) == SYMLINK_FLAG_RELATIVE;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return STATUS_IO_REPARSE_TAG_NOT_HANDLED;
|
||||
+ }
|
||||
+ nt_target->Buffer = target;
|
||||
+ nt_target->Length = target_len;
|
||||
+ return STATUS_REPARSE;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/*
|
||||
* 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.
|
||||
@@ -3917,16 +3946,14 @@ cleanup:
|
||||
|
||||
|
||||
/*
|
||||
- * Retrieve the unix name corresponding to a file handle and use that to find the destination of the
|
||||
- * symlink corresponding to that file handle.
|
||||
+ * Obtain the reparse point buffer from the unix filename for the reparse point.
|
||||
*/
|
||||
-NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *size)
|
||||
+NTSTATUS get_reparse_point_unix(const char *unix_name, REPARSE_DATA_BUFFER *buffer, ULONG *size)
|
||||
{
|
||||
char link_dir[PATH_MAX], link_path[PATH_MAX], *d;
|
||||
int link_path_len, buffer_len, encoded_len;
|
||||
REPARSE_DATA_BUFFER header;
|
||||
ULONG out_size = *size;
|
||||
- char *unix_name = NULL;
|
||||
char *encoded = NULL;
|
||||
int link_dir_fd = -1;
|
||||
NTSTATUS status;
|
||||
@@ -3934,9 +3961,6 @@ NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *si
|
||||
int depth;
|
||||
char *p;
|
||||
|
||||
- if ((status = server_get_unix_name( handle, &unix_name )))
|
||||
- goto cleanup;
|
||||
-
|
||||
ret = readlink( unix_name, link_path, sizeof(link_path) );
|
||||
if (ret < 0)
|
||||
{
|
||||
@@ -4036,12 +4060,76 @@ NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *si
|
||||
|
||||
cleanup:
|
||||
if (link_dir_fd != -1) close( link_dir_fd );
|
||||
- free( unix_name );
|
||||
free( encoded );
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
+/*
|
||||
+ * Retrieve the unix name corresponding to a file handle and use that to find the destination of the
|
||||
+ * symlink corresponding to that file handle.
|
||||
+ */
|
||||
+NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *size)
|
||||
+{
|
||||
+ char *unix_name = NULL;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ if ((status = server_get_unix_name( handle, &unix_name )))
|
||||
+ return status;
|
||||
+ status = get_reparse_point_unix( unix_name, buffer, size );
|
||||
+ free( unix_name );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/* find the NT target of a reparse point */
|
||||
+static NTSTATUS find_reparse_target( const char *unix_name, const WCHAR *parent, int parent_len,
|
||||
+ WCHAR **new_name, int *new_name_len)
|
||||
+{
|
||||
+ REPARSE_DATA_BUFFER *buffer = NULL;
|
||||
+ UNICODE_STRING nt_target;
|
||||
+ ULONG buffer_len = 0;
|
||||
+ int is_relative;
|
||||
+ NTSTATUS status;
|
||||
+
|
||||
+ status = get_reparse_point_unix( unix_name, NULL, &buffer_len );
|
||||
+ if (status != STATUS_BUFFER_TOO_SMALL)
|
||||
+ return status;
|
||||
+
|
||||
+ buffer = malloc( buffer_len );
|
||||
+ if (!buffer)
|
||||
+ return STATUS_NO_MEMORY;
|
||||
+ if ((status = get_reparse_point_unix( unix_name, buffer, &buffer_len )) != STATUS_SUCCESS)
|
||||
+ {
|
||||
+ free( buffer );
|
||||
+ return status;
|
||||
+ }
|
||||
+ if ((status = get_reparse_target( &nt_target, buffer, &is_relative )) == STATUS_REPARSE)
|
||||
+ {
|
||||
+ WCHAR *p;
|
||||
+
|
||||
+ p = *new_name = malloc( nt_target.Length + parent_len*sizeof(WCHAR) );
|
||||
+ if (!p)
|
||||
+ {
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ goto done;
|
||||
+ }
|
||||
+ if (is_relative)
|
||||
+ {
|
||||
+ memcpy( p, parent, parent_len*sizeof(WCHAR) );
|
||||
+ p += parent_len;
|
||||
+ }
|
||||
+ memcpy( p, nt_target.Buffer, nt_target.Length );
|
||||
+ p += nt_target.Length/sizeof(WCHAR);
|
||||
+ *new_name_len = p - *new_name;
|
||||
+ }
|
||||
+
|
||||
+done:
|
||||
+ free( buffer );
|
||||
+ return status;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/*
|
||||
* Retrieve the unix name corresponding to a file handle, remove that symlink, and then recreate
|
||||
* a directory at the location of the old filename.
|
||||
@@ -4135,15 +4223,24 @@ cleanup:
|
||||
}
|
||||
|
||||
|
||||
+static NTSTATUS IoReplaceFileObjectName( FILE_OBJECT *fileobj, PWSTR name, USHORT name_len )
|
||||
+{
|
||||
+ fileobj->FileName.Buffer = name;
|
||||
+ fileobj->FileName.Length = name_len;
|
||||
+ return STATUS_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+
|
||||
/******************************************************************************
|
||||
* lookup_unix_name
|
||||
*
|
||||
* Helper for nt_to_unix_file_name
|
||||
*/
|
||||
-static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len, char **buffer, int unix_len,
|
||||
+static NTSTATUS lookup_unix_name( FILE_OBJECT *fileobj, int root_fd, const WCHAR *name, int name_len, char **buffer, int unix_len,
|
||||
int pos, UINT disposition, BOOL is_unix )
|
||||
{
|
||||
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, '/', 0 };
|
||||
+ const WCHAR *fullname = fileobj->FileName.Buffer;
|
||||
NTSTATUS status;
|
||||
int ret;
|
||||
struct stat st;
|
||||
@@ -4200,6 +4297,8 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
|
||||
while (name_len)
|
||||
{
|
||||
const WCHAR *end, *next;
|
||||
+ WCHAR *target = NULL;
|
||||
+ int target_len = 0;
|
||||
|
||||
end = name;
|
||||
while (end < name + name_len && *end != '\\') end++;
|
||||
@@ -4219,8 +4318,31 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
|
||||
|
||||
status = find_file_in_dir( root_fd, unix_name, pos, name, end - name, is_unix );
|
||||
|
||||
+ /* follow reparse point and restart from there (if applicable) */
|
||||
+ if (name_len && find_reparse_target( unix_name, fullname, name - fullname, &target, &target_len ) == STATUS_REPARSE)
|
||||
+ {
|
||||
+ int new_name_len = target_len + name_len + 1;
|
||||
+ WCHAR *p, *new_name;
|
||||
+
|
||||
+ if (!(p = new_name = malloc( new_name_len*sizeof(WCHAR) )))
|
||||
+ {
|
||||
+ free( target );
|
||||
+ status = STATUS_NO_MEMORY;
|
||||
+ break;
|
||||
+ }
|
||||
+ memcpy( p, target, target_len*sizeof(WCHAR) );
|
||||
+ p += target_len;
|
||||
+ (p++)[0] = '\\';
|
||||
+ memcpy( p, next, name_len*sizeof(WCHAR) );
|
||||
+ TRACE( "Follow reparse point %s => %s\n", debugstr_wn(fullname, end-fullname),
|
||||
+ debugstr_wn(new_name, new_name_len) );
|
||||
+ free( target );
|
||||
+ if (IoReplaceFileObjectName( fileobj, new_name, new_name_len*sizeof(WCHAR) ))
|
||||
+ free( new_name );
|
||||
+ return STATUS_REPARSE;
|
||||
+ }
|
||||
/* if this is the last element, not finding it is not necessarily fatal */
|
||||
- if (!name_len)
|
||||
+ else if (!name_len)
|
||||
{
|
||||
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
|
||||
{
|
||||
@@ -4259,12 +4381,12 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
|
||||
/******************************************************************************
|
||||
* nt_to_unix_file_name_no_root
|
||||
*/
|
||||
-static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char **unix_name_ret,
|
||||
+static NTSTATUS nt_to_unix_file_name_no_root( FILE_OBJECT *fileobj, char **unix_name_ret,
|
||||
UINT disposition )
|
||||
{
|
||||
static const WCHAR unixW[] = {'u','n','i','x'};
|
||||
static const WCHAR invalid_charsW[] = { INVALID_NT_CHARS, 0 };
|
||||
-
|
||||
+ const UNICODE_STRING *nameW = &fileobj->FileName;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
const WCHAR *name;
|
||||
struct stat st;
|
||||
@@ -4354,7 +4476,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
|
||||
name += prefix_len;
|
||||
name_len -= prefix_len;
|
||||
|
||||
- status = lookup_unix_name( AT_FDCWD, name, name_len, &unix_name, unix_len, pos, disposition, is_unix );
|
||||
+ status = lookup_unix_name( fileobj, AT_FDCWD, name, name_len, &unix_name, unix_len, pos, disposition, is_unix );
|
||||
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
||||
{
|
||||
TRACE( "%s -> %s\n", debugstr_us(nameW), debugstr_a(unix_name) );
|
||||
@@ -4362,7 +4484,8 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
|
||||
}
|
||||
else
|
||||
{
|
||||
- TRACE( "%s not found in %s\n", debugstr_w(name), debugstr_an(unix_name, pos) );
|
||||
+ if (status != STATUS_REPARSE)
|
||||
+ TRACE( "%s not found in %s\n", debugstr_w(name), debugstr_an(unix_name, pos) );
|
||||
free( unix_name );
|
||||
}
|
||||
return status;
|
||||
@@ -4380,18 +4503,30 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
|
||||
*/
|
||||
static NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, UINT disposition )
|
||||
{
|
||||
+ HANDLE rootdir = attr->RootDirectory;
|
||||
enum server_fd_type type;
|
||||
- int root_fd, needs_close;
|
||||
+ int old_cwd, root_fd, needs_close;
|
||||
+ int reparse_count = 0;
|
||||
+ FILE_OBJECT fileobj;
|
||||
const WCHAR *name;
|
||||
char *unix_name;
|
||||
int name_len, unix_len;
|
||||
NTSTATUS status;
|
||||
|
||||
- if (!attr->RootDirectory) /* without root dir fall back to normal lookup */
|
||||
- return nt_to_unix_file_name_no_root( attr->ObjectName, name_ret, disposition );
|
||||
+ fileobj.FileName = *attr->ObjectName;
|
||||
+reparse:
|
||||
+ if (reparse_count++ == 31)
|
||||
+ return STATUS_REPARSE_POINT_NOT_RESOLVED;
|
||||
+ if (!rootdir) /* without root dir fall back to normal lookup */
|
||||
+ {
|
||||
+ status = nt_to_unix_file_name_no_root( &fileobj, name_ret, disposition );
|
||||
+ if (status == STATUS_REPARSE) goto reparse;
|
||||
+ if (fileobj.FileName.Buffer != attr->ObjectName->Buffer) free( fileobj.FileName.Buffer);
|
||||
+ return status;
|
||||
+ }
|
||||
|
||||
- name = attr->ObjectName->Buffer;
|
||||
- name_len = attr->ObjectName->Length / sizeof(WCHAR);
|
||||
+ name = fileobj.FileName.Buffer;
|
||||
+ name_len = fileobj.FileName.Length / sizeof(WCHAR);
|
||||
|
||||
if (name_len && name[0] == '\\') return STATUS_INVALID_PARAMETER;
|
||||
|
||||
@@ -4399,7 +4534,7 @@ static NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name
|
||||
if (!(unix_name = malloc( unix_len ))) return STATUS_NO_MEMORY;
|
||||
unix_name[0] = '.';
|
||||
|
||||
- if (!(status = server_get_unix_fd( attr->RootDirectory, 0, &root_fd, &needs_close, &type, NULL )))
|
||||
+ if (!(status = server_get_unix_fd( rootdir, 0, &root_fd, &needs_close, &type, NULL )))
|
||||
{
|
||||
if (type != FD_TYPE_DIR)
|
||||
{
|
||||
@@ -4408,7 +4543,16 @@ static NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name
|
||||
}
|
||||
else
|
||||
{
|
||||
- status = lookup_unix_name( root_fd, name, name_len, &unix_name, unix_len, 1, disposition, FALSE );
|
||||
+ mutex_lock( &dir_mutex );
|
||||
+ if ((old_cwd = open( ".", O_RDONLY )) != -1 && fchdir( root_fd ) != -1)
|
||||
+ {
|
||||
+ status = lookup_unix_name( &fileobj, root_fd, name, name_len, &unix_name, unix_len, 1,
|
||||
+ disposition, FALSE );
|
||||
+ if (fchdir( old_cwd ) == -1) chdir( "/" );
|
||||
+ }
|
||||
+ else status = errno_to_status( errno );
|
||||
+ mutex_unlock( &dir_mutex );
|
||||
+ if (old_cwd != -1) close( old_cwd );
|
||||
if (needs_close) close( root_fd );
|
||||
}
|
||||
}
|
||||
@@ -4416,14 +4560,22 @@ static NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name
|
||||
|
||||
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
|
||||
{
|
||||
- TRACE( "%s -> %s\n", debugstr_us(attr->ObjectName), debugstr_a(unix_name) );
|
||||
+ TRACE( "%s -> %s\n", debugstr_us(&fileobj.FileName), debugstr_a(unix_name) );
|
||||
*name_ret = unix_name;
|
||||
}
|
||||
+ else if (status == STATUS_REPARSE)
|
||||
+ {
|
||||
+ if (fileobj.FileName.Buffer[0] == '\\') rootdir = 0;
|
||||
+ free( unix_name );
|
||||
+ goto reparse;
|
||||
+ }
|
||||
else
|
||||
{
|
||||
TRACE( "%s not found in %s\n", debugstr_w(name), unix_name );
|
||||
free( unix_name );
|
||||
}
|
||||
+
|
||||
+ if (fileobj.FileName.Buffer != attr->ObjectName->Buffer) free( fileobj.FileName.Buffer);
|
||||
return status;
|
||||
}
|
||||
|
||||
--
|
||||
2.47.2
|
||||
|
||||
@@ -1 +1 @@
|
||||
76e7e90c3679766ac327b138e3269fb61ead6e4a
|
||||
fe1175af410d04f806dda770502d0476a8ccbef6
|
||||
|
||||
Reference in New Issue
Block a user