[NTOSKRNL] Implement support for PROCESS_DEVICEMAP_INFORMATION_EX in NtQueryInformati...
[reactos.git] / ntoskrnl / fstub / disksup.c
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 */
10
11 /* INCLUDES ******************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <debug.h>
16 #include <internal/hal.h>
17
18 /* DEPRECATED FUNCTIONS ******************************************************/
19
20 #if 1
21 const WCHAR DiskMountString[] = L"\\DosDevices\\%C:";
22
23 #define AUTO_DRIVE MAXULONG
24
25 #define PARTITION_MAGIC 0xaa55
26
27 #define EFI_PMBR_OSTYPE_EFI 0xEE
28
29 #include <pshpack1.h>
30
31 typedef struct _REG_DISK_MOUNT_INFO
32 {
33 ULONG Signature;
34 LARGE_INTEGER StartingOffset;
35 } REG_DISK_MOUNT_INFO, *PREG_DISK_MOUNT_INFO;
36
37 #include <poppack.h>
38
39 typedef enum _DISK_MANAGER
40 {
41 NoDiskManager,
42 OntrackDiskManager,
43 EZ_Drive
44 } DISK_MANAGER;
45
46 static BOOLEAN
47 HalpAssignDrive(IN PUNICODE_STRING PartitionName,
48 IN ULONG DriveNumber,
49 IN UCHAR DriveType,
50 IN ULONG Signature,
51 IN LARGE_INTEGER StartingOffset,
52 IN HANDLE hKey,
53 IN PUNICODE_STRING BootDevice,
54 OUT PUCHAR NtSystemPath)
55 {
56 WCHAR DriveNameBuffer[16];
57 UNICODE_STRING DriveName;
58 ULONG i;
59 NTSTATUS Status;
60 REG_DISK_MOUNT_INFO DiskMountInfo;
61
62 DPRINT("HalpAssignDrive()\n");
63
64 if ((DriveNumber != AUTO_DRIVE) && (DriveNumber < 26))
65 {
66 /* Force assignment */
67 KeAcquireGuardedMutex(&ObpDeviceMapLock);
68 if ((ObSystemDeviceMap->DriveMap & (1 << DriveNumber)) != 0)
69 {
70 DbgPrint("Drive letter already used!\n");
71 KeReleaseGuardedMutex(&ObpDeviceMapLock);
72 return FALSE;
73 }
74 KeReleaseGuardedMutex(&ObpDeviceMapLock);
75 }
76 else
77 {
78 /* Automatic assignment */
79 DriveNumber = AUTO_DRIVE;
80 KeAcquireGuardedMutex(&ObpDeviceMapLock);
81 for (i = 2; i < 26; i++)
82 {
83 if ((ObSystemDeviceMap->DriveMap & (1 << i)) == 0)
84 {
85 DriveNumber = i;
86 break;
87 }
88 }
89 KeReleaseGuardedMutex(&ObpDeviceMapLock);
90
91 if (DriveNumber == AUTO_DRIVE)
92 {
93 DbgPrint("No drive letter available!\n");
94 return FALSE;
95 }
96 }
97
98 DPRINT("DriveNumber %lu\n", DriveNumber);
99
100 /* Build drive name */
101 swprintf(DriveNameBuffer,
102 L"\\??\\%C:",
103 'A' + DriveNumber);
104 RtlInitUnicodeString(&DriveName,
105 DriveNameBuffer);
106
107 DPRINT(" %wZ ==> %wZ\n",
108 &DriveName,
109 PartitionName);
110
111 /* Create symbolic link */
112 Status = IoCreateSymbolicLink(&DriveName,
113 PartitionName);
114
115 if (hKey &&
116 DriveType == DOSDEVICE_DRIVE_FIXED &&
117 Signature)
118 {
119 DiskMountInfo.Signature = Signature;
120 DiskMountInfo.StartingOffset = StartingOffset;
121 swprintf(DriveNameBuffer, DiskMountString, L'A' + DriveNumber);
122 RtlInitUnicodeString(&DriveName, DriveNameBuffer);
123
124 Status = ZwSetValueKey(hKey,
125 &DriveName,
126 0,
127 REG_BINARY,
128 &DiskMountInfo,
129 sizeof(DiskMountInfo));
130 if (!NT_SUCCESS(Status))
131 {
132 DPRINT1("ZwCreateValueKey failed for %wZ, status=%x\n", &DriveName, Status);
133 }
134 }
135
136 /* Check if this is a boot partition */
137 if (RtlCompareUnicodeString(PartitionName, BootDevice, FALSE) == 0)
138 {
139 /* Set NtSystemPath to that partition's disk letter */
140 *NtSystemPath = (UCHAR)('A' + DriveNumber);
141 }
142
143 return TRUE;
144 }
145
146 ULONG
147 xHalpGetRDiskCount(VOID)
148 {
149 NTSTATUS Status;
150 UNICODE_STRING ArcName;
151 PWCHAR ArcNameBuffer;
152 OBJECT_ATTRIBUTES ObjectAttributes;
153 HANDLE DirectoryHandle;
154 POBJECT_DIRECTORY_INFORMATION DirectoryInfo;
155 ULONG Skip;
156 ULONG ResultLength;
157 ULONG CurrentRDisk;
158 ULONG RDiskCount;
159 BOOLEAN First = TRUE;
160 ULONG Count;
161
162 DirectoryInfo = ExAllocatePoolWithTag(PagedPool, 2 * PAGE_SIZE, TAG_FILE_SYSTEM);
163 if (DirectoryInfo == NULL)
164 {
165 return 0;
166 }
167
168 RtlInitUnicodeString(&ArcName, L"\\ArcName");
169 InitializeObjectAttributes(&ObjectAttributes,
170 &ArcName,
171 0,
172 NULL,
173 NULL);
174
175 Status = ZwOpenDirectoryObject (&DirectoryHandle,
176 DIRECTORY_ALL_ACCESS,
177 &ObjectAttributes);
178 if (!NT_SUCCESS(Status))
179 {
180 DPRINT1("ZwOpenDirectoryObject for %wZ failed, status=%lx\n", &ArcName, Status);
181 ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM);
182 return 0;
183 }
184
185 RDiskCount = 0;
186 Skip = 0;
187 while (NT_SUCCESS(Status))
188 {
189 Status = ZwQueryDirectoryObject (DirectoryHandle,
190 DirectoryInfo,
191 2 * PAGE_SIZE,
192 FALSE,
193 First,
194 &Skip,
195 &ResultLength);
196 First = FALSE;
197 if (NT_SUCCESS(Status))
198 {
199 Count = 0;
200 while (DirectoryInfo[Count].Name.Buffer)
201 {
202 DPRINT("Count %x\n", Count);
203 DirectoryInfo[Count].Name.Buffer[DirectoryInfo[Count].Name.Length / sizeof(WCHAR)] = 0;
204 ArcNameBuffer = DirectoryInfo[Count].Name.Buffer;
205 if (DirectoryInfo[Count].Name.Length >= sizeof(L"multi(0)disk(0)rdisk(0)") - sizeof(WCHAR) &&
206 !_wcsnicmp(ArcNameBuffer, L"multi(0)disk(0)rdisk(", (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR)))
207 {
208 DPRINT("%S\n", ArcNameBuffer);
209 ArcNameBuffer += (sizeof(L"multi(0)disk(0)rdisk(") - sizeof(WCHAR)) / sizeof(WCHAR);
210 CurrentRDisk = 0;
211 while (iswdigit(*ArcNameBuffer))
212 {
213 CurrentRDisk = CurrentRDisk * 10 + *ArcNameBuffer - L'0';
214 ArcNameBuffer++;
215 }
216 if (!_wcsicmp(ArcNameBuffer, L")") &&
217 CurrentRDisk >= RDiskCount)
218 {
219 RDiskCount = CurrentRDisk + 1;
220 }
221 }
222 Count++;
223 }
224 }
225 }
226
227 ZwClose(DirectoryHandle);
228
229 ExFreePoolWithTag(DirectoryInfo, TAG_FILE_SYSTEM);
230 return RDiskCount;
231 }
232
233 NTSTATUS
234 xHalpGetDiskNumberFromRDisk(ULONG RDisk, PULONG DiskNumber)
235 {
236 WCHAR NameBuffer[80];
237 UNICODE_STRING ArcName;
238 UNICODE_STRING LinkName;
239 OBJECT_ATTRIBUTES ObjectAttributes;
240 HANDLE LinkHandle;
241 NTSTATUS Status;
242
243 swprintf(NameBuffer,
244 L"\\ArcName\\multi(0)disk(0)rdisk(%lu)",
245 RDisk);
246
247 RtlInitUnicodeString(&ArcName, NameBuffer);
248 InitializeObjectAttributes(&ObjectAttributes,
249 &ArcName,
250 0,
251 NULL,
252 NULL);
253 Status = ZwOpenSymbolicLinkObject(&LinkHandle,
254 SYMBOLIC_LINK_ALL_ACCESS,
255 &ObjectAttributes);
256 if (!NT_SUCCESS(Status))
257 {
258 DPRINT1("ZwOpenSymbolicLinkObject failed for %wZ, status=%lx\n", &ArcName, Status);
259 return Status;
260 }
261
262 LinkName.Buffer = NameBuffer;
263 LinkName.Length = 0;
264 LinkName.MaximumLength = sizeof(NameBuffer);
265 Status = ZwQuerySymbolicLinkObject(LinkHandle,
266 &LinkName,
267 NULL);
268 ZwClose(LinkHandle);
269 if (!NT_SUCCESS(Status))
270 {
271 DPRINT1("ZwQuerySymbolicLinkObject failed, status=%lx\n", Status);
272 return Status;
273 }
274 if (LinkName.Length < sizeof(L"\\Device\\Harddisk0\\Partition0") - sizeof(WCHAR) ||
275 LinkName.Length >= sizeof(NameBuffer))
276 {
277 return STATUS_UNSUCCESSFUL;
278 }
279
280 NameBuffer[LinkName.Length / sizeof(WCHAR)] = 0;
281 if (_wcsnicmp(NameBuffer, L"\\Device\\Harddisk", (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR)))
282 {
283 return STATUS_UNSUCCESSFUL;
284 }
285 LinkName.Buffer += (sizeof(L"\\Device\\Harddisk") - sizeof(WCHAR)) / sizeof(WCHAR);
286
287 if (!iswdigit(*LinkName.Buffer))
288 {
289 return STATUS_UNSUCCESSFUL;
290 }
291 *DiskNumber = 0;
292 while (iswdigit(*LinkName.Buffer))
293 {
294 *DiskNumber = *DiskNumber * 10 + *LinkName.Buffer - L'0';
295 LinkName.Buffer++;
296 }
297 if (_wcsicmp(LinkName.Buffer, L"\\Partition0"))
298 {
299 return STATUS_UNSUCCESSFUL;
300 }
301 return STATUS_SUCCESS;
302 }
303
304 NTSTATUS
305 FASTCALL
306 xHalQueryDriveLayout(IN PUNICODE_STRING DeviceName,
307 OUT PDRIVE_LAYOUT_INFORMATION *LayoutInfo)
308 {
309 IO_STATUS_BLOCK StatusBlock;
310 DISK_GEOMETRY DiskGeometry;
311 PDEVICE_OBJECT DeviceObject = NULL;
312 PFILE_OBJECT FileObject;
313 KEVENT Event;
314 PIRP Irp;
315 NTSTATUS Status;
316
317 DPRINT("xHalpQueryDriveLayout %wZ %p\n",
318 DeviceName,
319 LayoutInfo);
320
321 /* Get the drives sector size */
322 Status = IoGetDeviceObjectPointer(DeviceName,
323 FILE_READ_ATTRIBUTES,
324 &FileObject,
325 &DeviceObject);
326 if (!NT_SUCCESS(Status))
327 {
328 DPRINT("Status %x\n", Status);
329 return(Status);
330 }
331
332 KeInitializeEvent(&Event,
333 NotificationEvent,
334 FALSE);
335
336 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
337 DeviceObject,
338 NULL,
339 0,
340 &DiskGeometry,
341 sizeof(DISK_GEOMETRY),
342 FALSE,
343 &Event,
344 &StatusBlock);
345 if (Irp == NULL)
346 {
347 ObDereferenceObject(FileObject);
348 return(STATUS_INSUFFICIENT_RESOURCES);
349 }
350
351 Status = IoCallDriver(DeviceObject,
352 Irp);
353 if (Status == STATUS_PENDING)
354 {
355 KeWaitForSingleObject(&Event,
356 Executive,
357 KernelMode,
358 FALSE,
359 NULL);
360 Status = StatusBlock.Status;
361 }
362 if (!NT_SUCCESS(Status))
363 {
364 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
365 {
366 DiskGeometry.BytesPerSector = 512;
367 }
368 else
369 {
370 ObDereferenceObject(FileObject);
371 return(Status);
372 }
373 }
374
375 DPRINT("DiskGeometry.BytesPerSector: %lu\n",
376 DiskGeometry.BytesPerSector);
377
378 if (DeviceObject->Characteristics & FILE_REMOVABLE_MEDIA)
379 {
380 PDRIVE_LAYOUT_INFORMATION Buffer;
381
382 /* Allocate a partition list for a single entry. */
383 Buffer = ExAllocatePoolWithTag(NonPagedPool,
384 sizeof(DRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM);
385 if (Buffer != NULL)
386 {
387 RtlZeroMemory(Buffer,
388 sizeof(DRIVE_LAYOUT_INFORMATION));
389 Buffer->PartitionCount = 1;
390 *LayoutInfo = Buffer;
391
392 Status = STATUS_SUCCESS;
393 }
394 else
395 {
396 Status = STATUS_UNSUCCESSFUL;
397 }
398 }
399 else
400 {
401 /* Read the partition table */
402 Status = IoReadPartitionTable(DeviceObject,
403 DiskGeometry.BytesPerSector,
404 TRUE,
405 LayoutInfo);
406 }
407
408 ObDereferenceObject(FileObject);
409
410 return(Status);
411 }
412
413 VOID
414 FASTCALL
415 xHalIoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
416 IN PSTRING NtDeviceName,
417 OUT PUCHAR NtSystemPath,
418 OUT PSTRING NtSystemPathString)
419 {
420 PDRIVE_LAYOUT_INFORMATION *LayoutArray;
421 PCONFIGURATION_INFORMATION ConfigInfo;
422 OBJECT_ATTRIBUTES ObjectAttributes;
423 IO_STATUS_BLOCK StatusBlock;
424 UNICODE_STRING UnicodeString1;
425 UNICODE_STRING UnicodeString2;
426 HANDLE FileHandle;
427 PWSTR Buffer1;
428 PWSTR Buffer2;
429 ULONG i, j, k;
430 ULONG DiskNumber;
431 ULONG RDisk;
432 NTSTATUS Status;
433 HANDLE hKey;
434 ULONG Length;
435 PKEY_VALUE_PARTIAL_INFORMATION PartialInformation;
436 PREG_DISK_MOUNT_INFO DiskMountInfo;
437 ULONG RDiskCount;
438 UNICODE_STRING BootDevice;
439
440 Status = RtlAnsiStringToUnicodeString(&BootDevice,
441 NtDeviceName,
442 TRUE);
443
444 DPRINT("xHalIoAssignDriveLetters()\n");
445
446 ConfigInfo = IoGetConfigurationInformation();
447
448 RDiskCount = xHalpGetRDiskCount();
449
450 DPRINT("RDiskCount %lu\n", RDiskCount);
451
452 Buffer1 = ExAllocatePoolWithTag(PagedPool,
453 64 * sizeof(WCHAR),
454 TAG_FILE_SYSTEM);
455 if (!Buffer1) return;
456
457 Buffer2 = ExAllocatePoolWithTag(PagedPool,
458 32 * sizeof(WCHAR),
459 TAG_FILE_SYSTEM);
460 if (!Buffer2)
461 {
462 ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
463 return;
464 }
465
466 PartialInformation = ExAllocatePoolWithTag(PagedPool,
467 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO),
468 TAG_FILE_SYSTEM);
469 if (!PartialInformation)
470 {
471 ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
472 ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
473 return;
474 }
475
476 DiskMountInfo = (PREG_DISK_MOUNT_INFO) PartialInformation->Data;
477
478 /* Create or open the 'MountedDevices' key */
479 RtlInitUnicodeString(&UnicodeString1, L"\\Registry\\Machine\\SYSTEM\\MountedDevices");
480 InitializeObjectAttributes(&ObjectAttributes,
481 &UnicodeString1,
482 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
483 NULL,
484 NULL);
485 Status = ZwCreateKey(&hKey,
486 KEY_ALL_ACCESS,
487 &ObjectAttributes,
488 0,
489 NULL,
490 REG_OPTION_NON_VOLATILE,
491 NULL);
492 if (!NT_SUCCESS(Status))
493 {
494 hKey = NULL;
495 DPRINT("ZwCreateKey failed for %wZ, status=%x\n", &UnicodeString1, Status);
496 }
497
498 /* Create PhysicalDrive links */
499 DPRINT("Physical disk drives: %lu\n", ConfigInfo->DiskCount);
500 for (i = 0; i < ConfigInfo->DiskCount; i++)
501 {
502 swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i);
503 RtlInitUnicodeString(&UnicodeString1, Buffer1);
504
505 InitializeObjectAttributes(&ObjectAttributes,
506 &UnicodeString1,
507 0,
508 NULL,
509 NULL);
510
511 Status = ZwOpenFile(&FileHandle,
512 FILE_READ_DATA | SYNCHRONIZE,
513 &ObjectAttributes,
514 &StatusBlock,
515 FILE_SHARE_READ,
516 FILE_SYNCHRONOUS_IO_NONALERT);
517 if (NT_SUCCESS(Status))
518 {
519 ZwClose(FileHandle);
520
521 swprintf(Buffer2, L"\\??\\PhysicalDrive%lu", i);
522 RtlInitUnicodeString(&UnicodeString2, Buffer2);
523
524 DPRINT("Creating link: %S ==> %S\n",
525 Buffer2,
526 Buffer1);
527
528 IoCreateSymbolicLink(&UnicodeString2,
529 &UnicodeString1);
530 }
531 }
532
533 /* Initialize layout array */
534 if (ConfigInfo->DiskCount == 0)
535 goto end_assign_disks;
536 LayoutArray = ExAllocatePoolWithTag(NonPagedPool,
537 ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION), TAG_FILE_SYSTEM);
538 if (!LayoutArray)
539 {
540 ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM);
541 ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
542 ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
543 if (hKey) ObCloseHandle(hKey, KernelMode);
544 return;
545 }
546
547 RtlZeroMemory(LayoutArray,
548 ConfigInfo->DiskCount * sizeof(PDRIVE_LAYOUT_INFORMATION));
549 for (i = 0; i < ConfigInfo->DiskCount; i++)
550 {
551 swprintf(Buffer1, L"\\Device\\Harddisk%lu\\Partition0", i);
552 RtlInitUnicodeString(&UnicodeString1, Buffer1);
553
554 Status = xHalQueryDriveLayout(&UnicodeString1, &LayoutArray[i]);
555 if (!NT_SUCCESS(Status))
556 {
557 DbgPrint("xHalQueryDriveLayout() failed (Status = 0x%lx)\n",
558 Status);
559 LayoutArray[i] = NULL;
560 continue;
561 }
562 /* We don't use the RewritePartition value while mounting the disks.
563 * We use this value for marking pre-assigned (registry) partitions.
564 */
565 for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
566 {
567 LayoutArray[i]->PartitionEntry[j].RewritePartition = FALSE;
568 }
569 }
570
571 #ifndef NDEBUG
572 /* Dump layout array */
573 for (i = 0; i < ConfigInfo->DiskCount; i++)
574 {
575 DPRINT("Harddisk %d:\n",
576 i);
577
578 if (LayoutArray[i] == NULL)
579 continue;
580
581 DPRINT("Logical partitions: %d\n",
582 LayoutArray[i]->PartitionCount);
583
584 for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
585 {
586 DPRINT(" %d: nr:%x boot:%x type:%x startblock:%I64u count:%I64u\n",
587 j,
588 LayoutArray[i]->PartitionEntry[j].PartitionNumber,
589 LayoutArray[i]->PartitionEntry[j].BootIndicator,
590 LayoutArray[i]->PartitionEntry[j].PartitionType,
591 LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart,
592 LayoutArray[i]->PartitionEntry[j].PartitionLength.QuadPart);
593 }
594 }
595 #endif
596
597 /* Assign pre-assigned (registry) partitions */
598 if (hKey)
599 {
600 for (k = 2; k < 26; k++)
601 {
602 swprintf(Buffer1, DiskMountString, L'A' + k);
603 RtlInitUnicodeString(&UnicodeString1, Buffer1);
604 Status = ZwQueryValueKey(hKey,
605 &UnicodeString1,
606 KeyValuePartialInformation,
607 PartialInformation,
608 sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(REG_DISK_MOUNT_INFO),
609 &Length);
610 if (NT_SUCCESS(Status) &&
611 PartialInformation->Type == REG_BINARY &&
612 PartialInformation->DataLength == sizeof(REG_DISK_MOUNT_INFO))
613 {
614 DPRINT("%wZ => %08x:%08x%08x\n", &UnicodeString1, DiskMountInfo->Signature,
615 DiskMountInfo->StartingOffset.u.HighPart, DiskMountInfo->StartingOffset.u.LowPart);
616 {
617 BOOLEAN Found = FALSE;
618 for (i = 0; i < ConfigInfo->DiskCount; i++)
619 {
620 DPRINT("%x\n", LayoutArray[i]->Signature);
621 if (LayoutArray[i] &&
622 LayoutArray[i]->Signature &&
623 LayoutArray[i]->Signature == DiskMountInfo->Signature)
624 {
625 for (j = 0; j < LayoutArray[i]->PartitionCount; j++)
626 {
627 if (LayoutArray[i]->PartitionEntry[j].StartingOffset.QuadPart == DiskMountInfo->StartingOffset.QuadPart)
628 {
629 if (IsRecognizedPartition(LayoutArray[i]->PartitionEntry[j].PartitionType) &&
630 LayoutArray[i]->PartitionEntry[j].RewritePartition == FALSE)
631 {
632 swprintf(Buffer2,
633 L"\\Device\\Harddisk%lu\\Partition%lu",
634 i,
635 LayoutArray[i]->PartitionEntry[j].PartitionNumber);
636 RtlInitUnicodeString(&UnicodeString2, Buffer2);
637
638 /* Assign drive */
639 DPRINT(" %wZ\n", &UnicodeString2);
640 Found = HalpAssignDrive(&UnicodeString2,
641 k,
642 DOSDEVICE_DRIVE_FIXED,
643 DiskMountInfo->Signature,
644 DiskMountInfo->StartingOffset,
645 NULL,
646 &BootDevice,
647 NtSystemPath);
648 /* Mark the partition as assigned */
649 LayoutArray[i]->PartitionEntry[j].RewritePartition = TRUE;
650 }
651 break;
652 }
653 }
654 }
655 }
656 if (Found == FALSE)
657 {
658 /* We didn't find a partition for this entry, remove them. */
659 Status = ZwDeleteValueKey(hKey, &UnicodeString1);
660 }
661 }
662 }
663 }
664 }
665
666 /* Assign bootable partition on first harddisk */
667 DPRINT("Assigning bootable primary partition on first harddisk:\n");
668 if (RDiskCount > 0)
669 {
670 Status = xHalpGetDiskNumberFromRDisk(0, &DiskNumber);
671 if (NT_SUCCESS(Status) &&
672 DiskNumber < ConfigInfo->DiskCount &&
673 LayoutArray[DiskNumber])
674 {
675 /* Search for bootable partition */
676 for (j = 0; j < NUM_PARTITION_TABLE_ENTRIES && j < LayoutArray[DiskNumber]->PartitionCount; j++)
677 {
678 if ((LayoutArray[DiskNumber]->PartitionEntry[j].BootIndicator != FALSE) &&
679 IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
680 {
681 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE)
682 {
683 swprintf(Buffer2,
684 L"\\Device\\Harddisk%lu\\Partition%lu",
685 DiskNumber,
686 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
687 RtlInitUnicodeString(&UnicodeString2, Buffer2);
688
689 /* Assign drive */
690 DPRINT(" %wZ\n", &UnicodeString2);
691 HalpAssignDrive(&UnicodeString2,
692 AUTO_DRIVE,
693 DOSDEVICE_DRIVE_FIXED,
694 LayoutArray[DiskNumber]->Signature,
695 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
696 hKey,
697 &BootDevice,
698 NtSystemPath);
699 /* Mark the partition as assigned */
700 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
701 }
702 break;
703 }
704 }
705 }
706 }
707
708 /* Assign remaining primary partitions */
709 DPRINT("Assigning remaining primary partitions:\n");
710 for (RDisk = 0; RDisk < RDiskCount; RDisk++)
711 {
712 Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber);
713 if (NT_SUCCESS(Status) &&
714 DiskNumber < ConfigInfo->DiskCount &&
715 LayoutArray[DiskNumber])
716 {
717 /* Search for primary partitions */
718 for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++)
719 {
720 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
721 IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
722 {
723 swprintf(Buffer2,
724 L"\\Device\\Harddisk%lu\\Partition%lu",
725 DiskNumber,
726 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
727 RtlInitUnicodeString(&UnicodeString2, Buffer2);
728
729 /* Assign drive */
730 DPRINT(" %wZ\n",
731 &UnicodeString2);
732 HalpAssignDrive(&UnicodeString2,
733 AUTO_DRIVE,
734 DOSDEVICE_DRIVE_FIXED,
735 LayoutArray[DiskNumber]->Signature,
736 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
737 hKey,
738 &BootDevice,
739 NtSystemPath);
740 /* Mark the partition as assigned */
741 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
742 }
743 }
744 }
745 }
746
747 /* Assign extended (logical) partitions */
748 DPRINT("Assigning extended (logical) partitions:\n");
749 for (RDisk = 0; RDisk < RDiskCount; RDisk++)
750 {
751 Status = xHalpGetDiskNumberFromRDisk(RDisk, &DiskNumber);
752 if (NT_SUCCESS(Status) &&
753 DiskNumber < ConfigInfo->DiskCount &&
754 LayoutArray[DiskNumber])
755 {
756 /* Search for extended partitions */
757 for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++)
758 {
759 if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) &&
760 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
761 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0)
762 {
763 swprintf(Buffer2,
764 L"\\Device\\Harddisk%lu\\Partition%lu",
765 DiskNumber,
766 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
767 RtlInitUnicodeString(&UnicodeString2, Buffer2);
768
769 /* Assign drive */
770 DPRINT(" %wZ\n",
771 &UnicodeString2);
772 HalpAssignDrive(&UnicodeString2,
773 AUTO_DRIVE,
774 DOSDEVICE_DRIVE_FIXED,
775 LayoutArray[DiskNumber]->Signature,
776 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
777 hKey,
778 &BootDevice,
779 NtSystemPath);
780 /* Mark the partition as assigned */
781 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
782 }
783 }
784 }
785 }
786
787 /* Assign remaining primary partitions without an arc-name */
788 DPRINT("Assigning remaining primary partitions:\n");
789 for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++)
790 {
791 if (LayoutArray[DiskNumber])
792 {
793 /* Search for primary partitions */
794 for (j = 0; (j < NUM_PARTITION_TABLE_ENTRIES) && (j < LayoutArray[DiskNumber]->PartitionCount); j++)
795 {
796 if (LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
797 IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType))
798 {
799 swprintf(Buffer2,
800 L"\\Device\\Harddisk%lu\\Partition%lu",
801 DiskNumber,
802 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
803 RtlInitUnicodeString(&UnicodeString2, Buffer2);
804
805 /* Assign drive */
806 DPRINT(" %wZ\n",
807 &UnicodeString2);
808 HalpAssignDrive(&UnicodeString2,
809 AUTO_DRIVE,
810 DOSDEVICE_DRIVE_FIXED,
811 LayoutArray[DiskNumber]->Signature,
812 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
813 hKey,
814 &BootDevice,
815 NtSystemPath);
816 /* Mark the partition as assigned */
817 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
818 }
819 }
820 }
821 }
822
823 /* Assign extended (logical) partitions without an arc-name */
824 DPRINT("Assigning extended (logical) partitions:\n");
825 for (DiskNumber = 0; DiskNumber < ConfigInfo->DiskCount; DiskNumber++)
826 {
827 if (LayoutArray[DiskNumber])
828 {
829 /* Search for extended partitions */
830 for (j = NUM_PARTITION_TABLE_ENTRIES; j < LayoutArray[DiskNumber]->PartitionCount; j++)
831 {
832 if (IsRecognizedPartition(LayoutArray[DiskNumber]->PartitionEntry[j].PartitionType) &&
833 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition == FALSE &&
834 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber != 0)
835 {
836 swprintf(Buffer2,
837 L"\\Device\\Harddisk%lu\\Partition%lu",
838 DiskNumber,
839 LayoutArray[DiskNumber]->PartitionEntry[j].PartitionNumber);
840 RtlInitUnicodeString(&UnicodeString2, Buffer2);
841
842 /* Assign drive */
843 DPRINT(" %wZ\n",
844 &UnicodeString2);
845 HalpAssignDrive(&UnicodeString2,
846 AUTO_DRIVE,
847 DOSDEVICE_DRIVE_FIXED,
848 LayoutArray[DiskNumber]->Signature,
849 LayoutArray[DiskNumber]->PartitionEntry[j].StartingOffset,
850 hKey,
851 &BootDevice,
852 NtSystemPath);
853 /* Mark the partition as assigned */
854 LayoutArray[DiskNumber]->PartitionEntry[j].RewritePartition = TRUE;
855 }
856 }
857 }
858 }
859
860 /* Assign removable disk drives */
861 DPRINT("Assigning removable disk drives:\n");
862 for (i = 0; i < ConfigInfo->DiskCount; i++)
863 {
864 if (LayoutArray[i])
865 {
866 /* Search for virtual partitions */
867 if (LayoutArray[i]->PartitionCount == 1 &&
868 LayoutArray[i]->PartitionEntry[0].PartitionType == 0)
869 {
870 swprintf(Buffer2, L"\\Device\\Harddisk%lu\\Partition1", i);
871 RtlInitUnicodeString(&UnicodeString2, Buffer2);
872
873 /* Assign drive */
874 DPRINT(" %wZ\n",
875 &UnicodeString2);
876 HalpAssignDrive(&UnicodeString2,
877 AUTO_DRIVE,
878 DOSDEVICE_DRIVE_REMOVABLE,
879 0,
880 RtlConvertLongToLargeInteger(0),
881 hKey,
882 &BootDevice,
883 NtSystemPath);
884 }
885 }
886 }
887
888 /* Free layout array */
889 for (i = 0; i < ConfigInfo->DiskCount; i++)
890 {
891 if (LayoutArray[i] != NULL)
892 ExFreePoolWithTag(LayoutArray[i], TAG_FILE_SYSTEM);
893 }
894 ExFreePoolWithTag(LayoutArray, TAG_FILE_SYSTEM);
895 end_assign_disks:
896
897 /* Assign floppy drives */
898 DPRINT("Floppy drives: %lu\n", ConfigInfo->FloppyCount);
899 for (i = 0; i < ConfigInfo->FloppyCount; i++)
900 {
901 swprintf(Buffer1, L"\\Device\\Floppy%lu", i);
902 RtlInitUnicodeString(&UnicodeString1, Buffer1);
903
904 /* Assign drive letters A: or B: or first free drive letter */
905 DPRINT(" %wZ\n",
906 &UnicodeString1);
907 HalpAssignDrive(&UnicodeString1,
908 (i < 2) ? i : AUTO_DRIVE,
909 DOSDEVICE_DRIVE_REMOVABLE,
910 0,
911 RtlConvertLongToLargeInteger(0),
912 hKey,
913 &BootDevice,
914 NtSystemPath);
915 }
916
917 /* Assign cdrom drives */
918 DPRINT("CD-Rom drives: %lu\n", ConfigInfo->CdRomCount);
919 for (i = 0; i < ConfigInfo->CdRomCount; i++)
920 {
921 swprintf(Buffer1, L"\\Device\\CdRom%lu", i);
922 RtlInitUnicodeString(&UnicodeString1, Buffer1);
923
924 /* Assign first free drive letter */
925 DPRINT(" %wZ\n", &UnicodeString1);
926 HalpAssignDrive(&UnicodeString1,
927 AUTO_DRIVE,
928 DOSDEVICE_DRIVE_CDROM,
929 0,
930 RtlConvertLongToLargeInteger(0),
931 hKey,
932 &BootDevice,
933 NtSystemPath);
934 }
935
936 /* Anything else to do? */
937
938 ExFreePoolWithTag(PartialInformation, TAG_FILE_SYSTEM);
939 ExFreePoolWithTag(Buffer2, TAG_FILE_SYSTEM);
940 ExFreePoolWithTag(Buffer1, TAG_FILE_SYSTEM);
941 if (hKey) ObCloseHandle(hKey, KernelMode);
942 }
943
944 #endif
945
946 /* PRIVATE FUNCTIONS *********************************************************/
947
948 NTSTATUS
949 NTAPI
950 HalpGetFullGeometry(IN PDEVICE_OBJECT DeviceObject,
951 IN PDISK_GEOMETRY Geometry,
952 OUT PULONGLONG RealSectorCount)
953 {
954 PIRP Irp;
955 IO_STATUS_BLOCK IoStatusBlock;
956 PKEVENT Event;
957 NTSTATUS Status;
958 PARTITION_INFORMATION PartitionInfo;
959 PAGED_CODE();
960
961 /* Allocate a non-paged event */
962 Event = ExAllocatePoolWithTag(NonPagedPool,
963 sizeof(KEVENT),
964 TAG_FILE_SYSTEM);
965 if (!Event) return STATUS_INSUFFICIENT_RESOURCES;
966
967 /* Initialize it */
968 KeInitializeEvent(Event, NotificationEvent, FALSE);
969
970 /* Build the IRP */
971 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
972 DeviceObject,
973 NULL,
974 0UL,
975 Geometry,
976 sizeof(DISK_GEOMETRY),
977 FALSE,
978 Event,
979 &IoStatusBlock);
980 if (!Irp)
981 {
982 /* Fail, free the event */
983 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
984 return STATUS_INSUFFICIENT_RESOURCES;
985 }
986
987 /* Call the driver and check if it's pending */
988 Status = IoCallDriver(DeviceObject, Irp);
989 if (Status == STATUS_PENDING)
990 {
991 /* Wait on the driver */
992 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
993 Status = IoStatusBlock.Status;
994 }
995
996 /* Check if the driver returned success */
997 if(NT_SUCCESS(Status))
998 {
999 /* Build another IRP */
1000 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_PARTITION_INFO,
1001 DeviceObject,
1002 NULL,
1003 0UL,
1004 &PartitionInfo,
1005 sizeof(PARTITION_INFORMATION),
1006 FALSE,
1007 Event,
1008 &IoStatusBlock);
1009 if (!Irp)
1010 {
1011 /* Fail, free the event */
1012 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1013 return STATUS_INSUFFICIENT_RESOURCES;
1014 }
1015
1016 /* Reset event */
1017 KeClearEvent(Event);
1018
1019 /* Call the driver and check if it's pending */
1020 Status = IoCallDriver(DeviceObject, Irp);
1021 if (Status == STATUS_PENDING)
1022 {
1023 /* Wait on the driver */
1024 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
1025 Status = IoStatusBlock.Status;
1026 }
1027
1028 /* Check if the driver returned success */
1029 if(NT_SUCCESS(Status))
1030 {
1031 /* Get the number of sectors */
1032 *RealSectorCount = (PartitionInfo.PartitionLength.QuadPart /
1033 Geometry->BytesPerSector);
1034 }
1035 }
1036
1037 /* Free the event and return the Status */
1038 ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1039 return Status;
1040 }
1041
1042 BOOLEAN
1043 NTAPI
1044 HalpIsValidPartitionEntry(IN PPARTITION_DESCRIPTOR Entry,
1045 IN ULONGLONG MaxOffset,
1046 IN ULONGLONG MaxSector)
1047 {
1048 ULONGLONG EndingSector;
1049 PAGED_CODE();
1050
1051 /* Unused partitions are considered valid */
1052 if (Entry->PartitionType == PARTITION_ENTRY_UNUSED) return TRUE;
1053
1054 /* Get the last sector of the partition */
1055 EndingSector = GET_STARTING_SECTOR(Entry) + GET_PARTITION_LENGTH(Entry);
1056
1057 /* Check if it's more then the maximum sector */
1058 if (EndingSector > MaxSector)
1059 {
1060 /* Invalid partition */
1061 DPRINT1("FSTUB: entry is invalid\n");
1062 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
1063 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
1064 DPRINT1("FSTUB: end %#I64x\n", EndingSector);
1065 DPRINT1("FSTUB: max %#I64x\n", MaxSector);
1066 return FALSE;
1067 }
1068 else if(GET_STARTING_SECTOR(Entry) > MaxOffset)
1069 {
1070 /* Invalid partition */
1071 DPRINT1("FSTUB: entry is invalid\n");
1072 DPRINT1("FSTUB: offset %#08lx\n", GET_STARTING_SECTOR(Entry));
1073 DPRINT1("FSTUB: length %#08lx\n", GET_PARTITION_LENGTH(Entry));
1074 DPRINT1("FSTUB: end %#I64x\n", EndingSector);
1075 DPRINT1("FSTUB: maxOffset %#I64x\n", MaxOffset);
1076 return FALSE;
1077 }
1078
1079 /* It's fine, return success */
1080 return TRUE;
1081 }
1082
1083 VOID
1084 NTAPI
1085 HalpCalculateChsValues(IN PLARGE_INTEGER PartitionOffset,
1086 IN PLARGE_INTEGER PartitionLength,
1087 IN CCHAR ShiftCount,
1088 IN ULONG SectorsPerTrack,
1089 IN ULONG NumberOfTracks,
1090 IN ULONG ConventionalCylinders,
1091 OUT PPARTITION_DESCRIPTOR PartitionDescriptor)
1092 {
1093 LARGE_INTEGER FirstSector, SectorCount;
1094 ULONG LastSector, Remainder, SectorsPerCylinder;
1095 ULONG StartingCylinder, EndingCylinder;
1096 ULONG StartingTrack, EndingTrack;
1097 ULONG StartingSector, EndingSector;
1098 PAGED_CODE();
1099
1100 /* Calculate the number of sectors for each cylinder */
1101 SectorsPerCylinder = SectorsPerTrack * NumberOfTracks;
1102
1103 /* Calculate the first sector, and the sector count */
1104 FirstSector.QuadPart = PartitionOffset->QuadPart >> ShiftCount;
1105 SectorCount.QuadPart = PartitionLength->QuadPart >> ShiftCount;
1106
1107 /* Now calculate the last sector */
1108 LastSector = FirstSector.LowPart + SectorCount.LowPart - 1;
1109
1110 /* Calculate the first and last cylinders */
1111 StartingCylinder = FirstSector.LowPart / SectorsPerCylinder;
1112 EndingCylinder = LastSector / SectorsPerCylinder;
1113
1114 /* Set the default number of cylinders */
1115 if (!ConventionalCylinders) ConventionalCylinders = 1024;
1116
1117 /* Normalize the values */
1118 if (StartingCylinder >= ConventionalCylinders)
1119 {
1120 /* Set the maximum to 1023 */
1121 StartingCylinder = ConventionalCylinders - 1;
1122 }
1123 if (EndingCylinder >= ConventionalCylinders)
1124 {
1125 /* Set the maximum to 1023 */
1126 EndingCylinder = ConventionalCylinders - 1;
1127 }
1128
1129 /* Calculate the starting head and sector that still remain */
1130 Remainder = FirstSector.LowPart % SectorsPerCylinder;
1131 StartingTrack = Remainder / SectorsPerTrack;
1132 StartingSector = Remainder % SectorsPerTrack;
1133
1134 /* Calculate the ending head and sector that still remain */
1135 Remainder = LastSector % SectorsPerCylinder;
1136 EndingTrack = Remainder / SectorsPerTrack;
1137 EndingSector = Remainder % SectorsPerTrack;
1138
1139 /* Set cylinder data for the MSB */
1140 PartitionDescriptor->StartingCylinderMsb = (UCHAR)StartingCylinder;
1141 PartitionDescriptor->EndingCylinderMsb = (UCHAR)EndingCylinder;
1142
1143 /* Set the track data */
1144 PartitionDescriptor->StartingTrack = (UCHAR)StartingTrack;
1145 PartitionDescriptor->EndingTrack = (UCHAR)EndingTrack;
1146
1147 /* Update cylinder data for the LSB */
1148 StartingCylinder = ((StartingSector + 1) & 0x3F) |
1149 ((StartingCylinder >> 2) & 0xC0);
1150 EndingCylinder = ((EndingSector + 1) & 0x3F) |
1151 ((EndingCylinder >> 2) & 0xC0);
1152
1153 /* Set the cylinder data for the LSB */
1154 PartitionDescriptor->StartingCylinderLsb = (UCHAR)StartingCylinder;
1155 PartitionDescriptor->EndingCylinderLsb = (UCHAR)EndingCylinder;
1156 }
1157
1158 VOID
1159 FASTCALL
1160 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject,
1161 IN PULONG ConventionalCylinders,
1162 IN PLONGLONG DiskSize)
1163 {
1164 PDISK_GEOMETRY DiskGeometry = NULL;
1165 PIO_STATUS_BLOCK IoStatusBlock = NULL;
1166 PKEVENT Event = NULL;
1167 PIRP Irp;
1168 NTSTATUS Status;
1169
1170 /* Set defaults */
1171 *ConventionalCylinders = 0;
1172 *DiskSize = 0;
1173
1174 /* Allocate the structure in nonpaged pool */
1175 DiskGeometry = ExAllocatePoolWithTag(NonPagedPool,
1176 sizeof(DISK_GEOMETRY),
1177 TAG_FILE_SYSTEM);
1178 if (!DiskGeometry) goto Cleanup;
1179
1180 /* Allocate the status block in nonpaged pool */
1181 IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool,
1182 sizeof(IO_STATUS_BLOCK),
1183 TAG_FILE_SYSTEM);
1184 if (!IoStatusBlock) goto Cleanup;
1185
1186 /* Allocate the event in nonpaged pool too */
1187 Event = ExAllocatePoolWithTag(NonPagedPool,
1188 sizeof(KEVENT),
1189 TAG_FILE_SYSTEM);
1190 if (!Event) goto Cleanup;
1191
1192 /* Initialize the event */
1193 KeInitializeEvent(Event, NotificationEvent, FALSE);
1194
1195 /* Build the IRP */
1196 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
1197 DeviceObject,
1198 NULL,
1199 0,
1200 DiskGeometry,
1201 sizeof(DISK_GEOMETRY),
1202 FALSE,
1203 Event,
1204 IoStatusBlock);
1205 if (!Irp) goto Cleanup;
1206
1207 /* Now call the driver */
1208 Status = IoCallDriver(DeviceObject, Irp);
1209 if (Status == STATUS_PENDING)
1210 {
1211 /* Wait for it to complete */
1212 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
1213 Status = IoStatusBlock->Status;
1214 }
1215
1216 /* Check driver status */
1217 if (NT_SUCCESS(Status))
1218 {
1219 /* Return the cylinder count */
1220 *ConventionalCylinders = DiskGeometry->Cylinders.LowPart;
1221
1222 /* Make sure it's not larger then 1024 */
1223 if (DiskGeometry->Cylinders.LowPart >= 1024)
1224 {
1225 /* Otherwise, normalize the value */
1226 *ConventionalCylinders = 1024;
1227 }
1228
1229 /* Calculate the disk size */
1230 *DiskSize = DiskGeometry->Cylinders.QuadPart *
1231 DiskGeometry->TracksPerCylinder *
1232 DiskGeometry->SectorsPerTrack *
1233 DiskGeometry->BytesPerSector;
1234 }
1235
1236 Cleanup:
1237 /* Free all the pointers */
1238 if (Event) ExFreePoolWithTag(Event, TAG_FILE_SYSTEM);
1239 if (IoStatusBlock) ExFreePoolWithTag(IoStatusBlock, TAG_FILE_SYSTEM);
1240 if (DiskGeometry) ExFreePoolWithTag(DiskGeometry, TAG_FILE_SYSTEM);
1241 return;
1242 }
1243
1244 VOID
1245 FASTCALL
1246 xHalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
1247 IN ULONG SectorSize,
1248 IN ULONG MbrTypeIdentifier,
1249 OUT PVOID *MbrBuffer)
1250 {
1251 LARGE_INTEGER Offset;
1252 PUCHAR Buffer;
1253 ULONG BufferSize;
1254 KEVENT Event;
1255 IO_STATUS_BLOCK IoStatusBlock;
1256 PIRP Irp;
1257 PPARTITION_DESCRIPTOR PartitionDescriptor;
1258 NTSTATUS Status;
1259 PIO_STACK_LOCATION IoStackLocation;
1260 Offset.QuadPart = 0;
1261
1262 /* Assume failure */
1263 *MbrBuffer = NULL;
1264
1265 /* Normalize the buffer size */
1266 BufferSize = max(SectorSize, 512);
1267
1268 /* Allocate the buffer */
1269 Buffer = ExAllocatePoolWithTag(NonPagedPool,
1270 PAGE_SIZE > BufferSize ?
1271 PAGE_SIZE : BufferSize,
1272 TAG_FILE_SYSTEM);
1273 if (!Buffer) return;
1274
1275 /* Initialize the Event */
1276 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1277
1278 /* Build the IRP */
1279 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1280 DeviceObject,
1281 Buffer,
1282 BufferSize,
1283 &Offset,
1284 &Event,
1285 &IoStatusBlock);
1286 if (!Irp)
1287 {
1288 /* Failed */
1289 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1290 return;
1291 }
1292
1293 /* Make sure to override volume verification */
1294 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1295 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1296
1297 /* Call the driver */
1298 Status = IoCallDriver(DeviceObject, Irp);
1299 if (Status == STATUS_PENDING)
1300 {
1301 /* Wait for completion */
1302 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1303 Status = IoStatusBlock.Status;
1304 }
1305
1306 /* Check driver Status */
1307 if (NT_SUCCESS(Status))
1308 {
1309 /* Validate the MBR Signature */
1310 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1311 {
1312 /* Failed */
1313 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1314 return;
1315 }
1316
1317 /* Get the partition entry */
1318 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1319 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1320
1321 /* Make sure it's what the caller wanted */
1322 if (PartitionDescriptor->PartitionType != MbrTypeIdentifier)
1323 {
1324 /* It's not, free our buffer */
1325 ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1326 }
1327 else
1328 {
1329 /* Check if this is a secondary entry */
1330 if (PartitionDescriptor->PartitionType == 0x54)
1331 {
1332 /* Return our buffer, but at sector 63 */
1333 *(PULONG)Buffer = 63;
1334 *MbrBuffer = Buffer;
1335 }
1336 else if (PartitionDescriptor->PartitionType == 0x55)
1337 {
1338 /* EZ Drive, return the buffer directly */
1339 *MbrBuffer = Buffer;
1340 }
1341 else
1342 {
1343 /* Otherwise crash on debug builds */
1344 ASSERT(PartitionDescriptor->PartitionType == 0x55);
1345 }
1346 }
1347 }
1348 }
1349
1350 VOID
1351 NTAPI
1352 FstubFixupEfiPartition(IN PPARTITION_DESCRIPTOR PartitionDescriptor,
1353 IN ULONGLONG MaxOffset)
1354 {
1355 ULONG PartitionMaxOffset, PartitionLength;
1356 PAGED_CODE();
1357
1358 /* Compute partition length (according to MBR entry) */
1359 PartitionMaxOffset = GET_STARTING_SECTOR(PartitionDescriptor) + GET_PARTITION_LENGTH(PartitionDescriptor);
1360 /* In case the partition length goes beyond disk size... */
1361 if (PartitionMaxOffset > MaxOffset)
1362 {
1363 /* Resize partition to its maximum real length */
1364 PartitionLength = (ULONG)(PartitionMaxOffset - GET_STARTING_SECTOR(PartitionDescriptor));
1365 SET_PARTITION_LENGTH(PartitionDescriptor, PartitionLength);
1366 }
1367 }
1368
1369 NTSTATUS
1370 FASTCALL
1371 xHalIoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
1372 IN ULONG SectorSize,
1373 IN BOOLEAN ReturnRecognizedPartitions,
1374 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
1375 {
1376 KEVENT Event;
1377 IO_STATUS_BLOCK IoStatusBlock;
1378 PIRP Irp;
1379 PPARTITION_DESCRIPTOR PartitionDescriptor;
1380 CCHAR Entry;
1381 NTSTATUS Status;
1382 PPARTITION_INFORMATION PartitionInfo;
1383 PUCHAR Buffer = NULL;
1384 ULONG BufferSize = 2048, InputSize;
1385 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL;
1386 LONG j = -1, i = -1, k;
1387 DISK_GEOMETRY DiskGeometry;
1388 LONGLONG EndSector, MaxSector, StartOffset;
1389 ULONGLONG MaxOffset;
1390 LARGE_INTEGER Offset, VolumeOffset;
1391 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE, MbrFound = FALSE;
1392 BOOLEAN IsValid, IsEmpty = TRUE;
1393 PVOID MbrBuffer;
1394 PIO_STACK_LOCATION IoStackLocation;
1395 UCHAR PartitionType;
1396 LARGE_INTEGER HiddenSectors64;
1397 VolumeOffset.QuadPart = Offset.QuadPart = 0;
1398 PAGED_CODE();
1399
1400 /* Allocate the buffer */
1401 *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
1402 BufferSize,
1403 TAG_FILE_SYSTEM);
1404 if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES;
1405
1406 /* Normalize the buffer size */
1407 InputSize = max(512, SectorSize);
1408
1409 /* Check for EZ Drive */
1410 HalExamineMBR(DeviceObject, InputSize, 0x55, &MbrBuffer);
1411 if (MbrBuffer)
1412 {
1413 /* EZ Drive found, bias the offset */
1414 IsEzDrive = TRUE;
1415 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
1416 Offset.QuadPart = 512;
1417 }
1418
1419 /* Get drive geometry */
1420 Status = HalpGetFullGeometry(DeviceObject, &DiskGeometry, &MaxOffset);
1421 if (!NT_SUCCESS(Status))
1422 {
1423 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1424 *PartitionBuffer = NULL;
1425 return Status;
1426 }
1427
1428 /* Get the end and maximum sector */
1429 EndSector = MaxOffset;
1430 MaxSector = MaxOffset << 1;
1431 DPRINT("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n",
1432 MaxOffset, MaxSector);
1433
1434 /* Allocate our buffer */
1435 Buffer = ExAllocatePoolWithTag(NonPagedPool, InputSize, TAG_FILE_SYSTEM);
1436 if (!Buffer)
1437 {
1438 /* Fail, free the input buffer */
1439 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1440 *PartitionBuffer = NULL;
1441 return STATUS_INSUFFICIENT_RESOURCES;
1442 }
1443
1444 /* Start partition loop */
1445 do
1446 {
1447 /* Assume the partition is valid */
1448 IsValid = TRUE;
1449
1450 /* Initialize the event */
1451 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1452
1453 /* Clear the buffer and build the IRP */
1454 RtlZeroMemory(Buffer, InputSize);
1455 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1456 DeviceObject,
1457 Buffer,
1458 InputSize,
1459 &Offset,
1460 &Event,
1461 &IoStatusBlock);
1462 if (!Irp)
1463 {
1464 /* Failed */
1465 Status = STATUS_INSUFFICIENT_RESOURCES;
1466 break;
1467 }
1468
1469 /* Make sure to disable volume verification */
1470 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1471 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1472
1473 /* Call the driver */
1474 Status = IoCallDriver(DeviceObject, Irp);
1475 if (Status == STATUS_PENDING)
1476 {
1477 /* Wait for completion */
1478 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1479 Status = IoStatusBlock.Status;
1480 }
1481
1482 /* Normalize status code and check for failure */
1483 if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS;
1484 if (!NT_SUCCESS(Status)) break;
1485
1486 /* If we biased for EZ-Drive, unbias now */
1487 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
1488
1489 /* Make sure this is a valid MBR */
1490 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1491 {
1492 /* It's not, fail */
1493 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
1494 "partition table %d\n", j + 1);
1495 break;
1496 }
1497
1498 /* At this point we have a valid MBR */
1499 MbrFound = TRUE;
1500
1501 /* Check if we weren't given an offset */
1502 if (!Offset.QuadPart)
1503 {
1504 /* Then read the signature off the disk */
1505 (*PartitionBuffer)->Signature = ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1];
1506 }
1507
1508 /* Get the partition descriptor array */
1509 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1510 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1511
1512 /* Start looping partitions */
1513 j++;
1514 DPRINT("FSTUB: Partition Table %d:\n", j);
1515 for (Entry = 1, k = 0; Entry <= 4; Entry++, PartitionDescriptor++)
1516 {
1517 /* Get the partition type */
1518 PartitionType = PartitionDescriptor->PartitionType;
1519
1520 /* Print debug messages */
1521 DPRINT("Partition Entry %d,%d: type %#x %s\n",
1522 j,
1523 Entry,
1524 PartitionType,
1525 (PartitionDescriptor->ActiveFlag) ? "Active" : "");
1526 DPRINT("\tOffset %#08lx for %#08lx Sectors\n",
1527 GET_STARTING_SECTOR(PartitionDescriptor),
1528 GET_PARTITION_LENGTH(PartitionDescriptor));
1529
1530 /* Check whether we're facing a protective MBR */
1531 if (PartitionType == EFI_PMBR_OSTYPE_EFI)
1532 {
1533 /* Partition length might be bigger than disk size */
1534 FstubFixupEfiPartition(PartitionDescriptor,
1535 MaxOffset);
1536 }
1537
1538 /* Make sure that the partition is valid, unless it's the first */
1539 if (!(HalpIsValidPartitionEntry(PartitionDescriptor,
1540 MaxOffset,
1541 MaxSector)) && (j == 0))
1542 {
1543 /* It's invalid, so fail */
1544 IsValid = FALSE;
1545 break;
1546 }
1547
1548 /* Check if it's a container */
1549 if (IsContainerPartition(PartitionType))
1550 {
1551 /* Increase the count of containers */
1552 if (++k != 1)
1553 {
1554 /* More then one table is invalid */
1555 DPRINT1("FSTUB: Multiple container partitions found in "
1556 "partition table %d\n - table is invalid\n",
1557 j);
1558 IsValid = FALSE;
1559 break;
1560 }
1561 }
1562
1563 /* Check if the partition is supposedly empty */
1564 if (IsEmpty)
1565 {
1566 /* But check if it actually has a start and/or length */
1567 if ((GET_STARTING_SECTOR(PartitionDescriptor)) ||
1568 (GET_PARTITION_LENGTH(PartitionDescriptor)))
1569 {
1570 /* So then it's not really empty */
1571 IsEmpty = FALSE;
1572 }
1573 }
1574
1575 /* Check if the caller wanted only recognized partitions */
1576 if (ReturnRecognizedPartitions)
1577 {
1578 /* Then check if this one is unused, or a container */
1579 if ((PartitionType == PARTITION_ENTRY_UNUSED) ||
1580 IsContainerPartition(PartitionType))
1581 {
1582 /* Skip it, since the caller doesn't want it */
1583 continue;
1584 }
1585 }
1586
1587 /* Increase the structure count and check if they can fit */
1588 if ((sizeof(DRIVE_LAYOUT_INFORMATION) +
1589 (++i * sizeof(PARTITION_INFORMATION))) >
1590 BufferSize)
1591 {
1592 /* Allocate a new buffer that's twice as big */
1593 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool,
1594 BufferSize << 1,
1595 TAG_FILE_SYSTEM);
1596 if (!DriveLayoutInfo)
1597 {
1598 /* Out of memory, unto this extra structure */
1599 --i;
1600 Status = STATUS_INSUFFICIENT_RESOURCES;
1601 break;
1602 }
1603
1604 /* Copy the contents of the old buffer */
1605 RtlMoveMemory(DriveLayoutInfo,
1606 *PartitionBuffer,
1607 BufferSize);
1608
1609 /* Free the old buffer and set this one as the new one */
1610 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1611 *PartitionBuffer = DriveLayoutInfo;
1612
1613 /* Double the size */
1614 BufferSize <<= 1;
1615 }
1616
1617 /* Now get the current structure being filled and initialize it */
1618 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i];
1619 PartitionInfo->PartitionType = PartitionType;
1620 PartitionInfo->RewritePartition = FALSE;
1621
1622 /* Check if we're dealing with a partition that's in use */
1623 if (PartitionType != PARTITION_ENTRY_UNUSED)
1624 {
1625 /* Check if it's bootable */
1626 PartitionInfo->BootIndicator = PartitionDescriptor->
1627 ActiveFlag & 0x80 ?
1628 TRUE : FALSE;
1629
1630 /* Check if its' a container */
1631 if (IsContainerPartition(PartitionType))
1632 {
1633 /* Then don't recognize it and use the volume offset */
1634 PartitionInfo->RecognizedPartition = FALSE;
1635 StartOffset = VolumeOffset.QuadPart;
1636 }
1637 else
1638 {
1639 /* Then recognize it and use the partition offset */
1640 PartitionInfo->RecognizedPartition = TRUE;
1641 StartOffset = Offset.QuadPart;
1642 }
1643
1644 /* Get the starting offset */
1645 PartitionInfo->StartingOffset.QuadPart =
1646 StartOffset +
1647 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor),
1648 SectorSize);
1649
1650 /* Calculate the number of hidden sectors */
1651 HiddenSectors64.QuadPart = (PartitionInfo->
1652 StartingOffset.QuadPart -
1653 StartOffset) /
1654 SectorSize;
1655 PartitionInfo->HiddenSectors = HiddenSectors64.LowPart;
1656
1657 /* Get the partition length */
1658 PartitionInfo->PartitionLength.QuadPart =
1659 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor),
1660 SectorSize);
1661
1662 /* Get the partition number */
1663 PartitionInfo->PartitionNumber = (!IsContainerPartition(PartitionType)) ? i + 1 : 0;
1664 }
1665 else
1666 {
1667 /* Otherwise, clear all the relevant fields */
1668 PartitionInfo->BootIndicator = FALSE;
1669 PartitionInfo->RecognizedPartition = FALSE;
1670 PartitionInfo->StartingOffset.QuadPart = 0;
1671 PartitionInfo->PartitionLength.QuadPart = 0;
1672 PartitionInfo->HiddenSectors = 0;
1673
1674 PartitionInfo->PartitionNumber = 0;
1675 }
1676 }
1677
1678 /* Finish debug log, and check for failure */
1679 DPRINT("\n");
1680 if (!NT_SUCCESS(Status)) break;
1681
1682 /* Also check if we hit an invalid entry here */
1683 if (!IsValid)
1684 {
1685 /* We did, so break out of the loop minus one entry */
1686 j--;
1687 break;
1688 }
1689
1690 /* Reset the offset */
1691 Offset.QuadPart = 0;
1692
1693 /* Go back to the descriptor array and loop it */
1694 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1695 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1696 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1697 {
1698 /* Check if this is a container partition, since we skipped them */
1699 if (IsContainerPartition(PartitionDescriptor->PartitionType))
1700 {
1701 /* Get its offset */
1702 Offset.QuadPart = VolumeOffset.QuadPart +
1703 UInt32x32To64(
1704 GET_STARTING_SECTOR(PartitionDescriptor),
1705 SectorSize);
1706
1707 /* If this is a primary partition, this is the volume offset */
1708 if (IsPrimary) VolumeOffset = Offset;
1709
1710 /* Also update the maximum sector */
1711 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor);
1712 DPRINT1("FSTUB: MaxSector now = %I64d\n", MaxSector);
1713 break;
1714 }
1715 }
1716
1717 /* Loop the next partitions, which are not primary anymore */
1718 IsPrimary = FALSE;
1719 } while (Offset.HighPart | Offset.LowPart);
1720
1721 /* Check if this is a removable device that's probably a super-floppy */
1722 if ((DiskGeometry.MediaType == RemovableMedia) &&
1723 (j == 0) && (MbrFound) && (IsEmpty))
1724 {
1725 PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer;
1726
1727 /* Read the jump bytes to detect super-floppy */
1728 if ((BootSectorInfo->JumpByte[0] == 0xeb) ||
1729 (BootSectorInfo->JumpByte[0] == 0xe9))
1730 {
1731 /* Super floppes don't have typical MBRs, so skip them */
1732 DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
1733 "table - disk is a super floppy and has no valid MBR\n",
1734 BootSectorInfo->JumpByte);
1735 j = -1;
1736 }
1737 }
1738
1739 /* Check if we're still at partition -1 */
1740 if (j == -1)
1741 {
1742 /* The likely cause is the super floppy detection above */
1743 if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia))
1744 {
1745 /* Print out debugging information */
1746 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
1747 "super-floppy\n",
1748 DeviceObject);
1749 DPRINT1("FSTUB: Drive has %I64d sectors and is %#016I64x "
1750 "bytes large\n",
1751 EndSector, EndSector * DiskGeometry.BytesPerSector);
1752
1753 /* We should at least have some sectors */
1754 if (EndSector > 0)
1755 {
1756 /* Get the entry we'll use */
1757 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
1758
1759 /* Fill it out with data for a super-floppy */
1760 PartitionInfo->RewritePartition = FALSE;
1761 PartitionInfo->RecognizedPartition = TRUE;
1762 PartitionInfo->PartitionType = PARTITION_FAT_16;
1763 PartitionInfo->BootIndicator = FALSE;
1764 PartitionInfo->HiddenSectors = 0;
1765 PartitionInfo->StartingOffset.QuadPart = 0;
1766 PartitionInfo->PartitionLength.QuadPart = (EndSector *
1767 DiskGeometry.
1768 BytesPerSector);
1769
1770 /* FIXME: REACTOS HACK */
1771 PartitionInfo->PartitionNumber = 0;
1772
1773 /* Set the signature and set the count back to 0 */
1774 (*PartitionBuffer)->Signature = 1;
1775 i = 0;
1776 }
1777 }
1778 else
1779 {
1780 /* Otherwise, this isn't a super floppy, so set an invalid count */
1781 i = -1;
1782 }
1783 }
1784
1785 /* Set the partition count */
1786 (*PartitionBuffer)->PartitionCount = ++i;
1787
1788 /* If we have no count, delete the signature */
1789 if (!i) (*PartitionBuffer)->Signature = 0;
1790
1791 /* Free the buffer and check for success */
1792 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1793 if (!NT_SUCCESS(Status))
1794 {
1795 ExFreePoolWithTag(*PartitionBuffer, TAG_FILE_SYSTEM);
1796 *PartitionBuffer = NULL;
1797 }
1798
1799 /* Return status */
1800 return Status;
1801 }
1802
1803 NTSTATUS
1804 FASTCALL
1805 xHalIoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
1806 IN ULONG SectorSize,
1807 IN ULONG PartitionNumber,
1808 IN ULONG PartitionType)
1809 {
1810 PIRP Irp;
1811 KEVENT Event;
1812 IO_STATUS_BLOCK IoStatusBlock;
1813 NTSTATUS Status;
1814 LARGE_INTEGER Offset, VolumeOffset;
1815 PUCHAR Buffer = NULL;
1816 ULONG BufferSize;
1817 ULONG i = 0;
1818 ULONG Entry;
1819 PPARTITION_DESCRIPTOR PartitionDescriptor;
1820 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE;
1821 PVOID MbrBuffer;
1822 PIO_STACK_LOCATION IoStackLocation;
1823 VolumeOffset.QuadPart = Offset.QuadPart = 0;
1824 PAGED_CODE();
1825
1826 /* Normalize the buffer size */
1827 BufferSize = max(512, SectorSize);
1828
1829 /* Check for EZ Drive */
1830 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
1831 if (MbrBuffer)
1832 {
1833 /* EZ Drive found, bias the offset */
1834 IsEzDrive = TRUE;
1835 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
1836 Offset.QuadPart = 512;
1837 }
1838
1839 /* Allocate our partition buffer */
1840 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
1841 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1842
1843 /* Initialize the event we'll use and loop partitions */
1844 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1845 do
1846 {
1847 /* Reset the event since we reuse it */
1848 KeClearEvent(&Event);
1849
1850 /* Build the read IRP */
1851 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1852 DeviceObject,
1853 Buffer,
1854 BufferSize,
1855 &Offset,
1856 &Event,
1857 &IoStatusBlock);
1858 if (!Irp)
1859 {
1860 /* Fail */
1861 Status = STATUS_INSUFFICIENT_RESOURCES;
1862 break;
1863 }
1864
1865 /* Make sure to disable volume verification */
1866 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1867 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1868
1869 /* Call the driver */
1870 Status = IoCallDriver(DeviceObject, Irp);
1871 if (Status == STATUS_PENDING)
1872 {
1873 /* Wait for completion */
1874 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1875 Status = IoStatusBlock.Status;
1876 }
1877
1878 /* Check for failure */
1879 if (!NT_SUCCESS(Status)) break;
1880
1881 /* If we biased for EZ-Drive, unbias now */
1882 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
1883
1884 /* Make sure this is a valid MBR */
1885 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1886 {
1887 /* It's not, fail */
1888 Status = STATUS_BAD_MASTER_BOOT_RECORD;
1889 break;
1890 }
1891
1892 /* Get the partition descriptors and loop them */
1893 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1894 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1895 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1896 {
1897 /* Check if it's unused or a container partition */
1898 if ((PartitionDescriptor->PartitionType ==
1899 PARTITION_ENTRY_UNUSED) ||
1900 (IsContainerPartition(PartitionDescriptor->PartitionType)))
1901 {
1902 /* Go to the next one */
1903 continue;
1904 }
1905
1906 /* It's a valid partition, so increase the partition count */
1907 if (++i == PartitionNumber)
1908 {
1909 /* We found a match, set the type */
1910 PartitionDescriptor->PartitionType = (UCHAR)PartitionType;
1911
1912 /* Reset the reusable event */
1913 KeClearEvent(&Event);
1914
1915 /* Build the write IRP */
1916 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
1917 DeviceObject,
1918 Buffer,
1919 BufferSize,
1920 &Offset,
1921 &Event,
1922 &IoStatusBlock);
1923 if (!Irp)
1924 {
1925 /* Fail */
1926 Status = STATUS_INSUFFICIENT_RESOURCES;
1927 break;
1928 }
1929
1930 /* Disable volume verification */
1931 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1932 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1933
1934 /* Call the driver */
1935 Status = IoCallDriver(DeviceObject, Irp);
1936 if (Status == STATUS_PENDING)
1937 {
1938 /* Wait for completion */
1939 KeWaitForSingleObject(&Event,
1940 Executive,
1941 KernelMode,
1942 FALSE,
1943 NULL);
1944 Status = IoStatusBlock.Status;
1945 }
1946
1947 /* We're done, break out of the loop */
1948 break;
1949 }
1950 }
1951
1952 /* If we looped all the partitions, break out */
1953 if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break;
1954
1955 /* Nothing found yet, get the partition array again */
1956 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1957 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1958 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1959 {
1960 /* Check if this was a container partition (we skipped these) */
1961 if (IsContainerPartition(PartitionDescriptor->PartitionType))
1962 {
1963 /* Update the partition offset */
1964 Offset.QuadPart = VolumeOffset.QuadPart +
1965 GET_STARTING_SECTOR(PartitionDescriptor) *
1966 SectorSize;
1967
1968 /* If this was the primary partition, update the volume too */
1969 if (IsPrimary) VolumeOffset = Offset;
1970 break;
1971 }
1972 }
1973
1974 /* Check if we already searched all the partitions */
1975 if (Entry > NUM_PARTITION_TABLE_ENTRIES)
1976 {
1977 /* Then we failed to find a good MBR */
1978 Status = STATUS_BAD_MASTER_BOOT_RECORD;
1979 break;
1980 }
1981
1982 /* Loop the next partitions, which are not primary anymore */
1983 IsPrimary = FALSE;
1984 } while (i < PartitionNumber);
1985
1986 /* Everything done, cleanup */
1987 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
1988 return Status;
1989 }
1990
1991 NTSTATUS
1992 FASTCALL
1993 xHalIoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
1994 IN ULONG SectorSize,
1995 IN ULONG SectorsPerTrack,
1996 IN ULONG NumberOfHeads,
1997 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
1998 {
1999 KEVENT Event;
2000 IO_STATUS_BLOCK IoStatusBlock;
2001 PIRP Irp;
2002 NTSTATUS Status = STATUS_SUCCESS;
2003 ULONG BufferSize;
2004 PUSHORT Buffer;
2005 PPTE Entry;
2006 PPARTITION_TABLE PartitionTable;
2007 LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset;
2008 LARGE_INTEGER StartOffset, PartitionLength;
2009 ULONG i, j;
2010 CCHAR k;
2011 BOOLEAN IsEzDrive = FALSE, IsSuperFloppy = FALSE, DoRewrite = FALSE, IsMbr;
2012 ULONG ConventionalCylinders;
2013 LONGLONG DiskSize;
2014 PDISK_LAYOUT DiskLayout = (PDISK_LAYOUT)PartitionBuffer;
2015 PVOID MbrBuffer;
2016 UCHAR PartitionType;
2017 PIO_STACK_LOCATION IoStackLocation;
2018 PPARTITION_INFORMATION PartitionInfo = PartitionBuffer->PartitionEntry;
2019 PPARTITION_INFORMATION TableEntry;
2020 ExtendedOffset.QuadPart = NextOffset.QuadPart = Offset.QuadPart = 0;
2021 PAGED_CODE();
2022
2023 /* Normalize the buffer size */
2024 BufferSize = max(512, SectorSize);
2025
2026 /* Get the partial drive geometry */
2027 xHalGetPartialGeometry(DeviceObject, &ConventionalCylinders, &DiskSize);
2028
2029 /* Check for EZ Drive */
2030 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
2031 if (MbrBuffer)
2032 {
2033 /* EZ Drive found, bias the offset */
2034 IsEzDrive = TRUE;
2035 ExFreePoolWithTag(MbrBuffer, TAG_FILE_SYSTEM);
2036 Offset.QuadPart = 512;
2037 }
2038
2039 /* Get the number of bits to shift to multiply by the sector size */
2040 for (k = 0; k < 32; k++) if ((SectorSize >> k) == 1) break;
2041
2042 /* Check if there's only one partition */
2043 if (PartitionBuffer->PartitionCount == 1)
2044 {
2045 /* Check if it has no starting offset or hidden sectors */
2046 if (!(PartitionInfo->StartingOffset.QuadPart) &&
2047 !(PartitionInfo->HiddenSectors))
2048 {
2049 /* Then it's a super floppy */
2050 IsSuperFloppy = TRUE;
2051
2052 /* Which also means it must be non-bootable FAT-16 */
2053 if ((PartitionInfo->PartitionNumber) ||
2054 (PartitionInfo->PartitionType != PARTITION_FAT_16) ||
2055 (PartitionInfo->BootIndicator))
2056 {
2057 /* It's not, so we fail */
2058 return STATUS_INVALID_PARAMETER;
2059 }
2060
2061 /* Check if it needs a rewrite, and disable EZ drive for sure */
2062 if (PartitionInfo->RewritePartition) DoRewrite = TRUE;
2063 IsEzDrive = FALSE;
2064 }
2065 }
2066
2067 /* Count the number of partition tables */
2068 DiskLayout->TableCount = (PartitionBuffer->PartitionCount + 4 - 1) / 4;
2069
2070 /* Allocate our partition buffer */
2071 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
2072 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
2073
2074 /* Loop the entries */
2075 Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET];
2076 for (i = 0; i < DiskLayout->TableCount; i++)
2077 {
2078 /* Set if this is the MBR partition */
2079 IsMbr= (BOOLEAN)!i;
2080
2081 /* Initialize th event */
2082 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2083
2084 /* Build the read IRP */
2085 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
2086 DeviceObject,
2087 Buffer,
2088 BufferSize,
2089 &Offset,
2090 &Event,
2091 &IoStatusBlock);
2092 if (!Irp)
2093 {
2094 /* Fail */
2095 Status = STATUS_INSUFFICIENT_RESOURCES;
2096 break;
2097 }
2098
2099 /* Make sure to disable volume verification */
2100 IoStackLocation = IoGetNextIrpStackLocation(Irp);
2101 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2102
2103 /* Call the driver */
2104 Status = IoCallDriver(DeviceObject, Irp);
2105 if (Status == STATUS_PENDING)
2106 {
2107 /* Wait for completion */
2108 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
2109 Status = IoStatusBlock.Status;
2110 }
2111
2112 /* Check for failure */
2113 if (!NT_SUCCESS(Status)) break;
2114
2115 /* If we biased for EZ-Drive, unbias now */
2116 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2117
2118 /* Check if this is a normal disk */
2119 if (!IsSuperFloppy)
2120 {
2121 /* Set the boot record signature */
2122 Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
2123
2124 /* By default, don't require a rewrite */
2125 DoRewrite = FALSE;
2126
2127 /* Check if we don't have an offset */
2128 if (!Offset.QuadPart)
2129 {
2130 /* Check if the signature doesn't match */
2131 if (((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] !=
2132 PartitionBuffer->Signature)
2133 {
2134 /* Then write the signature and now we need a rewrite */
2135 ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] =
2136 PartitionBuffer->Signature;
2137 DoRewrite = TRUE;
2138 }
2139 }
2140
2141 /* Loop the partition table entries */
2142 PartitionTable = &DiskLayout->PartitionTable[i];
2143 for (j = 0; j < 4; j++)
2144 {
2145 /* Get the current entry and type */
2146 TableEntry = &PartitionTable->PartitionEntry[j];
2147 PartitionType = TableEntry->PartitionType;
2148
2149 /* Check if the entry needs a rewrite */
2150 if (TableEntry->RewritePartition)
2151 {
2152 /* Then we need one too */
2153 DoRewrite = TRUE;
2154
2155 /* Save the type and if it's a bootable partition */
2156 Entry[j].PartitionType = TableEntry->PartitionType;
2157 Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0;
2158
2159 /* Make sure it's used */
2160 if (PartitionType != PARTITION_ENTRY_UNUSED)
2161 {
2162 /* Make sure it's not a container (unless primary) */
2163 if ((IsMbr) || !(IsContainerPartition(PartitionType)))
2164 {
2165 /* Use the partition offset */
2166 StartOffset.QuadPart = Offset.QuadPart;
2167 }
2168 else
2169 {
2170 /* Use the extended logical partition offset */
2171 StartOffset.QuadPart = ExtendedOffset.QuadPart;
2172 }
2173
2174 /* Set the sector offset */
2175 SectorOffset.QuadPart = TableEntry->
2176 StartingOffset.QuadPart -
2177 StartOffset.QuadPart;
2178
2179 /* Now calculate the starting sector */
2180 StartOffset.QuadPart = SectorOffset.QuadPart >> k;
2181 Entry[j].StartingSector = StartOffset.LowPart;
2182
2183 /* As well as the length */
2184 PartitionLength.QuadPart = TableEntry->PartitionLength.
2185 QuadPart >> k;
2186 Entry[j].PartitionLength = PartitionLength.LowPart;
2187
2188 /* Calculate the CHS values */
2189 HalpCalculateChsValues(&TableEntry->StartingOffset,
2190 &TableEntry->PartitionLength,
2191 k,
2192 SectorsPerTrack,
2193 NumberOfHeads,
2194 ConventionalCylinders,
2195 (PPARTITION_DESCRIPTOR)
2196 &Entry[j]);
2197 }
2198 else
2199 {
2200 /* Otherwise set up an empty entry */
2201 Entry[j].StartingSector = 0;
2202 Entry[j].PartitionLength = 0;
2203 Entry[j].StartingTrack = 0;
2204 Entry[j].EndingTrack = 0;
2205 Entry[j].StartingCylinder = 0;
2206 Entry[j].EndingCylinder = 0;
2207 }
2208 }
2209
2210 /* Check if this is a container partition */
2211 if (IsContainerPartition(PartitionType))
2212 {
2213 /* Then update the offset to use */
2214 NextOffset = TableEntry->StartingOffset;
2215 }
2216 }
2217 }
2218
2219 /* Check if we need to write back the buffer */
2220 if (DoRewrite)
2221 {
2222 /* We don't need to do this again */
2223 DoRewrite = FALSE;
2224
2225 /* Initialize the event */
2226 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2227
2228 /* If we unbiased for EZ-Drive, rebias now */
2229 if ((IsEzDrive) && !(Offset.QuadPart)) Offset.QuadPart = 512;
2230
2231 /* Build the write IRP */
2232 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
2233 DeviceObject,
2234 Buffer,
2235 BufferSize,
2236 &Offset,
2237 &Event,
2238 &IoStatusBlock);
2239 if (!Irp)
2240 {
2241 /* Fail */
2242 Status = STATUS_INSUFFICIENT_RESOURCES;
2243 break;
2244 }
2245
2246 /* Make sure to disable volume verification */
2247 IoStackLocation = IoGetNextIrpStackLocation(Irp);
2248 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2249
2250 /* Call the driver */
2251 Status = IoCallDriver(DeviceObject, Irp);
2252 if (Status == STATUS_PENDING)
2253 {
2254 /* Wait for completion */
2255 KeWaitForSingleObject(&Event,
2256 Executive,
2257 KernelMode,
2258 FALSE,
2259 NULL);
2260 Status = IoStatusBlock.Status;
2261 }
2262
2263 /* Check for failure */
2264 if (!NT_SUCCESS(Status)) break;
2265
2266 /* If we biased for EZ-Drive, unbias now */
2267 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2268 }
2269
2270 /* Update the partition offset and set the extended offset if needed */
2271 Offset = NextOffset;
2272 if (IsMbr) ExtendedOffset = NextOffset;
2273 }
2274
2275 /* If we had a buffer, free it, then return status */
2276 if (Buffer) ExFreePoolWithTag(Buffer, TAG_FILE_SYSTEM);
2277 return Status;
2278 }
2279
2280 /* PUBLIC FUNCTIONS **********************************************************/
2281
2282 /*
2283 * @implemented
2284 */
2285 VOID
2286 FASTCALL
2287 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
2288 IN ULONG SectorSize,
2289 IN ULONG MbrTypeIdentifier,
2290 OUT PVOID *MbrBuffer)
2291 {
2292 HALDISPATCH->HalExamineMBR(DeviceObject,
2293 SectorSize,
2294 MbrTypeIdentifier,
2295 MbrBuffer);
2296 }
2297
2298 /*
2299 * @implemented
2300 */
2301 NTSTATUS
2302 FASTCALL
2303 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
2304 IN ULONG SectorSize,
2305 IN BOOLEAN ReturnRecognizedPartitions,
2306 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
2307 {
2308 return HALDISPATCH->HalIoReadPartitionTable(DeviceObject,
2309 SectorSize,
2310 ReturnRecognizedPartitions,
2311 PartitionBuffer);
2312 }
2313
2314 /*
2315 * @implemented
2316 */
2317 NTSTATUS
2318 FASTCALL
2319 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
2320 IN ULONG SectorSize,
2321 IN ULONG PartitionNumber,
2322 IN ULONG PartitionType)
2323 {
2324 return HALDISPATCH->HalIoSetPartitionInformation(DeviceObject,
2325 SectorSize,
2326 PartitionNumber,
2327 PartitionType);
2328 }
2329
2330 /*
2331 * @implemented
2332 */
2333 NTSTATUS
2334 FASTCALL
2335 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
2336 IN ULONG SectorSize,
2337 IN ULONG SectorsPerTrack,
2338 IN ULONG NumberOfHeads,
2339 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
2340 {
2341 return HALDISPATCH->HalIoWritePartitionTable(DeviceObject,
2342 SectorSize,
2343 SectorsPerTrack,
2344 NumberOfHeads,
2345 PartitionBuffer);
2346 }
2347
2348 /*
2349 * @implemented
2350 */
2351 VOID
2352 FASTCALL
2353 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
2354 IN PSTRING NtDeviceName,
2355 OUT PUCHAR NtSystemPath,
2356 OUT PSTRING NtSystemPathString)
2357 {
2358 HALDISPATCH->HalIoAssignDriveLetters(LoaderBlock,
2359 NtDeviceName,
2360 NtSystemPath,
2361 NtSystemPathString);
2362 }
2363
2364 /* EOF */