Alexandre Julliard : mountmgr: Add requests to query and set shell folder symbolic links.

Alexandre Julliard julliard at winehq.org
Tue Sep 7 16:25:18 CDT 2021


Module: wine
Branch: master
Commit: 0a8776d455d3f784c357c8e8bbfd2ae91581c4cd
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=0a8776d455d3f784c357c8e8bbfd2ae91581c4cd

Author: Alexandre Julliard <julliard at winehq.org>
Date:   Tue Sep  7 13:18:17 2021 +0200

mountmgr: Add requests to query and set shell folder symbolic links.

Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/mountmgr.sys/mountmgr.c | 146 +++++++++++++++++++++++++++++++++++++++++++
 include/ddk/mountmgr.h       |  13 +++-
 2 files changed, 157 insertions(+), 2 deletions(-)

diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c
index 1e018a9fc0b..2f669fcc868 100644
--- a/dlls/mountmgr.sys/mountmgr.c
+++ b/dlls/mountmgr.sys/mountmgr.c
@@ -18,6 +18,9 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#include "config.h"
+#include "wine/port.h"
+
 #ifdef __APPLE__
 #include <CoreFoundation/CFString.h>
 #define LoadResource mac_LoadResource
@@ -29,6 +32,9 @@
 
 #include <stdarg.h>
 #include <unistd.h>
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
 
 #define NONAMELESSUNION
 
@@ -286,6 +292,125 @@ static NTSTATUS define_unix_drive( const void *in_buff, SIZE_T insize )
     }
 }
 
+/* implementation of IOCTL_MOUNTMGR_DEFINE_SHELL_FOLDER */
+static NTSTATUS define_shell_folder( const void *in_buff, SIZE_T insize )
+{
+    const struct mountmgr_shell_folder *input = in_buff;
+    const char *link = NULL;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING name;
+    NTSTATUS status;
+    ULONG size = 256;
+    char *buffer, *backup = NULL;
+    struct stat st;
+    unsigned int i;
+
+    if (input->folder_offset >= insize || input->folder_size > insize - input->folder_offset ||
+        input->symlink_offset >= insize)
+        return STATUS_INVALID_PARAMETER;
+
+    /* make sure string is null-terminated */
+    if (input->symlink_offset)
+    {
+        link = (const char *)in_buff + input->symlink_offset;
+        for (i = input->symlink_offset; i < insize; i++)
+            if (!*((const char *)in_buff + i)) break;
+        if (i >= insize) return STATUS_INVALID_PARAMETER;
+        if (!link[0]) link = NULL;
+    }
+
+    /* ignore nonexistent link targets */
+    if (link && stat( link, &st )) return STATUS_OBJECT_NAME_NOT_FOUND;
+
+    name.Buffer = (WCHAR *)((char *)in_buff + input->folder_offset);
+    name.Length = input->folder_size;
+    InitializeObjectAttributes( &attr, &name, 0, 0, NULL );
+
+    for (;;)
+    {
+        if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
+        status = wine_nt_to_unix_file_name( &attr, buffer, &size, FILE_OPEN );
+        if (!status) break;
+        HeapFree( GetProcessHeap(), 0, buffer );
+        if (status != STATUS_BUFFER_TOO_SMALL) return status;
+    }
+
+    if (!(backup = HeapAlloc( GetProcessHeap(), 0, strlen(buffer) + sizeof(".backup" ) )))
+    {
+        status = STATUS_NO_MEMORY;
+        goto done;
+    }
+    strcpy( backup, buffer );
+    strcat( backup, ".backup" );
+
+    if (!lstat( buffer, &st )) /* move old folder/link out of the way */
+    {
+        if (S_ISLNK( st.st_mode ))
+        {
+            unlink( buffer );
+        }
+        else if (link && S_ISDIR( st.st_mode ))
+        {
+            if (rmdir( buffer ))  /* non-empty dir, try to make a backup */
+            {
+                if (!backup || rename( buffer, backup ))
+                {
+                    status = STATUS_OBJECT_NAME_COLLISION;
+                    goto done;
+                }
+            }
+        }
+        else goto done; /* nothing to do, folder already exists */
+    }
+
+    if (link) symlink( link, buffer );
+    else
+    {
+        if (backup && !lstat( backup, &st ) && S_ISDIR( st.st_mode )) rename( backup, buffer );
+        else mkdir( buffer, 0777 );
+    }
+
+done:
+    HeapFree( GetProcessHeap(), 0, buffer );
+    HeapFree( GetProcessHeap(), 0, backup );
+    return status;
+}
+
+/* implementation of IOCTL_MOUNTMGR_QUERY_SHELL_FOLDER */
+static NTSTATUS query_shell_folder( void *buff, SIZE_T insize, SIZE_T outsize, IO_STATUS_BLOCK *iosb )
+{
+    char *output = buff;
+    OBJECT_ATTRIBUTES attr;
+    UNICODE_STRING name;
+    NTSTATUS status;
+    ULONG size = 256;
+    char *buffer;
+    int ret;
+
+    name.Buffer = buff;
+    name.Length = insize;
+    InitializeObjectAttributes( &attr, &name, 0, 0, NULL );
+
+    for (;;)
+    {
+        if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
+        status = wine_nt_to_unix_file_name( &attr, buffer, &size, FILE_OPEN );
+        if (!status) break;
+        HeapFree( GetProcessHeap(), 0, buffer );
+        if (status != STATUS_BUFFER_TOO_SMALL) return status;
+    }
+    ret = readlink( buffer, output, outsize - 1 );
+    if (ret >= 0)
+    {
+        output[ret] = 0;
+        iosb->Information = ret + 1;
+    }
+    else status = STATUS_OBJECT_NAME_NOT_FOUND;
+
+    HeapFree( GetProcessHeap(), 0, buffer );
+    return status;
+}
+
 /* implementation of IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS */
 static void WINAPI query_dhcp_request_params( TP_CALLBACK_INSTANCE *instance, void *context )
 {
@@ -934,6 +1059,27 @@ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
                                    irpsp->Parameters.DeviceIoControl.OutputBufferLength,
                                    &irp->IoStatus );
         break;
