Module: wine Branch: master Commit: 0a8776d455d3f784c357c8e8bbfd2ae91581c4cd URL: https://source.winehq.org/git/wine.git/?a=commit;h=0a8776d455d3f784c357c8e8b...
Author: Alexandre Julliard julliard@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@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)