ntdll-Junction_Points: Updates from Erich E. Hoover.

This commit is contained in:
Zebediah Figura 2020-12-02 10:34:50 -06:00
parent 023588ac34
commit f9e86098b3
7 changed files with 452 additions and 1 deletions

View File

@ -0,0 +1,77 @@
From 3ca3985f573529e825c167e8e60d909ad3963260 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Sun, 22 Nov 2020 22:37:33 -0700
Subject: [PATCH] ntdll: Allow set_file_times_precise to work on reparse
points.
---
configure.ac | 3 ++-
dlls/ntdll/unix/file.c | 21 ++++++++++++++-------
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/configure.ac b/configure.ac
index 6a761565e86..2809ff48d1a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -2203,7 +2203,8 @@ AC_CHECK_FUNCS(\
sigprocmask \
symlink \
tcdrain \
- thr_kill2
+ thr_kill2 \
+ utimensat
)
CFLAGS="$ac_save_CFLAGS"
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index ebb79c9963b..c3000b25dcd 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -1726,12 +1726,12 @@ static int get_file_info( const char *path, struct stat *st, ULONG *attr )
}
-#if defined(__ANDROID__) && !defined(HAVE_FUTIMENS)
-static int futimens( int fd, const struct timespec spec[2] )
+#if !defined(HAVE_UTIMENSAT) && defined(__ANDROID__)
+static int utimensat( int fd, const char *name, const struct timespec spec[2], int flags )
{
- return syscall( __NR_utimensat, fd, NULL, spec, 0 );
+ return syscall( __NR_utimensat, fd, name, spec, flags );
}
-#define HAVE_FUTIMENS
+#define HAVE_UTIMENSAT
#endif /* __ANDROID__ */
#ifndef UTIME_OMIT
@@ -1741,7 +1741,7 @@ static int futimens( int fd, const struct timespec spec[2] )
static BOOL set_file_times_precise( int fd, const LARGE_INTEGER *mtime,
const LARGE_INTEGER *atime, NTSTATUS *status )
{
-#ifdef HAVE_FUTIMENS
+#if defined(HAVE_FUTIMENS) || defined(HAVE_UTIMENSAT)
struct timespec tv[2];
tv[0].tv_sec = tv[1].tv_sec = 0;
@@ -1757,9 +1757,16 @@ static BOOL set_file_times_precise( int fd, const LARGE_INTEGER *mtime,
tv[1].tv_nsec = (mtime->QuadPart % 10000000) * 100;
}
#ifdef __APPLE__
- if (!&futimens) return FALSE;
+ if (!&utimensat) return FALSE;
+#endif
+#if defined(HAVE_UTIMENSAT)
+ /* futimens does not work on O_PATH|O_NOFOLLOW (O_SYMLINK) file descriptors, so if the file
+ * descriptor is for a symlink then use utimensat with an empty path (.) and do not follow the
+ * link. Since this approach works for both symlinks and regular files, just use utimensat. */
+ if (utimensat(fd, ".", tv, AT_SYMLINK_NOFOLLOW) == -1) *status = errno_to_status( errno );
+#else
+ if (futimens(fd, tv) == -1) *status = errno_to_status( errno );
#endif
- if (futimens( fd, tv ) == -1) *status = errno_to_status( errno );
else *status = STATUS_SUCCESS;
return TRUE;
#else
--
2.29.2

View File

@ -0,0 +1,26 @@
From d1ccfa832c14af4940c7b6cd2ca63aa7d23bb2d5 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Sun, 22 Nov 2020 22:35:50 -0700
Subject: [PATCH] kernelbase: Convert FILE_FLAG_OPEN_REPARSE_POINT for passing
to ntdll.
---
dlls/kernelbase/file.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/dlls/kernelbase/file.c b/dlls/kernelbase/file.c
index b21e5d3222d..478bc63fc75 100644
--- a/dlls/kernelbase/file.c
+++ b/dlls/kernelbase/file.c
@@ -724,6 +724,8 @@ static UINT get_nt_file_options( DWORD attributes )
options |= FILE_RANDOM_ACCESS;
if (attributes & FILE_FLAG_WRITE_THROUGH)
options |= FILE_WRITE_THROUGH;
+ if (attributes & FILE_FLAG_OPEN_REPARSE_POINT)
+ options |= FILE_OPEN_REPARSE_POINT;
return options;
}
--
2.29.2

