From 887a1f98e91eb0c929d0e191a9c445b645ef1f65 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Aida=20Jonikien=C4=97?= <aidas957@gmail.com>
Date: Mon, 22 Jan 2024 14:56:45 +0200
Subject: [PATCH 3/6] Updated ntdll-Junction_Points patchset

Fix a broken rebase (and add some fixes for non-Z drives)

Tested against ntdll:file tests (they seem to pass)

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53093
---
 ...ement-FILE_OPEN_REPARSE_POINT-option.patch | 136 +++++++++---------
 ...arse-point-creation-for-non-Z-drives.patch |  61 ++++++++
 2 files changed, 125 insertions(+), 72 deletions(-)
 create mode 100644 patches/ntdll-Junction_Points/0026-ntdll-Fix-reparse-point-creation-for-non-Z-drives.patch

diff --git a/patches/ntdll-Junction_Points/0005-server-Implement-FILE_OPEN_REPARSE_POINT-option.patch b/patches/ntdll-Junction_Points/0005-server-Implement-FILE_OPEN_REPARSE_POINT-option.patch
index ed5ebcd5..8636a760 100644
--- a/patches/ntdll-Junction_Points/0005-server-Implement-FILE_OPEN_REPARSE_POINT-option.patch
+++ b/patches/ntdll-Junction_Points/0005-server-Implement-FILE_OPEN_REPARSE_POINT-option.patch
@@ -1,4 +1,4 @@
-From c58ac24e08827a2b5aac12f365197d1c5174db3a Mon Sep 17 00:00:00 2001
+From 37c9cbdcbf43c3fe8c38d9a52db2023314c42ee6 Mon Sep 17 00:00:00 2001
 From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
 Date: Thu, 16 Jan 2014 21:02:11 -0700
 Subject: [PATCH] server: Implement FILE_OPEN_REPARSE_POINT option.
@@ -6,11 +6,11 @@ Subject: [PATCH] server: Implement FILE_OPEN_REPARSE_POINT option.
 Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
 ---
  dlls/kernelbase/file.c |   2 +
- server/fd.c            | 152 +++++++++++++++++++++++++++++++++++++++--
- 2 files changed, 147 insertions(+), 7 deletions(-)
+ server/fd.c            | 144 +++++++++++++++++++++++++++++++++++++++--
+ 2 files changed, 139 insertions(+), 7 deletions(-)
 
 diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
-index 7c2e132bdcb..2a8dc8df875 100644
+index 42c47707582..b05aedcd57a 100644
 --- a/dlls/kernelbase/file.c
 +++ b/dlls/kernelbase/file.c
 @@ -732,6 +732,8 @@ static UINT get_nt_file_options( DWORD attributes )
@@ -23,7 +23,7 @@ index 7c2e132bdcb..2a8dc8df875 100644
  }
  
 diff --git a/server/fd.c b/server/fd.c
-index 0b0e91ebfbb..233c9eb94ef 100644
+index 8576882aaa9..e4a70770c8e 100644
 --- a/server/fd.c
 +++ b/server/fd.c
 @@ -31,6 +31,7 @@
@@ -45,10 +45,31 @@ index 0b0e91ebfbb..233c9eb94ef 100644
  #if defined(HAVE_SYS_EPOLL_H) && defined(HAVE_EPOLL_CREATE)
  # include <sys/epoll.h>
  # define USE_EPOLL
-@@ -1152,6 +1157,59 @@ static void inode_dump( struct object *obj, int verbose )
-     fprintf( stderr, "\n" );
- }
+@@ -1069,14 +1074,86 @@ static void device_destroy( struct object *obj )
+ /****************************************************************/
+ /* inode functions */
  
++/* determine whether a reparse point is meant to be a directory or a file */
++static int is_reparse_dir( const char *path, int *is_dir )
++{
++    char link_path[PATH_MAX], *p;
++    int ret;
++
++    if ((ret = readlink( path, link_path, sizeof(link_path) )) < 0)
++        return ret;
++    /* confirm that this file is a reparse point */
++    if (strncmp( link_path, ".REPARSE_POINT/", 15) != 0)
++        return -1;
++    /* skip past the reparse point indicator and the filename */
++    p = &link_path[15];
++    if ((p = strchr( p, '/' )) == NULL)
++        return -1;
++    p++;
++    /* read the flag indicating whether this reparse point is a directory */
++    if (is_dir) *is_dir = (*p == '.');
++    return 0;
++}
++
 +/* recursively delete everything in a directory */
 +static int rmdir_recursive( int dir_fd, const char *pathname )
 +{
@@ -81,67 +102,38 @@ index 0b0e91ebfbb..233c9eb94ef 100644
 +    return unlinkat( dir_fd, pathname, AT_REMOVEDIR );
 +}
 +
