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