View File

@ -0,0 +1,42 @@
From d5db8e054c0dc8987c0f469cccfa0652a56cf220 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Sun, 22 Nov 2020 22:39:48 -0700
Subject: [PATCH] server: Implement FILE_OPEN_REPARSE_POINT option.
---
dlls/ntdll/tests/file.c | 4 ++--
server/fd.c | 3 +++
2 files changed, 5 insertions(+), 2 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 053441923b3..6a99fa94ebc 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5401,8 +5401,8 @@ static void test_reparse_points(void)
ok(handle != INVALID_HANDLE_VALUE, "Failed to open symlink file.\n");
todo_wine ok(GetFileSize(handle, NULL) == 0, "symlink size is not zero\n");
bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL);
- ok(bret, "Failed to read data from the symlink.\n");
- todo_wine ok(dwLen == 0, "Length of symlink data is not zero.\n");
+ todo_wine ok(bret, "Failed to read data from the symlink.\n");
+ ok(dwLen == 0, "Length of symlink data is not zero.\n");
CloseHandle(handle);
/* Check the size/data of the symlink target */
diff --git a/server/fd.c b/server/fd.c
index c3c53489212..6f1e796c0bc 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -1957,6 +1957,9 @@ struct fd *open_fd( struct fd *root, const char *name, int flags, mode_t *mode,
}
else rw_mode = O_RDONLY;
+ if ((options & FILE_OPEN_REPARSE_POINT) && !(flags & O_CREAT))
+ flags |= O_SYMLINK;
+
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 */
--
2.29.2

View File

