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