-+/* determine whether a reparse point is meant to be a directory or a file */
-+static int is_reparse_dir( const char *path, int *is_dir )
-+{
-+    char link_path[PATH_MAX], *p;
-+    int ret;
-+
-+    if ((ret = readlink( path, link_path, sizeof(link_path) )) < 0)
-+        return ret;
-+    /* confirm that this file is a reparse point */
-+    if (strncmp( link_path, ".REPARSE_POINT/", 15) != 0)
-+        return -1;
-+    /* skip past the reparse point indicator and the filename */
-+    p = &link_path[15];
-+    if ((p = strchr( p, '/' )) == NULL)
-+        return -1;
-+    p++;
-+    /* read the flag indicating whether this reparse point is a directory */
-+    if (is_dir) *is_dir = (*p == '.');
-+    return 0;
-+}
-+
- static void inode_destroy( struct object *obj )
+ static void unlink_closed_fd( struct inode *inode, struct closed_fd *fd )
  {
-     struct inode *inode = (struct inode *)obj;
-@@ -1168,7 +1226,34 @@ static void inode_destroy( struct object *obj )
-         list_remove( ptr );
-         if (fd->unix_fd != -1) close( fd->unix_fd );
-         if (fd->disp_flags & FILE_DISPOSITION_DELETE)
--            unlink_closed_fd( inode, fd );
+     /* make sure it is still the same file */
+     struct stat st;
+-    if (!stat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
++    if (!lstat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
+     {
++        int is_reparse_point = (is_reparse_dir( fd->unix_name, NULL ) == 0);
+         if (S_ISDIR(st.st_mode)) rmdir( fd->unix_name );
+         else unlink( fd->unix_name );
++        /* remove reparse point metadata (if applicable) */
++        if (is_reparse_point)
 +        {
-+            /* make sure it is still the same file */
-+            struct stat st;
-+            if (!lstat( fd->unix_name, &st ) && st.st_dev == inode->device->dev && st.st_ino == inode->ino)
-+            {
-+                int is_reparse_point = (is_reparse_dir( fd->unix_name, NULL ) == 0);
-+                if (S_ISDIR(st.st_mode)) rmdir( fd->unix_name );
-+                else unlink_closed_fd( inode, fd );
-+                /* remove reparse point metadata (if applicable) */
-+                if (is_reparse_point)
-+                {
-+                    char tmp[PATH_MAX], metadata_path[PATH_MAX], *p;
++            char tmp[PATH_MAX], metadata_path[PATH_MAX], *p;
 +
-+                    strcpy( tmp, fd->unix_name );
-+                    p = dirname( tmp );
-+                    if (p != tmp ) strcpy( tmp, p );
-+                    strcpy( metadata_path, tmp );
-+                    strcat( metadata_path, "/.REPARSE_POINT/" );
-+                    strcpy( tmp, fd->unix_name );
-+                    p = basename( tmp );
-+                    if (p != tmp) strcpy( tmp, p );
-+                    strcat( metadata_path, tmp );
++            strcpy( tmp, fd->unix_name );
++            p = dirname( tmp );
++            if (p != tmp ) strcpy( tmp, p );
++            strcpy( metadata_path, tmp );
++            strcat( metadata_path, "/.REPARSE_POINT/" );
++            strcpy( tmp, fd->unix_name );
++            p = basename( tmp );
++            if (p != tmp) strcpy( tmp, p );
++            strcat( metadata_path, tmp );
 +
-+                    rmdir_recursive( AT_FDCWD, metadata_path );
-+                    rmdir( dirname( metadata_path ) );
-+                }
-+            }
++            rmdir_recursive( AT_FDCWD, metadata_path );
++            rmdir( dirname( metadata_path ) );
 +        }
-         free( fd->unix_name );
-         free( fd );
      }
-@@ -1902,6 +1987,38 @@ void get_nt_name( struct fd *fd, struct unicode_str *name )
+ }
+ 
+@@ -1870,6 +1947,38 @@ void get_nt_name( struct fd *fd, struct unicode_str *name )
      name->len = fd->nt_namelen;
  }
  
@@ -180,7 +172,7 @@ index 0b0e91ebfbb..233c9eb94ef 100644
  /* open() wrapper that returns a struct fd with no fd user set */
  struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_name,
                      int flags, mode_t *mode, unsigned int access,
-@@ -1962,6 +2079,15 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
+@@ -1930,6 +2039,15 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
      }
      else rw_mode = O_RDONLY;
  
