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