From 7a25fabadf15c7514dec080502df19595249a3f6 Mon Sep 17 00:00:00 2001
From: "Erich E. Hoover" <erich.e.hoover@gmail.com>
Date: Sat, 18 Jul 2020 09:13:29 -0600
Subject: server: Fix obtaining information about a symlink.

Signed-off-by: Erich E. Hoover <erich.e.hoover@gmail.com>
---
 dlls/ntdll/unix/file.c | 19 ++++++++++---------
 server/fd.c            |  7 ++++---
 server/protocol.def    |  1 +
 3 files changed, 15 insertions(+), 12 deletions(-)

diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c
index a7dc12f0a3e..b507d575766 100644
--- a/dlls/ntdll/unix/file.c
+++ b/dlls/ntdll/unix/file.c
@@ -1775,7 +1775,7 @@ static NTSTATUS fill_file_info( const struct stat *st, ULONG attr, void *ptr,
 }
 
 
-static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name )
+static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name, BOOL nofollow )
 {
     data_size_t size = 1024;
     NTSTATUS ret;
@@ -1788,6 +1788,7 @@ static NTSTATUS server_get_unix_name( HANDLE handle, char **unix_name )
         SERVER_START_REQ( get_handle_unix_name )
         {
             req->handle = wine_server_obj_handle( handle );
+            req->nofollow = nofollow;
             wine_server_set_reply( req, name, size );
             ret = wine_server_call( req );
             size = reply->name_len;
@@ -1962,7 +1963,7 @@ static NTSTATUS get_mountmgr_fs_info( HANDLE handle, int fd, struct mountmgr_uni
     NTSTATUS status;
     int letter;
 
-    if ((status = server_get_unix_name( handle, &unix_name ))) return status;
+    if ((status = server_get_unix_name( handle, &unix_name, FALSE ))) return status;
     letter = find_dos_device( unix_name );
     free( unix_name );
 
@@ -3973,7 +3974,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
             if (fd_get_file_info( fd, options, &st, &attr ) == -1) io->u.Status = errno_to_status( errno );
             else if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode))
                 io->u.Status = STATUS_INVALID_INFO_CLASS;
-            else if (!(io->u.Status = server_get_unix_name( handle, &unix_name )))
+            else if (!(io->u.Status = server_get_unix_name( handle, &unix_name, FALSE )))
             {
                 LONG name_len = len - FIELD_OFFSET(FILE_ALL_INFORMATION, NameInformation.FileName);
 
@@ -4034,7 +4035,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
             FILE_NAME_INFORMATION *info = ptr;
             char *unix_name;
 
-            if (!(io->u.Status = server_get_unix_name( handle, &unix_name )))
+            if (!(io->u.Status = server_get_unix_name( handle, &unix_name, FALSE )))
             {
                 LONG name_len = len - FIELD_OFFSET(FILE_NAME_INFORMATION, FileName);
                 io->u.Status = fill_name_info( unix_name, info, &name_len );
@@ -4048,7 +4049,7 @@ NTSTATUS WINAPI NtQueryInformationFile( HANDLE handle, IO_STATUS_BLOCK *io,
             FILE_NETWORK_OPEN_INFORMATION *info = ptr;
             char *unix_name;
 
-            if (!(io->u.Status = server_get_unix_name( handle, &unix_name )))
+            if (!(io->u.Status = server_get_unix_name( handle, &unix_name, FALSE )))
             {
                 ULONG attributes;
                 struct stat st;
@@ -5661,7 +5662,7 @@ NTSTATUS FILE_CreateSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer)
     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_src )))
+    if ((status = server_get_unix_name( handle, &unix_src, FALSE )))
         goto cleanup;
     src_allocated = TRUE;
     if (flags == SYMLINK_FLAG_RELATIVE)
@@ -5940,7 +5941,7 @@ NTSTATUS FILE_GetSymlink(HANDLE handle, REPARSE_DATA_BUFFER *buffer, ULONG out_s
     if ((status = server_get_unix_fd( handle, FILE_ANY_ACCESS, &dest_fd, &needs_close, NULL, NULL )))
         return status;
 
-    if ((status = server_get_unix_name( handle, &unix_src )))
+    if ((status = server_get_unix_name( handle, &unix_src, TRUE )))
         goto cleanup;
 
     if ((status = FILE_DecodeSymlink( unix_src, unix_dest, &unix_dest_len, &buffer->ReparseTag, &flags, NULL )))
@@ -6078,7 +6079,7 @@ NTSTATUS FILE_RemoveSymlink(HANDLE handle, REPARSE_GUID_DATA_BUFFER *buffer)
     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 )))
+    if ((status = server_get_unix_name( handle, &unix_name, TRUE )))
         goto cleanup;
 
     TRACE( "Deleting symlink %s\n", unix_name );
@@ -7104,7 +7105,7 @@ NTSTATUS WINAPI NtQueryObject( HANDLE handle, OBJECT_INFORMATION_CLASS info_clas
 
         /* first try as a file object */
 
-        if (!(status = server_get_unix_name( handle, &unix_name )))
+        if (!(status = server_get_unix_name( handle, &unix_name, FALSE )))
         {
             if (!(status = unix_to_nt_file_name( unix_name, &nt_name )))
             {
diff --git a/server/fd.c b/server/fd.c
index 03966cd3067..100c3865126 100644
--- a/server/fd.c
+++ b/server/fd.c
@@ -2729,11 +2729,12 @@ DECL_HANDLER(get_handle_unix_name)
 
     if ((fd = get_handle_fd_obj( current->process, req->handle, 0 )))
     {
-        if (fd->unix_name)
+        char *name = (req->nofollow ? fd->unlink_name : fd->unix_name);
+        if (name)
         {
-            data_size_t name_len = strlen( fd->unix_name );
+            data_size_t name_len = strlen( name );
             reply->name_len = name_len;
-            if (name_len <= get_reply_max_size()) set_reply_data( fd->unix_name, name_len );
+            if (name_len <= get_reply_max_size()) set_reply_data( name, name_len );
             else set_error( STATUS_BUFFER_OVERFLOW );
         }
         else set_error( STATUS_OBJECT_TYPE_MISMATCH );
diff --git a/server/protocol.def b/server/protocol.def
index a121c371c19..faf4891a01e 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1297,6 +1297,7 @@ enum event_op { PULSE_EVENT, SET_EVENT, RESET_EVENT };
 /* Get the Unix name from a file handle */
 @REQ(get_handle_unix_name)
     obj_handle_t   handle;      /* file handle */
+    int            nofollow;    /* do not follow symlinks (return the link) */
 @REPLY
     data_size_t    name_len;    /* unix name length */
     VARARG(name,string);        /* unix name */
-- 
2.17.1