@@ -196,7 +188,7 @@ index 0b0e91ebfbb..233c9eb94ef 100644
      if ((fd->unix_fd = open( name, rw_mode | (flags & ~O_TRUNC), *mode )) == -1)
      {
          /* if we tried to open a directory for write access, retry read-only */
-@@ -1986,7 +2112,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
+@@ -1954,7 +2072,7 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
      fd->unix_name = NULL;
      if ((path = dup_fd_name( root, name )))
      {
@@ -205,7 +197,7 @@ index 0b0e91ebfbb..233c9eb94ef 100644
          free( path );
      }
  
-@@ -1997,10 +2123,11 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
+@@ -1965,10 +2083,11 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
      *mode = st.st_mode;
  
      /* only bother with an inode for normal files and directories */
@@ -218,7 +210,7 @@ index 0b0e91ebfbb..233c9eb94ef 100644
  
          if (!inode)
          {
-@@ -2015,13 +2142,17 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
+@@ -1983,13 +2102,17 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
          list_add_head( &inode->open, &fd->inode_entry );
          closed_fd = NULL;
  
@@ -238,7 +230,7 @@ index 0b0e91ebfbb..233c9eb94ef 100644
          {
              set_error( STATUS_FILE_IS_A_DIRECTORY );
              goto error;
-@@ -2454,6 +2585,7 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
+@@ -2436,6 +2559,7 @@ static struct fd *get_handle_fd_obj( struct process *process, obj_handle_t handl
  
  static int is_dir_empty( int fd )
  {
@@ -246,7 +238,7 @@ index 0b0e91ebfbb..233c9eb94ef 100644
      DIR *dir;
      int empty;
      struct dirent *de;
-@@ -2461,8 +2593,13 @@ static int is_dir_empty( int fd )
+@@ -2443,8 +2567,13 @@ static int is_dir_empty( int fd )
      if ((fd = dup( fd )) == -1)
          return -1;
  
@@ -261,7 +253,7 @@ index 0b0e91ebfbb..233c9eb94ef 100644
          close( fd );
          return -1;
      }
-@@ -2474,6 +2611,7 @@ static int is_dir_empty( int fd )
+@@ -2456,6 +2585,7 @@ static int is_dir_empty( int fd )
          empty = 0;
      }
      closedir( dir );
@@ -269,7 +261,7 @@ index 0b0e91ebfbb..233c9eb94ef 100644
      return empty;
  }
  
-@@ -2512,7 +2650,7 @@ static void set_fd_disposition( struct fd *fd, unsigned int flags )
+@@ -2494,7 +2624,7 @@ static void set_fd_disposition( struct fd *fd, unsigned int flags )
              file_set_error();
              return;
          }
@@ -279,5 +271,5 @@ index 0b0e91ebfbb..233c9eb94ef 100644
              if (!(flags & FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE) &&
                  !(st.st_mode & (S_IWUSR | S_IWGRP | S_IWOTH)))
 -- 
-2.40.1
+2.43.0
 
diff --git a/patches/ntdll-Junction_Points/0026-ntdll-Fix-reparse-point-creation-for-non-Z-drives.patch b/patches/ntdll-Junction_Points/0026-ntdll-Fix-reparse-point-creation-for-non-Z-drives.patch
new file mode 100644
index 00000000..8cc90fac
--- /dev/null
+++ b/patches/ntdll-Junction_Points/0026-ntdll-Fix-reparse-point-creation-for-non-Z-drives.patch
@@ -0,0 +1,61 @@
+From a74fb111482ab787136b3db80d06d9ce1c4c50ea Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Aida=20Jonikien=C4=97?= <aidas957@gmail.com>
+Date: Mon, 22 Jan 2024 14:28:06 +0200
+Subject: [PATCH] ntdll: Fix reparse point creation for non-Z drives.
+
+This makes creating reparse points work properly when the target
+includes ${WINEPREFIX} (previously it didn't work because compholio
+forgot to change one symlink() call in their patchset update and the
+link path buffer was fixed-size so it would explode with long enough
+paths as seen in the bug below).
+
+This change also wraps some strings with debugstr_a() to avoid a buffer
+overflow with +file channel enabled.
+
+Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=53093
+---
+ dlls/ntdll/unix/file.c | 9 +++++----
+ 1 file changed, 5 insertions(+), 4 deletions(-)
+
+diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
+index 48300b21d99..abf04b3a7d4 100644
+--- a/dlls/ntdll/unix/file.c
++++ b/dlls/ntdll/unix/file.c
+@@ -3700,21 +3700,22 @@ NTSTATUS create_reparse_target( int dirfd, const char *unix_src, int depth, cons
+         }
+         else if (find_prefix_end( unix_target, &relative_offset ))
+         {
+-            char prefix_link[MAX_PATH];
++            char *prefix_link = calloc(1, strlen( link_path ) + strlen( prefix_string ) + 1);
+ 
+             append_prefix = TRUE;
+             is_relative = FALSE;
+             strcpy( prefix_link, link_path );
+             prefix_link[strlen(prefix_link)-1] = 0;
+             strcat( prefix_link, prefix_string );
+-            symlink( config_dir, prefix_link );
++            symlinkat( config_dir, dirfd, prefix_link );
++            free( 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", target_path );
++        TRACE( "adding reparse point target: %s\n", debugstr_a(target_path) );
+         symlinkat( target_path, dirfd, link_path );
+     }
+     free( unix_target );
+@@ -3768,7 +3769,7 @@ NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
+     }
+     encoded_len = encode_base64url( (const char *)buffer, buffer_len, encoded );
+ 
+-    TRACE( "Linking %s to %s\n", unix_src, encoded );
++    TRACE( "Linking %s to %s\n", debugstr_a(unix_src), debugstr_a(encoded) );
+     strcpy( filename_buf, unix_src );
+     filename = basename( filename_buf );
+ 
+-- 
+2.43.0
+
-- 
2.43.0

