ntdll: Rename local variables in heap_reallocate.
[wine.git] / dlls / mountmgr.sys / mountmgr.c
blob66034621b446387d21c002e69b944ee10413edd1
1 /*
2 * Mount manager service implementation
4 * Copyright 2008 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
22 #include <stdlib.h>
24 #define NONAMELESSUNION
26 #include "mountmgr.h"
27 #include "winreg.h"
28 #include "unixlib.h"
29 #include "wine/list.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
34 #define MIN_ID_LEN 4
36 struct mount_point
38 struct list entry; /* entry in mount points list */
39 DEVICE_OBJECT *device; /* disk device */
40 UNICODE_STRING name; /* device name */
41 UNICODE_STRING link; /* DOS device symlink */
42 void *id; /* device unique id */
43 unsigned int id_len;
46 static struct list mount_points_list = LIST_INIT(mount_points_list);
47 static HKEY mount_key;
49 unixlib_handle_t mountmgr_handle = 0;
51 void set_mount_point_id( struct mount_point *mount, const void *id, unsigned int id_len )
53 RtlFreeHeap( GetProcessHeap(), 0, mount->id );
54 mount->id_len = max( MIN_ID_LEN, id_len );
55 if ((mount->id = RtlAllocateHeap( GetProcessHeap(), HEAP_ZERO_MEMORY, mount->id_len )))
57 memcpy( mount->id, id, id_len );
58 RegSetValueExW( mount_key, mount->link.Buffer, 0, REG_BINARY, mount->id, mount->id_len );
60 else mount->id_len = 0;
63 static struct mount_point *add_mount_point( DEVICE_OBJECT *device, UNICODE_STRING *device_name,
64 const WCHAR *link )
66 struct mount_point *mount;
67 WCHAR *str;
68 UINT len = (lstrlenW(link) + 1) * sizeof(WCHAR) + device_name->Length + sizeof(WCHAR);
70 if (!(mount = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*mount) + len ))) return NULL;
72 str = (WCHAR *)(mount + 1);
73 lstrcpyW( str, link );
74 RtlInitUnicodeString( &mount->link, str );
75 str += lstrlenW(str) + 1;
76 memcpy( str, device_name->Buffer, device_name->Length );
77 str[device_name->Length / sizeof(WCHAR)] = 0;
78 mount->name.Buffer = str;
79 mount->name.Length = device_name->Length;
80 mount->name.MaximumLength = device_name->Length + sizeof(WCHAR);
81 mount->device = device;
82 mount->id = NULL;
83 list_add_tail( &mount_points_list, &mount->entry );
85 IoCreateSymbolicLink( &mount->link, device_name );
87 TRACE( "created %s id %s for %s\n", debugstr_w(mount->link.Buffer),
88 debugstr_a(mount->id), debugstr_w(mount->name.Buffer) );
89 return mount;
92 /* create the DosDevices mount point symlink for a new device */
93 struct mount_point *add_dosdev_mount_point( DEVICE_OBJECT *device, UNICODE_STRING *device_name, int drive )
95 WCHAR link[] = L"\\DosDevices\\A:";
97 link[12] = 'A' + drive;
98 return add_mount_point( device, device_name, link );
101 /* create the Volume mount point symlink for a new device */
102 struct mount_point *add_volume_mount_point( DEVICE_OBJECT *device, UNICODE_STRING *device_name,
103 const GUID *guid )
105 WCHAR link[64];
107 swprintf( link, ARRAY_SIZE(link), L"\\??\\Volume{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
108 guid->Data1, guid->Data2, guid->Data3,
109 guid->Data4[0], guid->Data4[1], guid->Data4[2], guid->Data4[3],
110 guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
111 return add_mount_point( device, device_name, link );
114 /* delete the mount point symlinks when a device goes away */
115 void delete_mount_point( struct mount_point *mount )
117 TRACE( "deleting %s\n", debugstr_w(mount->link.Buffer) );
118 list_remove( &mount->entry );
119 RegDeleteValueW( mount_key, mount->link.Buffer );
120 IoDeleteSymbolicLink( &mount->link );
121 RtlFreeHeap( GetProcessHeap(), 0, mount->id );
122 RtlFreeHeap( GetProcessHeap(), 0, mount );
125 /* check if a given mount point matches the requested specs */
126 static BOOL matching_mount_point( const struct mount_point *mount, const MOUNTMGR_MOUNT_POINT *spec )
128 if (spec->SymbolicLinkNameOffset)
130 const WCHAR *name = (const WCHAR *)((const char *)spec + spec->SymbolicLinkNameOffset);
131 if (spec->SymbolicLinkNameLength != mount->link.Length) return FALSE;
132 if (wcsnicmp( name, mount->link.Buffer, mount->link.Length/sizeof(WCHAR)))
133 return FALSE;
135 if (spec->DeviceNameOffset)
137 const WCHAR *name = (const WCHAR *)((const char *)spec + spec->DeviceNameOffset);
138 if (spec->DeviceNameLength != mount->name.Length) return FALSE;
139 if (wcsnicmp( name, mount->name.Buffer, mount->name.Length/sizeof(WCHAR)))
140 return FALSE;
142 if (spec->UniqueIdOffset)
144 const void *id = ((const char *)spec + spec->UniqueIdOffset);
145 if (spec->UniqueIdLength != mount->id_len) return FALSE;
146 if (memcmp( id, mount->id, mount->id_len )) return FALSE;
148 return TRUE;
151 /* implementation of IOCTL_MOUNTMGR_QUERY_POINTS */
152 static NTSTATUS query_mount_points( void *buff, SIZE_T insize,
153 SIZE_T outsize, IO_STATUS_BLOCK *iosb )
155 UINT count, pos, size;
156 MOUNTMGR_MOUNT_POINT *input = buff;
157 MOUNTMGR_MOUNT_POINTS *info;
158 struct mount_point *mount;
160 if (insize < sizeof(*input) ||
161 outsize < sizeof(*info) ||
162 input->SymbolicLinkNameOffset + input->SymbolicLinkNameLength > insize ||
163 input->UniqueIdOffset + input->UniqueIdLength > insize ||
164 input->DeviceNameOffset + input->DeviceNameLength > insize ||
165 input->SymbolicLinkNameOffset + input->SymbolicLinkNameLength < input->SymbolicLinkNameOffset ||
166 input->UniqueIdOffset + input->UniqueIdLength < input->UniqueIdOffset ||
167 input->DeviceNameOffset + input->DeviceNameLength < input->DeviceNameOffset)
168 return STATUS_INVALID_PARAMETER;
170 count = size = 0;
171 LIST_FOR_EACH_ENTRY( mount, &mount_points_list, struct mount_point, entry )
173 if (!matching_mount_point( mount, input )) continue;
174 size += mount->name.Length;
175 size += mount->link.Length;
176 size += mount->id_len;
177 size = (size + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
178 count++;
180 pos = FIELD_OFFSET( MOUNTMGR_MOUNT_POINTS, MountPoints[count] );
181 size += pos;
183 if (size > outsize)
185 info = buff;
186 info->Size = size;
187 iosb->Information = sizeof(info->Size);
188 return STATUS_BUFFER_OVERFLOW;
191 input = HeapAlloc( GetProcessHeap(), 0, insize );
192 if (!input)
193 return STATUS_NO_MEMORY;
194 memcpy( input, buff, insize );
195 info = buff;
197 info->NumberOfMountPoints = count;
198 count = 0;
199 LIST_FOR_EACH_ENTRY( mount, &mount_points_list, struct mount_point, entry )
201 if (!matching_mount_point( mount, input )) continue;
203 info->MountPoints[count].DeviceNameOffset = pos;
204 info->MountPoints[count].DeviceNameLength = mount->name.Length;
205 memcpy( (char *)buff + pos, mount->name.Buffer, mount->name.Length );
206 pos += mount->name.Length;
208 info->MountPoints[count].SymbolicLinkNameOffset = pos;
209 info->MountPoints[count].SymbolicLinkNameLength = mount->link.Length;
210 memcpy( (char *)buff + pos, mount->link.Buffer, mount->link.Length );
211 pos += mount->link.Length;
213 info->MountPoints[count].UniqueIdOffset = pos;
214 info->MountPoints[count].UniqueIdLength = mount->id_len;
215 memcpy( (char *)buff + pos, mount->id, mount->id_len );
216 pos += mount->id_len;
217 pos = (pos + sizeof(WCHAR) - 1) & ~(sizeof(WCHAR) - 1);
218 count++;
220 info->Size = pos;
221 iosb->Information = pos;
222 HeapFree( GetProcessHeap(), 0, input );
223 return STATUS_SUCCESS;
226 /* implementation of IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE */
227 static NTSTATUS define_unix_drive( const void *in_buff, SIZE_T insize )
229 const struct mountmgr_unix_drive *input = in_buff;
230 const char *mount_point = NULL, *device = NULL;
231 WCHAR letter = towlower( input->letter );
233 if (letter < 'a' || letter > 'z') return STATUS_INVALID_PARAMETER;
234 if (input->type > DRIVE_RAMDISK) return STATUS_INVALID_PARAMETER;
235 if (input->mount_point_offset > insize || input->device_offset > insize)
236 return STATUS_INVALID_PARAMETER;
238 /* make sure string are null-terminated */
239 if (input->mount_point_offset)
241 mount_point = (const char *)in_buff + input->mount_point_offset;
242 if (!memchr( mount_point, 0, insize - input->mount_point_offset )) return STATUS_INVALID_PARAMETER;
244 if (input->device_offset)
246 device = (const char *)in_buff + input->device_offset;
247 if (!memchr( device, 0, insize - input->device_offset )) return STATUS_INVALID_PARAMETER;
250 if (input->type != DRIVE_NO_ROOT_DIR)
252 enum device_type type = DEVICE_UNKNOWN;
254 TRACE( "defining %c: dev %s mount %s type %lu\n",
255 letter, debugstr_a(device), debugstr_a(mount_point), input->type );
256 switch (input->type)
258 case DRIVE_REMOVABLE: type = (letter >= 'c') ? DEVICE_HARDDISK : DEVICE_FLOPPY; break;
259 case DRIVE_REMOTE: type = DEVICE_NETWORK; break;
260 case DRIVE_CDROM: type = DEVICE_CDROM; break;
261 case DRIVE_RAMDISK: type = DEVICE_RAMDISK; break;
262 case DRIVE_FIXED: type = DEVICE_HARDDISK_VOL; break;
264 return add_dos_device( letter - 'a', NULL, device, mount_point, type, NULL, NULL );
266 else
268 TRACE( "removing %c:\n", letter );
269 return remove_dos_device( letter - 'a', NULL );
273 /* implementation of IOCTL_MOUNTMGR_DEFINE_SHELL_FOLDER */
274 static NTSTATUS define_shell_folder( const void *in_buff, SIZE_T insize )
276 const struct mountmgr_shell_folder *input = in_buff;
277 const char *link = NULL;
278 OBJECT_ATTRIBUTES attr;
279 UNICODE_STRING name;
280 NTSTATUS status;
281 ULONG size = 256;
282 char *buffer = NULL, *backup = NULL;
283 struct set_shell_folder_params params;
285 if (input->folder_offset >= insize || input->folder_size > insize - input->folder_offset ||
286 input->symlink_offset >= insize)
287 return STATUS_INVALID_PARAMETER;
289 /* make sure string is null-terminated */
290 if (input->symlink_offset)
292 link = (const char *)in_buff + input->symlink_offset;
293 if (!memchr( link, 0, insize - input->symlink_offset )) return STATUS_INVALID_PARAMETER;
294 if (!link[0]) link = NULL;
297 name.Buffer = (WCHAR *)((char *)in_buff + input->folder_offset);
298 name.Length = input->folder_size;
299 InitializeObjectAttributes( &attr, &name, 0, 0, NULL );
301 for (;;)
303 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size )))
305 status = STATUS_NO_MEMORY;
306 goto done;
308 status = wine_nt_to_unix_file_name( &attr, buffer, &size, FILE_OPEN_IF );
309 if (status == STATUS_NO_SUCH_FILE) status = STATUS_SUCCESS;
310 if (status == STATUS_SUCCESS) break;
311 if (status != STATUS_BUFFER_TOO_SMALL) goto done;
312 HeapFree( GetProcessHeap(), 0, buffer );
315 if (input->create_backup)
317 if (!(backup = HeapAlloc( GetProcessHeap(), 0, strlen(buffer) + sizeof(".backup" ) )))
319 status = STATUS_NO_MEMORY;
320 goto done;
322 strcpy( backup, buffer );
323 strcat( backup, ".backup" );
326 params.folder = buffer;
327 params.backup = backup;
328 params.link = link;
329 status = MOUNTMGR_CALL( set_shell_folder, &params );
331 done:
332 HeapFree( GetProcessHeap(), 0, buffer );
333 HeapFree( GetProcessHeap(), 0, backup );
334 return status;
337 /* implementation of IOCTL_MOUNTMGR_QUERY_SHELL_FOLDER */
338 static NTSTATUS query_shell_folder( void *buff, SIZE_T insize, SIZE_T outsize, IO_STATUS_BLOCK *iosb )
340 char *output = buff;
341 OBJECT_ATTRIBUTES attr;
342 UNICODE_STRING name;
343 NTSTATUS status;
344 ULONG size = 256;
345 char *buffer;
347 name.Buffer = buff;
348 name.Length = insize;
349 InitializeObjectAttributes( &attr, &name, 0, 0, NULL );
351 for (;;)
353 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, size ))) return STATUS_NO_MEMORY;
354 status = wine_nt_to_unix_file_name( &attr, buffer, &size, FILE_OPEN );
355 if (!status)
357 struct get_shell_folder_params params = { buffer, output, outsize };
358 status = MOUNTMGR_CALL( get_shell_folder, &params );
359 if (!status) iosb->Information = strlen(output) + 1;
360 break;
362 if (status != STATUS_BUFFER_TOO_SMALL) break;
363 HeapFree( GetProcessHeap(), 0, buffer );
366 HeapFree( GetProcessHeap(), 0, buffer );
367 return status;
370 /* implementation of IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS */
371 static void WINAPI query_dhcp_request_params( TP_CALLBACK_INSTANCE *instance, void *context )
373 IRP *irp = context;
374 struct mountmgr_dhcp_request_params *query = irp->AssociatedIrp.SystemBuffer;
375 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
376 SIZE_T insize = irpsp->Parameters.DeviceIoControl.InputBufferLength;
377 SIZE_T outsize = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
378 ULONG i, offset = 0;
380 /* sanity checks */
381 if (FIELD_OFFSET(struct mountmgr_dhcp_request_params, params[query->count]) > insize)
383 irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
384 goto err;
387 for (i = 0; i < query->count; i++)
388 if (query->params[i].offset + query->params[i].size > insize)
390 irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
391 goto err;
394 if (!memchr( query->unix_name, 0, sizeof(query->unix_name) ))
396 irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
397 goto err;
400 offset = FIELD_OFFSET(struct mountmgr_dhcp_request_params, params[query->count]);
401 for (i = 0; i < query->count; i++)
403 ULONG ret_size;
404 struct dhcp_request_params params = { query->unix_name, &query->params[i],
405 (char *)query, offset, outsize - offset, &ret_size };
406 MOUNTMGR_CALL( dhcp_request, &params );
407 offset += ret_size;
408 if (offset > outsize)
410 if (offset >= sizeof(query->size)) query->size = offset;
411 offset = sizeof(query->size);
412 irp->IoStatus.u.Status = STATUS_BUFFER_OVERFLOW;
413 goto err;
416 irp->IoStatus.u.Status = STATUS_SUCCESS;
418 err:
419 irp->IoStatus.Information = offset;
420 IoCompleteRequest( irp, IO_NO_INCREMENT );
423 static void WINAPI query_symbol_file_callback( TP_CALLBACK_INSTANCE *instance, void *context )
425 IRP *irp = context;
426 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
427 ULONG info = 0;
428 struct ioctl_params params = { irp->AssociatedIrp.SystemBuffer,
429 irpsp->Parameters.DeviceIoControl.InputBufferLength,
430 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
431 &info };
432 NTSTATUS status = MOUNTMGR_CALL( query_symbol_file, &params );
434 irp->IoStatus.Information = info;
435 irp->IoStatus.u.Status = status;
436 IoCompleteRequest( irp, IO_NO_INCREMENT );
439 /* NT APC called from Unix side to add/remove devices */
440 static void CALLBACK device_op( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
442 struct device_info info;
443 struct dequeue_device_op_params params = { arg1, &info };
445 if (MOUNTMGR_CALL( dequeue_device_op, &params )) return;
447 switch (info.op)
449 case ADD_DOS_DEVICE:
450 add_dos_device( -1, info.udi, info.device, info.mount_point,
451 info.type, info.guid, info.scsi_info );
452 break;
453 case ADD_VOLUME:
454 add_volume( info.udi, info.device, info.mount_point, DEVICE_HARDDISK_VOL,
455 info.guid, info.serial, info.scsi_info );
456 break;
457 case REMOVE_DEVICE:
458 if (!remove_dos_device( -1, info.udi )) remove_volume( info.udi );
459 break;
463 /* handler for ioctls on the mount manager device */
464 static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
466 IO_STACK_LOCATION *irpsp = IoGetCurrentIrpStackLocation( irp );
467 NTSTATUS status;
468 ULONG info = 0;
470 TRACE( "ioctl %lx insize %lu outsize %lu\n",
471 irpsp->Parameters.DeviceIoControl.IoControlCode,
472 irpsp->Parameters.DeviceIoControl.InputBufferLength,
473 irpsp->Parameters.DeviceIoControl.OutputBufferLength );
475 switch(irpsp->Parameters.DeviceIoControl.IoControlCode)
477 case IOCTL_MOUNTMGR_QUERY_POINTS:
478 status = query_mount_points( irp->AssociatedIrp.SystemBuffer,
479 irpsp->Parameters.DeviceIoControl.InputBufferLength,
480 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
481 &irp->IoStatus );
482 break;
483 case IOCTL_MOUNTMGR_DEFINE_UNIX_DRIVE:
484 if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_unix_drive))
486 status = STATUS_INVALID_PARAMETER;
487 break;
489 irp->IoStatus.Information = 0;
490 status = define_unix_drive( irp->AssociatedIrp.SystemBuffer,
491 irpsp->Parameters.DeviceIoControl.InputBufferLength );
492 break;
493 case IOCTL_MOUNTMGR_QUERY_UNIX_DRIVE:
494 if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_unix_drive))
496 status = STATUS_INVALID_PARAMETER;
497 break;
499 status = query_unix_drive( irp->AssociatedIrp.SystemBuffer,
500 irpsp->Parameters.DeviceIoControl.InputBufferLength,
501 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
502 &irp->IoStatus );
503 break;
504 case IOCTL_MOUNTMGR_DEFINE_SHELL_FOLDER:
505 if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_shell_folder))
507 status = STATUS_INVALID_PARAMETER;
508 break;
510 irp->IoStatus.Information = 0;
511 status = define_shell_folder( irp->AssociatedIrp.SystemBuffer,
512 irpsp->Parameters.DeviceIoControl.InputBufferLength );
513 break;
514 case IOCTL_MOUNTMGR_QUERY_SHELL_FOLDER:
515 if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_shell_folder))
517 status = STATUS_INVALID_PARAMETER;
518 break;
520 status = query_shell_folder( irp->AssociatedIrp.SystemBuffer,
521 irpsp->Parameters.DeviceIoControl.InputBufferLength,
522 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
523 &irp->IoStatus );
524 break;
525 case IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS:
526 if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_dhcp_request_params))
528 status = STATUS_INVALID_PARAMETER;
529 break;
532 if (TrySubmitThreadpoolCallback( query_dhcp_request_params, irp, NULL ))
533 return (irp->IoStatus.u.Status = STATUS_PENDING);
534 status = STATUS_NO_MEMORY;
535 break;
536 case IOCTL_MOUNTMGR_QUERY_SYMBOL_FILE:
537 if (irpsp->Parameters.DeviceIoControl.InputBufferLength != sizeof(GUID))
539 status = STATUS_INVALID_PARAMETER;
540 break;
542 if (TrySubmitThreadpoolCallback( query_symbol_file_callback, irp, NULL ))
543 return (irp->IoStatus.u.Status = STATUS_PENDING);
544 status = STATUS_NO_MEMORY;
545 break;
546 case IOCTL_MOUNTMGR_READ_CREDENTIAL:
547 if (irpsp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(struct mountmgr_credential))
549 struct ioctl_params params = { irp->AssociatedIrp.SystemBuffer,
550 irpsp->Parameters.DeviceIoControl.InputBufferLength,
551 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
552 &info };
553 status = MOUNTMGR_CALL( read_credential, &params );
554 irp->IoStatus.Information = info;
556 else status = STATUS_INVALID_PARAMETER;
557 break;
558 case IOCTL_MOUNTMGR_WRITE_CREDENTIAL:
559 if (irpsp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(struct mountmgr_credential))
561 struct ioctl_params params = { irp->AssociatedIrp.SystemBuffer,
562 irpsp->Parameters.DeviceIoControl.InputBufferLength,
563 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
564 &info };
565 status = MOUNTMGR_CALL( write_credential, &params );
566 irp->IoStatus.Information = info;
568 else status = STATUS_INVALID_PARAMETER;
569 break;
570 case IOCTL_MOUNTMGR_DELETE_CREDENTIAL:
571 if (irpsp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(struct mountmgr_credential))
573 struct ioctl_params params = { irp->AssociatedIrp.SystemBuffer,
574 irpsp->Parameters.DeviceIoControl.InputBufferLength,
575 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
576 &info };
577 status = MOUNTMGR_CALL( delete_credential, &params );
578 irp->IoStatus.Information = info;
580 else status = STATUS_INVALID_PARAMETER;
581 break;
582 case IOCTL_MOUNTMGR_ENUMERATE_CREDENTIALS:
583 if (irpsp->Parameters.DeviceIoControl.InputBufferLength >= sizeof(struct mountmgr_credential))
585 struct ioctl_params params = { irp->AssociatedIrp.SystemBuffer,
586 irpsp->Parameters.DeviceIoControl.InputBufferLength,
587 irpsp->Parameters.DeviceIoControl.OutputBufferLength,
588 &info };
589 status = MOUNTMGR_CALL( enumerate_credentials, &params );
590 irp->IoStatus.Information = info;
592 else status = STATUS_INVALID_PARAMETER;
593 break;
594 default:
595 FIXME( "ioctl %lx not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
596 status = STATUS_NOT_SUPPORTED;
597 break;
599 irp->IoStatus.u.Status = status;
600 IoCompleteRequest( irp, IO_NO_INCREMENT );
601 return status;
604 static DWORD WINAPI device_op_thread( void *arg )
606 for (;;) SleepEx( INFINITE, TRUE ); /* wait for APCs */
607 return 0;
610 static DWORD WINAPI run_loop_thread( void *arg )
612 struct run_loop_params params = {.op_thread = arg, .op_apc = device_op};
613 return MOUNTMGR_CALL( run_loop, &params );
617 /* main entry point for the mount point manager driver */
618 NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
620 #ifdef _WIN64
621 HKEY wow64_ports_key = NULL;
622 #endif
623 void *instance;
624 UNICODE_STRING nameW, linkW;
625 DEVICE_OBJECT *device;
626 HKEY devicemap_key;
627 NTSTATUS status;
628 HANDLE thread;
630 TRACE( "%s\n", debugstr_w(path->Buffer) );
632 RtlPcToFileHeader( DriverEntry, &instance );
633 status = NtQueryVirtualMemory( GetCurrentProcess(), instance, MemoryWineUnixFuncs,
634 &mountmgr_handle, sizeof(mountmgr_handle), NULL );
635 if (status) return status;
637 driver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = mountmgr_ioctl;
639 RtlInitUnicodeString( &nameW, L"\\Device\\MountPointManager" );
640 RtlInitUnicodeString( &linkW, L"\\??\\MountPointManager" );
641 if (!(status = IoCreateDevice( driver, 0, &nameW, 0, 0, FALSE, &device )))
642 status = IoCreateSymbolicLink( &linkW, &nameW );
643 if (status)
645 FIXME( "failed to create device error %lx\n", status );
646 return status;
649 RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"System\\MountedDevices", 0, NULL,
650 REG_OPTION_VOLATILE, KEY_ALL_ACCESS, NULL, &mount_key, NULL );
652 if (!RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"HARDWARE\\DEVICEMAP\\Scsi", 0, NULL, REG_OPTION_VOLATILE,
653 KEY_ALL_ACCESS, NULL, &devicemap_key, NULL ))
654 RegCloseKey( devicemap_key );
656 RtlInitUnicodeString( &nameW, L"\\Driver\\Harddisk" );
657 status = IoCreateDriver( &nameW, harddisk_driver_entry );
659 thread = CreateThread( NULL, 0, device_op_thread, NULL, 0, NULL );
660 CloseHandle( CreateThread( NULL, 0, run_loop_thread, thread, 0, NULL ));
662 #ifdef _WIN64
663 /* create a symlink so that the Wine port overrides key can be edited with 32-bit reg or regedit */
664 RegCreateKeyExW( HKEY_LOCAL_MACHINE, L"Software\\Wow6432Node\\Wine\\Ports", 0, NULL,
665 REG_OPTION_CREATE_LINK, KEY_SET_VALUE, NULL, &wow64_ports_key, NULL );
666 RegSetValueExW( wow64_ports_key, L"SymbolicLinkValue", 0, REG_LINK,
667 (BYTE *)L"\\REGISTRY\\MACHINE\\Software\\Wine\\Ports",
668 sizeof(L"\\REGISTRY\\MACHINE\\Software\\Wine\\Ports") - sizeof(WCHAR) );
669 RegCloseKey( wow64_ports_key );
670 #endif
672 RtlInitUnicodeString( &nameW, L"\\Driver\\Serial" );
673 IoCreateDriver( &nameW, serial_driver_entry );
675 RtlInitUnicodeString( &nameW, L"\\Driver\\Parallel" );
676 IoCreateDriver( &nameW, parallel_driver_entry );
678 return status;