Use Uint32x32To64() function instead of ULONG * ULONG. Fixes partition length truncation.
[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_DATA,
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 DPRINT1("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 0x10001,
485 &ObjectAttributes,
486 &StatusBlock,
487 1,
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) +
1020 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, LastSector;
1059 ULONG SectorsPerCylinder, StartCluster, EndCluster;
1060 ULONG StartHead, EndHead;
1061 ULONG StartSector, EndSector;
1062 ULONG Remainder;
1063 PAGED_CODE();
1064
1065 /* Calculate the number of sectors for each cylinder */
1066 SectorsPerCylinder = SectorsPerTrack * NumberOfTracks;
1067
1068 /* Calculate the start and end sector, as well as the count */
1069 FirstSector.QuadPart = PartitionOffset->QuadPart >> ShiftCount;
1070 SectorCount.QuadPart = PartitionLength->QuadPart >> ShiftCount;
1071 LastSector.QuadPart = FirstSector.QuadPart + SectorCount.QuadPart - 1;
1072
1073 /* Calculate the start and end clusters */
1074 StartCluster = FirstSector.LowPart / SectorsPerCylinder;
1075 EndCluster = LastSector.LowPart / SectorsPerCylinder;
1076
1077 /* Set the default number of cylinders */
1078 if (!ConventionalCylinders) ConventionalCylinders = 1024;
1079
1080 /* Normalize the values */
1081 if (StartCluster >= ConventionalCylinders)
1082 {
1083 /* Set the maximum to 1023 */
1084 StartCluster = ConventionalCylinders - 1;
1085 }
1086 if (EndCluster >= ConventionalCylinders)
1087 {
1088 /* Set the maximum to 1023 */
1089 EndCluster = ConventionalCylinders - 1;
1090 }
1091
1092 /* Calculate the starting head and sector that still remain */
1093 Remainder = StartCluster % SectorsPerCylinder;
1094 StartHead = Remainder / SectorsPerTrack;
1095 StartSector = Remainder % SectorsPerTrack;
1096
1097 /* Calculate the ending head and sector that still remain */
1098 Remainder = EndCluster % SectorsPerCylinder;
1099 EndHead = Remainder / SectorsPerTrack;
1100 EndSector = Remainder % SectorsPerTrack;
1101
1102 /* Write the values in the descriptor */
1103 PartitionDescriptor->StartingCylinderMsb = StartCluster;
1104 PartitionDescriptor->EndingCylinderMsb = EndCluster;
1105 PartitionDescriptor->StartingTrack = StartHead;
1106 PartitionDescriptor->EndingTrack = EndHead;
1107 PartitionDescriptor->StartingCylinderLsb = ((StartSector + 1) & 0x3F) |
1108 ((StartCluster >> 2) & 0xC0);
1109 PartitionDescriptor->EndingCylinderLsb = ((EndSector + 1) & 0x3F) |
1110 ((EndCluster >> 2) & 0xC0);
1111 }
1112
1113 VOID
1114 FASTCALL
1115 xHalGetPartialGeometry(IN PDEVICE_OBJECT DeviceObject,
1116 IN PULONG ConventionalCylinders,
1117 IN PLONGLONG DiskSize)
1118 {
1119 PDISK_GEOMETRY DiskGeometry = NULL;
1120 PIO_STATUS_BLOCK IoStatusBlock = NULL;
1121 PKEVENT Event = NULL;
1122 PIRP Irp;
1123 NTSTATUS Status;
1124
1125 /* Set defaults */
1126 *ConventionalCylinders = 0;
1127 *DiskSize = 0;
1128
1129 /* Allocate the structure in nonpaged pool */
1130 DiskGeometry = ExAllocatePoolWithTag(NonPagedPool,
1131 sizeof(DISK_GEOMETRY),
1132 TAG_FILE_SYSTEM);
1133 if (!DiskGeometry) goto Cleanup;
1134
1135 /* Allocate the status block in nonpaged pool */
1136 IoStatusBlock = ExAllocatePoolWithTag(NonPagedPool,
1137 sizeof(IO_STATUS_BLOCK),
1138 TAG_FILE_SYSTEM);
1139 if (!IoStatusBlock) goto Cleanup;
1140
1141 /* Allocate the event in nonpaged pool too */
1142 Event = ExAllocatePoolWithTag(NonPagedPool,
1143 sizeof(KEVENT),
1144 TAG_FILE_SYSTEM);
1145 if (!Event) goto Cleanup;
1146
1147 /* Initialize the event */
1148 KeInitializeEvent(Event, NotificationEvent, FALSE);
1149
1150 /* Build the IRP */
1151 Irp = IoBuildDeviceIoControlRequest(IOCTL_DISK_GET_DRIVE_GEOMETRY,
1152 DeviceObject,
1153 NULL,
1154 0,
1155 DiskGeometry,
1156 sizeof(DISK_GEOMETRY),
1157 FALSE,
1158 Event,
1159 IoStatusBlock);
1160 if (!Irp) goto Cleanup;
1161
1162 /* Now call the driver */
1163 Status = IoCallDriver(DeviceObject, Irp);
1164 if (Status == STATUS_PENDING)
1165 {
1166 /* Wait for it to complete */
1167 KeWaitForSingleObject(Event, Executive, KernelMode, FALSE, NULL);
1168 Status = IoStatusBlock->Status;
1169 }
1170
1171 /* Check driver status */
1172 if (NT_SUCCESS(Status))
1173 {
1174 /* Return the cylinder count */
1175 *ConventionalCylinders = DiskGeometry->Cylinders.LowPart;
1176
1177 /* Make sure it's not larger then 1024 */
1178 if (DiskGeometry->Cylinders.LowPart >= 1024)
1179 {
1180 /* Otherwise, normalize the value */
1181 *ConventionalCylinders = 1024;
1182 }
1183
1184 /* Calculate the disk size */
1185 *DiskSize = DiskGeometry->Cylinders.QuadPart *
1186 DiskGeometry->TracksPerCylinder *
1187 DiskGeometry->SectorsPerTrack *
1188 DiskGeometry->BytesPerSector;
1189 }
1190
1191 Cleanup:
1192 /* Free all the pointers */
1193 if (Event) ExFreePool(Event);
1194 if (IoStatusBlock) ExFreePool(IoStatusBlock);
1195 if (DiskGeometry) ExFreePool(DiskGeometry);
1196 return;
1197 }
1198
1199 /* PUBLIC FUNCTIONS **********************************************************/
1200
1201 /*
1202 * @implemented
1203 */
1204 VOID
1205 FASTCALL
1206 HalExamineMBR(IN PDEVICE_OBJECT DeviceObject,
1207 IN ULONG SectorSize,
1208 IN ULONG MbrTypeIdentifier,
1209 OUT PVOID *MbrBuffer)
1210 {
1211 LARGE_INTEGER Offset;
1212 PUCHAR Buffer;
1213 ULONG BufferSize;
1214 KEVENT Event;
1215 IO_STATUS_BLOCK IoStatusBlock;
1216 PIRP Irp;
1217 PPARTITION_DESCRIPTOR PartitionDescriptor;
1218 NTSTATUS Status;
1219 PIO_STACK_LOCATION IoStackLocation;
1220 Offset.QuadPart = 0;
1221
1222 /* Assume failure */
1223 *MbrBuffer = NULL;
1224
1225 /* Normalize the buffer size */
1226 BufferSize = max(SectorSize, 512);
1227
1228 /* Allocate the buffer */
1229 Buffer = ExAllocatePoolWithTag(NonPagedPool,
1230 PAGE_SIZE > BufferSize ?
1231 PAGE_SIZE : BufferSize,
1232 TAG_FILE_SYSTEM);
1233 if (!Buffer) return;
1234
1235 /* Initialize the Event */
1236 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1237
1238 /* Build the IRP */
1239 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1240 DeviceObject,
1241 Buffer,
1242 BufferSize,
1243 &Offset,
1244 &Event,
1245 &IoStatusBlock);
1246 if (!Irp)
1247 {
1248 /* Failed */
1249 ExFreePool(Buffer);
1250 return;
1251 }
1252
1253 /* Make sure to override volume verification */
1254 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1255 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1256
1257 /* Call the driver */
1258 Status = IoCallDriver(DeviceObject, Irp);
1259 if (Status == STATUS_PENDING)
1260 {
1261 /* Wait for completion */
1262 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1263 Status = IoStatusBlock.Status;
1264 }
1265
1266 /* Check driver Status */
1267 if (NT_SUCCESS(Status))
1268 {
1269 /* Validate the MBR Signature */
1270 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1271 {
1272 /* Failed */
1273 ExFreePool(Buffer);
1274 return;
1275 }
1276
1277 /* Get the partition entry */
1278 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1279 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1280
1281 /* Make sure it's what the caller wanted */
1282 if (PartitionDescriptor->PartitionType != MbrTypeIdentifier)
1283 {
1284 /* It's not, free our buffer */
1285 ExFreePool(Buffer);
1286 }
1287 else
1288 {
1289 /* Check if this is a secondary entry */
1290 if (PartitionDescriptor->PartitionType == 0x54)
1291 {
1292 /* Return our buffer, but at sector 63 */
1293 *(PULONG)Buffer = 63;
1294 *MbrBuffer = Buffer;
1295 }
1296 else if (PartitionDescriptor->PartitionType == 0x55)
1297 {
1298 /* EZ Drive, return the buffer directly */
1299 *MbrBuffer = Buffer;
1300 }
1301 else
1302 {
1303 /* Otherwise crash on debug builds */
1304 ASSERT(PartitionDescriptor->PartitionType == 0x55);
1305 }
1306 }
1307 }
1308 }
1309
1310 /*
1311 * @implemented
1312 */
1313 NTSTATUS
1314 FASTCALL
1315 IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject,
1316 IN ULONG SectorSize,
1317 IN BOOLEAN ReturnRecognizedPartitions,
1318 IN OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
1319 {
1320 KEVENT Event;
1321 IO_STATUS_BLOCK IoStatusBlock;
1322 PIRP Irp;
1323 PPARTITION_DESCRIPTOR PartitionDescriptor;
1324 CCHAR Entry;
1325 NTSTATUS Status;
1326 PPARTITION_INFORMATION PartitionInfo;
1327 PUCHAR Buffer = NULL;
1328 ULONG BufferSize = 2048, InputSize;
1329 PDRIVE_LAYOUT_INFORMATION DriveLayoutInfo = NULL;
1330 LONG j = -1, i = -1, k;
1331 DISK_GEOMETRY DiskGeometry;
1332 LONGLONG EndSector, MaxSector, StartOffset;
1333 ULONGLONG MaxOffset;
1334 LARGE_INTEGER Offset, VolumeOffset;
1335 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE, MbrFound = FALSE;
1336 BOOLEAN IsValid, IsEmpty = TRUE;
1337 PVOID MbrBuffer;
1338 PIO_STACK_LOCATION IoStackLocation;
1339 PBOOT_SECTOR_INFO BootSectorInfo = (PBOOT_SECTOR_INFO)Buffer;
1340 UCHAR PartitionType;
1341 VolumeOffset.QuadPart = Offset.QuadPart = 0;
1342 PAGED_CODE();
1343
1344 /* Allocate the buffer */
1345 *PartitionBuffer = ExAllocatePoolWithTag(NonPagedPool,
1346 BufferSize,
1347 TAG_FILE_SYSTEM);
1348 if (!(*PartitionBuffer)) return STATUS_INSUFFICIENT_RESOURCES;
1349
1350 /* Normalize the buffer size */
1351 InputSize = max(512, SectorSize);
1352
1353 /* Check for EZ Drive */
1354 HalExamineMBR(DeviceObject, InputSize, 0x55, &MbrBuffer);
1355 if (MbrBuffer)
1356 {
1357 /* EZ Drive found, bias the offset */
1358 IsEzDrive = TRUE;
1359 ExFreePool(MbrBuffer);
1360 Offset.QuadPart = 512;
1361 }
1362
1363 /* Get drive geometry */
1364 Status = HalpGetFullGeometry(DeviceObject, &DiskGeometry, &MaxOffset);
1365 if (!NT_SUCCESS(Status))
1366 {
1367 ExFreePool(*PartitionBuffer);
1368 *PartitionBuffer = NULL;
1369 return Status;
1370 }
1371
1372 /* Get the end and maximum sector */
1373 EndSector = MaxOffset;
1374 MaxSector = MaxOffset << 1;
1375 DPRINT1("FSTUB: MaxOffset = %#I64x, MaxSector = %#I64x\n",
1376 MaxOffset, MaxSector);
1377
1378 /* Allocate our buffer */
1379 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
1380 if (!Buffer)
1381 {
1382 /* Fail, free the input buffer */
1383 ExFreePool(*PartitionBuffer);
1384 return STATUS_INSUFFICIENT_RESOURCES;
1385 }
1386
1387 /* Start partition loop */
1388 do
1389 {
1390 /* Assume the partition is valid */
1391 IsValid = TRUE;
1392
1393 /* Initialize the event */
1394 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1395
1396 /* Clear the buffer and build the IRP */
1397 RtlZeroMemory(Buffer, InputSize);
1398 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1399 DeviceObject,
1400 Buffer,
1401 InputSize,
1402 &Offset,
1403 &Event,
1404 &IoStatusBlock);
1405 if (!Irp)
1406 {
1407 /* Failed */
1408 Status = STATUS_INSUFFICIENT_RESOURCES;
1409 break;
1410 }
1411
1412 /* Make sure to disable volume verification */
1413 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1414 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1415
1416 /* Call the driver */
1417 Status = IoCallDriver(DeviceObject, Irp);
1418 if (Status == STATUS_PENDING)
1419 {
1420 /* Wait for completion */
1421 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1422 Status = IoStatusBlock.Status;
1423 }
1424
1425 /* Normalize status code and check for failure */
1426 if (Status == STATUS_NO_DATA_DETECTED) Status = STATUS_SUCCESS;
1427 if (!NT_SUCCESS(Status)) break;
1428
1429 /* If we biased for EZ-Drive, unbias now */
1430 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
1431
1432 /* Make sure this is a valid MBR */
1433 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1434 {
1435 /* It's not, fail */
1436 DPRINT1("FSTUB: (IoReadPartitionTable) No 0xaa55 found in "
1437 "partition table %d\n", j + 1);
1438 break;
1439 }
1440
1441 /* At this point we have a valid MBR */
1442 MbrFound = TRUE;
1443
1444 /* Check if we weren't given an offset */
1445 if (!Offset.QuadPart)
1446 {
1447 /* Then read the signature off the disk */
1448 (*PartitionBuffer)->Signature = ((PULONG)Buffer)
1449 [PARTITION_TABLE_OFFSET / 2 - 1];
1450 }
1451
1452 /* Get the partition descriptor array */
1453 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1454 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1455
1456 /* Get the partition type */
1457 PartitionType = PartitionDescriptor->PartitionType;
1458
1459 /* Start looping partitions */
1460 j++;
1461 DPRINT1("FSTUB: Partition Table %d:\n", j);
1462 for (Entry = 1, k = 0; Entry <= 4; Entry++, PartitionDescriptor++)
1463 {
1464 /* Get the partition type */
1465 PartitionType = PartitionDescriptor->PartitionType;
1466
1467 /* Print debug messages */
1468 DPRINT1("Partition Entry %d,%d: type %#x %s\n",
1469 j,
1470 Entry,
1471 PartitionType,
1472 (PartitionDescriptor->ActiveFlag) ? "Active" : "");
1473 DPRINT1("\tOffset %#08lx for %#08lx Sectors\n",
1474 GET_STARTING_SECTOR(PartitionDescriptor),
1475 GET_PARTITION_LENGTH(PartitionDescriptor));
1476
1477 /* Make sure that the partition is valid, unless it's the first */
1478 if (!(HalpIsValidPartitionEntry(PartitionDescriptor,
1479 MaxOffset,
1480 MaxSector)) && !(j))
1481 {
1482 /* It's invalid, so fail */
1483 IsValid = FALSE;
1484 break;
1485 }
1486
1487 /* Check if it's a container */
1488 if (IsContainerPartition(PartitionType))
1489 {
1490 /* Increase the count of containers */
1491 if (++k != 1)
1492 {
1493 /* More then one table is invalid */
1494 DPRINT1("FSTUB: Multiple container partitions found in "
1495 "partition table %d\n - table is invalid\n",
1496 j);
1497 IsValid = FALSE;
1498 break;
1499 }
1500 }
1501
1502 /* Check if the partition is supposedly empty */
1503 if (IsEmpty)
1504 {
1505 /* But check if it actually has a start and/or length */
1506 if ((GET_STARTING_SECTOR(PartitionDescriptor)) ||
1507 (GET_PARTITION_LENGTH(PartitionDescriptor)))
1508 {
1509 /* So then it's not really empty */
1510 IsEmpty = FALSE;
1511 }
1512 }
1513
1514 /* Check if the caller wanted only recognized partitions */
1515 if (ReturnRecognizedPartitions)
1516 {
1517 /* Then check if this one is unused, or a container */
1518 if ((PartitionType == PARTITION_ENTRY_UNUSED) ||
1519 IsContainerPartition(PartitionType))
1520 {
1521 /* Skip it, since the caller doesn't want it */
1522 continue;
1523 }
1524 }
1525
1526 /* Increase the structure count and check if they can fit */
1527 if ((sizeof(DRIVE_LAYOUT_INFORMATION) +
1528 (++i * sizeof(PARTITION_INFORMATION))) >
1529 BufferSize)
1530 {
1531 /* Allocate a new buffer that's twice as big */
1532 DriveLayoutInfo = ExAllocatePoolWithTag(NonPagedPool,
1533 BufferSize << 1,
1534 TAG_FILE_SYSTEM);
1535 if (!DriveLayoutInfo)
1536 {
1537 /* Out of memory, unto this extra structure */
1538 --i;
1539 Status = STATUS_INSUFFICIENT_RESOURCES;
1540 break;
1541 }
1542
1543 /* Copy the contents of the old buffer */
1544 RtlMoveMemory(DriveLayoutInfo,
1545 *PartitionBuffer,
1546 BufferSize);
1547
1548 /* Free the old buffer and set this one as the new one */
1549 ExFreePool(*PartitionBuffer);
1550 *PartitionBuffer = DriveLayoutInfo;
1551
1552 /* Double the size */
1553 BufferSize <<= 1;
1554 }
1555
1556 /* Now get the current structure being filled and initialize it */
1557 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[i];
1558 PartitionInfo->PartitionType = PartitionType;
1559 PartitionInfo->RewritePartition = FALSE;
1560
1561 /* Check if we're dealing with a partition that's in use */
1562 if (PartitionType != PARTITION_ENTRY_UNUSED)
1563 {
1564 /* Check if it's bootable */
1565 PartitionInfo->BootIndicator = PartitionDescriptor->
1566 ActiveFlag & 0x80 ?
1567 TRUE : FALSE;
1568
1569 /* Check if its' a container */
1570 if (IsContainerPartition(PartitionType))
1571 {
1572 /* Then don't recognize it and use the volume offset */
1573 PartitionInfo->RecognizedPartition = FALSE;
1574 StartOffset = VolumeOffset.QuadPart;
1575 }
1576 else
1577 {
1578 /* Then recognize it and use the partition offset */
1579 PartitionInfo->RecognizedPartition = TRUE;
1580 StartOffset = Offset.QuadPart;
1581 }
1582
1583 /* Get the starting offset */
1584 PartitionInfo->StartingOffset.QuadPart =
1585 StartOffset +
1586 UInt32x32To64(GET_STARTING_SECTOR(PartitionDescriptor),
1587 SectorSize);
1588
1589 /* Calculate the number of hidden sectors */
1590 PartitionInfo->HiddenSectors = (PartitionInfo->
1591 StartingOffset.QuadPart -
1592 StartOffset) /
1593 SectorSize;
1594
1595 /* Get the partition length */
1596 PartitionInfo->PartitionLength.QuadPart =
1597 UInt32x32To64(GET_PARTITION_LENGTH(PartitionDescriptor),
1598 SectorSize);
1599
1600 /* FIXME: REACTOS HACK */
1601 PartitionInfo->PartitionNumber = i + 1;
1602 }
1603 else
1604 {
1605 /* Otherwise, clear all the relevant fields */
1606 PartitionInfo->BootIndicator = FALSE;
1607 PartitionInfo->RecognizedPartition = FALSE;
1608 PartitionInfo->StartingOffset.QuadPart = 0;
1609 PartitionInfo->PartitionLength.QuadPart = 0;
1610 PartitionInfo->HiddenSectors = 0;
1611
1612 /* FIXME: REACTOS HACK */
1613 PartitionInfo->PartitionNumber = 0;
1614 }
1615 }
1616
1617 /* Finish debug log, and check for failure */
1618 DPRINT1("\n");
1619 if (!NT_SUCCESS(Status)) break;
1620
1621 /* Also check if we hit an invalid entry here */
1622 if (!IsValid)
1623 {
1624 /* We did, so break out of the loop minus one entry */
1625 j--;
1626 break;
1627 }
1628
1629 /* Reset the offset */
1630 Offset.QuadPart = 0;
1631
1632 /* Go back to the descriptor array and loop it */
1633 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1634 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1635 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1636 {
1637 /* Check if this is a container partition, since we skipped them */
1638 if (IsContainerPartition(PartitionType))
1639 {
1640 /* Get its offset */
1641 Offset.QuadPart = VolumeOffset.QuadPart +
1642 UInt32x32To64(
1643 GET_STARTING_SECTOR(PartitionDescriptor),
1644 SectorSize);
1645
1646 /* If this is a primary partition, this is the volume offset */
1647 if (IsPrimary) VolumeOffset = Offset;
1648
1649 /* Also update the maximum sector */
1650 MaxSector = GET_PARTITION_LENGTH(PartitionDescriptor);
1651 DPRINT1("FSTUB: MaxSector now = %#08lx\n", MaxSector);
1652 break;
1653 }
1654 }
1655
1656 /* Loop the next partitions, which are not primary anymore */
1657 IsPrimary = FALSE;
1658 } while (Offset.HighPart | Offset.LowPart);
1659
1660 /* Check if this is a removable device that's probably a super-floppy */
1661 if ((DiskGeometry.MediaType == RemovableMedia) &&
1662 !(j) &&
1663 (MbrFound) &&
1664 (IsEmpty))
1665 {
1666 /* Read the jump bytes to detect super-floppy */
1667 if ((BootSectorInfo->JumpByte[0] == 0xeb) ||
1668 (BootSectorInfo->JumpByte[0] == 0xe9))
1669 {
1670 /* Super floppes don't have typical MBRs, so skip them */
1671 DPRINT1("FSTUB: Jump byte %#x found along with empty partition "
1672 "table - disk is a super floppy and has no valid MBR\n",
1673 BootSectorInfo->JumpByte);
1674 j = -1;
1675 }
1676 }
1677
1678 /* Check if we're still at partition -1 */
1679 if (j == -1)
1680 {
1681 /* The likely cause is the super floppy detection above */
1682 if ((MbrFound) || (DiskGeometry.MediaType == RemovableMedia))
1683 {
1684 /* Print out debugging information */
1685 DPRINT1("FSTUB: Drive %#p has no valid MBR. Make it into a "
1686 "super-floppy\n",
1687 DeviceObject);
1688 DPRINT1("FSTUB: Drive has %#08lx sectors and is %#016I64x "
1689 "bytes large\n",
1690 EndSector, EndSector * DiskGeometry.BytesPerSector);
1691
1692 /* We should at least have some sectors */
1693 if (EndSector > 0)
1694 {
1695 /* Get the entry we'll use */
1696 PartitionInfo = &(*PartitionBuffer)->PartitionEntry[0];
1697
1698 /* Fill it out with data for a super-floppy */
1699 PartitionInfo->RewritePartition = FALSE;
1700 PartitionInfo->RecognizedPartition = TRUE;
1701 PartitionInfo->PartitionType = PARTITION_FAT_16;
1702 PartitionInfo->BootIndicator = FALSE;
1703 PartitionInfo->HiddenSectors = 0;
1704 PartitionInfo->StartingOffset.QuadPart = 0;
1705 PartitionInfo->PartitionLength.QuadPart = (EndSector *
1706 DiskGeometry.
1707 BytesPerSector);
1708
1709 /* FIXME: REACTOS HACK */
1710 PartitionInfo->PartitionNumber = 0;
1711
1712 /* Set the signature and set the count back to 0 */
1713 (*PartitionBuffer)->Signature = 1;
1714 i = 0;
1715 }
1716 }
1717 else
1718 {
1719 /* Otherwise, this isn't a super floppy, so set an invalid count */
1720 i = -1;
1721 }
1722 }
1723
1724 /* Set the partition count */
1725 (*PartitionBuffer)->PartitionCount = ++i;
1726
1727 /* If we have no count, delete the signature */
1728 if (!i) (*PartitionBuffer)->Signature = 0;
1729
1730 /* Free the buffer and check for success */
1731 if (Buffer) ExFreePool(Buffer);
1732 if (!NT_SUCCESS(Status)) ExFreePool(*PartitionBuffer);
1733
1734 /* Return status */
1735 return Status;
1736 }
1737
1738 /*
1739 * @implemented
1740 */
1741 NTSTATUS
1742 FASTCALL
1743 IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject,
1744 IN ULONG SectorSize,
1745 IN ULONG PartitionNumber,
1746 IN ULONG PartitionType)
1747 {
1748 PIRP Irp;
1749 KEVENT Event;
1750 IO_STATUS_BLOCK IoStatusBlock;
1751 NTSTATUS Status;
1752 LARGE_INTEGER Offset, VolumeOffset;
1753 PUCHAR Buffer = NULL;
1754 ULONG BufferSize;
1755 ULONG i = 0;
1756 ULONG Entry;
1757 PPARTITION_DESCRIPTOR PartitionDescriptor;
1758 BOOLEAN IsPrimary = TRUE, IsEzDrive = FALSE;
1759 PVOID MbrBuffer;
1760 PIO_STACK_LOCATION IoStackLocation;
1761 VolumeOffset.QuadPart = Offset.QuadPart = 0;
1762 PAGED_CODE();
1763
1764 /* Normalize the buffer size */
1765 BufferSize = max(512, SectorSize);
1766
1767 /* Check for EZ Drive */
1768 HalExamineMBR(DeviceObject, BufferSize, 0x55, &MbrBuffer);
1769 if (MbrBuffer)
1770 {
1771 /* EZ Drive found, bias the offset */
1772 IsEzDrive = TRUE;
1773 ExFreePool(MbrBuffer);
1774 Offset.QuadPart = 512;
1775 }
1776
1777 /* Allocate our partition buffer */
1778 Buffer = ExAllocatePoolWithTag(NonPagedPool, PAGE_SIZE, TAG_FILE_SYSTEM);
1779 if (!Buffer) return STATUS_INSUFFICIENT_RESOURCES;
1780
1781 /* Initialize the event we'll use and loop partitions */
1782 KeInitializeEvent(&Event, NotificationEvent, FALSE);
1783 do
1784 {
1785 /* Reset the event since we reuse it */
1786 KeResetEvent(&Event);
1787
1788 /* Build the read IRP */
1789 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
1790 DeviceObject,
1791 Buffer,
1792 BufferSize,
1793 &Offset,
1794 &Event,
1795 &IoStatusBlock);
1796 if (!Irp)
1797 {
1798 /* Fail */
1799 Status = STATUS_INSUFFICIENT_RESOURCES;
1800 break;
1801 }
1802
1803 /* Make sure to disable volume verification */
1804 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1805 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1806
1807 /* Call the driver */
1808 Status = IoCallDriver(DeviceObject, Irp);
1809 if (Status == STATUS_PENDING)
1810 {
1811 /* Wait for completion */
1812 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1813 Status = IoStatusBlock.Status;
1814 }
1815
1816 /* Check for failure */
1817 if (!NT_SUCCESS(Status)) break;
1818
1819 /* If we biased for EZ-Drive, unbias now */
1820 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
1821
1822 /* Make sure this is a valid MBR */
1823 if (((PUSHORT)Buffer)[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
1824 {
1825 /* It's not, fail */
1826 Status = STATUS_BAD_MASTER_BOOT_RECORD;
1827 break;
1828 }
1829
1830 /* Get the partition descriptors and loop them */
1831 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1832 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1833 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1834 {
1835 /* Check if it's unused or a container partition */
1836 if ((PartitionDescriptor->PartitionType ==
1837 PARTITION_ENTRY_UNUSED) ||
1838 (IsContainerPartition(PartitionDescriptor->PartitionType)))
1839 {
1840 /* Go to the next one */
1841 continue;
1842 }
1843
1844 /* It's a valid partition, so increase the partition count */
1845 if (++i == PartitionNumber)
1846 {
1847 /* We found a match, set the type */
1848 PartitionDescriptor->PartitionType = PartitionType;
1849
1850 /* Reset the resusable event */
1851 KeResetEvent(&Event);
1852
1853 /* Build the write IRP */
1854 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
1855 DeviceObject,
1856 Buffer,
1857 BufferSize,
1858 &Offset,
1859 &Event,
1860 &IoStatusBlock);
1861 if (!Irp)
1862 {
1863 /* Fail */
1864 Status = STATUS_INSUFFICIENT_RESOURCES;
1865 break;
1866 }
1867
1868 /* Disable volume verification */
1869 IoStackLocation = IoGetNextIrpStackLocation(Irp);
1870 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1871
1872 /* Call the driver */
1873 Status = IoCallDriver(DeviceObject, Irp);
1874 if (Status == STATUS_PENDING)
1875 {
1876 /* Wait for completion */
1877 KeWaitForSingleObject(&Event,
1878 Executive,
1879 KernelMode,
1880 FALSE,
1881 NULL);
1882 Status = IoStatusBlock.Status;
1883 }
1884
1885 /* We're done, break out of the loop */
1886 break;
1887 }
1888 }
1889
1890 /* If we looped all the partitions, break out */
1891 if (Entry <= NUM_PARTITION_TABLE_ENTRIES) break;
1892
1893 /* Nothing found yet, get the partition array again */
1894 PartitionDescriptor = (PPARTITION_DESCRIPTOR)
1895 &(((PUSHORT)Buffer)[PARTITION_TABLE_OFFSET]);
1896 for (Entry = 1; Entry <= 4; Entry++, PartitionDescriptor++)
1897 {
1898 /* Check if this was a container partition (we skipped these) */
1899 if (IsContainerPartition(PartitionDescriptor->PartitionType))
1900 {
1901 /* Update the partition offset */
1902 Offset.QuadPart = VolumeOffset.QuadPart +
1903 GET_STARTING_SECTOR(PartitionDescriptor) *
1904 SectorSize;
1905
1906 /* If this was the primary partition, update the volume too */
1907 if (IsPrimary) VolumeOffset = Offset;
1908 break;
1909 }
1910 }
1911
1912 /* Check if we already searched all the partitions */
1913 if (Entry > NUM_PARTITION_TABLE_ENTRIES)
1914 {
1915 /* Then we failed to find a good MBR */
1916 Status = STATUS_BAD_MASTER_BOOT_RECORD;
1917 break;
1918 }
1919
1920 /* Loop the next partitions, which are not primary anymore */
1921 IsPrimary = FALSE;
1922 } while (i < PartitionNumber);
1923
1924 /* Everything done, cleanup */
1925 if (Buffer) ExFreePool(Buffer);
1926 return Status;
1927 }
1928
1929 /*
1930 * @implemented
1931 */
1932 NTSTATUS
1933 FASTCALL
1934 IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject,
1935 IN ULONG SectorSize,
1936 IN ULONG SectorsPerTrack,
1937 IN ULONG NumberOfHeads,
1938 IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
1939 {
1940 KEVENT Event;
1941 IO_STATUS_BLOCK IoStatusBlock;
1942 PIRP Irp;
1943 NTSTATUS Status = STATUS_SUCCESS;
1944 ULONG BufferSize;
1945 PUSHORT Buffer;
1946 PPTE Entry;
1947 PPARTITION_TABLE PartitionTable;
1948 LARGE_INTEGER Offset, NextOffset, ExtendedOffset, SectorOffset;
1949 LARGE_INTEGER StartOffset, PartitionLength;
1950 ULONG i, j, 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 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 Entry = (PPTE)&Buffer[PARTITION_TABLE_OFFSET];
2015 for (i = 0; i < DiskLayout->TableCount; i++)
2016 {
2017 /* Set if this is the MBR partition */
2018 IsMbr= !i;
2019
2020 /* Initialize th event */
2021 KeInitializeEvent( &Event, NotificationEvent, FALSE );
2022
2023 /* Build the read IRP */
2024 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
2025 DeviceObject,
2026 Buffer,
2027 BufferSize,
2028 &Offset,
2029 &Event,
2030 &IoStatusBlock);
2031 if (!Irp)
2032 {
2033 /* Fail */
2034 Status = STATUS_INSUFFICIENT_RESOURCES;
2035 break;
2036 }
2037
2038 /* Make sure to disable volume verification */
2039 IoStackLocation = IoGetNextIrpStackLocation(Irp);
2040 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2041
2042 /* Call the driver */
2043 Status = IoCallDriver(DeviceObject, Irp);
2044 if (Status == STATUS_PENDING)
2045 {
2046 /* Wait for completion */
2047 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
2048 Status = IoStatusBlock.Status;
2049 }
2050
2051 /* Check for failure */
2052 if (!NT_SUCCESS(Status)) break;
2053
2054 /* If we biased for EZ-Drive, unbias now */
2055 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2056
2057 /* Check if this is a normal disk */
2058 if (!IsSuperFloppy)
2059 {
2060 /* Set the boot record signature */
2061 Buffer[BOOT_SIGNATURE_OFFSET] = BOOT_RECORD_SIGNATURE;
2062
2063 /* By default, don't require a rewrite */
2064 DoRewrite = FALSE;
2065
2066 /* Check if we don't have an offset */
2067 if (!Offset.QuadPart)
2068 {
2069 /* Check if the signature doesn't match */
2070 if (((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] !=
2071 PartitionBuffer->Signature)
2072 {
2073 /* Then write the signature and now w need a rewrite */
2074 ((PULONG)Buffer)[PARTITION_TABLE_OFFSET / 2 - 1] =
2075 PartitionBuffer->Signature;
2076 DoRewrite = TRUE;
2077 }
2078 }
2079
2080 /* Loop the partition table entries */
2081 PartitionTable = &DiskLayout->PartitionTable[i];
2082 for (j = 0; j < 4; j++)
2083 {
2084 /* Get the current entry and type */
2085 TableEntry = &PartitionTable->PartitionEntry[j];
2086 PartitionType = TableEntry->PartitionType;
2087
2088 /* Check if the entry needs a rewrite */
2089 if (TableEntry->RewritePartition)
2090 {
2091 /* Then we need one too */
2092 DoRewrite = TRUE;
2093
2094 /* Save the type and if it's a bootable partition */
2095 Entry[j].PartitionType = TableEntry->PartitionType;
2096 Entry[j].ActiveFlag = TableEntry->BootIndicator ? 0x80 : 0;
2097
2098 /* Make sure it's used */
2099 if (PartitionType != PARTITION_ENTRY_UNUSED)
2100 {
2101 /* Make sure it's not a container (unless primary) */
2102 if ((IsMbr) || !(IsContainerPartition(PartitionType)))
2103 {
2104 /* Use the partition offset */
2105 StartOffset.QuadPart = Offset.QuadPart;
2106 }
2107 else
2108 {
2109 /* Use the extended logical partition offset */
2110 StartOffset.QuadPart = ExtendedOffset.QuadPart;
2111 }
2112
2113 /* Set the sector offset */
2114 SectorOffset.QuadPart = TableEntry->
2115 StartingOffset.QuadPart -
2116 StartOffset.QuadPart;
2117
2118 /* Now calculate the starting sector */
2119 StartOffset.QuadPart = SectorOffset.QuadPart >> k;
2120 Entry[j].StartingSector = StartOffset.LowPart;
2121
2122 /* As well as the length */
2123 PartitionLength.QuadPart = TableEntry->PartitionLength.
2124 QuadPart >> k;
2125 Entry[j].PartitionLength = PartitionLength.LowPart;
2126
2127 /* Calculate the CHS values */
2128 HalpCalculateChsValues(&TableEntry->StartingOffset,
2129 &TableEntry->PartitionLength,
2130 k,
2131 SectorsPerTrack,
2132 NumberOfHeads,
2133 ConventionalCylinders,
2134 (PPARTITION_DESCRIPTOR)
2135 &Entry[j]);
2136 }
2137 else
2138 {
2139 /* Otherwise set up an empty entry */
2140 Entry[j].StartingSector = 0;
2141 Entry[j].PartitionLength = 0;
2142 Entry[j].StartingTrack = 0;
2143 Entry[j].EndingTrack = 0;
2144 Entry[j].StartingCylinder = 0;
2145 Entry[j].EndingCylinder = 0;
2146 }
2147 }
2148
2149 /* Check if this is a container partition */
2150 if (IsContainerPartition(PartitionType))
2151 {
2152 /* Then update the offset to use */
2153 NextOffset = TableEntry->StartingOffset;
2154 }
2155 }
2156 }
2157
2158 /* Check if we need to write back the buffer */
2159 if (DoRewrite)
2160 {
2161 /* We don't need to do this again */
2162 DoRewrite = FALSE;
2163
2164 /* Initialize the event */
2165 KeInitializeEvent(&Event, NotificationEvent, FALSE);
2166
2167 /* If we unbiased for EZ-Drive, rebias now */
2168 if ((IsEzDrive) && !(Offset.QuadPart)) Offset.QuadPart = 512;
2169
2170 /* Build the write IRP */
2171 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_WRITE,
2172 DeviceObject,
2173 Buffer,
2174 BufferSize,
2175 &Offset,
2176 &Event,
2177 &IoStatusBlock);
2178 if (!Irp)
2179 {
2180 /* Fail */
2181 Status = STATUS_INSUFFICIENT_RESOURCES;
2182 break;
2183 }
2184
2185 /* Make sure to disable volume verification */
2186 IoStackLocation = IoGetNextIrpStackLocation(Irp);
2187 IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
2188
2189 /* Call the driver */
2190 Status = IoCallDriver(DeviceObject, Irp);
2191 if (Status == STATUS_PENDING)
2192 {
2193 /* Wait for completion */
2194 KeWaitForSingleObject(&Event,
2195 Executive,
2196 KernelMode,
2197 FALSE,
2198 NULL);
2199 Status = IoStatusBlock.Status;
2200 }
2201
2202 /* Check for failure */
2203 if (!NT_SUCCESS(Status)) break;
2204
2205 /* If we biased for EZ-Drive, unbias now */
2206 if (IsEzDrive && (Offset.QuadPart == 512)) Offset.QuadPart = 0;
2207 }
2208
2209 /* Update the partition offset and set the extended offset if needed */
2210 Offset = NextOffset;
2211 if (IsMbr) ExtendedOffset = NextOffset;
2212 }
2213
2214 /* If we had a buffer, free it, then return status */
2215 if (Buffer) ExFreePool(Buffer);
2216 return Status;
2217 }
2218
2219 /*
2220 * @implemented
2221 */
2222 VOID
2223 FASTCALL
2224 IoAssignDriveLetters(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
2225 IN PSTRING NtDeviceName,
2226 OUT PUCHAR NtSystemPath,
2227 OUT PSTRING NtSystemPathString)
2228 {
2229 /* Call our deprecated function for now */
2230 xHalIoAssignDriveLetters(LoaderBlock,
2231 NtDeviceName,
2232 NtSystemPath,
2233 NtSystemPathString);
2234 }
2235
2236 /* EOF */