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

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Alexandre Julliard 2021-09-07 13:18:17 +02:00
parent fa6e791ca5
commit 0a8776d455
2 changed files with 157 additions and 2 deletions

View file

@ -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))
{

View file

@ -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)