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