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