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