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