Rebase against 6298b0cab2086ae61f46b284d22c420dfbb2b44e.

This commit is contained in:
Alistair Leslie-Hughes
2025-03-18 10:16:45 +11:00
parent f247cd5d6b
commit fa0cd8ead0
3 changed files with 47 additions and 78 deletions

View File

@@ -1,4 +1,4 @@
From beaeb1935534ce99aa19b8009184b07bd602a24c Mon Sep 17 00:00:00 2001
From 4f26d71abf2447b5e0c6d7b6e878cf6b6c578558 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.
@@ -6,14 +6,14 @@ Subject: [PATCH] ntdll: Follow reparse points during path resolution.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/tests/file.c | 11 ++-
dlls/ntdll/unix/file.c | 189 +++++++++++++++++++++++++++++++++++-----
2 files changed, 177 insertions(+), 23 deletions(-)
dlls/ntdll/unix/file.c | 196 +++++++++++++++++++++++++++++++++++-----
2 files changed, 184 insertions(+), 23 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 390768f557d..a0b84849490 100644
index 39b98af7efa..80b967f5469 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5381,7 +5381,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags,
@@ -6082,7 +6082,7 @@ static INT build_reparse_buffer(const WCHAR *filename, ULONG tag, ULONG flags,
static void test_reparse_points(void)
{
@@ -22,7 +22,7 @@ index 390768f557d..a0b84849490 100644
static const WCHAR new_reparseW[] = {'\\','n','e','w','_','r','e','p','a','r','s','e',0};
static const WCHAR reparseW[] = {'\\','r','e','p','a','r','s','e',0};
static const WCHAR targetW[] = {'\\','t','a','r','g','e','t',0};
@@ -5768,11 +5768,20 @@ static void test_reparse_points(void)
@@ -6469,11 +6469,20 @@ static void test_reparse_points(void)
bret = CopyFileW(reparse_path, new_path, TRUE);
ok(!bret, "Reparse points cannot be copied.\n");
@@ -44,10 +44,10 @@ index 390768f557d..a0b84849490 100644
ok(bret, "Failed to remove temporary reparse point directory!\n");
bret = RemoveDirectoryW(target_path);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 9211c6964a6..e90670ffc71 100644
index 49afb57b2b6..26e412d28f1 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -3548,6 +3548,35 @@ done:
@@ -3725,6 +3725,35 @@ done:
}
@@ -83,7 +83,7 @@ index 9211c6964a6..e90670ffc71 100644
/*
* 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.
@@ -3724,16 +3753,14 @@ cleanup:
@@ -3901,16 +3930,14 @@ cleanup:
/*
@@ -102,7 +102,7 @@ index 9211c6964a6..e90670ffc71 100644
char *encoded = NULL;
int link_dir_fd = -1;
NTSTATUS status;
@@ -3741,9 +3768,6 @@ NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *si
@@ -3918,9 +3945,6 @@ NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *si
int depth;
char *p;
@@ -112,7 +112,7 @@ index 9211c6964a6..e90670ffc71 100644
ret = readlink( unix_name, link_path, sizeof(link_path) );
if (ret < 0)
{
@@ -3843,12 +3867,76 @@ NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *si
@@ -4020,12 +4044,76 @@ NTSTATUS get_reparse_point(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG *si
cleanup:
if (link_dir_fd != -1) close( link_dir_fd );
@@ -190,7 +190,7 @@ index 9211c6964a6..e90670ffc71 100644
/*
* Retrieve the unix name corresponding to a file handle, remove that symlink, and then recreate
* a directory at the location of the old filename.
@@ -3942,15 +4030,25 @@ cleanup:
@@ -4119,15 +4207,24 @@ cleanup:
}
@@ -207,18 +207,16 @@ index 9211c6964a6..e90670ffc71 100644
*
* Helper for nt_to_unix_file_name
*/
-static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer, int unix_len, int pos,
- UINT disposition, BOOL is_unix )
+static NTSTATUS lookup_unix_name( FILE_OBJECT *fileobj, const WCHAR *name, int name_len,
+ char **buffer, int unix_len, int pos, UINT disposition,
+ BOOL is_unix )
-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;
@@ -4007,6 +4105,8 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
@@ -4184,6 +4281,8 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
while (name_len)
{
const WCHAR *end, *next;
@@ -227,9 +225,9 @@ index 9211c6964a6..e90670ffc71 100644
end = name;
while (end < name + name_len && *end != '\\') end++;
@@ -4026,8 +4126,31 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
@@ -4203,8 +4302,31 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
status = find_file_in_dir( unix_name, pos, name, end - name, is_unix );
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)
@@ -260,7 +258,7 @@ index 9211c6964a6..e90670ffc71 100644
{
if (status == STATUS_OBJECT_NAME_NOT_FOUND)
{
@@ -4066,12 +4189,12 @@ static NTSTATUS lookup_unix_name( const WCHAR *name, int name_len, char **buffer
@@ -4243,12 +4365,12 @@ static NTSTATUS lookup_unix_name( int root_fd, const WCHAR *name, int name_len,
/******************************************************************************
* nt_to_unix_file_name_no_root
*/
@@ -275,16 +273,16 @@ index 9211c6964a6..e90670ffc71 100644
NTSTATUS status = STATUS_SUCCESS;
const WCHAR *name;
struct stat st;
@@ -4161,7 +4284,7 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
@@ -4338,7 +4460,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( name, name_len, &unix_name, unix_len, pos, disposition, is_unix );
+ status = lookup_unix_name( fileobj, name, name_len, &unix_name, unix_len, pos, disposition, is_unix );
- 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) );
@@ -4169,7 +4292,8 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
@@ -4346,7 +4468,8 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
}
else
{
@@ -294,13 +292,14 @@ index 9211c6964a6..e90670ffc71 100644
free( unix_name );
}
return status;
@@ -4187,18 +4311,30 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
@@ -4364,18 +4487,30 @@ static NTSTATUS nt_to_unix_file_name_no_root( const UNICODE_STRING *nameW, char
*/
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 old_cwd, root_fd, needs_close;
- int root_fd, needs_close;
+ int old_cwd, root_fd, needs_close;
+ int reparse_count = 0;
+ FILE_OBJECT fileobj;
const WCHAR *name;
@@ -329,7 +328,7 @@ index 9211c6964a6..e90670ffc71 100644
if (name_len && name[0] == '\\') return STATUS_INVALID_PARAMETER;
@@ -4206,7 +4342,7 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
@@ -4383,7 +4518,7 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
if (!(unix_name = malloc( unix_len ))) return STATUS_NO_MEMORY;
unix_name[0] = '.';
@@ -338,17 +337,25 @@ index 9211c6964a6..e90670ffc71 100644
{
if (type != FD_TYPE_DIR)
{
@@ -4218,7 +4354,8 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
mutex_lock( &dir_mutex );
if ((old_cwd = open( ".", O_RDONLY )) != -1 && fchdir( root_fd ) != -1)
{
- status = lookup_unix_name( name, name_len, &unix_name, unix_len, 1, disposition, FALSE );
+ status = lookup_unix_name( &fileobj, name, name_len, &unix_name, unix_len, 1,
@@ -4392,7 +4527,16 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
}
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 );
@@ -4231,14 +4368,22 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
+ 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 );
}
}
@@ -4400,14 +4544,22 @@ NTSTATUS nt_to_unix_file_name( const OBJECT_ATTRIBUTES *attr, char **name_ret, U
if (status == STATUS_SUCCESS || status == STATUS_NO_SUCH_FILE)
{
@@ -373,5 +380,5 @@ index 9211c6964a6..e90670ffc71 100644
}
--
2.35.1
2.47.2

View File

@@ -1,38 +0,0 @@
From a6b3f7507ade04bcd9338a0936a2b1bfa8696fc1 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Wed, 1 May 2019 17:48:51 -0600
Subject: ntdll: Find dangling symlinks quickly.
This is also necessary on systems (such as MacOS) that support
case-insensitive lookups of files.
Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
dlls/ntdll/unix/file.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index caa454c024f..b26b239574b 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -2904,7 +2904,7 @@ static NTSTATUS find_file_in_dir( char *unix_name, int pos, const WCHAR *name, i
if (ret >= 0 && ret <= MAX_DIR_ENTRY_LEN)
{
unix_name[pos + ret] = 0;
- if (!stat( unix_name, &st )) return STATUS_SUCCESS;
+ if (!lstat( unix_name, &st )) return STATUS_SUCCESS;
}
if (check_case) goto not_found; /* we want an exact match */
@@ -4228,7 +4228,7 @@ static NTSTATUS lookup_unix_name( FILE_OBJECT *fileobj, const WCHAR *name, int n
char *p;
unix_name[pos + 1 + ret] = 0;
for (p = unix_name + pos ; *p; p++) if (*p == '\\') *p = '/';
- if (!stat( unix_name, &st ))
+ if (!lstat( unix_name, &st ))
{
if (disposition == FILE_CREATE) return STATUS_OBJECT_NAME_COLLISION;
return STATUS_SUCCESS;
--
2.17.1