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