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