@ -0,0 +1,68 @@
From 466149c3b74fbf5a2e36350878d466e360451bda Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Mon, 23 Nov 2020 13:08:02 -0700
Subject: [PATCH] ntdll: Succeed with no data for NtReadFile on reparse points.
---
dlls/ntdll/tests/file.c | 2 +-
dlls/ntdll/unix/file.c | 5 +++++
server/file.c | 1 +
server/protocol.def | 1 +
4 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 6a99fa94ebc..d0112749258 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5401,7 +5401,7 @@ static void test_reparse_points(void)
ok(handle != INVALID_HANDLE_VALUE, "Failed to open symlink file.\n");
todo_wine ok(GetFileSize(handle, NULL) == 0, "symlink size is not zero\n");
bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL);
- todo_wine ok(bret, "Failed to read data from the symlink.\n");
+ ok(bret, "Failed to read data from the symlink.\n");
ok(dwLen == 0, "Length of symlink data is not zero.\n");
CloseHandle(handle);
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index c3000b25dcd..0cfa4f740ad 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -5225,6 +5225,11 @@ NTSTATUS WINAPI NtReadFile( HANDLE handle, HANDLE event, PIO_APC_ROUTINE apc, vo
goto done;
}
}
+ else if (type == FD_TYPE_SYMLINK)
+ {
+ status = STATUS_SUCCESS;
+ goto done;
+ }
if (type == FD_TYPE_SERIAL && async_read && length)
{
diff --git a/server/file.c b/server/file.c
index 2cc4a9d978c..42a812a32a2 100644
--- a/server/file.c
+++ b/server/file.c
@@ -301,6 +301,7 @@ static enum server_fd_type file_get_fd_type( struct fd *fd )
{
struct file *file = get_fd_user( fd );
+ if (S_ISLNK(file->mode)) return FD_TYPE_SYMLINK;
if (S_ISREG(file->mode) || S_ISBLK(file->mode)) return FD_TYPE_FILE;
if (S_ISDIR(file->mode)) return FD_TYPE_DIR;
return FD_TYPE_CHAR;
diff --git a/server/protocol.def b/server/protocol.def
index eba14534b9d..e2836843f4c 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1334,6 +1334,7 @@ enum server_fd_type
{
FD_TYPE_INVALID, /* invalid file (no associated fd) */
FD_TYPE_FILE, /* regular file */
+ FD_TYPE_SYMLINK, /* symbolic link */
FD_TYPE_DIR, /* directory */
FD_TYPE_SOCKET, /* socket */
FD_TYPE_SERIAL, /* serial port */
--
2.29.2

View File

@ -0,0 +1,166 @@
From 4a873f38d376596190ada3ed356fc773cff5b371 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Wed, 25 Nov 2020 09:05:51 -0700
Subject: [PATCH] ntdll: Support reparse point properties in fd_get_file_info.
---
dlls/ntdll/tests/file.c | 2 +-
dlls/ntdll/unix/file.c | 82 ++++++++++++++++++++++++-----------------
2 files changed, 50 insertions(+), 34 deletions(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index d0112749258..9ee9bd4e788 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5399,7 +5399,7 @@ static void test_reparse_points(void)
handle = CreateFileW(reparse_path, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0);
ok(handle != INVALID_HANDLE_VALUE, "Failed to open symlink file.\n");
- todo_wine ok(GetFileSize(handle, NULL) == 0, "symlink size is not zero\n");
+ ok(GetFileSize(handle, NULL) == 0, "symlink size is not zero\n");
bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL);
ok(bret, "Failed to read data from the symlink.\n");
ok(dwLen == 0, "Length of symlink data is not zero.\n");
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 0cfa4f740ad..738f317e176 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -1601,6 +1601,8 @@ static inline int get_file_xattr( char *hexattr, int attrlen )
NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, int *unix_dest_len,
DWORD *tag, ULONG *flags, BOOL *is_dir);
+NTSTATUS get_symlink_properties(const char *target, int len, char *unix_dest, int *unix_dest_len,
+ DWORD *tag, ULONG *flags, BOOL *is_dir);
/* fetch the attributes of a file */
static inline ULONG get_file_attributes( const struct stat *st )
@@ -1637,6 +1639,22 @@ static int fd_get_file_info( int fd, unsigned int options, struct stat *st, ULON
/* consider mount points to be reparse points (IO_REPARSE_TAG_MOUNT_POINT) */
if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, st ))
*attr |= FILE_ATTRIBUTE_REPARSE_POINT;
+ if (S_ISLNK( st->st_mode ))
+ {
+ char path[MAX_PATH];
+ ssize_t len;
+ BOOL is_dir;
+
+ if ((len = readlinkat( fd, "", path, sizeof(path))) == -1) goto done;
+ /* symbolic links (either junction points or NT symlinks) are "reparse points" */
+ *attr |= FILE_ATTRIBUTE_REPARSE_POINT;
+ /* symbolic links always report size 0 */
+ st->st_size = 0;
+ if (get_symlink_properties(path, len, NULL, NULL, NULL, NULL, &is_dir) == STATUS_SUCCESS)
+ st->st_mode = (st->st_mode & ~S_IFMT) | (is_dir ? S_IFDIR : S_IFREG);
+ }
+
+done:
return ret;
}
@@ -6037,41 +6055,22 @@ cleanup:
}
-NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, int *unix_dest_len,
- DWORD *tag, ULONG *flags, BOOL *is_dir)
+NTSTATUS get_symlink_properties(const char *target, int len, char *unix_dest, int *unix_dest_len,
+ DWORD *tag, ULONG *flags, BOOL *is_dir)
{
- int len = MAX_PATH;
+ const char *p = target;
DWORD reparse_tag;
- NTSTATUS status;
BOOL dir_flag;
- char *p, *tmp;
- ssize_t ret;
int i;
- if (unix_dest_len) len = *unix_dest_len;
- if (!unix_dest)
- tmp = malloc( len );
- else
- tmp = unix_dest;
- if ((ret = readlink( unix_src, tmp, len )) < 0)
- {
- status = errno_to_status( errno );
- goto cleanup;
- }
- len = ret;
-
/* Decode the reparse tag from the symlink */
- p = tmp;
if (*p == '.')
{
if (flags) *flags = SYMLINK_FLAG_RELATIVE;
p++;
}
if (*p++ != '/')
- {
- status = STATUS_NOT_IMPLEMENTED;
- goto cleanup;
- }
+ return STATUS_NOT_IMPLEMENTED;
reparse_tag = 0;
for (i = 0; i < sizeof(ULONG)*8; i++)
{
@@ -6083,10 +6082,7 @@ NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, int *unix_des
else if (c == '.' && *p++ == '/')
val = 1;
else
- {
- status = STATUS_NOT_IMPLEMENTED;
- goto cleanup;
- }
+ return STATUS_NOT_IMPLEMENTED;
reparse_tag |= (val << i);
}
/* skip past the directory/file flag */
@@ -6099,19 +6095,39 @@ NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, int *unix_des
else if (c == '.' && *p++ == '/')
dir_flag = TRUE;
else
- {
- status = STATUS_NOT_IMPLEMENTED;
- goto cleanup;
- }
+ return STATUS_NOT_IMPLEMENTED;
}
else
dir_flag = TRUE;
- len -= (p - tmp);
+ len -= (p - target);
if (tag) *tag = reparse_tag;
if (is_dir) *is_dir = dir_flag;
if (unix_dest) memmove(unix_dest, p, len + 1);
if (unix_dest_len) *unix_dest_len = len;
- status = STATUS_SUCCESS;
+ return STATUS_SUCCESS;
+}
+
+
+NTSTATUS FILE_DecodeSymlink(const char *unix_src, char *unix_dest, int *unix_dest_len,
+ DWORD *tag, ULONG *flags, BOOL *is_dir)
+{
+ int len = MAX_PATH;
+ NTSTATUS status;
+ ssize_t ret;
+ char *tmp;
+
+ if (unix_dest_len) len = *unix_dest_len;
+ if (!unix_dest)
+ tmp = malloc( len );
+ else
+ tmp = unix_dest;
+ if ((ret = readlink( unix_src, tmp, len )) < 0)
+ {
+ status = errno_to_status( errno );
+ goto cleanup;
+ }
+ len = ret;
+ status = get_symlink_properties(tmp, len, unix_dest, unix_dest_len, tag, flags, is_dir);
cleanup:
if (!unix_dest) free( tmp );
--
2.29.2

View File

@ -0,0 +1,66 @@
From ce9b55753298930f8efc758e7559bd0c40c88cf4 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@wine-staging.com>
Date: Wed, 25 Nov 2020 09:19:42 -0700
Subject: [PATCH] ntdll: Add support for FileAttributeTagInformation.
---
dlls/ntdll/tests/file.c | 6 ++++++
dlls/ntdll/unix/file.c | 11 ++++++++++-
2 files changed, 16 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c
index 9ee9bd4e788..ce65a14d5be 100644
--- a/dlls/ntdll/tests/file.c
+++ b/dlls/ntdll/tests/file.c
@@ -5216,6 +5216,7 @@ static void test_reparse_points(void)
static WCHAR volW[] = {'c',':','\\',0};
REPARSE_GUID_DATA_BUFFER guid_buffer;
static const WCHAR dotW[] = {'.',0};
+ FILE_ATTRIBUTE_TAG_INFORMATION info;
REPARSE_DATA_BUFFER *buffer = NULL;
DWORD dwret, dwLen, dwFlags, err;
WIN32_FILE_ATTRIBUTE_DATA fad;
@@ -5225,6 +5226,7 @@ static void test_reparse_points(void)
IO_STATUS_BLOCK iosb;
UNICODE_STRING nameW;
TOKEN_PRIVILEGES tp;
+ NTSTATUS status;
WCHAR *dest;
LUID luid;
BOOL bret;
@@ -5403,6 +5405,10 @@ static void test_reparse_points(void)
bret = ReadFile(handle, &buf, sizeof(buf), &dwLen, NULL);
ok(bret, "Failed to read data from the symlink.\n");
ok(dwLen == 0, "Length of symlink data is not zero.\n");
+ memset(&info, 0x0, sizeof(info));
+ status = pNtQueryInformationFile(handle, &iosb, &info, sizeof(info), FileAttributeTagInformation);
+ ok( status == STATUS_SUCCESS, "got %#x\n", status );
+ ok( info.ReparseTag == IO_REPARSE_TAG_SYMLINK, "got reparse tag %#x\n", info.ReparseTag );
CloseHandle(handle);
/* Check the size/data of the symlink target */
diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index 738f317e176..9cfc138209f 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -4328,7 +4328,16 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
{
FILE_ATTRIBUTE_TAG_INFORMATION *info = ptr;
info->FileAttributes = attr;
- info->ReparseTag = 0; /* FIXME */
+ info->ReparseTag = 0;
+ if (attr & FILE_ATTRIBUTE_REPARSE_POINT)
+ {
+ char path[MAX_PATH];
+ ssize_t len;
+ BOOL is_dir;
+
+ if ((len = readlinkat( fd, "", path, sizeof(path))) != -1)
+ get_symlink_properties(path, len, NULL, NULL, &info->ReparseTag, NULL, &is_dir);
+ }
if ((options & FILE_OPEN_REPARSE_POINT) && fd_is_mount_point( fd, &st ))
info->ReparseTag = IO_REPARSE_TAG_MOUNT_POINT;
}
--
2.29.2

View File

@ -2372,7 +2372,7 @@ fi
# | Modified files:
# | * configure.ac, dlls/kernel32/path.c, dlls/kernel32/tests/path.c, dlls/kernelbase/file.c, dlls/msvcp120/tests/msvcp120.c,
# | dlls/msvcp140/tests/msvcp140.c, dlls/ntdll/tests/file.c, dlls/ntdll/unix/file.c, include/Makefile.in, include/ntifs.h,
# | include/winternl.h, programs/cmd/builtins.c, programs/cmd/directory.c, server/fd.c, server/protocol.def
# | include/winternl.h, programs/cmd/builtins.c, programs/cmd/directory.c, server/fd.c, server/file.c, server/protocol.def
# |
if test "$enable_ntdll_Junction_Points" -eq 1; then
patch_apply ntdll-Junction_Points/0001-ntdll-Add-support-for-junction-point-creation.patch
@ -2398,6 +2398,12 @@ if test "$enable_ntdll_Junction_Points" -eq 1; then
patch_apply ntdll-Junction_Points/0022-wcmd-Show-reparse-point-target-in-directory-listing.patch
patch_apply ntdll-Junction_Points/0023-wcmd-Add-junction-point-support-to-mklink.patch
patch_apply ntdll-Junction_Points/0024-server-Fix-obtaining-information-about-a-symlink.patch
patch_apply ntdll-Junction_Points/0025-ntdll-Allow-set_file_times_precise-to-work-on-repars.patch
patch_apply ntdll-Junction_Points/0026-kernelbase-Convert-FILE_FLAG_OPEN_REPARSE_POINT-for-.patch
patch_apply ntdll-Junction_Points/0027-server-Implement-FILE_OPEN_REPARSE_POINT-option.patch
patch_apply ntdll-Junction_Points/0028-ntdll-Succeed-with-no-data-for-NtReadFile-on-reparse.patch
patch_apply ntdll-Junction_Points/0029-ntdll-Support-reparse-point-properties-in-fd_get_fil.patch
patch_apply ntdll-Junction_Points/0030-ntdll-Add-support-for-FileAttributeTagInformation.patch
fi
# Patchset server-PeekMessage