xref: /reactos/modules/rosapps/drivers/vfd/vfdmnt.c (revision 3ff08b64)
1 /*
2 	vfdmnt.c
3 
4 	Virtual Floppy Drive for Windows NT platform
5 	Kernel mode driver mount manager functions
6 
7 	Copyright (C) 2003-2005 Ken Kato
8 */
9 
10 #ifndef VFD_MOUNT_MANAGER
11 /*
12 	Not in working order for the time being
13 	so DO NOT define VFD_MOUNT_MANAGER macro
14 	unless you know exactly what you are doing...
15 */
16 #if !defined(__REACTOS__) || defined(_MSC_VER)
17 //	suppress empty compile unit warning
18 #pragma warning (disable: 4206)
19 #pragma message ("Mount Manager support feature is disabled.")
20 #endif
21 
22 #else	//	VFD_MOUNT_MANAGER
23 /*
24 	The flow of the drive letter assignment via the Mount Manager
25 	during the VFD driver start up
26 
27 	1)	IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION	VFD -> MM
28 		notifies the mount manager of VFD devices.
29 
30 	2)	IOCTL_MOUNTDEV_QUERY_DEVICE_NAME			VFD <- MM
31 		device name (\Device\Floppy<x>)				VFD -> MM
32 
33 	3)	IOCTL_MOUNTDEV_QUERY_UNIQUE_ID				VFD <- MM
34 		device unique ID (\??\VirtualFD<x>)			VFD -> MM
35 
36 	4)	IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME	VFD <- MM
37 		drive letter link (\DosDevices\<x>:)		VFD -> MM
38 
39 	5)	The mount manager creates the drive letter link
40 
41 	6)	IOCTL_MOUNTDEV_LINK_CREATED					VFD <- MM
42 		The driver stores the created drive letter
43 
44 	The flow of the drive letter operation with IOCTL_VFD_SET_LINK
45 
46 	1)	IOCTL_MOUNTMGR_CREATE_POINT or
47 		IOCTL_MOUNTMGR_DELETE_POINTS				VFD -> MM
48 
49 	2)	The mount manager creates/deletes the drive letter link
50 
51 	3)	IOCTL_MOUNTDEV_LINK_CREATED or
52 		IOCTL_MOUNTDEV_LINK_DELETED					VFD <- MM
53 		The driver stores the created/deleted drive letter
54 */
55 
56 #include "imports.h"
57 #include "vfddrv.h"
58 #include "vfddbg.h"
59 
60 //
61 //	Call the mount manager with an IO control IRP
62 //
63 static NTSTATUS
64 VfdMountMgrSendRequest(
65 	ULONG			ControlCode,
66 	PVOID			InputBuffer,
67 	ULONG			InputLength,
68 	PVOID			OutputBuffer,
69 	ULONG			OutputLength);
70 
71 #ifdef ALLOC_PRAGMA
72 //#pragma alloc_text(PAGE, VfdRegisterMountManager)
73 #pragma alloc_text(PAGE, VfdMountMgrNotifyVolume)
74 #pragma alloc_text(PAGE, VfdMountMgrMountPoint)
75 #pragma alloc_text(PAGE, VfdMountMgrSendRequest)
76 #pragma alloc_text(PAGE, VfdMountDevUniqueId)
77 #pragma alloc_text(PAGE, VfdMountDevDeviceName)
78 #pragma alloc_text(PAGE, VfdMountDevSuggestedLink)
79 #pragma alloc_text(PAGE, VfdMountDevLinkModified)
80 #endif	// ALLOC_PRAGMA
81 
82 /*
83 #include <initguid.h>
84 #include <mountmgr.h>
85 //
86 //	register a device to the mount manager interface
87 //	does not work...
88 //
89 NTSTATUS
90 VfdRegisterMountManager(
91 	PDEVICE_EXTENSION		DeviceExtension)
92 {
93 	NTSTATUS		status = STATUS_SUCCESS;
94 	UNICODE_STRING	interface;
95 	UNICODE_STRING	interface2;
96 
97 	VFDTRACE(VFDINFO,
98 		("[VFD] Registering %ws to the Mount Manager Interface\n",
99 		DeviceExtension->DeviceName.Buffer));
100 
101 	RtlInitUnicodeString(&interface, NULL);
102 
103 	status = IoRegisterDeviceInterface(
104 		DeviceExtension->DeviceObject,
105 		(LPGUID)&MOUNTDEV_MOUNTED_DEVICE_GUID,
106 		NULL,
107 		&interface);
108 
109 	if (!NT_SUCCESS(status)) {
110 		VFDTRACE(0,
111 			("[VFD] IoRegisterDeviceInterface - %s\n",
112 			GetStatusName(status)));
113 		return status;
114 	}
115 
116 	status = IoSetDeviceInterfaceState(&interface, TRUE);
117 
118 	if (NT_SUCCESS(status)) {
119 		if (VfdCopyUnicode(&interface2, &interface)) {
120 			VFDTRACE(VFDINFO,
121 				("[VFD] Interface: %ws\n", interface2.Buffer));
122 		}
123 		else {
124 			VFDTRACE(0,
125 				("[VFD] Failed to allocate an interface name buffer\n"));
126 			status = STATUS_INSUFFICIENT_RESOURCES;
127 		}
128 	}
129 	else {
130 		VFDTRACE(0,
131 			("[VFD] IoSetDeviceInterfaceState - %s\n",
132 			GetStatusName(status)));
133 	}
134 
135 	RtlFreeUnicodeString(&interface);
136 	VfdFreeUnicode(&interface2);
137 
138 	return status;
139 }
140 */
141 
142 //
143 //	informs the Mount Manager of a new VFD device
144 //
145 NTSTATUS
VfdMountMgrNotifyVolume(PDEVICE_EXTENSION DeviceExtension)146 VfdMountMgrNotifyVolume(
147 	PDEVICE_EXTENSION		DeviceExtension)
148 {
149 	PMOUNTMGR_TARGET_NAME	target_name;
150 	USHORT					target_name_buf[MAXIMUM_FILENAME_LENGTH];
151 	NTSTATUS				status;
152 
153 	VFDTRACE(VFDINFO,
154 		("[VFD] VfdMountMgrNotifyVolume - %ws\n",
155 		DeviceExtension->DeviceName.Buffer));
156 
157 	target_name = (PMOUNTMGR_TARGET_NAME)target_name_buf;
158 
159 	target_name->DeviceNameLength =
160 		DeviceExtension->DeviceName.Length;
161 
162 	RtlCopyMemory(
163 		target_name->DeviceName,
164 		DeviceExtension->DeviceName.Buffer,
165 		DeviceExtension->DeviceName.Length);
166 
167 	status = VfdMountMgrSendRequest(
168 		IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION,
169 		target_name,
170 		sizeof(target_name->DeviceNameLength) + target_name->DeviceNameLength,
171 		NULL,
172 		0);
173 
174 	VFDTRACE(VFDINFO,
175 		("[VFD] VfdMountMgrNotifyVolume - %s\n",
176 		GetStatusName(status)));
177 
178 	return status;
179 }
180 
181 //
182 //	Create / remove a drive letter via the Mount Manager
183 //
184 NTSTATUS
VfdMountMgrMountPoint(PDEVICE_EXTENSION DeviceExtension,CHAR DriveLetter)185 VfdMountMgrMountPoint(
186 	PDEVICE_EXTENSION	DeviceExtension,
187 	CHAR				DriveLetter)
188 {
189 	ULONG				alloc_size;
190 	UNICODE_STRING		link_name;
191 	WCHAR				link_buf[20];
192 	NTSTATUS			status;
193 
194 	VFDTRACE(VFDINFO, ("[VFD] VfdMountMgrMountPoint - IN\n"));
195 
196 	//	convert lower case into upper case
197 
198 	if (DriveLetter >= 'a' && DriveLetter <= 'z') {
199 		DriveLetter -= ('a' - 'A');
200 	}
201 
202 	if (DriveLetter >= 'A' && DriveLetter <= 'Z') {
203 
204 		//	Create a new drive letter
205 
206 		PMOUNTMGR_CREATE_POINT_INPUT	create;
207 
208 		swprintf(link_buf, L"\\DosDevices\\%wc:", DriveLetter);
209 
210 		RtlInitUnicodeString(&link_name, link_buf);
211 
212 		VFDTRACE(VFDINFO,
213 			("[VFD] Creating a link: %ws => %ws\n",
214 			link_buf, DeviceExtension->DeviceName.Buffer));
215 
216 		//	allocate buffer for MOUNTMGR_CREATE_POINT_INPUT
217 
218 		alloc_size = sizeof(MOUNTMGR_CREATE_POINT_INPUT) +
219 			link_name.Length + DeviceExtension->DeviceName.Length;
220 
221 		create = (PMOUNTMGR_CREATE_POINT_INPUT)ExAllocatePoolWithTag(
222 			NonPagedPool, alloc_size, VFD_POOL_TAG);
223 
224 		if (!create) {
225 			VFDTRACE(0, ("[VFD] Failed to allocate mount point input\n"));
226 			return STATUS_INSUFFICIENT_RESOURCES;
227 		}
228 
229 		//	set the symbolic link name
230 
231 		create->SymbolicLinkNameOffset	= sizeof(MOUNTMGR_CREATE_POINT_INPUT);
232 		create->SymbolicLinkNameLength	= link_name.Length;
233 
234 		RtlCopyMemory(
235 			(PCHAR)create + create->SymbolicLinkNameOffset,
236 			link_name.Buffer,
237 			link_name.Length);
238 
239 		//	set the target device name
240 
241 		create->DeviceNameOffset		= (USHORT)
242 			(create->SymbolicLinkNameOffset + create->SymbolicLinkNameLength);
243 		create->DeviceNameLength		= DeviceExtension->DeviceName.Length;
244 
245 		RtlCopyMemory(
246 			(PCHAR)create + create->DeviceNameOffset,
247 			DeviceExtension->DeviceName.Buffer,
248 			DeviceExtension->DeviceName.Length);
249 
250 		//	call the mount manager with the IO control request
251 
252 		status = VfdMountMgrSendRequest(
253 			IOCTL_MOUNTMGR_CREATE_POINT,
254 			create, alloc_size, NULL, 0);
255 
256 		ExFreePool(create);
257 
258 		//	no need to set the new drive letter into the
259 		//	DeviceExtension because the mount manager will issue an
260 		//	IOCTL_MOUNTDEV_LINK_CREATED and it will be processed then
261 	}
262 	else if (DriveLetter == 0) {
263 
264 		//	Delete the existing drive letter
265 
266 		PMOUNTMGR_MOUNT_POINT	mount;
267 		PMOUNTMGR_MOUNT_POINTS	points;
268 		UNICODE_STRING	unique_id;
269 		WCHAR			unique_buf[20];
270 
271 		swprintf(link_buf, L"\\DosDevices\\%wc:",
272 			DeviceExtension->DriveLetter);
273 
274 		VFDTRACE(VFDINFO,
275 			("[VFD] Deleting link: %ws\n", link_buf));
276 
277 		RtlInitUnicodeString(&link_name, link_buf);
278 
279 		swprintf(unique_buf, L"\\??\\" VFD_DEVICE_BASENAME L"%lu",
280 			DeviceExtension->DeviceNumber);
281 
282 		RtlInitUnicodeString(&unique_id, unique_buf);
283 
284 		//	allocate buffer for MOUNTMGR_MOUNT_POINT
285 
286 		alloc_size = sizeof(MOUNTMGR_MOUNT_POINT) +
287 			link_name.Length +
288 			unique_id.Length +
289 			DeviceExtension->DeviceName.Length;
290 
291 		mount = (PMOUNTMGR_MOUNT_POINT)ExAllocatePoolWithTag(
292 			NonPagedPool, alloc_size, VFD_POOL_TAG);
293 
294 		if (!mount) {
295 			VFDTRACE(0, ("[VFD] Failed to allocate mount point input\n"));
296 			return STATUS_INSUFFICIENT_RESOURCES;
297 		}
298 
299 		RtlZeroMemory(mount, alloc_size + sizeof(WCHAR));
300 
301 		//	set the symbolic link name
302 
303 		mount->SymbolicLinkNameOffset	= sizeof(MOUNTMGR_MOUNT_POINT);
304 		mount->SymbolicLinkNameLength	= link_name.Length;
305 
306 		RtlCopyMemory(
307 			(PCHAR)mount + mount->SymbolicLinkNameOffset,
308 			link_name.Buffer, link_name.Length);
309 
310 		//	set the unique id
311 
312 		mount->UniqueIdOffset =
313 			mount->SymbolicLinkNameOffset +
314 			mount->SymbolicLinkNameLength;
315 		mount->UniqueIdLength = unique_id.Length;
316 
317 		RtlCopyMemory(
318 			(PCHAR)mount + mount->UniqueIdOffset,
319 			unique_id.Buffer, unique_id.Length);
320 
321 		//	set the target device name
322 
323 		mount->DeviceNameOffset =
324 			mount->UniqueIdOffset +
325 			mount->UniqueIdLength;
326 		mount->DeviceNameLength =
327 			DeviceExtension->DeviceName.Length;
328 
329 		RtlCopyMemory(
330 			(PCHAR)mount + mount->DeviceNameOffset,
331 			DeviceExtension->DeviceName.Buffer,
332 			DeviceExtension->DeviceName.Length);
333 
334 		//	prepare the output buffer
335 
336 		points = (PMOUNTMGR_MOUNT_POINTS)ExAllocatePoolWithTag(
337 			NonPagedPool, alloc_size * 2, VFD_POOL_TAG);
338 
339 		status = VfdMountMgrSendRequest(
340 			IOCTL_MOUNTMGR_DELETE_POINTS,
341 			mount, alloc_size, points, alloc_size * 2);
342 
343 		ExFreePool(mount);
344 		ExFreePool(points);
345 
346 		if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
347 			//	the drive letter did not exist in the first place
348 			DeviceExtension->DriveLetter = 0;
349 		}
350 
351 		//	no need to clear the drive letter in the
352 		//	DeviceExtension because the mount manager will issue an
353 		//	IOCTL_MOUNTDEV_LINK_DELETED and it will be processed then
354 	}
355 	else {
356 		return STATUS_INVALID_PARAMETER;
357 	}
358 
359 	VFDTRACE(VFDINFO, ("[VFD] VfdMountMgrMountPoint - %s\n",
360 		GetStatusName(status)));
361 
362 	return status;
363 }
364 
365 //
366 //	send a request to the Mount Manager
367 //
368 NTSTATUS
VfdMountMgrSendRequest(ULONG ControlCode,PVOID InputBuffer,ULONG InputLength,PVOID OutputBuffer,ULONG OutputLength)369 VfdMountMgrSendRequest(
370 	ULONG			ControlCode,
371 	PVOID			InputBuffer,
372 	ULONG			InputLength,
373 	PVOID			OutputBuffer,
374 	ULONG			OutputLength)
375 {
376 	NTSTATUS		status = STATUS_SUCCESS;
377 	UNICODE_STRING	mntmgr_name;
378 	PDEVICE_OBJECT	mntmgr_dev;
379 	PFILE_OBJECT	mntmgr_file;
380 	IO_STATUS_BLOCK	io_status;
381 	KEVENT			event;
382 	PIRP			irp;
383 
384 	//	Obtain a pointer to the Mount Manager device object
385 
386 	RtlInitUnicodeString(
387 		&mntmgr_name,
388 		MOUNTMGR_DEVICE_NAME);
389 
390 	status = IoGetDeviceObjectPointer(
391 		&mntmgr_name,
392 		FILE_READ_ATTRIBUTES,
393 		&mntmgr_file,
394 		&mntmgr_dev);
395 
396 	if (!NT_SUCCESS(status)) {
397 		VFDTRACE(VFDWARN,
398 			("[VFD] IoGetDeviceObjectPointer - %s\n", GetStatusName(status)));
399 		return status;
400 	}
401 
402 	KeInitializeEvent(&event, NotificationEvent, FALSE);
403 
404 	//	Create an IRP request block
405 
406 	irp = IoBuildDeviceIoControlRequest(
407 		ControlCode,
408 		mntmgr_dev,
409 		InputBuffer,
410 		InputLength,
411 		OutputBuffer,
412 		OutputLength,
413 		FALSE,
414 		&event,
415 		&io_status);
416 
417 	if (!irp) {
418 		VFDTRACE(VFDWARN,
419 			("[VFD] IoBuildDeviceIoControlRequest\n"));
420 		ObDereferenceObject(mntmgr_file);
421 		return STATUS_DRIVER_INTERNAL_ERROR;
422 	}
423 
424 	//	Call the mount manager
425 
426 	status = IoCallDriver(mntmgr_dev, irp);
427 
428 	if (!NT_SUCCESS(status)) {
429 		VFDTRACE(VFDWARN,
430 			("[VFD] IoCallDriver - %s\n", GetStatusName(status)));
431 	}
432 
433 	if (status == STATUS_PENDING) {
434 
435 		//	Wait for the operation to complete
436 
437 		KeWaitForSingleObject(
438 			&event, Executive, KernelMode, FALSE, NULL);
439 
440 		status = io_status.Status;
441 
442 		if (!NT_SUCCESS(status)) {
443 			VFDTRACE(VFDWARN,
444 				("[VFD] IoCallDriver - %s\n", GetStatusName(status)));
445 		}
446 	}
447 
448 	ObDereferenceObject(mntmgr_file);
449 
450 	return status;
451 }
452 
453 //
454 //	IOCTL_MOUNTDEV_QUERY_UNIQUE_ID
455 //	-- use the device interface link (\??\VirtualFD<x>) as the unique ID
456 //
457 NTSTATUS
VfdMountDevUniqueId(PDEVICE_EXTENSION DeviceExtension,PMOUNTDEV_UNIQUE_ID UniqueId,ULONG OutputLength,PIO_STATUS_BLOCK IoStatus)458 VfdMountDevUniqueId(
459 	PDEVICE_EXTENSION	DeviceExtension,
460 	PMOUNTDEV_UNIQUE_ID	UniqueId,
461 	ULONG				OutputLength,
462 	PIO_STATUS_BLOCK	IoStatus)
463 {
464 	WCHAR				buf[20];
465 	UNICODE_STRING		unicode;
466 
467 	if (OutputLength < sizeof(MOUNTDEV_UNIQUE_ID)) {
468 		return STATUS_INVALID_PARAMETER;
469 	}
470 
471 	swprintf(buf,
472 		L"\\??\\" VFD_DEVICE_BASENAME L"%lu",
473 		DeviceExtension->DeviceNumber);
474 
475 	RtlInitUnicodeString(&unicode, buf);
476 
477 	UniqueId->UniqueIdLength = unicode.Length;
478 
479 	if (OutputLength <
480 		sizeof(UniqueId->UniqueIdLength) + UniqueId->UniqueIdLength) {
481 
482 		IoStatus->Information = sizeof(MOUNTDEV_UNIQUE_ID);
483 		return STATUS_BUFFER_OVERFLOW;
484 	}
485 
486 	RtlCopyMemory(
487 		UniqueId->UniqueId, buf, unicode.Length);
488 
489 	IoStatus->Information =
490 		sizeof(UniqueId->UniqueIdLength) + UniqueId->UniqueIdLength;
491 
492 	return STATUS_SUCCESS;
493 }
494 
495 //
496 //	IOCTL_MOUNTDEV_QUERY_DEVICE_NAME
497 //	Returns the device name of the target device (\Device\Floppy<n>)
498 //
499 NTSTATUS
VfdMountDevDeviceName(PDEVICE_EXTENSION DeviceExtension,PMOUNTDEV_NAME DeviceName,ULONG OutputLength,PIO_STATUS_BLOCK IoStatus)500 VfdMountDevDeviceName(
501 	PDEVICE_EXTENSION	DeviceExtension,
502 	PMOUNTDEV_NAME		DeviceName,
503 	ULONG				OutputLength,
504 	PIO_STATUS_BLOCK	IoStatus)
505 {
506 	if (OutputLength < sizeof(MOUNTDEV_NAME)) {
507 		return STATUS_INVALID_PARAMETER;
508 	}
509 
510 	DeviceName->NameLength = DeviceExtension->DeviceName.Length;
511 
512 	if (OutputLength <
513 		sizeof(DeviceName->NameLength) + DeviceName->NameLength) {
514 
515 		IoStatus->Information = sizeof(MOUNTDEV_NAME);
516 		return STATUS_BUFFER_OVERFLOW;
517 	}
518 
519 	RtlCopyMemory(
520 		DeviceName->Name,
521 		DeviceExtension->DeviceName.Buffer,
522 		DeviceName->NameLength);
523 
524 	IoStatus->Information =
525 		sizeof(DeviceName->NameLength) + DeviceName->NameLength;
526 
527 	return STATUS_SUCCESS;
528 }
529 
530 //
531 //	IOCTL_MOUNTDEV_QUERY_SUGGESTED_LINK_NAME
532 //	Returns the drive letter link which we want the mount manager
533 //	to create.	This request is issued in response to the volume
534 //	arrival notification, and the mount manager will create the
535 //	symbolic link.
536 //
537 NTSTATUS
VfdMountDevSuggestedLink(PDEVICE_EXTENSION DeviceExtension,PMOUNTDEV_SUGGESTED_LINK_NAME LinkName,ULONG OutputLength,PIO_STATUS_BLOCK IoStatus)538 VfdMountDevSuggestedLink(
539 	PDEVICE_EXTENSION	DeviceExtension,
540 	PMOUNTDEV_SUGGESTED_LINK_NAME	LinkName,
541 	ULONG				OutputLength,
542 	PIO_STATUS_BLOCK	IoStatus)
543 {
544 	WCHAR				buf[20];
545 	UNICODE_STRING		unicode;
546 
547 	if (OutputLength < sizeof(MOUNTDEV_SUGGESTED_LINK_NAME)) {
548 		return STATUS_INVALID_PARAMETER;
549 	}
550 
551 	LinkName->UseOnlyIfThereAreNoOtherLinks = TRUE;
552 
553 	if (!DeviceExtension->DriveLetter) {
554 
555 		//	No persistent drive letter stored in the registry
556 		VFDTRACE(VFDINFO, ("[VFD] suggested link : none\n"));
557 
558 		LinkName->NameLength  = 0;
559 
560 		IoStatus->Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
561 		return STATUS_SUCCESS;
562 	}
563 
564 	//	A persistent drive letter exists
565 
566 	swprintf(buf, L"\\DosDevices\\%wc:",
567 		DeviceExtension->DriveLetter);
568 
569 	VFDTRACE(VFDINFO, ("[VFD] suggested link : %ws\n", buf));
570 
571 	RtlInitUnicodeString(&unicode, buf);
572 
573 	LinkName->NameLength = unicode.Length;
574 
575 	if (OutputLength <
576 		sizeof(MOUNTDEV_SUGGESTED_LINK_NAME) +
577 		LinkName->NameLength - sizeof(WCHAR)) {
578 
579 		IoStatus->Information = sizeof(MOUNTDEV_SUGGESTED_LINK_NAME);
580 		return STATUS_BUFFER_OVERFLOW;
581 	}
582 
583 	RtlCopyMemory(LinkName->Name, buf, unicode.Length);
584 
585 	IoStatus->Information =
586 		sizeof(MOUNTDEV_SUGGESTED_LINK_NAME) +
587 		LinkName->NameLength - sizeof(WCHAR);
588 
589 	return STATUS_SUCCESS;
590 }
591 
592 //
593 //	IOCTL_MOUNTDEV_LINK_CREATED / IOCTL_MOUNTDEV_LINK_DELETED
594 //	Issued after the mount manager created/deleted a symbolic link
595 //	If the link is a drive letter, store the new value into the
596 //	registry as the new drive letter
597 //
598 NTSTATUS
VfdMountDevLinkModified(PDEVICE_EXTENSION DeviceExtension,PMOUNTDEV_NAME LinkName,ULONG InputLength,ULONG ControlCode)599 VfdMountDevLinkModified(
600 	PDEVICE_EXTENSION	DeviceExtension,
601 	PMOUNTDEV_NAME		LinkName,
602 	ULONG				InputLength,
603 	ULONG				ControlCode)
604 {
605 	if (InputLength < sizeof(MOUNTDEV_NAME)) {
606 		return STATUS_INVALID_PARAMETER;
607 	}
608 
609 	if (InputLength < sizeof(MOUNTDEV_NAME) +
610 		LinkName->NameLength - sizeof(WCHAR)) {
611 
612 		return STATUS_INVALID_PARAMETER;
613 	}
614 
615 #if DBG
616 	{	//	Print the reported link name
617 		PWSTR buf = ExAllocatePoolWithTag(
618 			PagedPool, LinkName->NameLength + sizeof(WCHAR), VFD_POOL_TAG);
619 
620 		if (buf) {
621 			RtlZeroMemory(buf, LinkName->NameLength + sizeof(WCHAR));
622 			RtlCopyMemory(buf, LinkName->Name, LinkName->NameLength);
623 			VFDTRACE(VFDINFO, ("[VFD] %ws\n", buf));
624 			ExFreePool(buf);
625 		}
626 	}
627 #endif	// DBG
628 
629 	if (LinkName->NameLength == 28		&&
630 		LinkName->Name[0]	== L'\\'	&&
631 		LinkName->Name[1]	== L'D'		&&
632 		LinkName->Name[2]	== L'o'		&&
633 		LinkName->Name[3]	== L's'		&&
634 		LinkName->Name[4]	== L'D'		&&
635 		LinkName->Name[5]	== L'e'		&&
636 		LinkName->Name[6]	== L'v'		&&
637 		LinkName->Name[7]	== L'i'		&&
638 		LinkName->Name[8]	== L'c'		&&
639 		LinkName->Name[9]	== L'e'		&&
640 		LinkName->Name[10]	== L's'		&&
641 		LinkName->Name[11]	== L'\\'	&&
642 		LinkName->Name[12]	>= L'A'		&&
643 		LinkName->Name[12]	<= L'Z'		&&
644 		LinkName->Name[13]	== L':') {
645 
646 		//	The link is a drive letter
647 
648 		if (ControlCode == IOCTL_MOUNTDEV_LINK_CREATED) {
649 			//	link is created - store the new drive letter
650 			DeviceExtension->DriveLetter = (CHAR)LinkName->Name[12];
651 		}
652 		else {
653 			//	link is deleted - clear the drive letter
654 			DeviceExtension->DriveLetter = 0;
655 		}
656 
657 		//	Store the value into the registry
658 
659 		VfdStoreLink(DeviceExtension);
660 	}
661 
662 	return STATUS_SUCCESS;
663 }
664 
665 #endif	//	VFD_MOUNT_MANAGER
666