1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fstub/disksup.c
5 * PURPOSE: I/O HAL Routines for Disk Access
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 * Casper S. Hornstrup (chorns@users.sourceforge.net)
9 * Pierre Schweitzer
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <debug.h>
17 #include <internal/hal.h>
18
19 const WCHAR DiskMountString[] = L"\\DosDevices\\%C:";
20
21 #define AUTO_DRIVE MAXULONG
22
23 #define PARTITION_MAGIC 0xaa55
24
25 #define EFI_PMBR_OSTYPE_EFI 0xEE
26
27 #include <pshpack1.h>
28
29 typedef struct _REG_DISK_MOUNT_INFO
30 {
31 ULONG Signature;
32 LARGE_INTEGER StartingOffset;
33 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
34
35 #include <poppack.h>
36
37 typedef enum _DISK_MANAGER
38 {
39 NoDiskManager,
40 OntrackDiskManager,
41 EZ_Drive
42 } DISK_MANAGER;
43
44 typedef enum _PARTITION_TYPE
45 {
46 BootablePartition,
47 PrimaryPartition,
48 LogicalPartition,
49 FtPartition,
50 UnknownPartition,
51 DataPartition
52 } PARTITION_TYPE, *PPARTITION_TYPE;
53
54 NTSTATUS
55 FASTCALL
HalpQueryDriveLayout(IN PUNICODE_STRING DeviceName,OUT PDRIVE_LAYOUT_INFORMATION * LayoutInfo)56 HalpQueryDriveLayout(IN PUNICODE_STRING DeviceName,
57 OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo)
58 {
59 IO_STATUS_BLOCK StatusBlock;
60 PDEVICE_OBJECT DeviceObject = NULL;
61 PFILE_OBJECT FileObject;
62 KEVENT Event;
63 PIRP Irp;
64 NTSTATUS Status;
65 ULONG BufferSize;
66 PDRIVE_LAYOUT_INFORMATION Buffer;
67 PAGED_CODE();
68
69 /* Get device pointers */
70 Status = IoGetDeviceObjectPointer(DeviceName,
71 FILE_READ_ATTRIBUTES,
72 &FileObject,
73 &DeviceObject);
74 if (!NT_SUCCESS(Status))
75 {
76 return Status;
77 }
78
79 /* Get attached device object */
80 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
81 ObDereferenceObject(FileObject);
82
83 /* Do not handle removable media */
84 if (BooleanFlagOn(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
85 {
86 ObDereferenceObject(DeviceObject);
87 return STATUS_NO_MEDIA;
88 }
89
90 /* We'll loop until our buffer is big enough */
91 Buffer = NULL;
92 BufferSize = 0x1000;
93 KeInitializeEvent(&Event, NotificationEvent, FALSE);
94 do
95 {
96 /* If we already had a buffer, it means it's not big
97 * enough, so free and multiply size by two
98 */
99 if (Buffer != NULL)
100 {
101 ExFreePoolWithTag(Buffer, TAG_FSTUB);
102 BufferSize *= 2;
103 }
104
105 /* Allocate buffer for output buffer */
106 Buffer = ExAllocatePoolWithTag(NonPagedPool, BufferSize, TAG_FSTUB);
107 if (Buffer == NULL)
108 {
109 Status = STATUS_NO_MEMORY;
110 break;
111 }
112
113 /* Build the IRP to query drive layout */
114 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_LAYOUT,
115 DeviceObject,
116 NULL,
117 0,
118 Buffer,
119 BufferSize,
120 FALSE,
121 &Event,
122 &StatusBlock);
123 if (Irp == NULL)
124 {
125 Status = STATUS_INSUFFICIENT_RESOURCES;
126 break;
127 }
128
129 /* Call the driver and wait if appropriate */
130 Status = IoCallDriver(DeviceObject, Irp);
131 if (Status == STATUS_PENDING)
132 {
133 KeWaitForSingleObject(&Event,
134 Executive,
135 KernelMode,
136 FALSE,
137 NULL);
138 Status = StatusBlock.Status;
139 }
140 /* If buffer is too small, keep looping */
141 } while (Status == STATUS_BUFFER_TOO_SMALL);
142
143 /* We're done with the device */
144 ObDereferenceObject(DeviceObject);
145
146 /* If querying worked, then return the buffer to the caller */
147 if (NT_SUCCESS(Status))
148 {
149 ASSERT(Buffer != NULL);
150 *LayoutInfo = Buffer;
151 }
152 /* Else, release the buffer if still allocated and fail */
153 else
154 {
155 if (Buffer != NULL)
156 {
157 ExFreePoolWithTag(Buffer, TAG_FSTUB);
158 }
159 }
160
161 return Status;
162 }
163
164 NTSTATUS
HalpQueryPartitionType(IN PUNICODE_STRING DeviceName,IN PDRIVE_LAYOUT_INFORMATION LayoutInfo,OUT PPARTITION_TYPE PartitionType)165 HalpQueryPartitionType(IN PUNICODE_STRING DeviceName,
166 IN PDRIVE_LAYOUT_INFORMATION LayoutInfo,
167 OUT PPARTITION_TYPE PartitionType)
168 {
169 USHORT i;
170 PIRP Irp;
171 KEVENT Event;
172 NTSTATUS Status;
173 PFILE_OBJECT FileObject;
174 PDEVICE_OBJECT DeviceObject;
175 IO_STATUS_BLOCK IoStatusBlock;
176 PARTITION_INFORMATION_EX PartitionInfo;
177
178 PAGED_CODE();
179
180 /* Get device pointers */
181 Status = IoGetDeviceObjectPointer(DeviceName,
182 FILE_READ_ATTRIBUTES,
183 &FileObject,
184 &DeviceObject);
185 if (!NT_SUCCESS(Status))
186 {
187 return Status;
188 }
189
190 /* Get attached device object */
191 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
192 ObDereferenceObject(FileObject);
193
194 /* Assume logical partition for removable devices */
195 if (BooleanFlagOn(DeviceObject->Characteristics, FILE_REMOVABLE_MEDIA))
196 {
197 ObDereferenceObject(DeviceObject);
198 *PartitionType = LogicalPartition;
199 return STATUS_SUCCESS;
200 }
201
202 /* For the others, query partition info */
203 KeInitializeEvent(&Event, NotificationEvent, FALSE);
204 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO_EX,
205 DeviceObject,
206 NULL,
207 0,
208 &PartitionInfo,
209 sizeof(PartitionInfo),
210 FALSE,
211 &Event,
212 &IoStatusBlock);
213 if (Irp == NULL)
214 {
215 ObDereferenceObject(DeviceObject);
216 return STATUS_INSUFFICIENT_RESOURCES;
217 }
218
219 Status = IoCallDriver(DeviceObject, Irp);
220 if (Status == STATUS_PENDING)
221 {
222 KeWaitForSingleObject(&Event,
223 Executive,
224 KernelMode,
225 FALSE,
226 NULL);
227 Status = IoStatusBlock.Status;
228 }
229
230 /* We're done with the device */
231 ObDereferenceObject(DeviceObject);
232
233 /* If we failed querying partition info, try to return something
234 * if caller didn't provide a precise layout, assume logical
235 * partition and fake success. Otherwise, just fail.
236 */
237 if (!NT_SUCCESS(Status))
238 {
239 if (LayoutInfo == NULL)
240 {
241 *PartitionType = LogicalPartition;
242 return STATUS_SUCCESS;
243 }
244
245 return Status;
246 }
247
248 /* First, handle non MBR style (easy cases) */
249 if (PartitionInfo.PartitionStyle != PARTITION_STYLE_MBR)
250 {
251 /* If not GPT, we don't know what it is */
252 if (PartitionInfo.PartitionStyle != PARTITION_STYLE_GPT)
253 {
254 *PartitionType = UnknownPartition;
255 return STATUS_SUCCESS;
256 }
257
258 /* Check whether that's data partition */
259 if (RtlCompareMemory(&PartitionInfo.Gpt.PartitionType,
260 &PARTITION_BASIC_DATA_GUID,
261 sizeof(GUID)) == sizeof(GUID))
262 {
263 *PartitionType = DataPartition;
264 return STATUS_SUCCESS;
265 }
266
267 /* Otherwise, we don't know */
268 *PartitionType = UnknownPartition;
269 return STATUS_SUCCESS;
270 }
271
272 /* If we don't recognize partition type, return unknown */
273 if (!IsRecognizedPartition(PartitionInfo.Mbr.PartitionType))
274 {
275 *PartitionType = UnknownPartition;
276 return STATUS_SUCCESS;
277 }
278
279 /* Check if that's a FT volume */
280 if (IsFTPartition(PartitionInfo.Mbr.PartitionType))
281 {
282 *PartitionType = FtPartition;
283 return STATUS_SUCCESS;
284 }
285
286 /* If the caller didn't provide the complete layout, just return */
287 if (LayoutInfo == NULL)
288 {
289 *PartitionType = LogicalPartition;
290 return STATUS_SUCCESS;
291 }
292
293 /* Now, evaluate the partition to the 4 in the input layout */
294 for (i = 0; i < 4; ++i)
295 {
296 /* If we find a partition matching */
297 if (LayoutInfo->PartitionEntry[i].StartingOffset.QuadPart == PartitionInfo.StartingOffset.QuadPart)
298 {
299 /* Return boot if boot flag is set */
300 if (PartitionInfo.Mbr.BootIndicator)
301 {
302 *PartitionType = BootablePartition;
303 }
304 /* Primary otherwise */
305 else
306 {
307 *PartitionType = PrimaryPartition;
308 }
309
310 return STATUS_SUCCESS;
311 }
312 }
313
314 /* Otherwise, assume logical */
315 *PartitionType = LogicalPartition;
316 return STATUS_SUCCESS;
317 }
318
319 PULONG
IopComputeHarddiskDerangements(IN ULONG DiskCount)320 IopComputeHarddiskDerangements(IN ULONG DiskCount)
321 {
322 PIRP Irp;
323 KEVENT Event;
324 ULONG i, j, k;
325 PULONG Devices;
326 NTSTATUS Status;
327 WCHAR Buffer[100];
328 UNICODE_STRING ArcName;
329 PFILE_OBJECT FileObject;
330 PDEVICE_OBJECT DeviceObject;
331 IO_STATUS_BLOCK IoStatusBlock;
332 STORAGE_DEVICE_NUMBER DeviceNumber;
333
334 /* No disks, nothing to do */
335 if (DiskCount == 0)
336 {
337 return NULL;
338 }
339
340 /* Allocate a buffer big enough to hold all the disks */
341 Devices = ExAllocatePoolWithTag(PagedPool | POOL_COLD_ALLOCATION,
342 sizeof(ULONG) * DiskCount,
343 TAG_FSTUB);
344 if (Devices == NULL)
345 {
346 return NULL;
347 }
348
349 /* Now, we'll query all the disks */
350 for (i = 0; i < DiskCount; ++i)
351 {
352 /* Using their ARC name */
353 swprintf(Buffer, L"\\ArcName\\multi(0)disk(0)rdisk(%d)", i);
354 RtlInitUnicodeString(&ArcName, Buffer);
355 /* Get the attached DeviceObject */
356 if (NT_SUCCESS(IoGetDeviceObjectPointer(&ArcName, FILE_READ_ATTRIBUTES, &FileObject, &DeviceObject)))
357 {
358 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
359 ObDereferenceObject(FileObject);
360
361 /* And query it for device number */
362 KeInitializeEvent(&Event, NotificationEvent, FALSE);
363 Irp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_GET_DEVICE_NUMBER,
364 DeviceObject,
365 NULL,
366 0,
367 &DeviceNumber,
368 sizeof(DeviceNumber),
369 FALSE,
370 &Event,
371 &IoStatusBlock);
372 if (Irp != NULL)
373 {
374 Status = IoCallDriver(DeviceObject, Irp);
375 if (Status == STATUS_PENDING)
376 {
377 KeWaitForSingleObject(&Event,
378 Executive,
379 KernelMode,
380 FALSE,
381 NULL);
382 Status = IoStatusBlock.Status;
383 }
384
385 ObDereferenceObject(DeviceObject);
386
387 /* In case of a success remember device number */
388 if (NT_SUCCESS(Status))
389 {
390 Devices[i] = DeviceNumber.DeviceNumber;
391 /* Move on, not to fall into our default case */
392 continue;
393 }
394 }
395 else
396 {
397 ObDereferenceObject(DeviceObject);
398 }
399
400 /* Default case, for failures, set -1 */
401 Devices[i] = -1;
402 }
403 }
404
405 /* Now, we'll check all device numbers */
406 for (i = 0; i < DiskCount; ++i)
407 {
408 /* First of all, check if we're at the right place */
409 for (j = 0; j < DiskCount; ++j)
410 {
411 if (Devices[j] == i)
412 {
413 break;
414 }
415 }
416
417 /* If not, perform the change */
418 if (j >= DiskCount)
419 {
420 k = 0;
421 while (Devices[k] != -1)
422 {
423 if (++k >= DiskCount)
424 {
425 break;
426 }
427 }
428
429 if (k < DiskCount)
430 {
431 Devices[k] = i;
432 }
433 }
434 }
435
436 /* Return our device derangement map */
437 return Devices;
438 }
439
440 NTSTATUS
HalpNextMountLetter(IN PUNICODE_STRING DeviceName,OUT PUCHAR DriveLetter)441 HalpNextMountLetter(IN PUNICODE_STRING DeviceName,
442 OUT PUCHAR DriveLetter)
443 {
444 PIRP Irp;
445 KEVENT Event;
446 NTSTATUS Status;
447 UNICODE_STRING MountMgr;
448 PFILE_OBJECT FileObject;
449 PDEVICE_OBJECT DeviceObject;
450 IO_STATUS_BLOCK IoStatusBlock;
451 PMOUNTMGR_DRIVE_LETTER_TARGET Target;
452 MOUNTMGR_DRIVE_LETTER_INFORMATION LetterInfo;
453
454 /* To get next mount letter, we need the MountMgr */
455 RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager");
456 Status = IoGetDeviceObjectPointer(&MountMgr,
457 FILE_READ_ATTRIBUTES,
458 &FileObject,
459 &DeviceObject);
460 if (!NT_SUCCESS(Status))
461 {
462 return Status;
463 }
464
465 /* Allocate our input buffer */
466 Target = ExAllocatePoolWithTag(PagedPool,
467 DeviceName->Length + FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName),
468 TAG_FSTUB);
469 if (Target == NULL)
470 {
471 ObDereferenceObject(FileObject);
472 return STATUS_INSUFFICIENT_RESOURCES;
473 }
474
475 /* And fill it with the device hat needs a drive letter */
476 Target->DeviceNameLength = DeviceName->Length;
477 RtlCopyMemory(&Target->DeviceName[0], DeviceName->Buffer, DeviceName->Length);
478
479 /* Call the mount manager */
480 KeInitializeEvent(&Event, NotificationEvent, FALSE);
481 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_NEXT_DRIVE_LETTER,
482 DeviceObject,
483 Target,
484 DeviceName->Length + FIELD_OFFSET(MOUNTMGR_DRIVE_LETTER_TARGET, DeviceName),
485 &LetterInfo,
486 sizeof(LetterInfo),
487 FALSE,
488 &Event,
489 &IoStatusBlock);
490 if (Irp == NULL)
491 {
492 ExFreePoolWithTag(Target, TAG_FSTUB);
493 ObDereferenceObject(FileObject);
494 return STATUS_INSUFFICIENT_RESOURCES;
495 }
496
497 Status = IoCallDriver(DeviceObject, Irp);
498 if (Status == STATUS_PENDING)
499 {
500 KeWaitForSingleObject(&Event,
501 Executive,
502 KernelMode,
503 FALSE,
504 NULL);
505 Status = IoStatusBlock.Status;
506 }
507
508 ExFreePoolWithTag(Target, TAG_FSTUB);
509 ObDereferenceObject(FileObject);
510
511 DPRINT("Done: %d %c\n", LetterInfo.DriveLetterWasAssigned,
512 LetterInfo.CurrentDriveLetter);
513
514 /* Return the drive letter the MountMgr potentially assigned */
515 *DriveLetter = LetterInfo.CurrentDriveLetter;
516
517 /* Also return the success */
518 return Status;
519 }
520
521 NTSTATUS
HalpSetMountLetter(IN PUNICODE_STRING DeviceName,UCHAR DriveLetter)522 HalpSetMountLetter(IN PUNICODE_STRING DeviceName,
523 UCHAR DriveLetter)
524 {
525 PIRP Irp;
526 KEVENT Event;
527 NTSTATUS Status;
528 WCHAR Buffer[30];
529 ULONG InputBufferLength;
530 PFILE_OBJECT FileObject;
531 PDEVICE_OBJECT DeviceObject;
532 IO_STATUS_BLOCK IoStatusBlock;
533 UNICODE_STRING DosDevice, MountMgr;
534 PMOUNTMGR_CREATE_POINT_INPUT InputBuffer;
535
536 /* Setup the DosDevice name */
537 swprintf(Buffer, L"\\DosDevices\\%c:", DriveLetter);
538 RtlInitUnicodeString(&DosDevice, Buffer);
539
540 /* Allocate the input buffer for the MountMgr */
541 InputBufferLength = DosDevice.Length + DeviceName->Length + sizeof(MOUNTMGR_CREATE_POINT_INPUT);
542 InputBuffer = ExAllocatePoolWithTag(PagedPool, InputBufferLength, TAG_FSTUB);
543 if (InputBuffer == NULL)
544 {
545 return STATUS_INSUFFICIENT_RESOURCES;
546 }
547
548 /* Fill the input buffer */
549 InputBuffer->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
550 InputBuffer->SymbolicLinkNameLength = DosDevice.Length;
551 InputBuffer->DeviceNameOffset = DosDevice.Length + sizeof(MOUNTMGR_CREATE_POINT_INPUT);
552 InputBuffer->DeviceNameLength = DeviceName->Length;
553 RtlCopyMemory(&InputBuffer[1], DosDevice.Buffer, DosDevice.Length);
554 RtlCopyMemory((PVOID)((ULONG_PTR)InputBuffer + InputBuffer->DeviceNameOffset),
555 DeviceName->Buffer,
556 DeviceName->Length);
557
558 /* Get the MountMgr device pointer, to send the IOCTL */
559 RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager");
560 Status = IoGetDeviceObjectPointer(&MountMgr,
561 FILE_READ_ATTRIBUTES,
562 &FileObject,
563 &DeviceObject);
564 if (!NT_SUCCESS(Status))
565 {
566 ExFreePoolWithTag(InputBuffer, TAG_FSTUB);
567 return Status;
568 }
569
570 /* Call the MountMgr */
571 KeInitializeEvent(&Event, NotificationEvent, FALSE);
572 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_CREATE_POINT,
573 DeviceObject,
574 InputBuffer,
575 InputBufferLength,
576 NULL,
577 0,
578 FALSE,
579 &Event,
580 &IoStatusBlock);
581 if (Irp == NULL)
582 {
583 ObDereferenceObject(FileObject);
584 ExFreePoolWithTag(InputBuffer, TAG_FSTUB);
585 return STATUS_INSUFFICIENT_RESOURCES;
586 }
587
588 Status = IoCallDriver(DeviceObject, Irp);
589 if (Status == STATUS_PENDING)
590 {
591 KeWaitForSingleObject(&Event,
592 Executive,
593 KernelMode,
594 FALSE,
595 NULL);
596 Status = IoStatusBlock.Status;
597 }
598
599 ObDereferenceObject(FileObject);
600 ExFreePoolWithTag(InputBuffer, TAG_FSTUB);
601
602 /* Return the MountMgr status */
603 return Status;
604 }
605
606 UCHAR
HalpNextDriveLetter(IN PUNICODE_STRING DeviceName,IN PSTRING NtDeviceName,OUT PUCHAR NtSystemPath,BOOLEAN IsRemovable)607 HalpNextDriveLetter(IN PUNICODE_STRING DeviceName,
608 IN PSTRING NtDeviceName,
609 OUT PUCHAR NtSystemPath,
610 BOOLEAN IsRemovable)
611 {
612 UCHAR i;
613 WCHAR Buffer[40];
614 UCHAR DriveLetter;
615 UNICODE_STRING FloppyString, CdString, NtDeviceNameU, DosDevice;
616
617 /* Quick path, ask directly the mount manager to assign the next
618 * free drive letter
619 */
620 if (NT_SUCCESS(HalpNextMountLetter(DeviceName, &DriveLetter)))
621 {
622 return DriveLetter;
623 }
624
625 /* We'll allow MountMgr to fail only for non vital path */
626 if (NtDeviceName == NULL || NtSystemPath == NULL)
627 {
628 return -1;
629 }
630
631 /* And for removable devices */
632 if (!IsRemovable)
633 {
634 return 0;
635 }
636
637 /* Removable might be floppy or cdrom */
638 RtlInitUnicodeString(&FloppyString, L"\\Device\\Floppy");
639 RtlInitUnicodeString(&CdString, L"\\Device\\CdRom");
640
641 /* If floppy, start at A */
642 if (RtlPrefixUnicodeString(&FloppyString, DeviceName, TRUE))
643 {
644 DriveLetter = 'A';
645 }
646 /* If CD start C */
647 else if (RtlPrefixUnicodeString(&CdString, DeviceName, TRUE))
648 {
649 DriveLetter = 'D';
650 }
651 /* For the rest start at C */
652 else
653 {
654 DriveLetter = 'C';
655 }
656
657 /* Now, try to assign a drive letter manually with the MountMgr */
658 for (i = DriveLetter; i <= 'Z'; ++i)
659 {
660 if (NT_SUCCESS(HalpSetMountLetter(DeviceName, i)))
661 {
662 /* If it worked, if we were managing system path, update manually */
663 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NtDeviceNameU, NtDeviceName, TRUE)))
664 {
665 if (RtlEqualUnicodeString(&NtDeviceNameU, DeviceName, TRUE))
666 {
667 *NtSystemPath = i;
668 }
669
670 RtlFreeUnicodeString(&NtDeviceNameU);
671 }
672
673 return i;
674 }
675 }
676
677 /* Last fall back, we're not on a PnP device... */
678 for (i = DriveLetter; i <= 'Z'; ++i)
679 {
680 /* We'll link manually, without MountMgr knowing anything about the device */
681 swprintf(Buffer, L"\\DosDevices\\%c:", i);
682 RtlInitUnicodeString(&DosDevice, Buffer);
683
684 /* If linking worked, then the letter was free ;-) */
685 if (NT_SUCCESS(IoCreateSymbolicLink(&DosDevice, DeviceName)))
686 {
687 /* If it worked, if we were managing system path, update manually */
688 if (NT_SUCCESS(RtlAnsiStringToUnicodeString(&NtDeviceNameU, NtDeviceName, TRUE)))
689 {
690 if (RtlEqualUnicodeString(&NtDeviceNameU, DeviceName, TRUE))
691 {
692 *NtSystemPath = i;
693 }
694
695 RtlFreeUnicodeString(&NtDeviceNameU);
696 }
697
698 return i;
699 }
700 }
701
702 /* We're done, nothing happened */
703 return 0;
704 }
705
706 BOOLEAN
HalpIsOldStyleFloppy(PUNICODE_STRING DeviceName)707 HalpIsOldStyleFloppy(PUNICODE_STRING DeviceName)
708 {
709 PIRP Irp;
710 KEVENT Event;
711 NTSTATUS Status;
712 MOUNTDEV_NAME DevName;
713 PFILE_OBJECT FileObject;
714 PDEVICE_OBJECT DeviceObject;
715 IO_STATUS_BLOCK IoStatusBlock;
716 PAGED_CODE();
717
718 /* Get the attached device object to our device */
719 if (!NT_SUCCESS(IoGetDeviceObjectPointer(DeviceName,
720 FILE_READ_ATTRIBUTES,
721 &FileObject,
722 &DeviceObject)))
723 {
724 return FALSE;
725 }
726
727 DeviceObject = IoGetAttachedDeviceReference(FileObject->DeviceObject);
728 ObDereferenceObject(FileObject);
729
730 /* Query its device name (ie, check floppy.sys implements MountMgr interface) */
731 KeInitializeEvent(&Event, NotificationEvent, FALSE);
732 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTDEV_QUERY_DEVICE_NAME,
733 DeviceObject,
734 NULL,
735 0,
736 &DevName,
737 sizeof(DevName),
738 FALSE,
739 &Event,
740 &IoStatusBlock);
741 if (Irp == NULL)
742 {
743 ObDereferenceObject(DeviceObject);
744 return FALSE;
745 }
746
747 Status = IoCallDriver(DeviceObject, Irp);
748 if (Status == STATUS_PENDING)
749 {
750 KeWaitForSingleObject(&Event,
751 Executive,
752 KernelMode,
753 FALSE,
754 NULL);
755 Status = IoStatusBlock.Status;
756 }
757
758 /* If status is not STATUS_BUFFER_OVERFLOW, it means
759 * it's pre-mountmgr driver, aka "Old style".
760 */
761 ObDereferenceObject(DeviceObject);
762 return (Status != STATUS_BUFFER_OVERFLOW);
763 }
764
765 NTSTATUS
HalpDeleteMountLetter(UCHAR DriveLetter)766 HalpDeleteMountLetter(UCHAR DriveLetter)
767 {
768 PIRP Irp;
769 KEVENT Event;
770 NTSTATUS Status;
771 WCHAR Buffer[30];
772 ULONG InputBufferLength;
773 PFILE_OBJECT FileObject;
774 PDEVICE_OBJECT DeviceObject;
775 IO_STATUS_BLOCK IoStatusBlock;
776 PMOUNTMGR_MOUNT_POINT InputBuffer;
777 UNICODE_STRING DosDevice, MountMgr;
778 PMOUNTMGR_MOUNT_POINTS OutputBuffer;
779
780 /* Setup the device name of the letter to delete */
781 swprintf(Buffer, L"\\DosDevices\\%c:", DriveLetter);
782 RtlInitUnicodeString(&DosDevice, Buffer);
783
784 /* Allocate the input buffer for MountMgr */
785 InputBufferLength = DosDevice.Length + sizeof(MOUNTMGR_MOUNT_POINT);
786 InputBuffer = ExAllocatePoolWithTag(PagedPool, InputBufferLength, TAG_FSTUB);
787 if (InputBuffer == NULL)
788 {
789 return STATUS_INSUFFICIENT_RESOURCES;
790 }
791
792 /* Fill it in */
793 RtlZeroMemory(InputBuffer, InputBufferLength);
794 InputBuffer->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
795 InputBuffer->SymbolicLinkNameLength = DosDevice.Length;
796 RtlCopyMemory(&InputBuffer[1], DosDevice.Buffer, DosDevice.Length);
797
798 /* Allocate big enough output buffer (we don't care about the output) */
799 OutputBuffer = ExAllocatePoolWithTag(PagedPool, 0x1000, TAG_FSTUB);
800 if (OutputBuffer == NULL)
801 {
802 ExFreePoolWithTag(InputBuffer, TAG_FSTUB);
803 return STATUS_INSUFFICIENT_RESOURCES;
804 }
805
806 /* Get the device pointer to the MountMgr */
807 RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager");
808 Status = IoGetDeviceObjectPointer(&MountMgr,
809 FILE_READ_ATTRIBUTES,
810 &FileObject,
811 &DeviceObject);
812 if (!NT_SUCCESS(Status))
813 {
814 ExFreePoolWithTag(OutputBuffer, TAG_FSTUB);
815 ExFreePoolWithTag(InputBuffer, TAG_FSTUB);
816 return Status;
817 }
818
819 /* Call the mount manager to delete the drive letter */
820 KeInitializeEvent(&Event, NotificationEvent, FALSE);
821 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_DELETE_POINTS,
822 DeviceObject,
823 InputBuffer,
824 InputBufferLength,
825 OutputBuffer,
826 0x1000,
827 FALSE,
828 &Event,
829 &IoStatusBlock);
830 if (Irp == NULL)
831 {
832 ObDereferenceObject(FileObject);
833 ExFreePoolWithTag(OutputBuffer, TAG_FSTUB);
834 ExFreePoolWithTag(InputBuffer, TAG_FSTUB);
835 return STATUS_INSUFFICIENT_RESOURCES;
836 }
837
838 Status = IoCallDriver(DeviceObject, Irp);
839 if (Status == STATUS_PENDING)
840 {
841 KeWaitForSingleObject(&Event,
842 Executive,
843 KernelMode,
844 FALSE,
845 NULL);
846 Status = IoStatusBlock.Status;
847 }
848
849 ObDereferenceObject(FileObject);
850 ExFreePoolWithTag(OutputBuffer, TAG_FSTUB);
851 ExFreePoolWithTag(InputBuffer, TAG_FSTUB);
852
853 return Status;
854 }
855
856 VOID
HalpEnableAutomaticDriveLetterAssignment(VOID)857 HalpEnableAutomaticDriveLetterAssignment(VOID)
858 {
859 PIRP Irp;
860 KEVENT Event;
861 NTSTATUS Status;
862 UNICODE_STRING MountMgr;
863 PFILE_OBJECT FileObject;
864 PDEVICE_OBJECT DeviceObject;
865 IO_STATUS_BLOCK IoStatusBlock;
866
867 /* Get the device pointer to the MountMgr */
868 RtlInitUnicodeString(&MountMgr, L"\\Device\\MountPointManager");
869 Status = IoGetDeviceObjectPointer(&MountMgr,
870 FILE_READ_ATTRIBUTES,
871 &FileObject,
872 &DeviceObject);
873 if (!NT_SUCCESS(Status))
874 {
875 return;
876 }
877
878 /* Just send an IOCTL to enable the feature */
879 KeInitializeEvent(&Event, NotificationEvent, FALSE);
880 Irp = IoBuildDeviceIoControlRequest(IOCTL_MOUNTMGR_AUTO_DL_ASSIGNMENTS,
881 DeviceObject,
882 NULL,
883 0,
884 NULL,
885 0,
886 FALSE,
887 &Event,
888 &IoStatusBlock);
889 if (Irp == NULL)
890 {
891 return;
892 }
893
894 Status = IoCallDriver(DeviceObject, Irp);
895 if (Status == STATUS_PENDING)
896 {
897 KeWaitForSingleObject(&Event,
898 Executive,
899 KernelMode,
900 FALSE,
901 NULL);
902 Status = IoStatusBlock.Status;
903 }
904
905 ObDereferenceObject(FileObject);
906
907 return;
908 }
909
910 VOID
911 FASTCALL
xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,IN PSTRING NtDeviceName,OUT PUCHAR NtSystemPath,OUT PSTRING NtSystemPathString)912 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
913 IN PSTRING NtDeviceName,
914 OUT PUCHAR NtSystemPath,
915 OUT PSTRING NtSystemPathString)
916 {
917 USHORT i;
918 PULONG Devices;
919 NTSTATUS Status;
920 WCHAR Buffer[50];
921 HANDLE FileHandle;
922 UCHAR DriveLetter;
923 BOOLEAN SystemFound;
924 IO_STATUS_BLOCK StatusBlock;
925 PARTITION_TYPE PartitionType;
926 ANSI_STRING StringA1, StringA2;
927 PSTR Buffer1, Buffer2, LoadOptions;
928 OBJECT_ATTRIBUTES ObjectAttributes;
929 PDRIVE_LAYOUT_INFORMATION LayoutInfo;
930 PCONFIGURATION_INFORMATION ConfigInfo;
931 UNICODE_STRING StringU1, StringU2, StringU3;
932 ULONG Increment, DiskCount, RealDiskCount, HarddiskCount, PartitionCount, SystemPartition;
933
934 PAGED_CODE();
935
936 /* Get our disk count */
937 ConfigInfo = IoGetConfigurationInformation();
938 DiskCount = ConfigInfo->DiskCount;
939 RealDiskCount = 0;
940
941 /* Allocate two generic string buffers we'll use and reuser later on */
942 Buffer1 = ExAllocatePoolWithTag(NonPagedPool, 128, TAG_FSTUB);
943 Buffer2 = ExAllocatePoolWithTag(NonPagedPool, 64, TAG_FSTUB);
944 if (Buffer1 == NULL || Buffer2 == NULL)
945 {
946 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED);
947 }
948
949 /* In case of a remote boot, setup system path */
950 if (IoRemoteBootClient)
951 {
952 PSTR Last, Saved;
953
954 /* Find last \ */
955 Last = strrchr(LoaderBlock->NtBootPathName, '\\');
956 Saved = NULL;
957 /* Misformed name, fail */
958 if (Last == NULL)
959 {
960 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED);
961 }
962
963 /* In case the name was terminated by a \... */
964 if (Last[1] == ANSI_NULL)
965 {
966 /* Erase it, save position and find the previous \ */
967 *Last = ANSI_NULL;
968 Saved = Last;
969 Last = strrchr(LoaderBlock->NtBootPathName, '\\');
970 *Saved = '\\';
971 }
972
973 /* Misformed name, fail */
974 if (Last == NULL)
975 {
976 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED);
977 }
978
979 /* For a remote boot, assign X drive letter */
980 NtSystemPath[0] = 'X';
981 NtSystemPath[1] = ':';
982 /* And copy the end of the boot path */
983 strcpy((PSTR)&NtSystemPath[2], Last);
984
985 /* If we had to remove the trailing \, remove it here too */
986 if (Saved != NULL)
987 {
988 NtSystemPath[strlen((PSTR)NtSystemPath) - 1] = ANSI_NULL;
989 }
990
991 /* Setup output string */
992 RtlInitString(NtSystemPathString, (PSTR)NtSystemPath);
993 }
994
995 /* For each of our disks, create the physical device DOS device */
996 Increment = 0;
997 if (DiskCount != 0)
998 {
999 for (i = 0; i < DiskCount; ++i)
1000 {
1001 /* Setup the origin name */
1002 sprintf(Buffer1, "\\Device\\Harddisk%d\\Partition%d", i, 0);
1003 RtlInitAnsiString(&StringA1, Buffer1);
1004 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, &StringA1, TRUE)))
1005 {
1006 /* We cannot fail */
1007 KeBugCheck(ASSIGN_DRIVE_LETTERS_FAILED);
1008 }
1009
1010 /* Open the device */
1011 InitializeObjectAttributes(&ObjectAttributes,
1012 &StringU1,
1013 OBJ_CASE_INSENSITIVE,
1014 NULL,
1015 NULL);
1016 Status = ZwOpenFile(&FileHandle,
1017 SYNCHRONIZE | FILE_READ_DATA,
1018 &ObjectAttributes,
1019 &StatusBlock,
1020 FILE_SHARE_READ,
1021 FILE_SYNCHRONOUS_IO_NONALERT);
1022 if (NT_SUCCESS(Status))
1023 {
1024 /* If we managed, create the link */
1025 sprintf(Buffer2, "\\DosDevices\\PhysicalDrive%d", i);
1026 RtlInitAnsiString(&StringA2, Buffer2);
1027 Status = RtlAnsiStringToUnicodeString(&StringU2, &StringA2, TRUE);
1028 if (NT_SUCCESS(Status))
1029 {
1030 IoCreateSymbolicLink(&StringU2, &StringU1);
1031 RtlFreeUnicodeString(&StringU2);
1032 }
1033
1034 ZwClose(FileHandle);
1035
1036 RealDiskCount = i + 1;
1037 }
1038
1039 RtlFreeUnicodeString(&StringU1);
1040
1041 if (!NT_SUCCESS(Status))
1042 {
1043 if (Increment < 50)
1044 {
1045 ++Increment;
1046 ++DiskCount;
1047 }
1048 }
1049 }
1050 }
1051
1052 /* We done for our buffers */
1053 ExFreePoolWithTag(Buffer1, TAG_FSTUB);
1054 ExFreePoolWithTag(Buffer2, TAG_FSTUB);
1055
1056 /* Upcase our load options, if any */
1057 if (LoaderBlock->LoadOptions != NULL)
1058 {
1059 LoadOptions = _strupr(LoaderBlock->LoadOptions);
1060 }
1061 else
1062 {
1063 LoadOptions = NULL;
1064 }
1065
1066 /* If we boot with /MININT (system hive as volatile) option, assign X letter to boot device */
1067 if (LoadOptions != NULL &&
1068 strstr(LoadOptions, "MININT") != 0 &&
1069 NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, NtDeviceName, TRUE)))
1070 {
1071 if (NT_SUCCESS(HalpSetMountLetter(&StringU1, 'X')))
1072 {
1073 *NtSystemPath = 'X';
1074 }
1075
1076 RtlFreeUnicodeString(&StringU1);
1077 }
1078
1079 /* Compute our disks derangements */
1080 DiskCount -= Increment;
1081 if (RealDiskCount > DiskCount)
1082 {
1083 DiskCount = RealDiskCount;
1084 }
1085 Devices = IopComputeHarddiskDerangements(DiskCount);
1086
1087 /* Now, start browsing all our disks for assigning drive letters
1088 * Here, we'll only handle boot partition and primary partitions
1089 */
1090 HarddiskCount = 0;
1091 for (i = 0; i < DiskCount; ++i)
1092 {
1093 /* Get device ID according to derangements map */
1094 if (Devices != NULL)
1095 {
1096 HarddiskCount = Devices[i];
1097 }
1098
1099 /* Query disk layout */
1100 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount);
1101 RtlInitUnicodeString(&StringU1, Buffer);
1102 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo)))
1103 {
1104 LayoutInfo = NULL;
1105 }
1106
1107 /* Assume we didn't find system */
1108 SystemFound = FALSE;
1109 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, 1);
1110 RtlInitUnicodeString(&StringU1, Buffer);
1111 /* Query partition info for our disk */
1112 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType)))
1113 {
1114 /* It failed, retry for all the partitions */
1115 for (PartitionCount = 1; ; ++PartitionCount)
1116 {
1117 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
1118 RtlInitUnicodeString(&StringU1, Buffer);
1119 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType)))
1120 {
1121 break;
1122 }
1123
1124 /* We found a primary partition, assign a drive letter */
1125 if (PartitionType == PrimaryPartition)
1126 {
1127 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0);
1128 break;
1129 }
1130 }
1131 }
1132 else
1133 {
1134 /* All right */
1135 for (PartitionCount = 2; ; ++PartitionCount)
1136 {
1137 /* If our partition is bootable (MBR) or data (GPT), that's system partition */
1138 if (PartitionType == BootablePartition || PartitionType == DataPartition)
1139 {
1140 SystemFound = TRUE;
1141
1142 /* Assign a drive letter and stop here if MBR */
1143 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0);
1144 if (PartitionType == BootablePartition)
1145 {
1146 break;
1147 }
1148 }
1149
1150 /* Keep looping on all the partitions */
1151 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
1152 RtlInitUnicodeString(&StringU1, Buffer);
1153 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType)))
1154 {
1155 /* Mount every primary partition if we didn't find system */
1156 if (!SystemFound)
1157 {
1158 for (PartitionCount = 1; ; ++PartitionCount)
1159 {
1160 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
1161 RtlInitUnicodeString(&StringU1, Buffer);
1162 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType)))
1163 {
1164 break;
1165 }
1166
1167 if (PartitionType == PrimaryPartition)
1168 {
1169 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0);
1170 break;
1171 }
1172 }
1173 }
1174
1175 break;
1176 }
1177 }
1178 }
1179
1180 /* Free layout, we'll reallocate it for next device */
1181 if (LayoutInfo != NULL)
1182 {
1183 ExFreePoolWithTag(LayoutInfo, TAG_FSTUB);
1184 }
1185
1186 HarddiskCount = i + 1;
1187 }
1188
1189 /* Now, assign logical partitions */
1190 for (i = 0; i < DiskCount; ++i)
1191 {
1192 /* Get device ID according to derangements map */
1193 if (Devices != NULL)
1194 {
1195 HarddiskCount = Devices[i];
1196 }
1197 else
1198 {
1199 HarddiskCount = i;
1200 }
1201
1202 /* Query device layout */
1203 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount);
1204 RtlInitUnicodeString(&StringU1, Buffer);
1205 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo)))
1206 {
1207 LayoutInfo = NULL;
1208 }
1209
1210 /* And assign drive letter to logical partitions */
1211 for (PartitionCount = 1; ; ++PartitionCount)
1212 {
1213 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
1214 RtlInitUnicodeString(&StringU1, Buffer);
1215 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType)))
1216 {
1217 break;
1218 }
1219
1220 if (PartitionType == LogicalPartition)
1221 {
1222 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0);
1223 }
1224 }
1225
1226 /* Free layout, we'll reallocate it for next device */
1227 if (LayoutInfo != NULL)
1228 {
1229 ExFreePoolWithTag(LayoutInfo, 0);
1230 }
1231 }
1232
1233 /* Now, assign drive letters to everything else */
1234 for (i = 0; i < DiskCount; ++i)
1235 {
1236 /* Get device ID according to derangements map */
1237 if (Devices != NULL)
1238 {
1239 HarddiskCount = Devices[i];
1240 }
1241 else
1242 {
1243 HarddiskCount = i;
1244 }
1245
1246 /* Query device layout */
1247 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition0", HarddiskCount);
1248 RtlInitUnicodeString(&StringU1, Buffer);
1249 if (!NT_SUCCESS(HalpQueryDriveLayout(&StringU1, &LayoutInfo)))
1250 {
1251 LayoutInfo = NULL;
1252 }
1253
1254 /* Save system partition if any */
1255 SystemPartition = 0;
1256 for (PartitionCount = 1; ; ++PartitionCount)
1257 {
1258 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
1259 RtlInitUnicodeString(&StringU1, Buffer);
1260 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType)))
1261 {
1262 break;
1263 }
1264
1265 if ((PartitionType == BootablePartition || PartitionType == PrimaryPartition) && (SystemPartition == 0))
1266 {
1267 SystemPartition = PartitionCount;
1268 }
1269 }
1270
1271 /* And assign drive letter to anything but system partition */
1272 for (PartitionCount = 1; ; ++PartitionCount)
1273 {
1274 if (PartitionCount != SystemPartition)
1275 {
1276 swprintf(Buffer, L"\\Device\\Harddisk%d\\Partition%d", HarddiskCount, PartitionCount);
1277 RtlInitUnicodeString(&StringU1, Buffer);
1278 if (!NT_SUCCESS(HalpQueryPartitionType(&StringU1, LayoutInfo, &PartitionType)))
1279 {
1280 if (LayoutInfo != NULL)
1281 {
1282 ExFreePoolWithTag(LayoutInfo, 0);
1283 }
1284
1285 break;
1286 }
1287
1288 if (PartitionType == PrimaryPartition || PartitionType == FtPartition)
1289 {
1290 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, 0);
1291 }
1292 }
1293 }
1294 }
1295
1296 /* We're done with disks, if we have a device map, free it */
1297 if (Devices != NULL)
1298 {
1299 ExFreePoolWithTag(Devices, TAG_FSTUB);
1300 }
1301
1302 /* Now, assign drive letter to floppy drives */
1303 for (i = 0; i < ConfigInfo->FloppyCount; ++i)
1304 {
1305 swprintf(Buffer, L"\\Device\\Floppy%d", i);
1306 RtlInitUnicodeString(&StringU1, Buffer);
1307 if (HalpIsOldStyleFloppy(&StringU1))
1308 {
1309 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, TRUE);
1310 }
1311 }
1312
1313 /* And CD drives */
1314 for (i = 0; i < ConfigInfo->CdRomCount; ++i)
1315 {
1316 swprintf(Buffer, L"\\Device\\CdRom%d", i);
1317 RtlInitUnicodeString(&StringU1, Buffer);
1318 HalpNextDriveLetter(&StringU1, NtDeviceName, NtSystemPath, TRUE);
1319 }
1320
1321 /* If not remote boot, handle NtDeviceName */
1322 if (!IoRemoteBootClient && NT_SUCCESS(RtlAnsiStringToUnicodeString(&StringU1, NtDeviceName, TRUE)))
1323 {
1324 /* Assign it a drive letter */
1325 DriveLetter = HalpNextDriveLetter(&StringU1, NULL, NULL, TRUE);
1326 if (DriveLetter != 0)
1327 {
1328 if (DriveLetter != 0xFF)
1329 {
1330 *NtSystemPath = DriveLetter;
1331 }
1332 }
1333 /* If it fails through mount manager, retry manually */
1334 else
1335 {
1336 RtlInitUnicodeString(&StringU2, L"\\Device\\Floppy");
1337 RtlInitUnicodeString(&StringU3, L"\\Device\\CdRom");
1338
1339 if (RtlPrefixUnicodeString(&StringU2, &StringU1, TRUE))
1340 {
1341 DriveLetter = 'A';
1342 }
1343 else if (RtlPrefixUnicodeString(&StringU3, &StringU1, TRUE))
1344 {
1345 DriveLetter = 'D';
1346 }
1347 else
1348 {
1349 DriveLetter = 'C';
1350 }
1351
1352 /* Try any drive letter */
1353 while (HalpSetMountLetter(&StringU1, DriveLetter) != STATUS_SUCCESS)
1354 {
1355 ++DriveLetter;
1356
1357 if (DriveLetter > 'Z')
1358 {
1359 break;
1360 }
1361 }
1362
1363 /* If we're beyond Z (ie, no slot left) */
1364 if (DriveLetter > 'Z')
1365 {
1366 /* Delete Z, and reuse it for system */
1367 HalpDeleteMountLetter('Z');
1368 HalpSetMountLetter(&StringU1, 'Z');
1369 *NtSystemPath = 'Z';
1370 }
1371 else
1372 {
1373 /* Return matching drive letter */
1374 *NtSystemPath = DriveLetter;
1375 }
1376 }
1377
1378 RtlFreeUnicodeString(&StringU1);
1379 }
1380
1381 /* Enable auto assignement for mountmgr */
1382 HalpEnableAutomaticDriveLetterAssignment();
1383 }
1384
1385 /* PRIVATE FUNCTIONS *********************************************************/
1386
1387 NTSTATUS
1388 NTAPI
HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject,OUT PDISK_GEOMETRY_EX Geometry)1389 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject,
1390 OUT PDISK_GEOMETRY_EX Geometry)
1391 {
1392 PIRP Irp;
1393 IO_STATUS_BLOCK IoStatusBlock;
1394 PKEVENT Event;
1395 NTSTATUS Status;
1396
1397 PAGED_CODE();
1398
1399 /* Allocate a non-paged event */
1400 Event = ExAllocatePoolWithTag(NonPagedPool,
1401 sizeof(KEVENT),
1402 TAG_FILE_SYSTEM);
1403 if (!Event) return STATUS_INSUFFICIENT_RESOURCES;
1404
1405 /* Initialize it */
1406 KeInitializeEvent(Event, NotificationEvent, FALSE);
1407
1408 /* Build the IRP */
1409 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY_EX,
1410 DeviceObject,
1411 NULL,
1412 0UL,
1413 Geometry,
1414 sizeof(DISK_GEOMETRY_EX),
1415 FALSE,
1416 Event,
1417 &IoStatusBlock);
1418 if (!Irp)
1419 {
1420 /* Fail, free the event */
1421 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1422 return STATUS_INSUFFICIENT_RESOURCES;
1423 }
1424
1425 /* Call the driver and check if it's pending */
1426 Status = IoCallDriver(DeviceObject, Irp);
1427 if (Status == STATUS_PENDING)
1428 {
1429 /* Wait on the driver */
1430 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
1431 Status = IoStatusBlock.Status;
1432 }
1433
1434 /* Free the event and return the Status */
1435 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1436 return Status;
1437 }
1438
1439 BOOLEAN
1440 NTAPI
HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry,IN ULONGLONG MaxOffset,IN ULONGLONG MaxSector)1441 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry,
1442 IN ULONGLONG MaxOffset,
1443 IN ULONGLONG MaxSector)
1444 {
1445 ULONGLONG EndingSector;
1446 PAGED_CODE();
1447
1448 /* Unused partitions are considered valid */
1449 if (Entry->PartitionType == PARTITION_ENTRY_UNUSED) return TRUE;
1450
1451 /* Get the last sector of the partition */
1452 EndingSector = GET_STARTING_SECTOR(Entry) + GET_PARTITION_LENGTH(Entry);
1453
1454 /* Check if it's more then the maximum sector */
1455 if (EndingSector > MaxSector)
1456 {
1457 /* Invalid partition */
1458 DPRINT1("FSTUB: entry is invalid\n");
1459 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
1460 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
1461 DPRINT1("FSTUB: end %#I64x\n", EndingSector);
1462 DPRINT1("FSTUB: max %#I64x\n", MaxSector);
1463 return FALSE;
1464 }
1465 else if (GET_STARTING_SECTOR(Entry) > MaxOffset)
1466 {
1467 /* Invalid partition */
1468 DPRINT1("FSTUB: entry is invalid\n");
1469 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
1470 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
1471 DPRINT1("FSTUB: end %#I64x\n", EndingSector);
1472 DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset);
1473 return FALSE;
1474 }
1475
1476 /* It's fine, return success */
1477 return TRUE;
1478 }
1479
1480 VOID
1481 NTAPI
HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset,IN PLARGE_INTEGER PartitionLength,IN CCHAR ShiftCount,IN ULONG SectorsPerTrack,IN ULONG NumberOfTracks,IN ULONG ConventionalCylinders,OUT PPARTITION_DESCRIPTOR PartitionDescriptor)1482 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset,
1483 IN PLARGE_INTEGER PartitionLength,
1484 IN CCHAR ShiftCount,
1485 IN ULONG SectorsPerTrack,
1486 IN ULONG NumberOfTracks,
1487 IN ULONG ConventionalCylinders,
1488 OUT PPARTITION_DESCRIPTOR PartitionDescriptor)
1489 {
1490 LARGE_INTEGER FirstSector, SectorCount;
1491 ULONG LastSector, Remainder, SectorsPerCylinder;
1492 ULONG StartingCylinder, EndingCylinder;
1493 ULONG StartingTrack, EndingTrack;
1494 ULONG StartingSector, EndingSector;
1495 PAGED_CODE();
1496
1497 /* Calculate the number of sectors for each cylinder */
1498 SectorsPerCylinder = SectorsPerTrack * NumberOfTracks;
1499
1500 /* Calculate the first sector, and the sector count */
1501 FirstSector.QuadPart = PartitionOffset->QuadPart >> ShiftCount;
1502 SectorCount.QuadPart = PartitionLength->QuadPart >> ShiftCount;
1503
1504 /* Now calculate the last sector */
1505 LastSector = FirstSector.LowPart + SectorCount.LowPart - 1;
1506
1507 /* Calculate the first and last cylinders */
1508 StartingCylinder = FirstSector.LowPart / SectorsPerCylinder;
1509 EndingCylinder = LastSector / SectorsPerCylinder;
1510
1511 /* Set the default number of cylinders */
1512 if (!ConventionalCylinders) ConventionalCylinders = 1024;
1513
1514 /* Normalize the values */
1515 if (StartingCylinder >= ConventionalCylinders)
1516 {
1517 /* Set the maximum to 1023 */
1518 StartingCylinder = ConventionalCylinders - 1;
1519 }
1520 if (EndingCylinder >= ConventionalCylinders)
1521 {
1522 /* Set the maximum to 1023 */
1523 EndingCylinder = ConventionalCylinders - 1;
1524 }
1525
1526 /* Calculate the starting head and sector that still remain */
1527 Remainder = FirstSector.LowPart % SectorsPerCylinder;
1528 StartingTrack = Remainder / SectorsPerTrack;
1529 StartingSector = Remainder % SectorsPerTrack;
1530
1531 /* Calculate the ending head and sector that still remain */
1532 Remainder = LastSector % SectorsPerCylinder;
1533 EndingTrack = Remainder / SectorsPerTrack;
1534 EndingSector = Remainder % SectorsPerTrack;
1535
1536 /* Set cylinder data for the MSB */
1537 PartitionDescriptor->StartingCylinderMsb = (UCHAR)StartingCylinder;
1538 PartitionDescriptor->EndingCylinderMsb = (UCHAR)EndingCylinder;
1539
1540 /* Set the track data */
1541 PartitionDescriptor->StartingTrack = (UCHAR)StartingTrack;
1542 PartitionDescriptor->EndingTrack = (UCHAR)EndingTrack;
1543
1544 /* Update cylinder data for the LSB */
1545 StartingCylinder = ((StartingSector + 1) & 0x3F) |
1546 ((StartingCylinder >> 2) & 0xC0);
1547 EndingCylinder = ((EndingSector + 1) & 0x3F) |
1548 ((EndingCylinder >> 2) & 0xC0);
1549
1550 /* Set the cylinder data for the LSB */
1551 PartitionDescriptor->StartingCylinderLsb = (UCHAR)StartingCylinder;
1552 PartitionDescriptor->EndingCylinderLsb = (UCHAR)EndingCylinder;
1553 }
1554
1555 VOID
1556 FASTCALL
xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject,IN PULONG ConventionalCylinders,IN PLONGLONG DiskSize)1557 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject,
1558 IN PULONG ConventionalCylinders,
1559 IN PLONGLONG DiskSize)
1560 {
1561 PDISK_GEOMETRY DiskGeometry = NULL;
1562 PIO_STATUS_BLOCK IoStatusBlock = NULL;
1563 PKEVENT Event = NULL;
1564 PIRP Irp;
1565 NTSTATUS Status;
1566
1567 /* Set defaults */
1568 *ConventionalCylinders = 0;
1569 *DiskSize = 0;
1570
1571 /* Allocate the structure in nonpaged pool */
1572 DiskGeometry = ExAllocatePoolWithTag(NonPagedPool,
1573 sizeof(DISK_GEOMETRY),
1574 TAG_FILE_SYSTEM);
1575 if (!DiskGeometry) goto Cleanup;
1576
1577 /* Allocate the status block in nonpaged pool */
1578 IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool,
1579 sizeof(IO_STATUS_BLOCK),
1580 TAG_FILE_SYSTEM);
1581 if (!IoStatusBlock) goto Cleanup;
1582
1583 /* Allocate the event in nonpaged pool too */
1584 Event = ExAllocatePoolWithTag(NonPagedPool,
1585 sizeof(KEVENT),
1586 TAG_FILE_SYSTEM);
1587 if (!Event) goto Cleanup;
1588
1589 /* Initialize the event */
1590 KeInitializeEvent(Event, NotificationEvent, FALSE);
1591
1592 /* Build the IRP */
1593 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
1594 DeviceObject,
1595 NULL,
1596 0,
1597 DiskGeometry,
1598 sizeof(DISK_GEOMETRY),
1599 FALSE,
1600 Event,
1601 IoStatusBlock);
1602 if (!Irp) goto Cleanup;
1603
1604 /* Now call the driver */
1605 Status = IoCallDriver(DeviceObject, Irp);
1606 if (Status == STATUS_PENDING)
1607 {
1608 /* Wait for it to complete */
1609 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
1610 Status = IoStatusBlock->Status;
1611 }
1612
1613 /* Check driver status */
1614 if (NT_SUCCESS(Status))
1615 {
1616 /* Return the cylinder count */
1617 *ConventionalCylinders = DiskGeometry->Cylinders.LowPart;
1618
1619 /* Make sure it's not larger then 1024 */
1620 if (DiskGeometry->Cylinders.LowPart >= 1024)
1621 {
1622 /* Otherwise, normalize the value */
1623 *ConventionalCylinders = 1024;
1624 }
1625
1626 /* Calculate the disk size */
1627 *DiskSize = DiskGeometry->Cylinders.QuadPart *
1628 DiskGeometry->TracksPerCylinder *
1629 DiskGeometry->SectorsPerTrack *
1630 DiskGeometry->BytesPerSector;
1631 }
1632
1633 Cleanup:
1634 /* Free all the pointers */
1635 if (Event) ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1636 if (IoStatusBlock) ExFreePoolWithTag(IoStatusBlock, TAG_FILE_SYSTEM);
1637 if (DiskGeometry) ExFreePoolWithTag(DiskGeometry, TAG_FILE_SYSTEM);
1638 return;
1639 }
1640
1641 VOID
1642 FASTCALL
xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG MbrTypeIdentifier,OUT PVOID * MbrBuffer)1643 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
1644 IN ULONG SectorSize,
1645 IN ULONG MbrTypeIdentifier,
1646 OUT PVOID *MbrBuffer)
1647 {
1648 LARGE_INTEGER Offset;
1649 PUCHAR Buffer;
1650 ULONG BufferSize;
1651 KEVENT Event;
1652 IO_STATUS_BLOCK IoStatusBlock;
1653 PIRP Irp;
1654 PPARTITION_DESCRIPTOR PartitionDescriptor;
1655 NTSTATUS Status;
1656 PIO_STACK_LOCATION IoStackLocation;
1657
1658 Offset.QuadPart = 0;
1659
1660 /* Assume failure */
1661 *MbrBuffer = NULL;
1662
1663 /* Normalize the buffer size */
1664 BufferSize = max(512, SectorSize);
1665
1666 /* Allocate the buffer */
1667 Buffer = ExAllocatePoolWithTag(NonPagedPool,
1668 max(PAGE_SIZE, BufferSize),
1669 TAG_FILE_SYSTEM);
1670 if (!Buffer) return;
1671
1672 /* Initialize the Event */
1673 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1674
1675 /* Build the IRP */
1676 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1677 DeviceObject,
1678 Buffer,
1679 BufferSize,
1680 &Offset,
1681 &Event,
1682 &IoStatusBlock);
1683 if (!Irp)
1684 {
1685 /* Failed */
1686 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1687 return;
1688 }
1689
1690 /* Make sure to override volume verification */
1691 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1692 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1693
1694 /* Call the driver */
1695 Status = IoCallDriver(DeviceObject, Irp);
1696 if (Status == STATUS_PENDING)
1697 {
1698 /* Wait for completion */
1699 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1700 Status = IoStatusBlock.Status;
1701 }
1702
1703 /* Check driver Status */
1704 if (NT_SUCCESS(Status))
1705 {
1706 /* Validate the MBR Signature */
1707 if (*(PUINT16)&Buffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1708 {
1709 /* Failed */
1710 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1711 return;
1712 }
1713
1714 /* Get the partition entry */
1715 PartitionDescriptor = (PPARTITION_DESCRIPTOR)&Buffer[PARTITION_TABLE_OFFSET];
1716
1717 /* Make sure it's what the caller wanted */
1718 if (PartitionDescriptor->PartitionType != MbrTypeIdentifier)
1719 {
1720 /* It's not, free our buffer */
1721 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1722 }
1723 else
1724 {
1725 /* Check for OnTrack Disk Manager 6.0 / EZ-Drive partitions */
1726
1727 if (PartitionDescriptor->PartitionType == PARTITION_DM)
1728 {
1729 /* Return our buffer, but at sector 63 */
1730 *(PULONG)Buffer = 63;
1731 *MbrBuffer = Buffer;
1732 }
1733 else if (PartitionDescriptor->PartitionType == PARTITION_EZDRIVE)
1734 {
1735 /* EZ-Drive, return the buffer directly */
1736 *MbrBuffer = Buffer;
1737 }
1738 else
1739 {
1740 /* Otherwise crash on debug builds */
1741 ASSERT(PartitionDescriptor->PartitionType == PARTITION_EZDRIVE);
1742 }
1743 }
1744 }
1745 }
1746
1747 VOID
1748 NTAPI
FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor,IN ULONGLONG MaxOffset)1749 FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor,
1750 IN ULONGLONG MaxOffset)
1751 {
1752 ULONG PartitionMaxOffset, PartitionLength;
1753 PAGED_CODE();
1754
1755 /* Compute partition length (according to MBR entry) */
1756 PartitionMaxOffset = GET_STARTING_SECTOR(PartitionDescriptor) + GET_PARTITION_LENGTH(PartitionDescriptor);
1757 /* In case the partition length goes beyond disk size... */
1758 if (PartitionMaxOffset > MaxOffset)
1759 {
1760 /* Resize partition to its maximum real length */
1761 PartitionLength = (ULONG)(PartitionMaxOffset - GET_STARTING_SECTOR(PartitionDescriptor));
1762 SET_PARTITION_LENGTH(PartitionDescriptor, PartitionLength);
1763 }
1764 }
1765
1766 NTSTATUS
1767 FASTCALL
xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN BOOLEAN ReturnRecognizedPartitions,IN OUT PDRIVE_LAYOUT_INFORMATION * PartitionBuffer)1768 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
1769 IN ULONG SectorSize,
1770 IN BOOLEAN ReturnRecognizedPartitions,
1771 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
1772 {
1773 KEVENT Event;
1774 IO_STATUS_BLOCK IoStatusBlock;
1775 PIRP Irp;
1776 PPARTITION_DESCRIPTOR PartitionDescriptor;
1777 CCHAR Entry;
1778 NTSTATUS Status;
1779 PPARTITION_INFORMATION PartitionInfo;
1780 PUCHAR Buffer = NULL;
1781 ULONG BufferSize = 2048, InputSize;
1782 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL;
1783 LONG j = -1, i = -1, k;
1784 DISK_GEOMETRY_EX DiskGeometryEx;
1785 LONGLONG EndSector, MaxSector, StartOffset;
1786 LARGE_INTEGER Offset, VolumeOffset;
1787 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE, MbrFound = FALSE;
1788 BOOLEAN IsValid, IsEmpty = TRUE;
1789 PVOID MbrBuffer;
1790 PIO_STACK_LOCATION IoStackLocation;
1791 UCHAR PartitionType;
1792 LARGE_INTEGER HiddenSectors64;
1793
1794 PAGED_CODE();
1795
1796 VolumeOffset.QuadPart = Offset.QuadPart = 0;
1797
1798 /* Allocate the buffer */
1799 *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
1800 BufferSize,
1801 TAG_FILE_SYSTEM);
1802 if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES;
1803
1804 /* Normalize the buffer size */
1805 InputSize = max(512, SectorSize);
1806
1807 /* Check for EZ-Drive */
1808 HalExamineMBR(DeviceObject, InputSize, PARTITION_EZDRIVE, &MbrBuffer);
1809 if (MbrBuffer)
1810 {
1811 /* EZ-Drive found, bias the offset */
1812 IsEzDrive = TRUE;
1813 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
1814 Offset.QuadPart = 512;
1815 }
1816
1817 /* Get drive geometry */
1818 Status = HalpGetFullGeometry(DeviceObject, &DiskGeometryEx);
1819 if (!NT_SUCCESS(Status))
1820 {
1821 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1822 *PartitionBuffer = NULL;
1823 return Status;
1824 }
1825
1826 /* Get the end and maximum sector */
1827 EndSector = DiskGeometryEx.DiskSize.QuadPart / DiskGeometryEx.Geometry.BytesPerSector;
1828 MaxSector = EndSector << 1;
1829 DPRINT("FSTUB: DiskSize = %#I64x, MaxSector = %#I64x\n",
1830 DiskGeometryEx.DiskSize, MaxSector);
1831
1832 /* Allocate our buffer */
1833 Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, InputSize, TAG_FILE_SYSTEM);
1834 if (!Buffer)
1835 {
1836 /* Fail, free the input buffer */
1837 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1838 *PartitionBuffer = NULL;
1839 return STATUS_INSUFFICIENT_RESOURCES;
1840 }
1841
1842 /* Start partition loop */
1843 do
1844 {
1845 /* Assume the partition is valid */
1846 IsValid = TRUE;
1847
1848 /* Initialize the event */
1849 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1850
1851 /* Clear the buffer and build the IRP */
1852 RtlZeroMemory(Buffer, InputSize);
1853 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1854 DeviceObject,
1855 Buffer,
1856 InputSize,
1857 &Offset,
1858 &Event,
1859 &IoStatusBlock);
1860 if (!Irp)
1861 {
1862 /* Failed */
1863 Status = STATUS_INSUFFICIENT_RESOURCES;
1864 break;
1865 }
1866
1867 /* Make sure to disable volume verification */
1868 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1869 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1870
1871 /* Call the driver */
1872 Status = IoCallDriver(DeviceObject, Irp);
1873 if (Status == STATUS_PENDING)
1874 {
1875 /* Wait for completion */
1876 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1877 Status = IoStatusBlock.Status;
1878 }
1879
1880 /* Normalize status code and check for failure */
1881 if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS;
1882 if (!NT_SUCCESS(Status)) break;
1883
1884 /* If we biased for EZ-Drive, unbias now */
1885 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
1886
1887 /* Make sure this is a valid MBR */
1888 if (*(PUINT16)&Buffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1889 {
1890 /* It's not, fail */
1891 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
1892 "partition table %d\n", j + 1);
1893 break;
1894 }
1895
1896 /* At this point we have a valid MBR */
1897 MbrFound = TRUE;
1898
1899 /* Check if we weren't given an offset */
1900 if (!Offset.QuadPart)
1901 {
1902 /* Then read the signature off the disk */
1903 (*PartitionBuffer)->Signature = *(PUINT32)&Buffer[DISK_SIGNATURE_OFFSET];
1904 }
1905
1906 /* Get the partition descriptor array */
1907 PartitionDescriptor = (PPARTITION_DESCRIPTOR)&Buffer[PARTITION_TABLE_OFFSET];
1908
1909 /* Start looping partitions */
1910 j++;
1911 DPRINT("FSTUB: Partition Table %d:\n", j);
1912 for (Entry = 1, k = 0; Entry <= NUM_PARTITION_TABLE_ENTRIES; Entry++, PartitionDescriptor++)
1913 {
1914 /* Get the partition type */
1915 PartitionType = PartitionDescriptor->PartitionType;
1916
1917 /* Print debug messages */
1918 DPRINT("Partition Entry %d,%d: type %#x %s\n",
1919 j,
1920 Entry,
1921 PartitionType,
1922 (PartitionDescriptor->ActiveFlag) ? "Active" : "");
1923 DPRINT("\tOffset %#08lx for %#08lx Sectors\n",
1924 GET_STARTING_SECTOR(PartitionDescriptor),
1925 GET_PARTITION_LENGTH(PartitionDescriptor));
1926
1927 /* Check whether we're facing a protective MBR */
1928 if (PartitionType == EFI_PMBR_OSTYPE_EFI)
1929 {
1930 /* Partition length might be bigger than disk size */
1931 FstubFixupEfiPartition(PartitionDescriptor, DiskGeometryEx.DiskSize.QuadPart);
1932 }
1933
1934 /* Make sure that the partition is valid, unless it's the first */
1935 if (!(HalpIsValidPartitionEntry(PartitionDescriptor,
1936 DiskGeometryEx.DiskSize.QuadPart,
1937 MaxSector)) && (j == 0))
1938 {
1939 /* It's invalid, so fail */
1940 IsValid = FALSE;
1941 break;
1942 }
1943
1944 /* Check if it's a container */
1945 if (IsContainerPartition(PartitionType))
1946 {
1947 /* Increase the count of containers */
1948 if (++k != 1)
1949 {
1950 /* More then one table is invalid */
1951 DPRINT1("FSTUB: Multiple container partitions found in "
1952 "partition table %d\n - table is invalid\n",
1953 j);
1954 IsValid = FALSE;
1955 break;
1956 }
1957 }
1958
1959 /* Check if the partition is supposedly empty */
1960 if (IsEmpty)
1961 {
1962 /* But check if it actually has a start and/or length */
1963 if ((GET_STARTING_SECTOR(PartitionDescriptor)) ||
1964 (GET_PARTITION_LENGTH(PartitionDescriptor)))
1965 {
1966 /* So then it's not really empty */
1967 IsEmpty = FALSE;
1968 }
1969 }
1970
1971 /* Check if the caller wanted only recognized partitions */
1972 if (ReturnRecognizedPartitions)
1973 {
1974 /* Then check if this one is unused, or a container */
1975 if ((PartitionType == PARTITION_ENTRY_UNUSED) ||
1976 IsContainerPartition(PartitionType))
1977 {
1978 /* Skip it, since the caller doesn't want it */
1979 continue;
1980 }
1981 }
1982
1983 /* Increase the structure count and check if they can fit */
1984 if ((sizeof(DRIVE_LAYOUT_INFORMATION) +
1985 (++i * sizeof(PARTITION_INFORMATION))) >
1986 BufferSize)
1987 {
1988 /* Allocate a new buffer that's twice as big */
1989 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool,
1990 BufferSize << 1,
1991 TAG_FILE_SYSTEM);
1992 if (!DriveLayoutInfo)
1993 {
1994 /* Out of memory, undo this extra structure */
1995 --i;
1996 Status = STATUS_INSUFFICIENT_RESOURCES;
1997 break;
1998 }
1999
2000 /* Copy the contents of the old buffer */
2001 RtlMoveMemory(DriveLayoutInfo,
2002 *PartitionBuffer,
2003 BufferSize);
2004
2005 /* Free the old buffer and set this one as the new one */
2006 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
2007 *PartitionBuffer = DriveLayoutInfo;
2008
2009 /* Double the size */
2010 BufferSize <<= 1;
2011 }
2012
2013 /* Now get the current structure being filled and initialize it */
2014 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i];
2015 PartitionInfo->PartitionType = PartitionType;
2016 PartitionInfo->RewritePartition = FALSE;
2017
2018 /* Check if we're dealing with a partition that's in use */
2019 if (PartitionType != PARTITION_ENTRY_UNUSED)
2020 {
2021 /* Check if it's bootable */
2022 PartitionInfo->BootIndicator = PartitionDescriptor->
2023 ActiveFlag & 0x80 ?
2024 TRUE : FALSE;
2025
2026 /* Check if its' a container */
2027 if (IsContainerPartition(PartitionType))
2028 {
2029 /* Then don't recognize it and use the volume offset */
2030 PartitionInfo->RecognizedPartition = FALSE;
2031 StartOffset = VolumeOffset.QuadPart;
2032 }
2033 else
2034 {
2035 /* Then recognize it and use the partition offset */
2036 PartitionInfo->RecognizedPartition = TRUE;
2037 StartOffset = Offset.QuadPart;
2038 }
2039
2040 /* Get the starting offset */
2041 PartitionInfo->StartingOffset.QuadPart =
2042 StartOffset +
2043 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor),
2044 SectorSize);
2045
2046 /* Calculate the number of hidden sectors */
2047 HiddenSectors64.QuadPart = (PartitionInfo->
2048 StartingOffset.QuadPart -
2049 StartOffset) /
2050 SectorSize;
2051 PartitionInfo->HiddenSectors = HiddenSectors64.LowPart;
2052
2053 /* Get the partition length */
2054 PartitionInfo->PartitionLength.QuadPart =
2055 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor),
2056 SectorSize);
2057
2058 /* Get the partition number */
2059 /* FIXME: REACTOS HACK -- Needed for xHalIoAssignDriveLetters() */
2060 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartitionType)) ? i + 1 : 0;
2061 }
2062 else
2063 {
2064 /* Otherwise, clear all the relevant fields */
2065 PartitionInfo->BootIndicator = FALSE;
2066 PartitionInfo->RecognizedPartition = FALSE;
2067 PartitionInfo->StartingOffset.QuadPart = 0;
2068 PartitionInfo->PartitionLength.QuadPart = 0;
2069 PartitionInfo->HiddenSectors = 0;
2070
2071 /* FIXME: REACTOS HACK -- Needed for xHalIoAssignDriveLetters() */
2072 PartitionInfo->PartitionNumber = 0;
2073 }
2074 }
2075
2076 /* Finish debug log, and check for failure */
2077 DPRINT("\n");
2078 if (!NT_SUCCESS(Status)) break;
2079
2080 /* Also check if we hit an invalid entry here */
2081 if (!IsValid)
2082 {
2083 /* We did, so break out of the loop minus one entry */
2084 j--;
2085 break;
2086 }
2087
2088 /* Reset the offset */
2089 Offset.QuadPart = 0;
2090
2091 /* Go back to the descriptor array and loop it */
2092 PartitionDescriptor = (PPARTITION_DESCRIPTOR)&Buffer[PARTITION_TABLE_OFFSET];
2093 for (Entry = 1; Entry <= NUM_PARTITION_TABLE_ENTRIES; Entry++, PartitionDescriptor++)
2094 {
2095 /* Check if this is a container partition, since we skipped them */
2096 if (IsContainerPartition(PartitionDescriptor->PartitionType))
2097 {
2098 /* Get its offset */
2099 Offset.QuadPart = VolumeOffset.QuadPart +
2100 UInt32x32To64(
2101 GET_STARTING_SECTOR(PartitionDescriptor),
2102 SectorSize);
2103
2104 /* If this is a primary partition, this is the volume offset */
2105 if (IsPrimary) VolumeOffset = Offset;
2106
2107 /* Also update the maximum sector */
2108 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor);
2109 DPRINT1("FSTUB: MaxSector now = %I64d\n", MaxSector);
2110 break;
2111 }
2112 }
2113
2114 /* Loop the next partitions, which are not primary anymore */
2115 IsPrimary = FALSE;
2116 } while (Offset.HighPart | Offset.LowPart);
2117
2118 /* Check if this is a removable device that's probably a super-floppy */
2119 if ((DiskGeometryEx.Geometry.MediaType == RemovableMedia) &&
2120 (j == 0) && (MbrFound) && (IsEmpty))
2121 {
2122 PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer;
2123
2124 /* Read the jump bytes to detect super-floppy */
2125 if ((BootSectorInfo->JumpByte[0] == 0xeb) ||
2126 (BootSectorInfo->JumpByte[0] == 0xe9))
2127 {
2128 /* Super floppes don't have typical MBRs, so skip them */
2129 DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
2130 "table - disk is a super floppy and has no valid MBR\n",
2131 BootSectorInfo->JumpByte);
2132 j = -1;
2133 }
2134 }
2135
2136 /* Check if we're still at partition -1 */
2137 if (j == -1)
2138 {
2139 /* The likely cause is the super floppy detection above */
2140 if ((MbrFound) || (DiskGeometryEx.Geometry.MediaType == RemovableMedia))
2141 {
2142 /* Print out debugging information */
2143 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
2144 "super-floppy\n",
2145 DeviceObject);
2146 DPRINT1("FSTUB: Drive has %I64d sectors and is %#016I64x "
2147 "bytes large\n",
2148 EndSector, DiskGeometryEx.DiskSize);
2149
2150 /* We should at least have some sectors */
2151 if (EndSector > 0)
2152 {
2153 /* Get the entry we'll use */
2154 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
2155
2156 /* Fill it out with data for a super-floppy */
2157 PartitionInfo->RewritePartition = FALSE;
2158 PartitionInfo->RecognizedPartition = TRUE;
2159 PartitionInfo->PartitionType = PARTITION_FAT_16;
2160 PartitionInfo->BootIndicator = FALSE;
2161 PartitionInfo->HiddenSectors = 0;
2162 PartitionInfo->StartingOffset.QuadPart = 0;
2163 PartitionInfo->PartitionLength = DiskGeometryEx.DiskSize;
2164
2165 /* FIXME: REACTOS HACK -- Needed for xHalIoAssignDriveLetters() */
2166 PartitionInfo->PartitionNumber = 0;
2167
2168 /* Set the signature and set the count back to 0 */
2169 (*PartitionBuffer)->Signature = 1;
2170 i = 0;
2171 }
2172 }
2173 else
2174 {
2175 /* Otherwise, this isn't a super floppy, so set an invalid count */
2176 i = -1;
2177 }
2178 }
2179
2180 /* Set the partition count */
2181 (*PartitionBuffer)->PartitionCount = ++i;
2182
2183 /* If we have no count, delete the signature */
2184 if (!i) (*PartitionBuffer)->Signature = 0;
2185
2186 /* Free the buffer and check for success */
2187 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
2188 if (!NT_SUCCESS(Status))
2189 {
2190 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
2191 *PartitionBuffer = NULL;
2192 }
2193
2194 /* Return status */
2195 return Status;
2196 }
2197
2198 NTSTATUS
2199 FASTCALL
xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG PartitionNumber,IN ULONG PartitionType)2200 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
2201 IN ULONG SectorSize,
2202 IN ULONG PartitionNumber,
2203 IN ULONG PartitionType)
2204 {
2205 PIRP Irp;
2206 KEVENT Event;
2207 IO_STATUS_BLOCK IoStatusBlock;
2208 NTSTATUS Status;
2209 LARGE_INTEGER Offset, VolumeOffset;
2210 PUCHAR Buffer = NULL;
2211 ULONG BufferSize;
2212 ULONG i = 0;
2213 ULONG Entry;
2214 PPARTITION_DESCRIPTOR PartitionDescriptor;
2215 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE;
2216 PVOID MbrBuffer;
2217 PIO_STACK_LOCATION IoStackLocation;
2218
2219 PAGED_CODE();
2220
2221 VolumeOffset.QuadPart = Offset.QuadPart = 0;
2222
2223 /* Normalize the buffer size */
2224 BufferSize = max(512, SectorSize);
2225
2226 /* Check for EZ-Drive */
2227 HalExamineMBR(DeviceObject, BufferSize, PARTITION_EZDRIVE, &MbrBuffer);
2228 if (MbrBuffer)
2229 {
2230 /* EZ-Drive found, bias the offset */
2231 IsEzDrive = TRUE;
2232 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
2233 Offset.QuadPart = 512;
2234 }
2235
2236 /* Allocate our partition buffer */
2237 Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, PAGE_SIZE, TAG_FILE_SYSTEM);
2238 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2239
2240 /* Initialize the event we'll use and loop partitions */
2241 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2242 do
2243 {
2244 /* Reset the event since we reuse it */
2245 KeClearEvent(&Event);
2246
2247 /* Build the read IRP */
2248 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
2249 DeviceObject,
2250 Buffer,
2251 BufferSize,
2252 &Offset,
2253 &Event,
2254 &IoStatusBlock);
2255 if (!Irp)
2256 {
2257 /* Fail */
2258 Status = STATUS_INSUFFICIENT_RESOURCES;
2259 break;
2260 }
2261
2262 /* Make sure to disable volume verification */
2263 IoStackLocation = IoGetNextIrpStackLocation(Irp);
2264 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2265
2266 /* Call the driver */
2267 Status = IoCallDriver(DeviceObject, Irp);
2268 if (Status == STATUS_PENDING)
2269 {
2270 /* Wait for completion */
2271 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
2272 Status = IoStatusBlock.Status;
2273 }
2274
2275 /* Check for failure */
2276 if (!NT_SUCCESS(Status)) break;
2277
2278 /* If we biased for EZ-Drive, unbias now */
2279 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2280
2281 /* Make sure this is a valid MBR */
2282 if (*(PUINT16)&Buffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
2283 {
2284 /* It's not, fail */
2285 Status = STATUS_BAD_MASTER_BOOT_RECORD;
2286 break;
2287 }
2288
2289 /* Get the partition descriptors and loop them */
2290 PartitionDescriptor = (PPARTITION_DESCRIPTOR)&Buffer[PARTITION_TABLE_OFFSET];
2291 for (Entry = 1; Entry <= NUM_PARTITION_TABLE_ENTRIES; Entry++, PartitionDescriptor++)
2292 {
2293 /* Check if it's unused or a container partition */
2294 if ((PartitionDescriptor->PartitionType == PARTITION_ENTRY_UNUSED) ||
2295 (IsContainerPartition(PartitionDescriptor->PartitionType)))
2296 {
2297 /* Go to the next one */
2298 continue;
2299 }
2300
2301 /* It's a valid partition, so increase the partition count */
2302 if (++i == PartitionNumber)
2303 {
2304 /* We found a match, set the type */
2305 PartitionDescriptor->PartitionType = (UCHAR)PartitionType;
2306
2307 /* Reset the reusable event */
2308 KeClearEvent(&Event);
2309
2310 /* Build the write IRP */
2311 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
2312 DeviceObject,
2313 Buffer,
2314 BufferSize,
2315 &Offset,
2316 &Event,
2317 &IoStatusBlock);
2318 if (!Irp)
2319 {
2320 /* Fail */
2321 Status = STATUS_INSUFFICIENT_RESOURCES;
2322 break;
2323 }
2324
2325 /* Disable volume verification */
2326 IoStackLocation = IoGetNextIrpStackLocation(Irp);
2327 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2328
2329 /* Call the driver */
2330 Status = IoCallDriver(DeviceObject, Irp);
2331 if (Status == STATUS_PENDING)
2332 {
2333 /* Wait for completion */
2334 KeWaitForSingleObject(&Event,
2335 Executive,
2336 KernelMode,
2337 FALSE,
2338 NULL);
2339 Status = IoStatusBlock.Status;
2340 }
2341
2342 /* We're done, break out of the loop */
2343 break;
2344 }
2345 }
2346
2347 /* If we looped all the partitions, break out */
2348 if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break;
2349
2350 /* Nothing found yet, get the partition array again */
2351 PartitionDescriptor = (PPARTITION_DESCRIPTOR)&Buffer[PARTITION_TABLE_OFFSET];
2352 for (Entry = 1; Entry <= NUM_PARTITION_TABLE_ENTRIES; Entry++, PartitionDescriptor++)
2353 {
2354 /* Check if this was a container partition (we skipped these) */
2355 if (IsContainerPartition(PartitionDescriptor->PartitionType))
2356 {
2357 /* Update the partition offset */
2358 Offset.QuadPart = VolumeOffset.QuadPart +
2359 GET_STARTING_SECTOR(PartitionDescriptor) *
2360 SectorSize;
2361
2362 /* If this was the primary partition, update the volume too */
2363 if (IsPrimary) VolumeOffset = Offset;
2364 break;
2365 }
2366 }
2367
2368 /* Check if we already searched all the partitions */
2369 if (Entry > NUM_PARTITION_TABLE_ENTRIES)
2370 {
2371 /* Then we failed to find a good MBR */
2372 Status = STATUS_BAD_MASTER_BOOT_RECORD;
2373 break;
2374 }
2375
2376 /* Loop the next partitions, which are not primary anymore */
2377 IsPrimary = FALSE;
2378 } while (i < PartitionNumber);
2379
2380 /* Everything done, cleanup */
2381 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
2382 return Status;
2383 }
2384
2385 NTSTATUS
2386 FASTCALL
xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG SectorsPerTrack,IN ULONG NumberOfHeads,IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)2387 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
2388 IN ULONG SectorSize,
2389 IN ULONG SectorsPerTrack,
2390 IN ULONG NumberOfHeads,
2391 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
2392 {
2393 KEVENT Event;
2394 IO_STATUS_BLOCK IoStatusBlock;
2395 PIRP Irp;
2396 NTSTATUS Status = STATUS_SUCCESS;
2397 ULONG BufferSize;
2398 PUCHAR Buffer;
2399 PPTE Entry;
2400 PPARTITION_TABLE PartitionTable;
2401 LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset;
2402 LARGE_INTEGER StartOffset, PartitionLength;
2403 ULONG i, j;
2404 CCHAR k;
2405 BOOLEAN IsEzDrive = FALSE, IsSuperFloppy = FALSE, DoRewrite = FALSE, IsMbr;
2406 ULONG ConventionalCylinders;
2407 LONGLONG DiskSize;
2408 PDISK_LAYOUT DiskLayout = (PDISK_LAYOUT)PartitionBuffer;
2409 PVOID MbrBuffer;
2410 UCHAR PartitionType;
2411 PIO_STACK_LOCATION IoStackLocation;
2412 PPARTITION_INFORMATION PartitionInfo = PartitionBuffer->PartitionEntry;
2413 PPARTITION_INFORMATION TableEntry;
2414
2415 PAGED_CODE();
2416
2417 ExtendedOffset.QuadPart = NextOffset.QuadPart = Offset.QuadPart = 0;
2418
2419 /* Normalize the buffer size */
2420 BufferSize = max(512, SectorSize);
2421
2422 /* Get the partial drive geometry */
2423 xHalGetPartialGeometry(DeviceObject, &ConventionalCylinders, &DiskSize);
2424
2425 /* Check for EZ-Drive */
2426 HalExamineMBR(DeviceObject, BufferSize, PARTITION_EZDRIVE, &MbrBuffer);
2427 if (MbrBuffer)
2428 {
2429 /* EZ-Drive found, bias the offset */
2430 IsEzDrive = TRUE;
2431 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
2432 Offset.QuadPart = 512;
2433 }
2434
2435 /* Get the number of bits to shift to multiply by the sector size */
2436 for (k = 0; k < 32; k++) if ((SectorSize >> k) == 1) break;
2437
2438 /* Check if there's only one partition */
2439 if (PartitionBuffer->PartitionCount == 1)
2440 {
2441 /* Check if it has no starting offset or hidden sectors */
2442 if (!(PartitionInfo->StartingOffset.QuadPart) &&
2443 !(PartitionInfo->HiddenSectors))
2444 {
2445 /* Then it's a super floppy */
2446 IsSuperFloppy = TRUE;
2447
2448 /* Which also means it must be non-bootable FAT-16 */
2449 if ((PartitionInfo->PartitionNumber) ||
2450 (PartitionInfo->PartitionType != PARTITION_FAT_16) ||
2451 (PartitionInfo->BootIndicator))
2452 {
2453 /* It's not, so we fail */
2454 return STATUS_INVALID_PARAMETER;
2455 }
2456
2457 /* Check if it needs a rewrite, and disable EZ-Drive for sure */
2458 if (PartitionInfo->RewritePartition) DoRewrite = TRUE;
2459 IsEzDrive = FALSE;
2460 }
2461 }
2462
2463 /* Count the number of partition tables */
2464 DiskLayout->TableCount = (PartitionBuffer->PartitionCount + NUM_PARTITION_TABLE_ENTRIES - 1) / NUM_PARTITION_TABLE_ENTRIES;
2465
2466 /* Allocate our partition buffer */
2467 Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, PAGE_SIZE, TAG_FILE_SYSTEM);
2468 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2469
2470 /* Loop the entries */
2471 Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET];
2472 for (i = 0; i < DiskLayout->TableCount; i++)
2473 {
2474 /* Set if this is the MBR partition */
2475 IsMbr= (BOOLEAN)!i;
2476
2477 /* Initialize th event */
2478 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2479
2480 /* Build the read IRP */
2481 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
2482 DeviceObject,
2483 Buffer,
2484 BufferSize,
2485 &Offset,
2486 &Event,
2487 &IoStatusBlock);
2488 if (!Irp)
2489 {
2490 /* Fail */
2491 Status = STATUS_INSUFFICIENT_RESOURCES;
2492 break;
2493 }
2494
2495 /* Make sure to disable volume verification */
2496 IoStackLocation = IoGetNextIrpStackLocation(Irp);
2497 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2498
2499 /* Call the driver */
2500 Status = IoCallDriver(DeviceObject, Irp);
2501 if (Status == STATUS_PENDING)
2502 {
2503 /* Wait for completion */
2504 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
2505 Status = IoStatusBlock.Status;
2506 }
2507
2508 /* Check for failure */
2509 if (!NT_SUCCESS(Status)) break;
2510
2511 /* If we biased for EZ-Drive, unbias now */
2512 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2513
2514 /* Check if this is a normal disk */
2515 if (!IsSuperFloppy)
2516 {
2517 /* Set the boot record signature */
2518 *(PUINT16)&Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
2519
2520 /* By default, don't require a rewrite */
2521 DoRewrite = FALSE;
2522
2523 /* Check if we don't have an offset */
2524 if (!Offset.QuadPart)
2525 {
2526 /* Check if the signature doesn't match */
2527 if (*(PUINT32)&Buffer[DISK_SIGNATURE_OFFSET] != PartitionBuffer->Signature)
2528 {
2529 /* Then write the signature and now we need a rewrite */
2530 *(PUINT32)&Buffer[DISK_SIGNATURE_OFFSET] = PartitionBuffer->Signature;
2531 DoRewrite = TRUE;
2532 }
2533 }
2534
2535 /* Loop the partition table entries */
2536 PartitionTable = &DiskLayout->PartitionTable[i];
2537 for (j = 0; j < NUM_PARTITION_TABLE_ENTRIES; j++)
2538 {
2539 /* Get the current entry and type */
2540 TableEntry = &PartitionTable->PartitionEntry[j];
2541 PartitionType = TableEntry->PartitionType;
2542
2543 /* Check if the entry needs a rewrite */
2544 if (TableEntry->RewritePartition)
2545 {
2546 /* Then we need one too */
2547 DoRewrite = TRUE;
2548
2549 /* Save the type and if it's a bootable partition */
2550 Entry[j].PartitionType = TableEntry->PartitionType;
2551 Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0;
2552
2553 /* Make sure it's used */
2554 if (PartitionType != PARTITION_ENTRY_UNUSED)
2555 {
2556 /* Make sure it's not a container (unless primary) */
2557 if ((IsMbr) || !(IsContainerPartition(PartitionType)))
2558 {
2559 /* Use the partition offset */
2560 StartOffset.QuadPart = Offset.QuadPart;
2561 }
2562 else
2563 {
2564 /* Use the extended logical partition offset */
2565 StartOffset.QuadPart = ExtendedOffset.QuadPart;
2566 }
2567
2568 /* Set the sector offset */
2569 SectorOffset.QuadPart = TableEntry->
2570 StartingOffset.QuadPart -
2571 StartOffset.QuadPart;
2572
2573 /* Now calculate the starting sector */
2574 StartOffset.QuadPart = SectorOffset.QuadPart >> k;
2575 Entry[j].StartingSector = StartOffset.LowPart;
2576
2577 /* As well as the length */
2578 PartitionLength.QuadPart = TableEntry->PartitionLength.
2579 QuadPart >> k;
2580 Entry[j].PartitionLength = PartitionLength.LowPart;
2581
2582 /* Calculate the CHS values */
2583 HalpCalculateChsValues(&TableEntry->StartingOffset,
2584 &TableEntry->PartitionLength,
2585 k,
2586 SectorsPerTrack,
2587 NumberOfHeads,
2588 ConventionalCylinders,
2589 (PPARTITION_DESCRIPTOR)
2590 &Entry[j]);
2591 }
2592 else
2593 {
2594 /* Otherwise set up an empty entry */
2595 Entry[j].StartingSector = 0;
2596 Entry[j].PartitionLength = 0;
2597 Entry[j].StartingTrack = 0;
2598 Entry[j].EndingTrack = 0;
2599 Entry[j].StartingCylinder = 0;
2600 Entry[j].EndingCylinder = 0;
2601 }
2602 }
2603
2604 /* Check if this is a container partition */
2605 if (IsContainerPartition(PartitionType))
2606 {
2607 /* Then update the offset to use */
2608 NextOffset = TableEntry->StartingOffset;
2609 }
2610 }
2611 }
2612
2613 /* Check if we need to write back the buffer */
2614 if (DoRewrite)
2615 {
2616 /* We don't need to do this again */
2617 DoRewrite = FALSE;
2618
2619 /* Initialize the event */
2620 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2621
2622 /* If we unbiased for EZ-Drive, rebias now */
2623 if (IsEzDrive && !Offset.QuadPart) Offset.QuadPart = 512;
2624
2625 /* Build the write IRP */
2626 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
2627 DeviceObject,
2628 Buffer,
2629 BufferSize,
2630 &Offset,
2631 &Event,
2632 &IoStatusBlock);
2633 if (!Irp)
2634 {
2635 /* Fail */
2636 Status = STATUS_INSUFFICIENT_RESOURCES;
2637 break;
2638 }
2639
2640 /* Make sure to disable volume verification */
2641 IoStackLocation = IoGetNextIrpStackLocation(Irp);
2642 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2643
2644 /* Call the driver */
2645 Status = IoCallDriver(DeviceObject, Irp);
2646 if (Status == STATUS_PENDING)
2647 {
2648 /* Wait for completion */
2649 KeWaitForSingleObject(&Event,
2650 Executive,
2651 KernelMode,
2652 FALSE,
2653 NULL);
2654 Status = IoStatusBlock.Status;
2655 }
2656
2657 /* Check for failure */
2658 if (!NT_SUCCESS(Status)) break;
2659
2660 /* If we biased for EZ-Drive, unbias now */
2661 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2662 }
2663
2664 /* Update the partition offset and set the extended offset if needed */
2665 Offset = NextOffset;
2666 if (IsMbr) ExtendedOffset = NextOffset;
2667 }
2668
2669 /* If we had a buffer, free it, then return status */
2670 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
2671 return Status;
2672 }
2673
2674 /* PUBLIC FUNCTIONS **********************************************************/
2675
2676 /*
2677 * @implemented
2678 */
2679 VOID
2680 FASTCALL
HalExamineMBR(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG MbrTypeIdentifier,OUT PVOID * MbrBuffer)2681 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
2682 IN ULONG SectorSize,
2683 IN ULONG MbrTypeIdentifier,
2684 OUT PVOID *MbrBuffer)
2685 {
2686 HALDISPATCH->HalExamineMBR(DeviceObject,
2687 SectorSize,
2688 MbrTypeIdentifier,
2689 MbrBuffer);
2690 }
2691
2692 /*
2693 * @implemented
2694 */
2695 NTSTATUS
2696 FASTCALL
IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN BOOLEAN ReturnRecognizedPartitions,IN OUT PDRIVE_LAYOUT_INFORMATION * PartitionBuffer)2697 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
2698 IN ULONG SectorSize,
2699 IN BOOLEAN ReturnRecognizedPartitions,
2700 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
2701 {
2702 return HALDISPATCH->HalIoReadPartitionTable(DeviceObject,
2703 SectorSize,
2704 ReturnRecognizedPartitions,
2705 PartitionBuffer);
2706 }
2707
2708 /*
2709 * @implemented
2710 */
2711 NTSTATUS
2712 FASTCALL
IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG PartitionNumber,IN ULONG PartitionType)2713 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
2714 IN ULONG SectorSize,
2715 IN ULONG PartitionNumber,
2716 IN ULONG PartitionType)
2717 {
2718 return HALDISPATCH->HalIoSetPartitionInformation(DeviceObject,
2719 SectorSize,
2720 PartitionNumber,
2721 PartitionType);
2722 }
2723
2724 /*
2725 * @implemented
2726 */
2727 NTSTATUS
2728 FASTCALL
IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,IN ULONG SectorSize,IN ULONG SectorsPerTrack,IN ULONG NumberOfHeads,IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)2729 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
2730 IN ULONG SectorSize,
2731 IN ULONG SectorsPerTrack,
2732 IN ULONG NumberOfHeads,
2733 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
2734 {
2735 return HALDISPATCH->HalIoWritePartitionTable(DeviceObject,
2736 SectorSize,
2737 SectorsPerTrack,
2738 NumberOfHeads,
2739 PartitionBuffer);
2740 }
2741
2742 /*
2743 * @implemented
2744 */
2745 VOID
2746 FASTCALL
IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,IN PSTRING NtDeviceName,OUT PUCHAR NtSystemPath,OUT PSTRING NtSystemPathString)2747 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
2748 IN PSTRING NtDeviceName,
2749 OUT PUCHAR NtSystemPath,
2750 OUT PSTRING NtSystemPathString)
2751 {
2752 HALDISPATCH->HalIoAssignDriveLetters(LoaderBlock,
2753 NtDeviceName,
2754 NtSystemPath,
2755 NtSystemPathString);
2756 }
2757
2758 /* EOF */
2759