+    case IOCTL_MOUNTMGR_DEFINE_SHELL_FOLDER:
+        if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_shell_folder))
+        {
+            status = STATUS_INVALID_PARAMETER;
+            break;
+        }
+        irp->IoStatus.Information = 0;
+        status = define_shell_folder( irp->AssociatedIrp.SystemBuffer,
+                                      irpsp->Parameters.DeviceIoControl.InputBufferLength );
+        break;
+    case IOCTL_MOUNTMGR_QUERY_SHELL_FOLDER:
+        if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_shell_folder))
+        {
+            status = STATUS_INVALID_PARAMETER;
+            break;
+        }
+        status = query_shell_folder( irp->AssociatedIrp.SystemBuffer,
+                                     irpsp->Parameters.DeviceIoControl.InputBufferLength,
+                                     irpsp->Parameters.DeviceIoControl.OutputBufferLength,
+                                     &irp->IoStatus );
+        break;
     case IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS:
         if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_dhcp_request_params))
         {
diff --git a/include/ddk/mountmgr.h b/include/ddk/mountmgr.h
index 6cf870f4f34..3c82e03ea36 100644
--- a/include/ddk/mountmgr.h
+++ b/include/ddk/mountmgr.h
@@ -51,8 +51,10 @@ static const WCHAR MOUNTMGR_DOS_DEVICE_NAME[] = {'\\','\\','.','\\','M','o','u',
 /* Wine extensions */
 #ifdef WINE_MOUNTMGR_EXTENSIONS
 
-#define IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE CTL_CODE(MOUNTMGRCONTROLTYPE, 32, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
-#define IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE  CTL_CODE(MOUNTMGRCONTROLTYPE, 33, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE   CTL_CODE(MOUNTMGRCONTROLTYPE, 32, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE    CTL_CODE(MOUNTMGRCONTROLTYPE, 33, METHOD_BUFFERED, FILE_READ_ACCESS)
+#define IOCTL_MOUNTMGR_DEFINE_SHELL_FOLDER CTL_CODE(MOUNTMGRCONTROLTYPE, 34, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#define IOCTL_MOUNTMGR_QUERY_SHELL_FOLDER  CTL_CODE(MOUNTMGRCONTROLTYPE, 35, METHOD_BUFFERED, FILE_READ_ACCESS)
 
 enum mountmgr_fs_type
 {
@@ -76,6 +78,13 @@ struct mountmgr_unix_drive
     USHORT    label_offset;
 };
 
+struct mountmgr_shell_folder
+{
+    ULONG    folder_offset;
+    ULONG    folder_size;
+    ULONG    symlink_offset;
+};
+
 #define IOCTL_MOUNTMGR_READ_CREDENTIAL       CTL_CODE(MOUNTMGRCONTROLTYPE, 48, METHOD_BUFFERED, FILE_READ_ACCESS)
 #define IOCTL_MOUNTMGR_WRITE_CREDENTIAL      CTL_CODE(MOUNTMGRCONTROLTYPE, 49, METHOD_BUFFERED, FILE_WRITE_ACCESS)
 #define IOCTL_MOUNTMGR_DELETE_CREDENTIAL     CTL_CODE(MOUNTMGRCONTROLTYPE, 50, METHOD_BUFFERED, FILE_WRITE_ACCESS)




More information about the wine-cvs mailing list