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