ntdll-Junction_Points: Remove support for making reparse points real symlinks.

This is not a priority upstream, and is unlikely to happen.
This commit is contained in:
Elizabeth Figura
2025-11-11 16:58:24 -06:00
parent 635849c3ed
commit 3950dc0efe
2 changed files with 0 additions and 219 deletions

View File

@@ -1,125 +0,0 @@
From 6b96b85136b078f9779c07e5c0daecd7b1006e09 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
file/directory.
Allows lookup_unix_name 'shortcut' to succeed, as well as allowing
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 | 90 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 90 insertions(+)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index f83a30d36ed..234a0fa7397 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3714,6 +3714,86 @@ static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFF
}
+/* add a symlink to the unix target at the last point of the reparse point metadata */
+NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, const char *link_path,
+ REPARSE_DATA_BUFFER *buffer )
+{
+ UNICODE_STRING nt_target, nt_full_target;
+ char *unix_path = NULL, *d;
+ char target_path[PATH_MAX];
+ int nt_target_len;
+ char *unix_target;
+ int is_relative;
+ NTSTATUS status;
+ WCHAR *nt_path;
+
+ if ((status = get_reparse_target( &nt_target, buffer, &is_relative )) != STATUS_REPARSE)
+ return status;
+ /* if the target path is relative then turn the source path into an NT path */
+ if (is_relative)
+ {
+ /* resolve the NT path of the source */
+ unix_path = malloc( strlen(unix_src) + 2 );
+ if (!unix_path) return STATUS_NO_MEMORY;
+ strcpy( unix_path, unix_src );
+ d = dirname( unix_path );
+ if (d != unix_path) strcpy( unix_path, d );
+ strcat( unix_path, "/");
+ status = unix_to_nt_file_name( unix_path, &nt_path, FILE_OPEN );
+ free( unix_path );
+ if (status != STATUS_SUCCESS)
+ return status;
+ /* re-resolve the unix path for the source */
+ status = ntdll_get_unix_file_name( nt_path, &unix_path, FILE_OPEN_IF );
+ }
+ else
+ {
+ nt_path = malloc( sizeof(WCHAR) );
+ if (!nt_path) return STATUS_NO_MEMORY;
+ nt_path[0] = 0;
+ }
+ /* append the target path (if absolute, appends to empty string) */
+ nt_target_len = nt_target.Length + sizeof(WCHAR);
+ nt_full_target.MaximumLength = nt_target_len + wcslen(nt_path) * sizeof(WCHAR);
+ nt_full_target.Buffer = malloc( nt_full_target.MaximumLength + 2 );
+ if (!nt_full_target.Buffer)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ wcscpy( nt_full_target.Buffer, nt_path );
+ free( nt_path );
+ memcpy( &nt_full_target.Buffer[wcslen(nt_full_target.Buffer)], nt_target.Buffer, nt_target_len );
+ /* find the unix path for the target */
+ status = ntdll_get_unix_file_name( nt_full_target.Buffer, &unix_target, FILE_OPEN_IF );
+ /* create the symlink to the target at the last metadata location */
+ if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
+ {
+ int relative_offset;
+
+ target_path[0] = 0;
+ relative_offset = unix_path ? strlen( unix_path ) : 0;
+ if (unix_path && strncmp( unix_path, unix_target, relative_offset ) != 0)
+ {
+ relative_offset = 0;
+ is_relative = FALSE;
+ }
+ for (;is_relative && depth > 0; depth--)
+ strcat( target_path, "../" );
+ strcat( target_path, &unix_target[relative_offset] );
+ TRACE( "adding reparse point target: %s\n", debugstr_a(target_path) );
+ symlinkat( target_path, dirfd, link_path );
+ }
+ free( unix_target );
+ status = STATUS_SUCCESS;
+
+cleanup:
+ free( unix_path );
+ free( nt_full_target.Buffer );
+ return status;
+}
+
+
/*
* 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.
@@ -3847,6 +3927,16 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
link_dir_fd = fd;
}
+ /* create the very last link directory */
+ if (IsReparseTagNameSurrogate( buffer->ReparseTag ))
+ {
+ strcpy( link_path, target_path );
+ strcpy( link_dir, link_path );
+ link_dir[strlen(link_dir)-1] = 0;
+ if (mkdir_p( link_dir_fd, link_dir, 0777 ) == 0)
+ create_reparse_target( link_dir_fd, unix_src, depth + 2, link_path, buffer );
+ }
+
/* Atomically move the initial link into position */
if (!renameat2( -1, tmplink, -1, unix_src, RENAME_EXCHANGE ))
{
--
2.47.2

View File

@@ -1,94 +0,0 @@
From 1f891d01326bcb1b7bf6bcaa35f6f10d311fe660 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Sat, 6 Feb 2021 16:16:17 -0700
Subject: [PATCH] ntdll: Add an intermediary prefix symlink in reparse point
metadata.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/unix/file.c | 39 +++++++++++++++++++++++++++++++++++++++
1 file changed, 39 insertions(+)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 63a27b89e20..a15c5e19dcb 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3577,6 +3577,18 @@ static NTSTATUS get_reparse_target( UNICODE_STRING *nt_target, REPARSE_DATA_BUFF
}
+int find_prefix_end( const char *path, int *offset )
+{
+ static int config_dir_len = 0;
+
+ if (!config_dir_len) config_dir_len = strlen(config_dir);
+ if (path[config_dir_len] != '/') return FALSE;
+ if (strncmp( config_dir, path, config_dir_len ) != 0) return FALSE;
+ *offset = config_dir_len;
+ return TRUE;
+}
+
+
/* add a symlink to the unix target at the last point of the reparse point metadata */
NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, const char *link_path,
REPARSE_DATA_BUFFER *buffer )
@@ -3671,6 +3683,8 @@ NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, cons
/* create the symlink to the target at the last metadata location */
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
{
+ const char prefix_string[] = "${WINEPREFIX}";
+ int append_prefix = FALSE;
int relative_offset;
target_path[0] = 0;
@@ -3680,8 +3694,21 @@ NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, cons
relative_offset = 0;
is_relative = FALSE;
}
+ else if (find_prefix_end( unix_target, &relative_offset ))
+ {
+ char prefix_link[PATH_MAX];
+
+ append_prefix = TRUE;
+ is_relative = FALSE;
+ strcpy( prefix_link, link_path );
+ prefix_link[strlen(prefix_link)-1] = 0;
+ strcat( prefix_link, prefix_string );
+ symlinkat( config_dir, dirfd, prefix_link );
+ }
for (;is_relative && depth > 0; depth--)
strcat( target_path, "../" );
+ if (append_prefix)
+ strcat( target_path, prefix_string );
strcat( target_path, &unix_target[relative_offset] );
TRACE( "adding reparse point target: %s\n", debugstr_a(target_path) );
symlinkat( target_path, dirfd, link_path );
@@ -3887,6 +3914,7 @@ cleanup:
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;
+ const char prefix_string[] = "${WINEPREFIX}";
int link_path_len, buffer_len, encoded_len;
REPARSE_DATA_BUFFER header;
ULONG out_size = *size;
@@ -3985,6 +4013,17 @@ NTSTATUS get_reparse_point_unix(const char *unix_name, REPARSE_DATA_BUFFER *buff
link_dir_fd = fd;
}
+ /* if the prefix location has moved then update the Unix prefix passthrough link */
+ strcpy( link_dir, link_path );
+ link_dir[strlen(link_dir)-1] = 0;
+ link_path_len = readlinkat( link_dir_fd, prefix_string, link_path, sizeof(link_path) );
+ if (link_path_len > 0) link_path[link_path_len] = 0;
+ if (link_path_len > 0 && strcmp( config_dir, link_path) != 0)
+ {
+ unlinkat( link_dir_fd, prefix_string, 0 );
+ symlinkat( config_dir, link_dir_fd, prefix_string );
+ }
+
/* Decode the reparse buffer from the base64-encoded symlink data */
*size = decode_base64url( encoded, strlen(encoded), (char*)buffer );
status = STATUS_SUCCESS;
--
2.43.0