Rebase against 9250ecc5a6a64c73aada0ea751815412f7f00410.

This commit is contained in:
Elizabeth Figura
2025-11-11 16:54:32 -06:00
parent 514e3884c5
commit 4ee9edf610
8 changed files with 30 additions and 896 deletions

View File

@@ -1,413 +0,0 @@
From 5f3feef99f8c9740f04dbe0ee1b23ca27d60548e Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 20:56:49 -0700
Subject: [PATCH] ntdll: Add support for creating reparse points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
configure.ac | 2 +
dlls/ntdll/Makefile.in | 2 +-
dlls/ntdll/unix/file.c | 302 +++++++++++++++++++++++++++++++++++++++++
include/ddk/ntifs.h | 5 +
4 files changed, 310 insertions(+), 1 deletion(-)
diff --git a/configure.ac b/configure.ac
index b675da34d58..63e3bb5bdc7 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2137,6 +2137,8 @@ AC_CHECK_FUNCS(\
process_vm_writev \
sched_getcpu \
sched_yield \
+ renameat \
+ renameat2 \
setproctitle \
setprogname \
sigprocmask \
diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
index 3c0dfa7a895..b9a8bcba4cf 100644
--- a/dlls/ntdll/Makefile.in
+++ b/dlls/ntdll/Makefile.in
@@ -5,7 +5,7 @@ IMPORTLIB = ntdll
IMPORTS = $(TOMCRYPT_PE_LIBS) $(MUSL_PE_LIBS)
EXTRAINCL = $(TOMCRYPT_PE_CFLAGS)
UNIX_CFLAGS = $(UNWIND_CFLAGS) $(HWLOC_CFLAGS)
-UNIX_LIBS = $(IOKIT_LIBS) $(COREFOUNDATION_LIBS) $(CORESERVICES_LIBS) $(RT_LIBS) $(PTHREAD_LIBS) $(UNWIND_LIBS) $(I386_LIBS) $(PROCSTAT_LIBS) $(HWLOC_LIBS)
+UNIX_LIBS = $(IOKIT_LIBS) $(COREFOUNDATION_LIBS) $(CORESERVICES_LIBS) $(RT_LIBS) $(PTHREAD_LIBS) $(UNWIND_LIBS) $(I386_LIBS) $(PROCSTAT_LIBS) $(HWLOC_LIBS) -lm
EXTRADLLFLAGS = -nodefaultlibs
i386_EXTRADLLFLAGS = -Wl,--image-base,0x7bc00000
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 7ab1dbb2b55..5b4fcb3711d 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -36,6 +36,8 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
+#include <math.h>
+#include <libgen.h>
#include <limits.h>
#include <unistd.h>
#ifdef HAVE_MNTENT_H
@@ -121,6 +123,7 @@
#include "wine/list.h"
#include "wine/debug.h"
#include "unix_private.h"
+#include "ddk/ntifs.h"
WINE_DEFAULT_DEBUG_CHANNEL(file);
WINE_DECLARE_DEBUG_CHANNEL(winediag);
@@ -132,6 +135,12 @@ WINE_DECLARE_DEBUG_CHANNEL(winediag);
#undef EXT2_IOC_GETFLAGS
#undef EXT4_CASEFOLD_FL
+#ifndef RENAME_EXCHANGE
+#define RENAME_EXCHANGE (1 << 1)
+#endif
+
+#define SYM_MAX (PATH_MAX-1) /* PATH_MAX includes the NUL character */
+
#ifdef linux
/* We want the real kernel dirent structure, not the libc one */
@@ -249,6 +258,95 @@ static const BOOL is_case_sensitive = FALSE;
static pthread_mutex_t dir_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t mnt_mutex = PTHREAD_MUTEX_INITIALIZER;
+#ifndef HAVE_RENAMEAT2
+int renameat2( int olddirfd, const char *oldpath, int newdirfd, const char *newpath,
+ unsigned int flags )
+{
+ if (flags == 0)
+ return renameat( olddirfd, oldpath, newdirfd, newpath );
+#if defined(__NR_renameat2)
+ return syscall( __NR_renameat2, olddirfd, oldpath, newdirfd, newpath, flags );
+#elif defined(RENAME_SWAP)
+ return renameatx_np(olddirfd, oldpath, newdirfd, newpath,
+ (flags & RENAME_EXCHANGE ? RENAME_SWAP : 0));
+#else
+ errno = ENOSYS;
+ return -1;
+#endif
+}
+#endif /* HAVE_RENAMEAT2 */
+
+static char *itoa( int i )
+{
+ static char buffer[11];
+
+ snprintf(buffer, sizeof(buffer), "%d", i);
+ return buffer;
+}
+
+/* base64url (RFC 4648 §5) encode a binary string
+ * 1) start with base64
+ * 2) replace '+' by '-' and replace '/' by '_'
+ * 3) do not add padding characters
+ * 4) do not add line separators
+ */
+static UINT encode_base64url( const char *bin, unsigned int len, char *base64 )
+{
+ UINT n = 0, x;
+ static const char base64enc[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
+
+ while (len > 0)
+ {
+ /* first 6 bits, all from bin[0] */
+ base64[n++] = base64enc[(bin[0] & 0xfc) >> 2];
+ x = (bin[0] & 3) << 4;
+
+ /* next 6 bits, 2 from bin[0] and 4 from bin[1] */
+ if (len == 1)
+ {
+ base64[n++] = base64enc[x];
+ break;
+ }
+ base64[n++] = base64enc[x | ((bin[1] & 0xf0) >> 4)];
+ x = (bin[1] & 0x0f) << 2;
+
+ /* next 6 bits 4 from bin[1] and 2 from bin[2] */
+ if (len == 2)
+ {
+ base64[n++] = base64enc[x];
+ break;
+ }
+ base64[n++] = base64enc[x | ((bin[2] & 0xc0) >> 6)];
+
+ /* last 6 bits, all from bin [2] */
+ base64[n++] = base64enc[bin[2] & 0x3f];
+ bin += 3;
+ len -= 3;
+ }
+ base64[n] = 0;
+ return n;
+}
+
+/* create a directory and all the needed parent directories */
+static int mkdir_p( int dirfd, const char *path, mode_t mode )
+{
+ char path_tmp[PATH_MAX], *p;
+
+ strcpy( path_tmp, path );
+ for (p = path_tmp + 1; *p; p++) {
+ if (*p == '/') {
+ *p = '\0';
+ if (mkdirat( dirfd, path_tmp, mode ) != 0 && errno != EEXIST)
+ return -1;
+ *p = '/';
+ }
+ }
+ if (mkdirat( dirfd, path_tmp, mode ) != 0 && errno != EEXIST)
+ return -1;
+ return 0;
+}
+
/* check if a given Unicode char is OK in a DOS short name */
static inline BOOL is_invalid_dos_char( WCHAR ch )
{
@@ -1653,6 +1751,28 @@ static int parse_samba_dos_attrib_data( char *data, int len )
}
+/* determine whether a reparse point is meant to be a directory or a file */
+static int is_reparse_dir( int fd, const char *path, BOOL *is_dir )
+{
+ char link_path[PATH_MAX], *p;
+ int ret;
+
+ if ((ret = readlinkat( fd, 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 BOOL fd_is_mount_point( int fd, const struct stat *st )
{
struct stat parent;
@@ -3455,6 +3575,181 @@ done:
}
+/*
+ * 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.
+ */
+NTSTATUS create_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
+{
+ int buffer_len = buffer->ReparseDataLength+FIELD_OFFSET(typeof(*buffer), GenericReparseBuffer);
+ char target_path[PATH_MAX], link_path[PATH_MAX], link_dir[PATH_MAX];
+ int encoded_len = (int)ceil(buffer_len*4/3.0) + 1, chunk_len;
+ char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
+ BOOL needs_close, tempdir_created = FALSE;
+ char filename_buf[PATH_MAX], *filename;
+ char *unix_src = NULL, *encoded = NULL;
+ int i = 0, j = 0, depth = 0, fd;
+ int link_dir_fd = -1;
+ NTSTATUS status;
+ struct stat st;
+ BOOL is_dir;
+
+ if (buffer_len > 16*1024)
+ return STATUS_IO_REPARSE_DATA_INVALID;
+
+ if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &fd, &needs_close, NULL, NULL )))
+ return status;
+ if (fstat( fd, &st ) == -1)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if ((status = server_get_unix_name( handle, &unix_src )))
+ goto cleanup;
+ is_dir = S_ISDIR( st.st_mode );
+ is_reparse_dir( AT_FDCWD, unix_src, &is_dir ); /* keep type (replace existing reparse point) */
+ encoded = malloc( encoded_len );
+ if (!encoded)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+ encoded_len = encode_base64url( (const char *)buffer, buffer_len, encoded );
+
+ TRACE( "Linking %s to %s\n", debugstr_a(unix_src), encoded );
+ strcpy( filename_buf, unix_src );
+ filename = basename( filename_buf );
+
+ /* Create the symlink that represents the initial data in the reparse tag:
+ * *) Begin all reparse tags with the hidden folder .REPARSE_POINT. This serves two purposes:
+ * 1) it makes it easy to identify reparse points
+ * 2) if the reparse buffer exceeds what can be stored in a single symlink (4095+1 bytes)
+ * then we need to store additional data, so link to it and store it in a hidden folder
+ * *) Append the filename of the reparse point to the hidden folder, this ensures that if
+ * multiple reparse points contain the same data that there is no possibility of collision
+ * *) Append a special flag to indicate whether this is a directory (./) or file (/)
+ * *) Append the base64-url encoded reparse point buffer
+ * *) Append the filename of the first continuing symlink (0) in case we need it
+ */
+ strcpy( target_path, ".REPARSE_POINT/" );
+ strcat( target_path, filename );
+ strcat( target_path, "/" );
+ if (is_dir)
+ strcat( target_path, "." );
+ strcat( target_path, "/" );
+ i = 0;
+ for (depth=0; i<encoded_len && strlen(target_path)<SYM_MAX-2; i+=chunk_len, depth++)
+ {
+ chunk_len = min(NAME_MAX, SYM_MAX-2-strlen(target_path));
+ strncat( target_path, &encoded[i], chunk_len );
+ strcat( target_path, "/" );
+ }
+ strcat( target_path, itoa(j) );
+
+ /* Produce the link in a temporary location in the same folder */
+ strcpy( tmpdir, unix_src );
+ d = dirname( tmpdir);
+ if (d != tmpdir) strcpy( tmpdir, d );
+ strcat( tmpdir, "/.winelink.XXXXXX" );
+ if (mkdtemp( tmpdir ) == NULL)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ tempdir_created = TRUE;
+ strcpy( tmplink, tmpdir );
+ strcat( tmplink, "/tmplink" );
+ if (symlink( target_path, tmplink ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+
+ /* change to the link folder so that we can build any necessary additional data */
+ strcpy( link_dir, tmpdir );
+ link_dir[strlen(link_dir)-16] = 0;
+ link_dir_fd = open( link_dir, O_RDONLY|O_DIRECTORY );
+
+ /* If there is any further information in the reparse tag then store it in the hidden folder */
+ while(i < encoded_len)
+ {
+ int fd;
+
+ j++;
+ strcpy( link_path, target_path );
+
+ target_path[0] = 0;
+ for (; depth>0; depth--)
+ {
+ strcat( target_path, "../" );
+ }
+ for (depth=0; i<encoded_len && strlen(target_path)<SYM_MAX-2; i+=chunk_len, depth++)
+ {
+ chunk_len = min(NAME_MAX, SYM_MAX-2-strlen(target_path));
+ strncat( target_path, &encoded[i], chunk_len );
+ strcat( target_path, "/" );
+ }
+ strcat( target_path, itoa(j) );
+
+ strcpy( link_dir, link_path );
+ link_dir[strlen(link_dir)-1] = 0;
+ if (mkdir_p( link_dir_fd, link_dir, 0777))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if (symlinkat( target_path, link_dir_fd, link_path ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ fd = openat( link_dir_fd, link_dir, O_RDONLY|O_DIRECTORY );
+ close( link_dir_fd );
+ link_dir_fd = fd;
+ }
+
+ /* Atomically move the initial link into position */
+ if (!renameat2( -1, tmplink, -1, unix_src, RENAME_EXCHANGE ))
+ {
+ /* success: link and folder/file have switched locations */
+ if (S_ISDIR( st.st_mode ))
+ rmdir( tmplink ); /* remove the folder (at link location) */
+ else
+ unlink( tmplink ); /* remove the file (at link location) */
+ }
+ else if (errno == ENOSYS)
+ {
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
+ "using unsafe exchange instead.\n" );
+ if (rmdir( unix_src ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if (rename( tmplink, unix_src ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
+ }
+ }
+ else
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ status = STATUS_SUCCESS;
+
+cleanup:
+ if (link_dir_fd != -1) close( link_dir_fd );
+ if (tempdir_created) rmdir( tmpdir );
+ if (needs_close) close( fd );
+ free( unix_src );
+ free( encoded );
+
+ return status;
+}
+
+
/******************************************************************************
* lookup_unix_name
*
@@ -6400,6 +6695,13 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
break;
}
+ case FSCTL_SET_REPARSE_POINT:
+ {
+ REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
+ status = create_reparse_point( handle, buffer );
+ break;
+ }
+
case FSCTL_SET_SPARSE:
TRACE("FSCTL_SET_SPARSE: Ignoring request\n");
status = STATUS_SUCCESS;
diff --git a/include/ddk/ntifs.h b/include/ddk/ntifs.h
index 980235abdc9..90248b4897c 100644
--- a/include/ddk/ntifs.h
+++ b/include/ddk/ntifs.h
@@ -166,6 +166,11 @@ typedef struct _REPARSE_DATA_BUFFER
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
+ struct {
+ ULONG Version;
+ UCHAR PathBuffer[1];
+ } LinuxSymbolicLinkReparseBuffer;
+
struct
{
UCHAR DataBuffer[1];
--
2.51.0

View File

@@ -1,266 +0,0 @@
From 369f4d92683910c01d82719e448d21a74b7b82d8 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 20:57:57 -0700
Subject: [PATCH] ntdll: Add support for reading reparse points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/unix/file.c | 221 ++++++++++++++++++++++++++++++++++++++--
2 files changed, 231 insertions(+), 11 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 0d58abbfa84..3e160fb1e5c 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -325,6 +325,84 @@ static UINT encode_base64url( const char *bin, unsigned int len, char *base64 )
return n;
}
+static inline char decode_base64url_char( char c )
+{
+ if (c >= 'A' && c <= 'Z') return c - 'A';
+ if (c >= 'a' && c <= 'z') return c - 'a' + 26;
+ if (c >= '0' && c <= '9') return c - '0' + 52;
+ if (c == '-') return 62;
+ if (c == '_') return 63;
+ return 64;
+}
+
+/* decode a base64url (RFC 4648 §5) binary string
+ * 1) start with base64
+ * 2) replace '+' by '-' and replace '/' by '_'
+ * 3) do not add padding characters
+ * 4) do not add line separators
+ */
+static unsigned int decode_base64url( const char *base64, unsigned int len, char *buf )
+{
+ unsigned int i = 0;
+ char c0, c1, c2, c3;
+ const char *p = base64;
+
+ while (len > 4)
+ {
+ if ((c0 = decode_base64url_char( p[0] )) > 63) return 0;
+ if ((c1 = decode_base64url_char( p[1] )) > 63) return 0;
+ if ((c2 = decode_base64url_char( p[2] )) > 63) return 0;
+ if ((c3 = decode_base64url_char( p[3] )) > 63) return 0;
+
+ if (buf)
+ {
+ buf[i + 0] = (c0 << 2) | (c1 >> 4);
+ buf[i + 1] = (c1 << 4) | (c2 >> 2);
+ buf[i + 2] = (c2 << 6) | c3;
+ }
+ len -= 4;
+ i += 3;
+ p += 4;
+ }
+ if (len == 2)
+ {
+ if ((c0 = decode_base64url_char( p[0] )) > 63) return 0;
+ if ((c1 = decode_base64url_char( p[1] )) > 63) return 0;
+
+ if (buf) buf[i] = (c0 << 2) | (c1 >> 4);
+ i++;
+ }
+ else if (len == 3)
+ {
+ if ((c0 = decode_base64url_char( p[0] )) > 63) return 0;
+ if ((c1 = decode_base64url_char( p[1] )) > 63) return 0;
+ if ((c2 = decode_base64url_char( p[2] )) > 63) return 0;
+
+ if (buf)
+ {
+ buf[i + 0] = (c0 << 2) | (c1 >> 4);
+ buf[i + 1] = (c1 << 4) | (c2 >> 2);
+ }
+ i += 2;
+ }
+ else
+ {
+ if ((c0 = decode_base64url_char( p[0] )) > 63) return 0;
+ if ((c1 = decode_base64url_char( p[1] )) > 63) return 0;
+ if ((c2 = decode_base64url_char( p[2] )) > 63) return 0;
+ if ((c3 = decode_base64url_char( p[3] )) > 63) return 0;
+
+ if (buf)
+ {
+ buf[i + 0] = (c0 << 2) | (c1 >> 4);
+ buf[i + 1] = (c1 << 4) | (c2 >> 2);
+ buf[i + 2] = (c2 << 6) | c3;
+ }
+ i += 3;
+ }
+ return i;
+}
+
/* create a directory and all the needed parent directories */
static int mkdir_p( int dirfd, const char *path, mode_t mode )
{
@@ -3715,6 +3793,132 @@ 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.
+ */
+NTSTATUS get_reparse_point(HANDLE handle, 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;
+ ssize_t ret;
+ 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)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ link_path_len = ret;
+ link_path[link_path_len] = 0;
+ if (strncmp( link_path, ".REPARSE_POINT/", 15 ) != 0)
+ {
+ status = STATUS_NOT_IMPLEMENTED;
+ goto cleanup;
+ }
+ encoded_len = link_path_len;
+ encoded = malloc( encoded_len );
+ if (!encoded)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* Copy the encoded data from the inital symlink */
+ encoded[0] = 0;
+ p = &link_path[15];
+ if ((p = strchr( p, '/' )) == NULL)
+ {
+ status = STATUS_IO_REPARSE_DATA_INVALID;
+ goto cleanup;
+ }
+ p++;
+ if (*(p++) == '.')
+ p++;
+ for (depth=0; p < link_path + link_path_len; p += NAME_MAX+1, depth++)
+ strncat( encoded, p, NAME_MAX );
+ encoded[strlen(encoded)-1] = 0; /* chunk id */
+ encoded[strlen(encoded)-1] = 0; /* final slash */
+
+ /* get the length of the full buffer so that we know when to stop collecting data */
+ decode_base64url( encoded, sizeof(header), (char*)&header );
+ buffer_len = header.ReparseDataLength+FIELD_OFFSET(typeof(header), GenericReparseBuffer);
+ *size = buffer_len;
+
+ if (buffer_len > out_size)
+ {
+ status = STATUS_BUFFER_TOO_SMALL;
+ goto cleanup;
+ }
+ encoded_len = (int)ceil(buffer_len*4/3.0);
+ encoded = realloc( encoded, encoded_len + 3 ); /* 3 chars = slash, chunk ID, NUL character */
+ if (!encoded)
+ {
+ status = STATUS_NO_MEMORY;
+ goto cleanup;
+ }
+
+ /* change to the link folder so that we can build any necessary additional data */
+ strcpy( link_dir, unix_name );
+ d = dirname( link_dir);
+ if (d != link_dir) strcpy( link_dir, d );
+ link_dir_fd = open( link_dir, O_RDONLY|O_DIRECTORY );
+
+ /* Copy the encoded data from the follow on symlinks */
+ while(strlen(encoded) < encoded_len)
+ {
+ int fd;
+
+ strcpy( link_dir, link_path );
+ ret = readlinkat( link_dir_fd, link_dir, link_path, sizeof(link_path) );
+ if (ret < 0)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ link_path_len = ret;
+ link_path[link_path_len] = 0; /* readlink does not NUL terminate */
+
+ p = &link_path[3*depth];
+ for (depth=0; p < link_path + link_path_len; p += NAME_MAX+1, depth++)
+ strncat( encoded, p, NAME_MAX );
+ encoded[strlen(encoded)-1] = 0; /* chunk id */
+ encoded[strlen(encoded)-1] = 0; /* final slash */
+
+ link_dir[strlen(link_dir)-1] = 0;
+ fd = openat( link_dir_fd, link_dir, O_RDONLY|O_DIRECTORY );
+ close( link_dir_fd );
+ link_dir_fd = fd;
+ }
+
+ /* Decode the reparse buffer from the base64-encoded symlink data */
+ *size = decode_base64url( encoded, strlen(encoded), (char*)buffer );
+ status = STATUS_SUCCESS;
+ if (buffer_len != *size)
+ {
+ status = STATUS_IO_REPARSE_DATA_INVALID;
+ ERR("Size mismatch decoding reparse point buffer (%d != %d)\n", *size, buffer_len);
+ }
+
+cleanup:
+ if (link_dir_fd != -1) close( link_dir_fd );
+ free( unix_name );
+ free( encoded );
+ return status;
+}
+
+
/******************************************************************************
* lookup_unix_name
*
@@ -6525,15 +6729,6 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
break;
}
- case FSCTL_GET_REPARSE_POINT:
- if (out_buffer && out_size)
- {
- FIXME("FSCTL_GET_REPARSE_POINT semi-stub\n");
- status = STATUS_NOT_A_REPARSE_POINT;
- }
- else status = STATUS_INVALID_USER_BUFFER;
- break;
-
case FSCTL_GET_OBJECT_ID:
{
FILE_OBJECTID_BUFFER *info = out_buffer;
@@ -6555,6 +6750,14 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
break;
}
+ case FSCTL_GET_REPARSE_POINT:
+ {
+ REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
+ ULONG size = out_size;
+ status = get_reparse_point( handle, buffer, &size );
+ io->Information = size;
+ break;
+ }
case FSCTL_SET_REPARSE_POINT:
{
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)in_buffer;
--
2.43.0

View File

@@ -1,130 +0,0 @@
From 3c25b2e7839c1493f97d144f137822cbf9a498a3 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Thu, 16 Jan 2014 21:00:21 -0700
Subject: [PATCH] ntdll: Add support for deleting reparse points.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/unix/file.c | 99 +++++++++++++++++++++++++++++++++++++++++
2 files changed, 121 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 92ce83b685e..ba77aab61b7 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3812,6 +3812,99 @@ cleanup:
}
+/*
+ * Retrieve the unix name corresponding to a file handle, remove that symlink, and then recreate
+ * a directory at the location of the old filename.
+ */
+NTSTATUS remove_reparse_point(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
+{
+ char tmpdir[PATH_MAX], tmplink[PATH_MAX], *d;
+ BOOL tempdir_created = FALSE;
+ int dest_fd, needs_close;
+ BOOL is_dir = TRUE;
+ NTSTATUS status;
+ char *unix_name;
+ struct stat st;
+
+ if ((status = server_get_unix_fd( handle, FILE_SPECIAL_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
+ return status;
+
+ if ((status = server_get_unix_name( handle, &unix_name )))
+ goto cleanup;
+
+ TRACE( "Deleting symlink %s\n", unix_name );
+
+ /* Produce the file/directory in a temporary location in the same folder */
+ if (fstat( dest_fd, &st ) == -1)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ is_dir = S_ISDIR(st.st_mode);
+ strcpy( tmpdir, unix_name );
+ d = dirname( tmpdir);
+ if (d != tmpdir) strcpy( tmpdir, d );
+ strcat( tmpdir, "/.winelink.XXXXXX" );
+ if (mkdtemp( tmpdir ) == NULL)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ tempdir_created = TRUE;
+ strcpy( tmplink, tmpdir );
+ strcat( tmplink, "/tmplink" );
+ if (is_dir && mkdir( tmplink, st.st_mode ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ else if (!is_dir)
+ {
+ int fd = open( tmplink, O_CREAT|O_WRONLY|O_TRUNC, st.st_mode );
+ if (fd < 0)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ close( fd );
+ }
+ /* attemp to retain the ownership (if possible) */
+ lchown( tmplink, st.st_uid, st.st_gid );
+ /* Atomically move the directory into position */
+ if (!renameat2( -1, tmplink, -1, unix_name, RENAME_EXCHANGE ))
+ {
+ /* success: link and folder/file have switched locations */
+ unlink( tmplink ); /* remove the file (at link location) */
+ }
+ else if (errno == ENOSYS)
+ {
+ FIXME( "Atomic exchange of directory with symbolic link unsupported on this system, "
+ "using unsafe exchange instead.\n" );
+ if (unlink( unix_name ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ if (rename( tmplink, unix_name ))
+ {
+ status = errno_to_status( errno );
+ goto cleanup; /* not moved, orignal file/folder at destination is orphaned */
+ }
+ }
+ else
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ status = STATUS_SUCCESS;
+
+cleanup:
+ if (tempdir_created) rmdir( tmpdir );
+ if (needs_close) close( dest_fd );
+ return status;
+}
+
+
/******************************************************************************
* lookup_unix_name
*
@@ -6571,6 +6664,12 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
break;
}
+ case FSCTL_DELETE_REPARSE_POINT:
+ {
+ REPARSE_GUID_DATA_BUFFER *buffer = (REPARSE_GUID_DATA_BUFFER *)in_buffer;
+ status = remove_reparse_point( handle, buffer );
+ break;
+ }
case FSCTL_GET_REPARSE_POINT:
{
REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
--
2.37.2

View File

@@ -1,51 +0,0 @@
From 246a50e7cf09bd1d77d327e170c2d7432e0d5f5e Mon Sep 17 00:00:00 2001
From: Lorenzo Ferrillo <lorenzofersteam@live.it>
Date: Mon, 6 May 2024 23:46:44 +0200
Subject: [PATCH] Return correct status value if handle is not a reparse point
---
dlls/ntdll/unix/file.c | 19 ++++++++++++++-----
1 file changed, 14 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 2bfb9b7d051..93732543ae4 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3944,9 +3944,11 @@ NTSTATUS get_reparse_point_unix(const char *unix_name, REPARSE_DATA_BUFFER *buff
char *p;
ret = readlink( unix_name, link_path, sizeof(link_path) );
+
if (ret < 0)
{
- status = errno_to_status( errno );
+ if (errno == EINVAL) status = STATUS_NOT_A_REPARSE_POINT;
+ else status = errno_to_status( errno );
goto cleanup;
}
link_path_len = ret;
@@ -7303,10 +7305,17 @@ NTSTATUS WINAPI NtFsControlFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE ap
}
case FSCTL_GET_REPARSE_POINT:
{
- REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
- ULONG size = out_size;
- status = get_reparse_point( handle, buffer, &size );
- io->Information = size;
+ io->Information = 0;
+ if (out_buffer){
+ REPARSE_DATA_BUFFER *buffer = (REPARSE_DATA_BUFFER *)out_buffer;
+ ULONG size = out_size;
+ status = get_reparse_point( handle, buffer, &size );
+ if (status == STATUS_SUCCESS)
+ io->Information = size;
+ }
+ else {
+ status = STATUS_INVALID_USER_BUFFER;
+ }
break;
}
case FSCTL_SET_REPARSE_POINT:
--
2.43.0

View File

@@ -1,15 +1,15 @@
From efd73d7778d8c083337bda1ad162618841c368e0 Mon Sep 17 00:00:00 2001
From 6bef707eb81bcdaf7a4f159f07852cbf092a3a2a 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 | 135 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 157 insertions(+), 3 deletions(-)
dlls/ntdll/unix/file.c | 133 +++++++++++++++++++++++++++++++++++++++-
2 files changed, 154 insertions(+), 4 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 25381caf313..7f048572e03 100644
index 7016ca166f9..362c9fcc640 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -139,18 +139,22 @@ static void WINAPI apc( void *arg, IO_STATUS_BLOCK *iosb, ULONG reserved )
@@ -63,10 +63,10 @@ index 25381caf313..7f048572e03 100644
static void open_file_test(void)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 542a314ea81..68587cbef11 100644
index a6873bb2f79..91afff6e49c 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -4593,7 +4593,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( FILE_OBJECT *fileobj, char **unix_
@@ -3721,7 +3721,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( OBJECT_ATTRIBUTES *attr, UNICODE_S
/******************************************************************************
@@ -75,16 +75,18 @@ index 542a314ea81..68587cbef11 100644
*
* Convert a file name from NT namespace to Unix namespace.
*
@@ -4601,7 +4601,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( FILE_OBJECT *fileobj, char **unix_
@@ -3729,8 +3729,8 @@ static NTSTATUS nt_to_unix_file_name_no_root( OBJECT_ATTRIBUTES *attr, UNICODE_S
* element doesn't have to exist; in that case STATUS_NO_SUCH_FILE is
* returned, but the unix name is still filled in properly.
*/
-static 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 )
-static NTSTATUS nt_to_unix_file_name( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name,
- char **name_ret, UINT disposition )
+NTSTATUS nt_to_unix_file_name_internal( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name,
+ char **name_ret, UINT disposition )
{
HANDLE rootdir = attr->RootDirectory;
enum server_fd_type type;
@@ -4680,6 +4680,137 @@ reparse:
int root_fd, needs_close;
@@ -3781,6 +3781,133 @@ static NTSTATUS nt_to_unix_file_name( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *n
}
@@ -162,18 +164,18 @@ index 542a314ea81..68587cbef11 100644
+ * 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( OBJECT_ATTRIBUTES *attr, UNICODE_STRING *nt_name,
+ 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;
+ UNICODE_STRING *nameW;
+ size_t offset, name_len;
+ NTSTATUS status;
+
+ if (attr->RootDirectory) return nt_to_unix_file_name_internal( attr, name_ret, disposition );
+ if (attr->RootDirectory) return nt_to_unix_file_name_internal( attr, nt_name, name_ret, disposition );
+
+ nameW = attr->ObjectName;
+
@@ -192,7 +194,7 @@ index 542a314ea81..68587cbef11 100644
+ prefix = user_shared_data->NtSystemRoot;
+ }
+ else
+ return nt_to_unix_file_name_internal( attr, name_ret, disposition );
+ return nt_to_unix_file_name_internal( attr, nt_name, name_ret, disposition );
+
+ name_len = sizeof(dosprefixW) + wcslen(prefix) * sizeof(WCHAR)
+ + sizeof(WCHAR) /* '\\' */ + nameW->Length - offset * sizeof(WCHAR) + sizeof(WCHAR);
@@ -208,14 +210,10 @@ index 542a314ea81..68587cbef11 100644
+ 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;
+ nt_name->Buffer = name;
+ nt_name->Length = wcslen( name ) * sizeof(WCHAR);
+ attr->ObjectName = nt_name;
+ return nt_to_unix_file_name_internal( attr, nt_name, name_ret, disposition );
+}
+
+
@@ -223,5 +221,5 @@ index 542a314ea81..68587cbef11 100644
* collapse_path
*
--
2.47.2
2.51.0

View File

@@ -1,4 +1,2 @@
Fixes: [37487] Resolve \\SystemRoot\\ prefix when opening files
Fixes: Implement opening files through nt device paths
Depends: ntdll-Junction_Points
Disabled: True

View File

@@ -1,4 +1,4 @@
From f8970096657145099840f30a355661e5cfe74b72 Mon Sep 17 00:00:00 2001
From 30cc9b257b136f32e1d04fe77411dcb9e4a818ef Mon Sep 17 00:00:00 2001
From: Ally Sommers <dropbear.sh@gmail.com>
Date: Thu, 30 Jan 2025 23:48:43 +0100
Subject: [PATCH] server: Allow for deletion of socket files.
@@ -10,10 +10,10 @@ is analogous to unbinding.
1 file changed, 27 insertions(+), 3 deletions(-)
diff --git a/server/fd.c b/server/fd.c
index dde92beb664..b937e1238b2 100644
index 4db5209ee4c..e4b1f03882a 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2072,6 +2072,19 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
@@ -1983,6 +1983,19 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
fd->unix_fd = open( name, O_RDONLY | (flags & ~(O_TRUNC | O_CREAT | O_EXCL)), *mode );
}
@@ -33,7 +33,7 @@ index dde92beb664..b937e1238b2 100644
if (fd->unix_fd == -1)
{
/* check for trailing slash on file path */
@@ -2083,13 +2096,24 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
@@ -1994,13 +2007,24 @@ struct fd *open_fd( struct fd *root, const char *name, struct unicode_str nt_nam
}
}
@@ -55,12 +55,12 @@ index dde92beb664..b937e1238b2 100644
*mode = st.st_mode;
- /* only bother with an inode for normal files and directories */
- if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode))
- if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode))
+ /* only bother with an inode for normal files, directories, and socket files */
+ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISLNK(st.st_mode) || S_ISSOCK(st.st_mode))
+ if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode) || S_ISSOCK(st.st_mode))
{
unsigned int err;
struct inode *inode = get_inode( st.st_dev, st.st_ino, fd->unix_fd );
--
2.47.2
2.51.0

View File

@@ -1,3 +1 @@
Fixes: [52568] ws_ws2: Support for AF_UNIX sockets.
Depends: ntdll-Junction_Points
Disabled: True