ReactOS  0.4.13-dev-52-g0efcfec
fstubex.c
Go to the documentation of this file.
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/fstub/fstubex.c
5 * PURPOSE: Extended FSTUB Routines (not linked to HAL)
6 * PROGRAMMERS: Pierre Schweitzer (pierre.schweitzer@reactos.org)
7 */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* PRIVATE FUNCTIONS *********************************************************/
16 
17 typedef struct _DISK_INFORMATION
18 {
25 
26 #include <pshpack1.h>
27 typedef struct _EFI_PARTITION_HEADER
28 {
33  ULONG Reserved; // 20
38  GUID DiskGUID; // 56
44 #include <poppack.h>
45 
46 typedef struct _EFI_PARTITION_ENTRY
47 {
53  WCHAR Name[0x24]; // 56
55 
56 typedef struct _PARTITION_TABLE_ENTRY
57 {
63  UCHAR EndHead;
69 
70 typedef struct _MASTER_BOOT_RECORD
71 {
73  ULONG Signature; // 440
74  USHORT Reserved; // 444
78 
79 /* Tag for Fstub allocations */
80 #define TAG_FSTUB 'BtsF'
81 /* Partition entry size (bytes) - FIXME: It's hardcoded as Microsoft does, but according to specs, it shouldn't be */
82 #define PARTITION_ENTRY_SIZE 128
83 /* Defines "EFI PART" */
84 #define EFI_HEADER_SIGNATURE 0x5452415020494645ULL
85 /* Defines version 1.0 */
86 #define EFI_HEADER_REVISION_1 0x00010000
87 /* Defines system type for MBR showing that a GPT is following */
88 #define EFI_PMBR_OSTYPE_EFI 0xEE
89 /* Defines size to store a complete GUID + null char */
90 #define EFI_GUID_STRING_SIZE 0x27
91 
92 #define IS_VALID_DISK_INFO(Disk) \
93  (Disk) && \
94  (Disk->DeviceObject) && \
95  (Disk->SectorSize) && \
96  (Disk->Buffer) && \
97  (Disk->SectorCount)
98 
99 VOID
100 NTAPI
103 );
104 
105 NTSTATUS
106 NTAPI
108  IN PARTITION_STYLE * PartitionStyle
109 );
110 
111 VOID
112 NTAPI
114 );
115 
116 NTSTATUS
117 NTAPI
119  OUT PDISK_GEOMETRY_EX Geometry
120 );
121 
122 NTSTATUS
123 NTAPI
126  IN ULONGLONG StartingSector OPTIONAL,
128 );
129 
130 NTSTATUS
131 NTAPI
133 );
134 
135 NTSTATUS
136 NTAPI
138  IN ULONG PartitionsSizeSector,
139  IN GUID DiskGUID,
140  IN ULONG NumberOfEntries,
141  IN ULONGLONG FirstUsableLBA,
142  IN ULONGLONG LastUsableLBA,
143  IN ULONG PartitionEntryCRC32,
144  IN BOOLEAN WriteBackupTable);
145 
146 NTSTATUS
147 NTAPI
149  IN GUID DiskGUID,
150  IN ULONG MaxPartitionCount,
151  IN ULONGLONG FirstUsableLBA,
152  IN ULONGLONG LastUsableLBA,
153  IN BOOLEAN WriteBackupTable,
154  IN ULONG PartitionCount,
155  IN PPARTITION_INFORMATION_EX PartitionEntries OPTIONAL
156 );
157 
158 NTSTATUS
159 NTAPI
162  IN ULONGLONG StartingSector OPTIONAL,
164 );
165 
166 VOID
167 NTAPI
169  IN OUT PULONG PartitionCount)
170 {
171  ULONG Count;
172  PAGED_CODE();
173 
175  ASSERT(PartitionCount);
176 
177  /* Get partition count */
178  Count = *PartitionCount;
179  /* We need at least 128 entries */
180  if (Count < 128)
181  {
182  Count = 128;
183  }
184 
185  /* Then, ensure that we will have a round value,
186  * ie, all sectors will be full of entries
187  * There won't be lonely entries
188  */
191  ASSERT(*PartitionCount <= Count);
192  /* Return result */
193  *PartitionCount = Count;
194 
195  /* One more sanity check */
196  if (SectorSize == 512)
197  {
198  ASSERT(Count % 4 == 0);
199  }
200 }
201 
202 NTSTATUS
203 NTAPI
205  OUT PDISK_INFORMATION * DiskBuffer,
206  PDISK_GEOMETRY_EX DiskGeometry OPTIONAL)
207 {
209  PDISK_INFORMATION DiskInformation;
210  PAGED_CODE();
211 
213  ASSERT(DiskBuffer);
214 
215  /* Allocate internal structure */
216  DiskInformation = ExAllocatePoolWithTag(NonPagedPool, sizeof(DISK_INFORMATION), TAG_FSTUB);
217  if (!DiskInformation)
218  {
220  }
221 
222  /* If caller don't pass needed information, let's get them */
223  if (!DiskGeometry)
224  {
225  Status = FstubGetDiskGeometry(DeviceObject, &(DiskInformation->DiskGeometry));
226  if (!NT_SUCCESS(Status))
227  {
228  ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
229  return Status;
230  }
231  }
232  else
233  {
234  RtlCopyMemory(&DiskInformation->DiskGeometry, DiskGeometry, sizeof(DISK_GEOMETRY_EX));
235  }
236 
237  /* Ensure read/received information are correct */
238  if (DiskInformation->DiskGeometry.Geometry.BytesPerSector == 0 ||
239  DiskInformation->DiskGeometry.DiskSize.QuadPart == 0)
240  {
241  ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
243  }
244 
245  /* Store vital information as well */
246  DiskInformation->DeviceObject = DeviceObject;
247  DiskInformation->SectorSize = DiskInformation->DiskGeometry.Geometry.BytesPerSector;
248  DiskInformation->SectorCount = DiskInformation->DiskGeometry.DiskSize.QuadPart / DiskInformation->SectorSize;
249 
250  /* Finally, allocate the buffer that will be used for different read */
251  DiskInformation->Buffer = ExAllocatePoolWithTag(NonPagedPoolCacheAligned, DiskInformation->SectorSize, TAG_FSTUB);
252  if (!DiskInformation->Buffer)
253  {
254  ExFreePoolWithTag(DiskInformation, TAG_FSTUB);
256  }
257 
258  /* Return allocated internal structure */
259  *DiskBuffer = DiskInformation;
260 
261  return STATUS_SUCCESS;
262 }
263 
265 NTAPI
267 {
268  ULONG i;
269  PDRIVE_LAYOUT_INFORMATION DriveLayout;
270  PAGED_CODE();
271 
272  ASSERT(LayoutEx);
273 
274  /* Check whether we're dealing with MBR partition table */
275  if (LayoutEx->PartitionStyle != PARTITION_STYLE_MBR)
276  {
277  ASSERT(FALSE);
278  return NULL;
279  }
280 
281  /* Allocate needed buffer */
282  DriveLayout = ExAllocatePoolWithTag(NonPagedPool,
283  FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION, PartitionEntry) +
284  LayoutEx->PartitionCount * sizeof(PARTITION_INFORMATION),
285  TAG_FSTUB);
286  if (!DriveLayout)
287  {
288  return NULL;
289  }
290 
291  /* Convert information about partition table */
292  DriveLayout->PartitionCount = LayoutEx->PartitionCount;
293  DriveLayout->Signature = LayoutEx->Mbr.Signature;
294 
295  /* Convert each partition */
296  for (i = 0; i < LayoutEx->PartitionCount; i++)
297  {
298  DriveLayout->PartitionEntry[i].StartingOffset = LayoutEx->PartitionEntry[i].StartingOffset;
299  DriveLayout->PartitionEntry[i].PartitionLength = LayoutEx->PartitionEntry[i].PartitionLength;
300  DriveLayout->PartitionEntry[i].HiddenSectors = LayoutEx->PartitionEntry[i].Mbr.HiddenSectors;
301  DriveLayout->PartitionEntry[i].PartitionNumber = LayoutEx->PartitionEntry[i].PartitionNumber;
302  DriveLayout->PartitionEntry[i].PartitionType = LayoutEx->PartitionEntry[i].Mbr.PartitionType;
303  DriveLayout->PartitionEntry[i].BootIndicator = LayoutEx->PartitionEntry[i].Mbr.BootIndicator;
304  DriveLayout->PartitionEntry[i].RecognizedPartition = LayoutEx->PartitionEntry[i].Mbr.RecognizedPartition;
305  DriveLayout->PartitionEntry[i].RewritePartition = LayoutEx->PartitionEntry[i].RewritePartition;
306  }
307 
308  return DriveLayout;
309 }
310 
311 VOID
312 NTAPI
314  IN PPARTITION_INFORMATION_EX Partition,
316 {
317  PAGED_CODE();
318 
319  ASSERT(Entry);
320  ASSERT(Partition);
322 
323  /* Just convert data to EFI partition entry type */
324  Entry->PartitionType = Partition->Gpt.PartitionType;
325  Entry->UniquePartition = Partition->Gpt.PartitionId;
326  Entry->StartingLBA = Partition->StartingOffset.QuadPart / SectorSize;
327  Entry->EndingLBA = (Partition->StartingOffset.QuadPart + Partition->PartitionLength.QuadPart - 1) / SectorSize;
328  Entry->Attributes = Partition->Gpt.Attributes;
329  RtlCopyMemory(Entry->Name, Partition->Gpt.Name, sizeof(Entry->Name));
330 }
331 
332 NTSTATUS
333 NTAPI
335  IN PCREATE_DISK_MBR DiskInfo)
336 {
338  PDISK_INFORMATION Disk = NULL;
339  PMASTER_BOOT_RECORD MasterBootRecord;
340  PAGED_CODE();
341 
343 
344  /* Allocate internal structure */
346  if (!NT_SUCCESS(Status))
347  {
348  return Status;
349  }
350 
351  /* Read previous MBR, if any */
353  Disk->SectorSize,
354  0ULL,
355  Disk->Buffer);
356  if (!NT_SUCCESS(Status))
357  {
359  return Status;
360  }
361  /* Fill the buffer with needed information, we won't overwrite boot code */
362  MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer;
363  MasterBootRecord->Signature = DiskInfo->Signature;
364  RtlZeroMemory(MasterBootRecord->PartitionTable, sizeof(PARTITION_TABLE_ENTRY) * 4);
365  MasterBootRecord->MasterBootRecordMagic = BOOT_RECORD_SIGNATURE;
366 
367  /* Finally, write MBR */
369  Disk->SectorSize,
370  0ULL,
371  Disk->Buffer);
372 
373  /* Release internal structure and return */
375  return Status;
376 }
377 
378 NTSTATUS
379 NTAPI
381  IN PCREATE_DISK_GPT DiskInfo)
382 {
384  PDISK_INFORMATION Disk = NULL;
385  ULONGLONG FirstUsableLBA, LastUsableLBA;
386  ULONG MaxPartitionCount, SectorsForPartitions;
387  PAGED_CODE();
388 
390  ASSERT(DiskInfo);
391 
392  /* Allocate internal structure */
394  if (!NT_SUCCESS(Status))
395  {
396  return Status;
397  }
398  ASSERT(Disk);
399 
400  /* Write legacy MBR */
402  if (!NT_SUCCESS(Status))
403  {
405  return Status;
406  }
407 
408  /* Get max entries and adjust its number */
409  MaxPartitionCount = DiskInfo->MaxPartitionCount;
410  FstubAdjustPartitionCount(Disk->SectorSize, &MaxPartitionCount);
411 
412  /* Count number of sectors needed to store partitions */
413  SectorsForPartitions = (MaxPartitionCount * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
414  /* Set first usable LBA: Legacy MBR + GPT header + Partitions entries */
415  FirstUsableLBA = SectorsForPartitions + 2;
416  /* Set last usable LBA: Last sector - GPT header - Partitions entries */
417  LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1;
418 
419  /* First, write primary table */
421  DiskInfo->DiskId,
422  MaxPartitionCount,
423  FirstUsableLBA,
424  LastUsableLBA,
425  FALSE,
426  0,
427  NULL);
428  /* Then, write backup table */
429  if (NT_SUCCESS(Status))
430  {
432  DiskInfo->DiskId,
433  MaxPartitionCount,
434  FirstUsableLBA,
435  LastUsableLBA,
436  TRUE,
437  0,
438  NULL);
439  }
440 
441  /* Release internal structure and return */
443  return Status;
444 }
445 
446 NTSTATUS
447 NTAPI
449 {
451  PDISK_INFORMATION Disk = NULL;
452  PARTITION_STYLE PartitionStyle;
453  PMASTER_BOOT_RECORD MasterBootRecord;
454  PAGED_CODE();
455 
457 
458  /* Allocate internal structure */
460  if (!NT_SUCCESS(Status))
461  {
462  return Status;
463  }
464 
465  /* Detect current disk partition style */
466  Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
467  if (!NT_SUCCESS(Status))
468  {
470  return Status;
471  }
472 
473  /* Read MBR, if any */
475  Disk->SectorSize,
476  0ULL,
477  Disk->Buffer);
478  if (!NT_SUCCESS(Status))
479  {
481  return Status;
482  }
483 
484  /* Only zero useful stuff */
485  MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer;
486  MasterBootRecord->Signature = 0;
487  RtlZeroMemory(MasterBootRecord->PartitionTable, sizeof(PARTITION_TABLE_ENTRY));
488  MasterBootRecord->MasterBootRecordMagic = 0;
489 
490  /* Write back that destroyed MBR */
492  Disk->SectorSize,
493  0ULL,
494  Disk->Buffer);
495  /* If previous style wasn't GPT, we're done here */
496  if (PartitionStyle != PARTITION_STYLE_GPT)
497  {
499  return Status;
500  }
501 
502  /* Otherwise, we've to zero the two GPT headers */
503  RtlZeroMemory(Disk->Buffer, Disk->SectorSize);
504  /* Erase primary header */
506  Disk->SectorSize,
507  1ULL,
508  Disk->Buffer);
509  /* In case of success, erase backup header */
510  if (NT_SUCCESS(Status))
511  {
513  Disk->SectorSize,
514  Disk->SectorCount - 1ULL,
515  Disk->Buffer);
516  }
517 
518  /* Release internal structure and return */
520  return Status;
521 }
522 
523 PCHAR
524 NTAPI
526  OUT PCHAR String)
527 {
528  sprintf(String,
529  "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
530  Guid->Data1,
531  Guid->Data2,
532  Guid->Data3,
533  Guid->Data4[0],
534  Guid->Data4[1],
535  Guid->Data4[2],
536  Guid->Data4[3],
537  Guid->Data4[4],
538  Guid->Data4[5],
539  Guid->Data4[6],
540  Guid->Data4[7]);
541 
542  return String;
543 }
544 
545 VOID
546 NTAPI
548 {
549  ULONG i;
551  PAGED_CODE();
552 
553  DPRINT("FSTUB: DRIVE_LAYOUT_INFORMATION_EX: %p\n", DriveLayout);
554  switch (DriveLayout->PartitionStyle)
555  {
556  case PARTITION_STYLE_MBR:
557  if (DriveLayout->PartitionCount % 4 != 0)
558  {
559  DPRINT("Warning: Partition count isn't a 4-factor: %lu!\n", DriveLayout->PartitionCount);
560  }
561 
562  DPRINT("Signature: %8.8x\n", DriveLayout->Mbr.Signature);
563  for (i = 0; i < DriveLayout->PartitionCount; i++)
564  {
565  FstubDbgPrintPartitionEx(DriveLayout->PartitionEntry, i);
566  }
567 
568  break;
569  case PARTITION_STYLE_GPT:
570  FstubDbgGuidToString(&(DriveLayout->Gpt.DiskId), Guid);
571  DPRINT("DiskId: %s\n", Guid);
572  DPRINT("StartingUsableOffset: %I64x\n", DriveLayout->Gpt.StartingUsableOffset.QuadPart);
573  DPRINT("UsableLength: %I64x\n", DriveLayout->Gpt.UsableLength.QuadPart);
574  DPRINT("MaxPartitionCount: %lu\n", DriveLayout->Gpt.MaxPartitionCount);
575  for (i = 0; i < DriveLayout->PartitionCount; i++)
576  {
577  FstubDbgPrintPartitionEx(DriveLayout->PartitionEntry, i);
578  }
579 
580  break;
581  default:
582  DPRINT("Unsupported partition style: %lu\n", DriveLayout->PartitionStyle);
583  }
584 }
585 
586 VOID
587 NTAPI
590 {
592  PAGED_CODE();
593 
594  DPRINT("Printing partition %lu\n", PartitionNumber);
595 
596  switch (PartitionEntry[PartitionNumber].PartitionStyle)
597  {
598  case PARTITION_STYLE_MBR:
599  DPRINT(" StartingOffset: %I64x\n", PartitionEntry[PartitionNumber].StartingOffset.QuadPart);
600  DPRINT(" PartitionLength: %I64x\n", PartitionEntry[PartitionNumber].PartitionLength.QuadPart);
601  DPRINT(" RewritePartition: %u\n", PartitionEntry[PartitionNumber].RewritePartition);
602  DPRINT(" PartitionType: %02x\n", PartitionEntry[PartitionNumber].Mbr.PartitionType);
603  DPRINT(" BootIndicator: %u\n", PartitionEntry[PartitionNumber].Mbr.BootIndicator);
604  DPRINT(" RecognizedPartition: %u\n", PartitionEntry[PartitionNumber].Mbr.RecognizedPartition);
605  DPRINT(" HiddenSectors: %lu\n", PartitionEntry[PartitionNumber].Mbr.HiddenSectors);
606 
607  break;
608  case PARTITION_STYLE_GPT:
609  DPRINT(" StartingOffset: %I64x\n", PartitionEntry[PartitionNumber].StartingOffset.QuadPart);
610  DPRINT(" PartitionLength: %I64x\n", PartitionEntry[PartitionNumber].PartitionLength.QuadPart);
611  DPRINT(" RewritePartition: %u\n", PartitionEntry[PartitionNumber].RewritePartition);
612  FstubDbgGuidToString(&(PartitionEntry[PartitionNumber].Gpt.PartitionType), Guid);
613  DPRINT(" PartitionType: %s\n", Guid);
614  FstubDbgGuidToString(&(PartitionEntry[PartitionNumber].Gpt.PartitionId), Guid);
615  DPRINT(" PartitionId: %s\n", Guid);
616  DPRINT(" Attributes: %I64x\n", PartitionEntry[PartitionNumber].Gpt.Attributes);
617  DPRINT(" Name: %ws\n", PartitionEntry[PartitionNumber].Gpt.Name);
618 
619  break;
620  default:
621  DPRINT(" Unsupported partition style: %ld\n", PartitionEntry[PartitionNumber].PartitionStyle);
622  }
623 }
624 
625 VOID
626 NTAPI
629 {
631  PAGED_CODE();
632 
633  DPRINT("FSTUB: SET_PARTITION_INFORMATION_EX: %p\n", PartitionEntry);
634  DPRINT("Modifying partition %lu\n", PartitionNumber);
635  switch (PartitionEntry->PartitionStyle)
636  {
637  case PARTITION_STYLE_MBR:
638  DPRINT(" PartitionType: %02x\n", PartitionEntry->Mbr.PartitionType);
639 
640  break;
641  case PARTITION_STYLE_GPT:
642  FstubDbgGuidToString(&(PartitionEntry->Gpt.PartitionType), Guid);
643  DPRINT(" PartitionType: %s\n", Guid);
644  FstubDbgGuidToString(&(PartitionEntry->Gpt.PartitionId), Guid);
645  DPRINT(" PartitionId: %s\n", Guid);
646  DPRINT(" Attributes: %I64x\n", PartitionEntry->Gpt.Attributes);
647  DPRINT(" Name: %ws\n", PartitionEntry->Gpt.Name);
648 
649  break;
650  default:
651  DPRINT(" Unsupported partition style: %ld\n", PartitionEntry[PartitionNumber].PartitionStyle);
652  }
653 }
654 
655 NTSTATUS
656 NTAPI
658  IN PARTITION_STYLE * PartitionStyle)
659 {
661  PPARTITION_DESCRIPTOR PartitionDescriptor;
662  PAGED_CODE();
663 
664  ASSERT(IS_VALID_DISK_INFO(Disk));
665  ASSERT(PartitionStyle);
666 
667  /* Read disk first sector */
668  Status = FstubReadSector(Disk->DeviceObject,
669  Disk->SectorSize,
670  0,
671  Disk->Buffer);
672  if (!NT_SUCCESS(Status))
673  {
674  return Status;
675  }
676 
677  /* Get the partition descriptor array */
678  PartitionDescriptor = (PPARTITION_DESCRIPTOR)
679  &(Disk->Buffer[PARTITION_TABLE_OFFSET]);
680  /* If we have not the 0xAA55 then it's raw partition */
681  if (Disk->Buffer[BOOT_SIGNATURE_OFFSET] != BOOT_RECORD_SIGNATURE)
682  {
683  *PartitionStyle = PARTITION_STYLE_RAW;
684  }
685  /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
686  else if (PartitionDescriptor[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
687  PartitionDescriptor[1].PartitionType == 0 &&
688  PartitionDescriptor[2].PartitionType == 0 &&
689  PartitionDescriptor[3].PartitionType == 0)
690  {
691  *PartitionStyle = PARTITION_STYLE_GPT;
692  }
693  /* Otherwise, partition table is in MBR */
694  else
695  {
696  *PartitionStyle = PARTITION_STYLE_MBR;
697  }
698 
699  return STATUS_SUCCESS;
700 }
701 
702 VOID
703 NTAPI
705 {
706  if (DiskBuffer)
707  {
708  if (DiskBuffer->Buffer)
709  {
710  ExFreePoolWithTag(DiskBuffer->Buffer, TAG_FSTUB);
711  }
712  ExFreePoolWithTag(DiskBuffer, TAG_FSTUB);
713  }
714 }
715 
716 NTSTATUS
717 NTAPI
719  OUT PDISK_GEOMETRY_EX Geometry)
720 {
721  PIRP Irp;
723  PKEVENT Event = NULL;
724  PDISK_GEOMETRY_EX DiskGeometry = NULL;
726  PAGED_CODE();
727 
729  ASSERT(Geometry);
730 
731  /* Allocate needed components */
733  if (!DiskGeometry)
734  {
736  goto Cleanup;
737  }
738 
740  if (!IoStatusBlock)
741  {
743  goto Cleanup;
744  }
745 
747  if (!Event)
748  {
750  goto Cleanup;
751  }
752  /* Initialize the waiting event */
754 
755  /* Build the request to get disk geometry */
757  DeviceObject,
758  0,
759  0,
760  DiskGeometry,
761  sizeof(DISK_GEOMETRY_EX),
762  FALSE,
763  Event,
764  IoStatusBlock);
765  if (!Irp)
766  {
768  goto Cleanup;
769  }
770 
771  /* Call the driver and wait for completion if needed */
773  if (Status == STATUS_PENDING)
774  {
777  }
778 
779  /* In case of a success, return read data */
780  if (NT_SUCCESS(Status))
781  {
782  *Geometry = *DiskGeometry;
783  }
784 
785 Cleanup:
786  if (DiskGeometry)
787  {
788  ExFreePoolWithTag(DiskGeometry, TAG_FSTUB);
789 
790  if (NT_SUCCESS(Status))
791  {
792  ASSERT(Geometry->Geometry.BytesPerSector % PARTITION_ENTRY_SIZE == 0);
793  }
794  }
795 
796  if (IoStatusBlock)
797  {
799  }
800 
801  if (Event)
802  {
804  }
805 
806  return Status;
807 }
808 
809 NTSTATUS
810 NTAPI
812  IN BOOLEAN ReadBackupTable,
813  PEFI_PARTITION_HEADER * HeaderBuffer)
814 {
816  PUCHAR Sector = NULL;
817  ULONGLONG StartingSector;
818  PEFI_PARTITION_HEADER EFIHeader;
819  ULONG i, HeaderCRC32, PreviousCRC32, SectoredPartitionEntriesSize, LonelyPartitions;
820  PAGED_CODE();
821 
822  ASSERT(Disk);
823  ASSERT(IS_VALID_DISK_INFO(Disk));
824  ASSERT(HeaderBuffer);
825 
826  /* In case we want to read backup table, we read last disk sector */
827  if (ReadBackupTable)
828  {
829  StartingSector = Disk->SectorCount - 1ULL;
830  }
831  else
832  {
833  /* Otherwise we start at first sector (as sector 0 is the MBR) */
834  StartingSector = 1ULL;
835  }
836 
837  Status = FstubReadSector(Disk->DeviceObject,
838  Disk->SectorSize,
839  StartingSector,
840  Disk->Buffer);
841  if (!NT_SUCCESS(Status))
842  {
843  DPRINT("EFI::Failed reading header!\n");
844  return Status;
845  }
846  /* Let's use read buffer as EFI_PARTITION_HEADER */
847  EFIHeader = (PEFI_PARTITION_HEADER)Disk->Buffer;
848 
849 
850  /* First check signature
851  * Then, check version (we only support v1)
852  * Finally check header size
853  */
854  if (EFIHeader->Signature != EFI_HEADER_SIGNATURE ||
855  EFIHeader->Revision != EFI_HEADER_REVISION_1 ||
856  EFIHeader->HeaderSize != sizeof(EFI_PARTITION_HEADER))
857  {
858  DPRINT("EFI::Wrong signature/version/header size!\n");
859  DPRINT("%I64x (expected: %I64x)\n", EFIHeader->Signature, EFI_HEADER_SIGNATURE);
860  DPRINT("%03x (expected: %03x)\n", EFIHeader->Revision, EFI_HEADER_REVISION_1);
861  DPRINT("%02x (expected: %02x)\n", EFIHeader->HeaderSize, sizeof(EFI_PARTITION_HEADER));
863  }
864 
865  /* Save current checksum */
866  HeaderCRC32 = EFIHeader->HeaderCRC32;
867  /* Then zero the one in EFI header. This is needed to compute header checksum */
868  EFIHeader->HeaderCRC32 = 0;
869  /* Compute header checksum and compare with the one present in partition table */
870  if (RtlComputeCrc32(0, (PUCHAR)Disk->Buffer, sizeof(EFI_PARTITION_HEADER)) != HeaderCRC32)
871  {
872  DPRINT("EFI::Not matching header checksum!\n");
874  }
875  /* Put back removed checksum in header */
876  EFIHeader->HeaderCRC32 = HeaderCRC32;
877 
878  /* Check if current LBA is matching with ours */
879  if (EFIHeader->MyLBA != StartingSector)
880  {
881  DPRINT("EFI::Not matching starting sector!\n");
883  }
884 
885  /* Allocate a buffer to read a sector on the disk */
887  Disk->SectorSize,
888  TAG_FSTUB);
889  if (!Sector)
890  {
891  DPRINT("EFI::Lacking resources!\n");
893  }
894 
895  /* Count how much sectors we'll have to read to read the whole partition table */
896  SectoredPartitionEntriesSize = (EFIHeader->NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
897  /* Compute partition table checksum */
898  for (i = 0, PreviousCRC32 = 0; i < SectoredPartitionEntriesSize; i++)
899  {
900  Status = FstubReadSector(Disk->DeviceObject,
901  Disk->SectorSize,
902  EFIHeader->PartitionEntryLBA + i,
903  (PUSHORT)Sector);
904  if (!NT_SUCCESS(Status))
905  {
906  ExFreePoolWithTag(Sector, TAG_FSTUB);
907  DPRINT("EFI::Failed reading sector for partition entry!\n");
908  return Status;
909  }
910 
911  PreviousCRC32 = RtlComputeCrc32(PreviousCRC32, Sector, Disk->SectorSize);
912  }
913 
914  /* Check whether we have a last sector not full of partitions */
915  LonelyPartitions = (EFIHeader->NumberOfEntries * PARTITION_ENTRY_SIZE) % Disk->SectorSize;
916  /* In such case, we have to complete checksum computation */
917  if (LonelyPartitions != 0)
918  {
919  /* Read the sector that contains those partitions */
920  Status = FstubReadSector(Disk->DeviceObject,
921  Disk->SectorSize,
922  EFIHeader->PartitionEntryLBA + i,
923  (PUSHORT)Sector);
924  if (!NT_SUCCESS(Status))
925  {
926  ExFreePoolWithTag(Sector, TAG_FSTUB);
927  DPRINT("EFI::Failed reading sector for partition entry!\n");
928  return Status;
929  }
930 
931  /* Then complete checksum by computing on each partition */
932  for (i = 0; i < LonelyPartitions; i++)
933  {
934  PreviousCRC32 = RtlComputeCrc32(PreviousCRC32, Sector + i * PARTITION_ENTRY_SIZE, PARTITION_ENTRY_SIZE);
935  }
936  }
937 
938  /* Finally, release memory */
939  ExFreePoolWithTag(Sector, TAG_FSTUB);
940 
941  /* Compare checksums */
942  if (PreviousCRC32 == EFIHeader->PartitionEntryCRC32)
943  {
944  /* In case of a success, return read header */
945  *HeaderBuffer = EFIHeader;
946  return STATUS_SUCCESS;
947  }
948  else
949  {
950  DPRINT("EFI::Not matching partition table checksum!\n");
951  DPRINT("EFI::Expected: %x, received: %x\n", EFIHeader->PartitionEntryCRC32, PreviousCRC32);
953  }
954 }
955 
956 NTSTATUS
957 NTAPI
959  IN BOOLEAN ReadBackupTable,
960  OUT struct _DRIVE_LAYOUT_INFORMATION_EX** DriveLayout)
961 {
963  ULONG NumberOfEntries;
964  PEFI_PARTITION_HEADER EfiHeader;
965  EFI_PARTITION_ENTRY PartitionEntry;
966 #if 0
967  BOOLEAN UpdatedPartitionTable = FALSE;
968  ULONGLONG SectorsForPartitions, PartitionEntryLBA;
969 #else
970  ULONGLONG PartitionEntryLBA;
971 #endif
972  PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx = NULL;
973  ULONG i, PartitionCount, PartitionIndex, PartitionsPerSector;
974  PAGED_CODE();
975 
976  ASSERT(Disk);
977 
978  /* Zero output */
979  *DriveLayout = NULL;
980 
981  /* Read EFI header */
982  Status = FstubReadHeaderEFI(Disk,
983  ReadBackupTable,
984  &EfiHeader);
985  if (!NT_SUCCESS(Status))
986  {
987  return Status;
988  }
989 
990  /* Backup the number of entries, will be used later on */
991  NumberOfEntries = EfiHeader->NumberOfEntries;
992 
993  /* Allocate a DRIVE_LAYOUT_INFORMATION_EX struct big enough */
994  DriveLayoutEx = ExAllocatePoolWithTag(NonPagedPool,
995  FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
996  EfiHeader->NumberOfEntries * sizeof(PARTITION_INFORMATION_EX),
997  TAG_FSTUB);
998  if (!DriveLayoutEx)
999  {
1001  }
1002 
1003 #if 0
1004  if (!ReadBackupTable)
1005  {
1006  /* If we weren't ask to read backup table,
1007  * check the status of the backup table.
1008  * In case it's not where we're expecting it, move it and ask
1009  * for a partition table rewrite.
1010  */
1011  if ((Disk->SectorCount - 1ULL) != EfiHeader->AlternateLBA)
1012  {
1013  /* We'll update it. First, count number of sectors needed to store partitions */
1014  SectorsForPartitions = ((ULONGLONG)EfiHeader->NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
1015  /* Then set first usable LBA: Legacy MBR + GPT header + Partitions entries */
1016  EfiHeader->FirstUsableLBA = SectorsForPartitions + 2;
1017  /* Then set last usable LBA: Last sector - GPT header - Partitions entries */
1018  EfiHeader->LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1;
1019  /* Inform that we'll rewrite partition table */
1020  UpdatedPartitionTable = TRUE;
1021  }
1022  }
1023 #endif
1024 
1025  DriveLayoutEx->PartitionStyle = PARTITION_STYLE_GPT;
1026  /* Translate LBA -> Offset */
1027  DriveLayoutEx->Gpt.StartingUsableOffset.QuadPart = EfiHeader->FirstUsableLBA * Disk->SectorSize;
1028  DriveLayoutEx->Gpt.UsableLength.QuadPart = EfiHeader->LastUsableLBA - EfiHeader->FirstUsableLBA * Disk->SectorSize;
1029  DriveLayoutEx->Gpt.MaxPartitionCount = EfiHeader->NumberOfEntries;
1030  DriveLayoutEx->Gpt.DiskId = EfiHeader->DiskGUID;
1031 
1032  /* Backup partition entry position */
1033  PartitionEntryLBA = EfiHeader->PartitionEntryLBA;
1034  /* Count number of partitions per sector */
1035  PartitionsPerSector = (Disk->SectorSize / PARTITION_ENTRY_SIZE);
1036  /* Read all partitions and fill in structure
1037  * BEWARE! Past that point EfiHeader IS NOT VALID ANYMORE
1038  * It will be erased by the reading of the partition entry
1039  */
1040  for (i = 0, PartitionCount = 0, PartitionIndex = PartitionsPerSector;
1041  i < NumberOfEntries;
1042  i++)
1043  {
1044  /* Only read following sector if we finished with previous sector */
1045  if (PartitionIndex == PartitionsPerSector)
1046  {
1047  Status = FstubReadSector(Disk->DeviceObject,
1048  Disk->SectorSize,
1049  PartitionEntryLBA + (i / PartitionsPerSector),
1050  Disk->Buffer);
1051  if (!NT_SUCCESS(Status))
1052  {
1053  ExFreePoolWithTag(DriveLayoutEx, TAG_FSTUB);
1054  return Status;
1055  }
1056 
1057  PartitionIndex = 0;
1058  }
1059  /* Read following partition */
1060  PartitionEntry = ((PEFI_PARTITION_ENTRY)Disk->Buffer)[PartitionIndex];
1061  PartitionIndex++;
1062 
1063  /* If partition GUID is 00000000-0000-0000-0000-000000000000, then it's unused, skip it */
1064  if (PartitionEntry.PartitionType.Data1 == 0 &&
1065  PartitionEntry.PartitionType.Data2 == 0 &&
1066  PartitionEntry.PartitionType.Data3 == 0 &&
1067  ((PULONGLONG)PartitionEntry.PartitionType.Data4)[0] == 0)
1068  {
1069  continue;
1070  }
1071 
1072  /* Write data to structure. Don't forget GPT is using sectors, Windows offsets */
1073  DriveLayoutEx->PartitionEntry[PartitionCount].StartingOffset.QuadPart = PartitionEntry.StartingLBA * Disk->SectorSize;
1074  DriveLayoutEx->PartitionEntry[PartitionCount].PartitionLength.QuadPart = (PartitionEntry.EndingLBA -
1075  PartitionEntry.StartingLBA + 1) *
1076  Disk->SectorSize;
1077  /* This number starts from 1 */
1078  DriveLayoutEx->PartitionEntry[PartitionCount].PartitionNumber = PartitionCount + 1;
1079  DriveLayoutEx->PartitionEntry[PartitionCount].RewritePartition = FALSE;
1080  DriveLayoutEx->PartitionEntry[PartitionCount].PartitionStyle = PARTITION_STYLE_GPT;
1081  DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.PartitionType = PartitionEntry.PartitionType;
1082  DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.PartitionId = PartitionEntry.UniquePartition;
1083  DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.Attributes = PartitionEntry.Attributes;
1084  RtlCopyMemory(DriveLayoutEx->PartitionEntry[PartitionCount].Gpt.Name,
1085  PartitionEntry.Name, sizeof(PartitionEntry.Name));
1086 
1087  /* Update partition count */
1088  PartitionCount++;
1089  }
1090  DriveLayoutEx->PartitionCount = PartitionCount;
1091 
1092 #if 0
1093  /* If we updated partition table using backup table, rewrite partition table */
1094  if (UpdatedPartitionTable)
1095  {
1096  IoWritePartitionTableEx(Disk->DeviceObject,
1097  DriveLayoutEx);
1098  }
1099 #endif
1100 
1101  /* Finally, return read data */
1102  *DriveLayout = DriveLayoutEx;
1103 
1104  return Status;
1105 }
1106 
1107 NTSTATUS
1108 NTAPI
1111  OUT struct _DRIVE_LAYOUT_INFORMATION_EX** ReturnedDriveLayout)
1112 {
1113  ULONG i;
1114  NTSTATUS Status;
1115  PDRIVE_LAYOUT_INFORMATION DriveLayout = NULL;
1116  PDRIVE_LAYOUT_INFORMATION_EX DriveLayoutEx = NULL;
1117  PAGED_CODE();
1118 
1119  ASSERT(IS_VALID_DISK_INFO(Disk));
1120  ASSERT(ReturnedDriveLayout);
1121 
1122  /* Zero output */
1123  *ReturnedDriveLayout = NULL;
1124 
1125  /* Read partition table the old way */
1126  Status = IoReadPartitionTable(Disk->DeviceObject,
1127  Disk->SectorSize,
1129  &DriveLayout);
1130  if (!NT_SUCCESS(Status))
1131  {
1132  return Status;
1133  }
1134 
1135  /* Allocate a DRIVE_LAYOUT_INFORMATION_EX struct big enough */
1136  DriveLayoutEx = ExAllocatePoolWithTag(NonPagedPool,
1137  FIELD_OFFSET(DRIVE_LAYOUT_INFORMATION_EX, PartitionEntry) +
1138  DriveLayout->PartitionCount * sizeof(PARTITION_INFORMATION_EX),
1139  TAG_FSTUB);
1140  if (!DriveLayoutEx)
1141  {
1142  /* Let's not leak memory as in Windows 2003 */
1143  ExFreePool(DriveLayout);
1145  }
1146 
1147  /* Start converting the DRIVE_LAYOUT_INFORMATION structure */
1148  DriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
1149  DriveLayoutEx->PartitionCount = DriveLayout->PartitionCount;
1150  DriveLayoutEx->Mbr.Signature = DriveLayout->Signature;
1151 
1152  /* Convert each found partition */
1153  for (i = 0; i < DriveLayout->PartitionCount; i++)
1154  {
1156  DriveLayoutEx->PartitionEntry[i].StartingOffset = DriveLayout->PartitionEntry[i].StartingOffset;
1157  DriveLayoutEx->PartitionEntry[i].PartitionLength = DriveLayout->PartitionEntry[i].PartitionLength;
1158  DriveLayoutEx->PartitionEntry[i].PartitionNumber = DriveLayout->PartitionEntry[i].PartitionNumber;
1159  DriveLayoutEx->PartitionEntry[i].RewritePartition = DriveLayout->PartitionEntry[i].RewritePartition;
1160  DriveLayoutEx->PartitionEntry[i].Mbr.PartitionType = DriveLayout->PartitionEntry[i].PartitionType;
1161  DriveLayoutEx->PartitionEntry[i].Mbr.BootIndicator = DriveLayout->PartitionEntry[i].BootIndicator;
1163  DriveLayoutEx->PartitionEntry[i].Mbr.HiddenSectors = DriveLayout->PartitionEntry[i].HiddenSectors;
1164  }
1165 
1166  /* Finally, return data and free old structure */
1167  *ReturnedDriveLayout = DriveLayoutEx;
1168  ExFreePool(DriveLayout);
1169 
1170  return STATUS_SUCCESS;
1171 }
1172 
1173 NTSTATUS
1174 NTAPI
1177  IN ULONGLONG StartingSector OPTIONAL,
1178  OUT PUSHORT Buffer)
1179 {
1180  PIRP Irp;
1181  KEVENT Event;
1182  NTSTATUS Status;
1185  PIO_STACK_LOCATION IoStackLocation;
1186  PAGED_CODE();
1187 
1189  ASSERT(Buffer);
1190  ASSERT(SectorSize);
1191 
1192  /* Compute starting offset */
1193  StartingOffset.QuadPart = StartingSector * SectorSize;
1194 
1195  /* Initialize waiting event */
1197 
1198  /* Prepare IRP */
1200  DeviceObject,
1201  Buffer,
1202  SectorSize,
1203  &StartingOffset,
1204  &Event,
1205  &IoStatusBlock);
1206  if (!Irp)
1207  {
1209  }
1210 
1211  /* Override volume verify */
1212  IoStackLocation = IoGetNextIrpStackLocation(Irp);
1213  IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1214 
1215  /* Then call driver, and wait for completion if needed */
1217  if (Status == STATUS_PENDING)
1218  {
1221  }
1222 
1223  return Status;
1224 }
1225 
1226 NTSTATUS
1227 NTAPI
1231 {
1232  NTSTATUS Status;
1234  PAGED_CODE();
1235 
1236  ASSERT(Disk);
1238 
1239  /* Partition 0 isn't correct (should start at 1) */
1240  if (PartitionNumber == 0)
1241  {
1242  return STATUS_INVALID_PARAMETER;
1243  }
1244 
1245  /* Read partition table */
1246  Status = IoReadPartitionTableEx(Disk->DeviceObject, &Layout);
1247  if (!NT_SUCCESS(Status))
1248  {
1249  return Status;
1250  }
1251  ASSERT(Layout);
1252 
1253  /* If our partition (started at 0 now) is higher than partition count, then, there's an issue */
1254  if (Layout->PartitionCount <= --PartitionNumber)
1255  {
1256  ExFreePool(Layout);
1257  return STATUS_INVALID_PARAMETER;
1258  }
1259 
1260  /* Erase actual partition entry data with provided ones */
1261  Layout->PartitionEntry[PartitionNumber].Gpt.PartitionType = PartitionInfo->PartitionType;
1265 
1266  /* Rewrite the whole partition table to update the modified entry */
1267  Status = IoWritePartitionTableEx(Disk->DeviceObject, Layout);
1268 
1269  /* Free partition table and return */
1270  ExFreePool(Layout);
1271  return Status;
1272 }
1273 
1274 NTSTATUS
1275 NTAPI
1278 {
1279  NTSTATUS Status;
1280  PEFI_PARTITION_HEADER EFIHeader, ReadEFIHeader;
1281  BOOLEAN PrimaryValid = FALSE, BackupValid = FALSE, WriteBackup;
1282  ULONGLONG ReadPosition, WritePosition, SectorsForPartitions, PartitionIndex;
1283  PAGED_CODE();
1284 
1286  if (!EFIHeader)
1287  {
1289  }
1290 
1291  Status = FstubReadHeaderEFI(Disk, FALSE, &ReadEFIHeader);
1292  if (NT_SUCCESS(Status))
1293  {
1294  PrimaryValid = TRUE;
1295  ASSERT(ReadEFIHeader);
1296  RtlCopyMemory(EFIHeader, ReadEFIHeader, sizeof(EFI_PARTITION_HEADER));
1297  }
1298 
1299  Status = FstubReadHeaderEFI(Disk, TRUE, &ReadEFIHeader);
1300  if (NT_SUCCESS(Status))
1301  {
1302  BackupValid = TRUE;
1303  ASSERT(ReadEFIHeader);
1304  RtlCopyMemory(EFIHeader, ReadEFIHeader, sizeof(EFI_PARTITION_HEADER));
1305  }
1306 
1307  /* If both are sane, just return */
1308  if (PrimaryValid && BackupValid)
1309  {
1310  ExFreePoolWithTag(EFIHeader, TAG_FSTUB);
1311  return STATUS_SUCCESS;
1312  }
1313 
1314  /* If both are damaged OR if we have not been ordered to fix
1315  * Then, quit and warn about disk corruption
1316  */
1317  if ((!PrimaryValid && !BackupValid) || !FixErrors)
1318  {
1319  ExFreePoolWithTag(EFIHeader, TAG_FSTUB);
1321  }
1322 
1323  /* Compute sectors taken by partitions */
1324  SectorsForPartitions = (((ULONGLONG)EFIHeader->NumberOfEntries * PARTITION_ENTRY_SIZE) + Disk->SectorSize - 1) / Disk->SectorSize;
1325  if (PrimaryValid)
1326  {
1327  WriteBackup = TRUE;
1328  /* Take position at backup table for writing */
1329  WritePosition = Disk->SectorCount - SectorsForPartitions;
1330  /* And read from primary table */
1331  ReadPosition = 2ULL;
1332 
1333  DPRINT("EFI::Will repair backup table from primary\n");
1334  }
1335  else
1336  {
1337  ASSERT(BackupValid);
1338  WriteBackup = FALSE;
1339  /* Take position at primary table for writing */
1340  WritePosition = 2ULL;
1341  /* And read from backup table */
1342  ReadPosition = Disk->SectorCount - SectorsForPartitions;
1343 
1344  DPRINT("EFI::Will repair primary table from backup\n");
1345  }
1346 
1347  PartitionIndex = 0ULL;
1348 
1349  /* If no partitions are to be copied, just restore header */
1350  if (SectorsForPartitions <= 0)
1351  {
1352  Status = FstubWriteHeaderEFI(Disk,
1353  SectorsForPartitions,
1354  EFIHeader->DiskGUID,
1355  EFIHeader->NumberOfEntries,
1356  EFIHeader->FirstUsableLBA,
1357  EFIHeader->LastUsableLBA,
1358  EFIHeader->PartitionEntryCRC32,
1359  WriteBackup);
1360 
1361  goto Cleanup;
1362  }
1363 
1364  /* Copy all the partitions */
1365  for (; PartitionIndex < SectorsForPartitions; ++PartitionIndex)
1366  {
1367  /* First, read the partition from the first table */
1368  Status = FstubReadSector(Disk->DeviceObject,
1369  Disk->SectorSize,
1370  ReadPosition + PartitionIndex,
1371  Disk->Buffer);
1372  if (!NT_SUCCESS(Status))
1373  {
1374  goto Cleanup;
1375  }
1376 
1377  /* Then, write it in the other table */
1378  Status = FstubWriteSector(Disk->DeviceObject,
1379  Disk->SectorSize,
1380  WritePosition + PartitionIndex,
1381  Disk->Buffer);
1382  if (!NT_SUCCESS(Status))
1383  {
1384  goto Cleanup;
1385  }
1386  }
1387 
1388  /* Now we're done, write the header */
1389  Status = FstubWriteHeaderEFI(Disk,
1390  SectorsForPartitions,
1391  EFIHeader->DiskGUID,
1392  EFIHeader->NumberOfEntries,
1393  EFIHeader->FirstUsableLBA,
1394  EFIHeader->LastUsableLBA,
1395  EFIHeader->PartitionEntryCRC32,
1396  WriteBackup);
1397 
1398 Cleanup:
1399  ExFreePoolWithTag(EFIHeader, TAG_FSTUB);
1400  return Status;
1401 }
1402 
1403 NTSTATUS
1404 NTAPI
1406 {
1407  NTSTATUS Status;
1408  ULONG Signature = 0;
1409  PMASTER_BOOT_RECORD MasterBootRecord;
1410  PAGED_CODE();
1411 
1412  ASSERT(Disk);
1413  ASSERT(IS_VALID_DISK_INFO(Disk));
1414 
1415  /* Read if a MBR is already present */
1416  Status = FstubReadSector(Disk->DeviceObject,
1417  Disk->SectorSize,
1418  0ULL,
1419  Disk->Buffer);
1420  MasterBootRecord = (PMASTER_BOOT_RECORD)Disk->Buffer;
1421  /* If one has been found */
1423  {
1424  /* Save its signature */
1425  Signature = MasterBootRecord->Signature;
1426  }
1427 
1428  /* Reset the MBR */
1429  RtlZeroMemory(MasterBootRecord, Disk->SectorSize);
1430  /* Then create a fake MBR matching those purposes:
1431  * It must have only partition. Type of this partition
1432  * has to be 0xEE to signal a GPT is following.
1433  * This partition has to cover the whole disk. To prevent
1434  * any disk modification by a program that wouldn't
1435  * understand anything to GPT.
1436  */
1437  MasterBootRecord->Signature = Signature;
1438  MasterBootRecord->PartitionTable[0].StartSector = 2;
1439  MasterBootRecord->PartitionTable[0].SystemIndicator = EFI_PMBR_OSTYPE_EFI;
1440  MasterBootRecord->PartitionTable[0].EndHead = 0xFF;
1441  MasterBootRecord->PartitionTable[0].EndSector = 0xFF;
1442  MasterBootRecord->PartitionTable[0].EndCylinder = 0xFF;
1443  MasterBootRecord->PartitionTable[0].SectorCountBeforePartition = 1;
1444  MasterBootRecord->PartitionTable[0].PartitionSectorCount = 0xFFFFFFFF;
1445  MasterBootRecord->MasterBootRecordMagic = BOOT_RECORD_SIGNATURE;
1446 
1447  /* Finally, write that MBR */
1448  return FstubWriteSector(Disk->DeviceObject,
1449  Disk->SectorSize,
1450  0,
1451  Disk->Buffer);
1452 }
1453 
1454 NTSTATUS
1455 NTAPI
1457  IN ULONG PartitionsSizeSector,
1458  IN ULONG PartitionEntryNumber,
1459  IN PEFI_PARTITION_ENTRY PartitionEntry,
1460  IN BOOLEAN WriteBackupTable,
1461  IN BOOLEAN ForceWrite,
1462  OUT PULONG PartitionEntryCRC32 OPTIONAL)
1463 {
1464  ULONG Offset;
1465  ULONGLONG FirstEntryLBA;
1467  PAGED_CODE();
1468 
1469  ASSERT(Disk);
1470  ASSERT(IS_VALID_DISK_INFO(Disk));
1471 
1472  /* Get the first LBA where the partition table is:
1473  * On primary table, it's sector 2 (skip MBR & Header)
1474  * On backup table, it's ante last sector (Header) minus partition table size
1475  */
1476  if (!WriteBackupTable)
1477  {
1478  FirstEntryLBA = 2ULL;
1479  }
1480  else
1481  {
1482  FirstEntryLBA = Disk->SectorCount - PartitionsSizeSector - 1;
1483  }
1484 
1485  /* Copy the entry at the proper place into the buffer
1486  * That way, we don't erase previous entries
1487  */
1488  RtlCopyMemory((PVOID)((ULONG_PTR)Disk->Buffer + ((PartitionEntryNumber * PARTITION_ENTRY_SIZE) % Disk->SectorSize)),
1489  PartitionEntry,
1490  sizeof(EFI_PARTITION_ENTRY));
1491  /* Compute size of buffer */
1492  Offset = (PartitionEntryNumber * PARTITION_ENTRY_SIZE) % Disk->SectorSize + PARTITION_ENTRY_SIZE;
1494 
1495  /* If it's full of partition entries, or if call ask for it, write down the data */
1496  if (Offset == Disk->SectorSize || ForceWrite)
1497  {
1498  /* We will write at first entry LBA + a shift made by already present/written entries */
1499  Status = FstubWriteSector(Disk->DeviceObject,
1500  Disk->SectorSize,
1501  FirstEntryLBA + ((PartitionEntryNumber * PARTITION_ENTRY_SIZE) / Disk->SectorSize),
1502  Disk->Buffer);
1503  if (!NT_SUCCESS(Status))
1504  {
1505  return Status;
1506  }
1507 
1508  /* We clean buffer */
1509  RtlZeroMemory(Disk->Buffer, Disk->SectorSize);
1510  }
1511 
1512  /* If we have a buffer for CRC32, then compute it */
1513  if (PartitionEntryCRC32)
1514  {
1515  *PartitionEntryCRC32 = RtlComputeCrc32(*PartitionEntryCRC32, (PUCHAR)PartitionEntry, PARTITION_ENTRY_SIZE);
1516  }
1517 
1518  return Status;
1519 }
1520 
1521 NTSTATUS
1522 NTAPI
1524  IN ULONG PartitionsSizeSector,
1525  IN GUID DiskGUID,
1526  IN ULONG NumberOfEntries,
1527  IN ULONGLONG FirstUsableLBA,
1528  IN ULONGLONG LastUsableLBA,
1529  IN ULONG PartitionEntryCRC32,
1530  IN BOOLEAN WriteBackupTable)
1531 {
1532  PEFI_PARTITION_HEADER EFIHeader;
1533  PAGED_CODE();
1534 
1535  ASSERT(Disk);
1536  ASSERT(IS_VALID_DISK_INFO(Disk));
1537 
1538  /* Let's use read buffer as EFI_PARTITION_HEADER */
1539  EFIHeader = (PEFI_PARTITION_HEADER)Disk->Buffer;
1540 
1541  /* Complete standard header information */
1542  EFIHeader->Signature = EFI_HEADER_SIGNATURE;
1543  EFIHeader->Revision = EFI_HEADER_REVISION_1;
1544  EFIHeader->HeaderSize = sizeof(EFI_PARTITION_HEADER);
1545  /* Set no CRC32 checksum at the moment */
1546  EFIHeader->HeaderCRC32 = 0;
1547  EFIHeader->Reserved = 0;
1548  /* Check whether we're writing primary or backup
1549  * That way, we can ajust LBA setting:
1550  * Primary is on first sector
1551  * Backup is on last sector
1552  */
1553  if (!WriteBackupTable)
1554  {
1555  EFIHeader->MyLBA = 1ULL;
1556  EFIHeader->AlternateLBA = Disk->SectorCount - 1ULL;
1557  }
1558  else
1559  {
1560  EFIHeader->MyLBA = Disk->SectorCount - 1ULL;
1561  EFIHeader->AlternateLBA = 1ULL;
1562  }
1563  /* Fill in with received data */
1564  EFIHeader->FirstUsableLBA = FirstUsableLBA;
1565  EFIHeader->LastUsableLBA = LastUsableLBA;
1566  EFIHeader->DiskGUID = DiskGUID;
1567  /* Check whether we're writing primary or backup
1568  * That way, we can ajust LBA setting:
1569  * On primary, partition entries are just after header, so sector 2
1570  * On backup, partition entries are just before header, so, last sector minus partition table size
1571  */
1572  if (!WriteBackupTable)
1573  {
1574  EFIHeader->PartitionEntryLBA = EFIHeader->MyLBA + 1ULL;
1575  }
1576  else
1577  {
1578  EFIHeader->PartitionEntryLBA = EFIHeader->MyLBA - PartitionsSizeSector;
1579  }
1580  /* Complete filling in */
1581  EFIHeader->NumberOfEntries = NumberOfEntries;
1583  EFIHeader->PartitionEntryCRC32 = PartitionEntryCRC32;
1584  /* Finally, compute header checksum */
1585  EFIHeader->HeaderCRC32 = RtlComputeCrc32(0, (PUCHAR)EFIHeader, sizeof(EFI_PARTITION_HEADER));
1586 
1587  /* Debug the way we'll break disk, to let user pray */
1588  DPRINT("FSTUB: About to write the following header for %s table\n", (WriteBackupTable ? "backup" : "primary"));
1589  DPRINT(" Signature: %I64x\n", EFIHeader->Signature);
1590  DPRINT(" Revision: %x\n", EFIHeader->Revision);
1591  DPRINT(" HeaderSize: %x\n", EFIHeader->HeaderSize);
1592  DPRINT(" HeaderCRC32: %x\n", EFIHeader->HeaderCRC32);
1593  DPRINT(" MyLBA: %I64x\n", EFIHeader->MyLBA);
1594  DPRINT(" AlternateLBA: %I64x\n", EFIHeader->AlternateLBA);
1595  DPRINT(" FirstUsableLBA: %I64x\n", EFIHeader->FirstUsableLBA);
1596  DPRINT(" LastUsableLBA: %I64x\n", EFIHeader->LastUsableLBA);
1597  DPRINT(" PartitionEntryLBA: %I64x\n", EFIHeader->PartitionEntryLBA);
1598  DPRINT(" NumberOfEntries: %x\n", EFIHeader->NumberOfEntries);
1599  DPRINT(" SizeOfPartitionEntry: %x\n", EFIHeader->SizeOfPartitionEntry);
1600  DPRINT(" PartitionEntryCRC32: %x\n", EFIHeader->PartitionEntryCRC32);
1601 
1602  /* Write header to disk */
1603  return FstubWriteSector(Disk->DeviceObject,
1604  Disk->SectorSize,
1605  EFIHeader->MyLBA,
1606  Disk->Buffer);
1607 }
1608 
1609 NTSTATUS
1610 NTAPI
1612  IN GUID DiskGUID,
1613  IN ULONG MaxPartitionCount,
1614  IN ULONGLONG FirstUsableLBA,
1615  IN ULONGLONG LastUsableLBA,
1616  IN BOOLEAN WriteBackupTable,
1617  IN ULONG PartitionCount,
1618  IN PPARTITION_INFORMATION_EX PartitionEntries OPTIONAL)
1619 {
1620  NTSTATUS Status;
1622  ULONG i, WrittenPartitions, SectoredPartitionEntriesSize, PartitionEntryCRC32;
1623  PAGED_CODE();
1624 
1625  ASSERT(Disk);
1626  ASSERT(MaxPartitionCount >= 128);
1627  ASSERT(PartitionCount <= MaxPartitionCount);
1628 
1629  PartitionEntryCRC32 = 0;
1630  /* Count how much sectors we'll have to read to read the whole partition table */
1631  SectoredPartitionEntriesSize = (MaxPartitionCount * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
1632 
1633  for (i = 0, WrittenPartitions = 0; i < PartitionCount; i++)
1634  {
1635  /* If partition GUID is 00000000-0000-0000-0000-000000000000, then it's unused, skip it */
1636  if (PartitionEntries[i].Gpt.PartitionType.Data1 == 0 &&
1637  PartitionEntries[i].Gpt.PartitionType.Data2 == 0 &&
1638  PartitionEntries[i].Gpt.PartitionType.Data3 == 0 &&
1639  ((PULONGLONG)PartitionEntries[i].Gpt.PartitionType.Data4)[0] == 0)
1640  {
1641  continue;
1642  }
1643 
1644  /* Copy the entry in the partition entry format */
1645  FstubCopyEntryEFI(&Entry, &PartitionEntries[i], Disk->SectorSize);
1646  /* Then write the entry to the disk */
1647  Status = FstubWriteEntryEFI(Disk,
1648  SectoredPartitionEntriesSize,
1649  WrittenPartitions,
1650  &Entry,
1651  WriteBackupTable,
1652  FALSE,
1653  &PartitionEntryCRC32);
1654  if (!NT_SUCCESS(Status))
1655  {
1656  return Status;
1657  }
1658  WrittenPartitions++;
1659  }
1660 
1661  /* Zero the buffer to write zeros to the disk */
1663  /* Write the disks with zeros for every unused remaining partition entry */
1664  for (i = WrittenPartitions; i < MaxPartitionCount; i++)
1665  {
1666  Status = FstubWriteEntryEFI(Disk,
1667  SectoredPartitionEntriesSize,
1668  i,
1669  &Entry,
1670  WriteBackupTable,
1671  FALSE,
1672  &PartitionEntryCRC32);
1673  if (!NT_SUCCESS(Status))
1674  {
1675  return Status;
1676  }
1677  }
1678 
1679  /* Once we're done, write the GPT header */
1680  return FstubWriteHeaderEFI(Disk,
1681  SectoredPartitionEntriesSize,
1682  DiskGUID,
1683  MaxPartitionCount,
1684  FirstUsableLBA,
1685  LastUsableLBA,
1686  PartitionEntryCRC32,
1687  WriteBackupTable);
1688 }
1689 
1690 NTSTATUS
1691 NTAPI
1694 {
1695  NTSTATUS Status;
1696  PDRIVE_LAYOUT_INFORMATION DriveLayout;
1697  PAGED_CODE();
1698 
1699  ASSERT(IS_VALID_DISK_INFO(Disk));
1700  ASSERT(LayoutEx);
1701 
1702  /* Convert data to the correct format */
1703  DriveLayout = FstubConvertExtendedToLayout(LayoutEx);
1704  if (!DriveLayout)
1705  {
1707  }
1708 
1709  /* Really write information */
1710  Status = IoWritePartitionTable(Disk->DeviceObject,
1711  Disk->SectorSize,
1712  Disk->DiskGeometry.Geometry.SectorsPerTrack,
1713  Disk->DiskGeometry.Geometry.TracksPerCylinder,
1714  DriveLayout);
1715 
1716  /* Free allocated structure and return */
1717  ExFreePoolWithTag(DriveLayout, TAG_FSTUB);
1718  return Status;
1719 }
1720 
1721 NTSTATUS
1722 NTAPI
1725  IN ULONGLONG StartingSector OPTIONAL,
1726  IN PUSHORT Buffer)
1727 {
1728  PIRP Irp;
1729  KEVENT Event;
1730  NTSTATUS Status;
1733  PIO_STACK_LOCATION IoStackLocation;
1734  PAGED_CODE();
1735 
1737  ASSERT(Buffer);
1738  ASSERT(SectorSize);
1739 
1740  /* Compute starting offset */
1741  StartingOffset.QuadPart = StartingSector * SectorSize;
1742 
1743  /* Initialize waiting event */
1745 
1746  /* Prepare IRP */
1748  DeviceObject,
1749  Buffer,
1750  SectorSize,
1751  &StartingOffset,
1752  &Event,
1753  &IoStatusBlock);
1754  if (!Irp)
1755  {
1757  }
1758 
1759  /* Override volume verify */
1760  IoStackLocation = IoGetNextIrpStackLocation(Irp);
1761  IoStackLocation->Flags |= SL_OVERRIDE_VERIFY_VOLUME;
1762 
1763  /* Then call driver, and wait for completion if needed */
1765  if (Status == STATUS_PENDING)
1766  {
1769  }
1770 
1771  return Status;
1772 }
1773 
1774 /* FUNCTIONS *****************************************************************/
1775 
1776 /*
1777  * @implemented
1778  */
1779 NTSTATUS
1780 NTAPI
1782  IN struct _CREATE_DISK* Disk)
1783 {
1784  PARTITION_STYLE PartitionStyle;
1785  PAGED_CODE();
1786 
1788 
1789  /* Get partition style. If caller didn't provided data, assume it's raw */
1790  PartitionStyle = ((Disk) ? Disk->PartitionStyle : PARTITION_STYLE_RAW);
1791  /* Then, call appropriate internal function */
1792  switch (PartitionStyle)
1793  {
1794  case PARTITION_STYLE_MBR:
1795  return FstubCreateDiskMBR(DeviceObject, &(Disk->Mbr));
1796  case PARTITION_STYLE_GPT:
1797  return FstubCreateDiskEFI(DeviceObject, &(Disk->Gpt));
1798  case PARTITION_STYLE_RAW:
1800  default:
1801  return STATUS_NOT_SUPPORTED;
1802  }
1803 }
1804 
1805 /*
1806  * @implemented
1807  */
1808 NTSTATUS
1809 NTAPI
1811  IN ULONG Size)
1812 {
1813  PIRP Irp;
1814  KEVENT Event;
1815  PLIST_ENTRY NextEntry;
1817  DISK_GEOMETRY DiskGeometry;
1819  UNICODE_STRING DeviceStringW;
1821  CHAR Buffer[128], ArcBuffer[128];
1823  BOOLEAN SingleDisk, IsBootDiskInfoEx;
1824  PARC_DISK_SIGNATURE ArcDiskSignature;
1825  PARC_DISK_INFORMATION ArcDiskInformation;
1826  PARTITION_INFORMATION_EX PartitionInformation;
1827  PDRIVE_LAYOUT_INFORMATION_EX DriveLayout = NULL;
1828  ULONG DiskCount, DiskNumber, Signature, PartitionNumber;
1829  ANSI_STRING ArcBootString, ArcSystemString, DeviceStringA, ArcNameStringA;
1831  PAGED_CODE();
1832 
1833  /* Get loader block. If it's null, we come to late */
1834  if (!IopLoaderBlock)
1835  {
1836  return STATUS_TOO_LATE;
1837  }
1838 
1839  /* Check buffer size */
1840  if (Size < sizeof(BOOTDISK_INFORMATION))
1841  {
1842  return STATUS_INVALID_PARAMETER;
1843  }
1844 
1845  /* Init some useful stuff:
1846  * Get arc disks information
1847  * Check whether we have a single disk
1848  * Check received structure size (extended or not?)
1849  * Init boot strings (system/boot)
1850  * Finaly, get disk count
1851  */
1852  ArcDiskInformation = IopLoaderBlock->ArcDiskInformation;
1853  SingleDisk = IsListEmpty(&(ArcDiskInformation->DiskSignatureListHead));
1854  IsBootDiskInfoEx = (Size >= sizeof(BOOTDISK_INFORMATION_EX));
1858 
1859  /* If no disk, return success */
1860  if (DiskCount == 0)
1861  {
1862  return STATUS_SUCCESS;
1863  }
1864 
1865  /* Now, browse all disks */
1866  for (DiskNumber = 0; DiskNumber < DiskCount; DiskNumber++)
1867  {
1868  /* Create the device name */
1869  sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition0", DiskNumber);
1870  RtlInitAnsiString(&DeviceStringA, Buffer);
1871  Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
1872  if (!NT_SUCCESS(Status))
1873  {
1874  continue;
1875  }
1876 
1877  /* Get its device object */
1878  Status = IoGetDeviceObjectPointer(&DeviceStringW,
1880  &FileObject,
1881  &DeviceObject);
1882  RtlFreeUnicodeString(&DeviceStringW);
1883  if (!NT_SUCCESS(Status))
1884  {
1885  continue;
1886  }
1887 
1888  /* Prepare for getting disk geometry */
1891  DeviceObject,
1892  NULL,
1893  0,
1894  &DiskGeometry,
1895  sizeof(DISK_GEOMETRY),
1896  FALSE,
1897  &Event,
1898  &IoStatusBlock);
1899  if (!Irp)
1900  {
1902  continue;
1903  }
1904 
1905  /* Then, call the drive, and wait for it if needed */
1907  if (Status == STATUS_PENDING)
1908  {
1911  }
1912  if (!NT_SUCCESS(Status))
1913  {
1915  continue;
1916  }
1917 
1918  /* Read partition table */
1920  &DriveLayout);
1921 
1922  /* FileObject, you can go! */
1924 
1925  if (!NT_SUCCESS(Status))
1926  {
1927  continue;
1928  }
1929 
1930  /* Ensure we have at least 512 bytes per sector */
1931  if (DiskGeometry.BytesPerSector < 512)
1932  {
1933  DiskGeometry.BytesPerSector = 512;
1934  }
1935 
1936  /* Now, for each arc disk, try to find the matching */
1937  for (NextEntry = ArcDiskInformation->DiskSignatureListHead.Flink;
1938  NextEntry != &ArcDiskInformation->DiskSignatureListHead;
1939  NextEntry = NextEntry->Flink)
1940  {
1941  ArcDiskSignature = CONTAINING_RECORD(NextEntry,
1943  ListEntry);
1944  /* If they matches, ie
1945  * - There's only one disk for both BIOS and detected
1946  * - Signatures are matching
1947  * - This is MBR
1948  * (We don't check checksums here)
1949  */
1950  if (((SingleDisk && DiskCount == 1) ||
1951  (IopVerifyDiskSignature(DriveLayout, ArcDiskSignature, &Signature))) &&
1952  (DriveLayout->PartitionStyle == PARTITION_STYLE_MBR))
1953  {
1954  /* Create arc name */
1955  sprintf(ArcBuffer, "\\ArcName\\%s", ArcDiskSignature->ArcName);
1956  RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
1957 
1958  /* Browse all partitions */
1959  for (PartitionNumber = 1; PartitionNumber <= DriveLayout->PartitionCount; PartitionNumber++)
1960  {
1961  /* Create its device name */
1962  sprintf(Buffer, "\\Device\\Harddisk%lu\\Partition%lu", DiskNumber, PartitionNumber);
1963  RtlInitAnsiString(&DeviceStringA, Buffer);
1964  Status = RtlAnsiStringToUnicodeString(&DeviceStringW, &DeviceStringA, TRUE);
1965  if (!NT_SUCCESS(Status))
1966  {
1967  continue;
1968  }
1969 
1970  /* If IopVerifyDiskSignature returned no signature, take the one from DriveLayout */
1971  if (!Signature)
1972  {
1973  Signature = DriveLayout->Mbr.Signature;
1974  }
1975 
1976  /* Create partial arc name */
1977  sprintf(ArcBuffer, "%spartition(%lu)", ArcDiskSignature->ArcName, PartitionNumber);
1978  RtlInitAnsiString(&ArcNameStringA, ArcBuffer);
1979 
1980  /* If it's matching boot string */
1981  if (RtlEqualString(&ArcNameStringA, &ArcBootString, TRUE))
1982  {
1983  /* Then, fill in information about boot device */
1984  BootDiskInformation->BootDeviceSignature = Signature;
1985 
1986  /* Get its device object */
1987  Status = IoGetDeviceObjectPointer(&DeviceStringW,
1989  &FileObject,
1990  &DeviceObject);
1991  if (!NT_SUCCESS(Status))
1992  {
1993  RtlFreeUnicodeString(&DeviceStringW);
1994  continue;
1995  }
1996 
1997  /* And call the drive to get information about partition */
2000  DeviceObject,
2001  NULL,
2002  0,
2003  &PartitionInformation,
2004  sizeof(PARTITION_INFORMATION_EX),
2005  FALSE,
2006  &Event,
2007  &IoStatusBlock);
2008  if (!Irp)
2009  {
2011  RtlFreeUnicodeString(&DeviceStringW);
2012  continue;
2013  }
2014 
2015  /* Call & wait if needed */
2017  if (Status == STATUS_PENDING)
2018  {
2021  }
2022  if (!NT_SUCCESS(Status))
2023  {
2025  RtlFreeUnicodeString(&DeviceStringW);
2026  continue;
2027  }
2028 
2029  /* We get partition offset as demanded and return it */
2030  BootDiskInformation->BootPartitionOffset = PartitionInformation.StartingOffset.QuadPart;
2031 
2032  /* If called passed a BOOTDISK_INFORMATION_EX structure, give more intel */
2033  if (IsBootDiskInfoEx)
2034  {
2035  /* Is PT MBR or GPT? */
2036  if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
2037  {
2038  ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceGuid = DriveLayout->Gpt.DiskId;
2039  ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceIsGpt = TRUE;
2040  }
2041  else
2042  {
2043  ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->BootDeviceIsGpt = FALSE;
2044  }
2045  }
2046 
2047  /* Dereference FileObject */
2049  }
2050 
2051  /* If it's matching system string */
2052  if (RtlEqualString(&ArcNameStringA, &ArcSystemString, TRUE))
2053  {
2054  /* Then, fill in information about the system device */
2055  BootDiskInformation->SystemDeviceSignature = Signature;
2056 
2057  /* Get its device object */
2058  Status = IoGetDeviceObjectPointer(&DeviceStringW,
2060  &FileObject,
2061  &DeviceObject);
2062  if (!NT_SUCCESS(Status))
2063  {
2064  RtlFreeUnicodeString(&DeviceStringW);
2065  continue;
2066  }
2067 
2068  /* And call the drive to get information about partition */
2071  DeviceObject,
2072  NULL,
2073  0,
2074  &PartitionInformation,
2075  sizeof(PARTITION_INFORMATION_EX),
2076  FALSE,
2077  &Event,
2078  &IoStatusBlock);
2079  if (!Irp)
2080  {
2082  RtlFreeUnicodeString(&DeviceStringW);
2083  continue;
2084  }
2085 
2086  /* Call & wait if needed */
2088  if (Status == STATUS_PENDING)
2089  {
2092  }
2093  if (!NT_SUCCESS(Status))
2094  {
2096  RtlFreeUnicodeString(&DeviceStringW);
2097  continue;
2098  }
2099 
2100  /* We get partition offset as demanded and return it */
2101  BootDiskInformation->SystemPartitionOffset = PartitionInformation.StartingOffset.QuadPart;
2102 
2103  /* If called passed a BOOTDISK_INFORMATION_EX structure, give more intel */
2104  if (IsBootDiskInfoEx)
2105  {
2106  /* Is PT MBR or GPT? */
2107  if (DriveLayout->PartitionStyle == PARTITION_STYLE_GPT)
2108  {
2109  ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceGuid = DriveLayout->Gpt.DiskId;
2110  ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceIsGpt = TRUE;
2111  }
2112  else
2113  {
2114  ((PBOOTDISK_INFORMATION_EX)BootDiskInformation)->SystemDeviceIsGpt = FALSE;
2115  }
2116  }
2117 
2118  /* Dereference FileObject */
2120  }
2121 
2122  /* Release device string */
2123  RtlFreeUnicodeString(&DeviceStringW);
2124  }
2125  }
2126  }
2127 
2128  /* Finally, release drive layout structure */
2129  ExFreePool(DriveLayout);
2130  }
2131 
2132  /* And return */
2133  return Status;
2134 }
2135 
2136 /*
2137  * @implemented
2138  */
2139 NTSTATUS
2140 NTAPI
2142  IN ULONG BytesPerSector,
2144 {
2145  PULONG Buffer;
2146  NTSTATUS Status;
2147  ULONG HeaderCRC32, i, CheckSum;
2148  PEFI_PARTITION_HEADER EFIHeader;
2149  PPARTITION_DESCRIPTOR PartitionDescriptor;
2150  PAGED_CODE();
2151 
2152  /* Ensure we'll read at least 512 bytes */
2153  if (BytesPerSector < 512)
2154  {
2155  BytesPerSector = 512;
2156  }
2157 
2158  /* Allocate a buffer for reading operations */
2160  if (!Buffer)
2161  {
2162  return STATUS_NO_MEMORY;
2163  }
2164 
2165  /* Read first sector (sector 0) for MBR */
2167  BytesPerSector,
2168  0ULL,
2169  (PUSHORT)Buffer);
2170  if (!NT_SUCCESS(Status))
2171  {
2172  goto Cleanup;
2173  }
2174 
2175  /* Get the partition descriptor array */
2176  PartitionDescriptor = (PPARTITION_DESCRIPTOR)
2178  /* Check partitions types: if first is 0xEE and all the others 0, we have GPT */
2179  if (PartitionDescriptor[0].PartitionType == EFI_PMBR_OSTYPE_EFI &&
2180  PartitionDescriptor[1].PartitionType == 0 &&
2181  PartitionDescriptor[2].PartitionType == 0 &&
2182  PartitionDescriptor[3].PartitionType == 0)
2183  {
2184  /* If we have GPT, read second sector (sector 1) for GPT header */
2186  BytesPerSector,
2187  1ULL,
2188  (PUSHORT)Buffer);
2189  if (!NT_SUCCESS(Status))
2190  {
2191  goto Cleanup;
2192  }
2193  EFIHeader = (PEFI_PARTITION_HEADER)Buffer;
2194 
2195  /* First check signature
2196  * Then, check version (we only support v1
2197  * Finally check header size
2198  */
2199  if (EFIHeader->Signature != EFI_HEADER_SIGNATURE ||
2200  EFIHeader->Revision != EFI_HEADER_REVISION_1 ||
2201  EFIHeader->HeaderSize != sizeof(EFI_PARTITION_HEADER))
2202  {
2204  goto Cleanup;
2205  }
2206 
2207  /* Save current checksum */
2208  HeaderCRC32 = EFIHeader->HeaderCRC32;
2209  /* Then zero the one in EFI header. This is needed to compute header checksum */
2210  EFIHeader->HeaderCRC32 = 0;
2211  /* Compute header checksum and compare with the one present in partition table */
2212  if (RtlComputeCrc32(0, (PUCHAR)Buffer, sizeof(EFI_PARTITION_HEADER)) != HeaderCRC32)
2213  {
2215  goto Cleanup;
2216  }
2217 
2218  /* Set partition table style to GPT and return disk GUID */
2219  Signature->PartitionStyle = PARTITION_STYLE_GPT;
2220  Signature->Gpt.DiskId = EFIHeader->DiskGUID;
2221  }
2222  else
2223  {
2224  /* Compute MBR checksum */
2225  for (i = 0, CheckSum = 0; i < 512 / sizeof(ULONG) ; i++)
2226  {
2227  CheckSum += Buffer[i];
2228  }
2229 
2230  /* Set partition table style to MBR and return signature (offset 440) and checksum */
2231  Signature->PartitionStyle = PARTITION_STYLE_MBR;
2232  Signature->Mbr.Signature = Buffer[PARTITION_TABLE_OFFSET / 2 - 1];
2233  Signature->Mbr.CheckSum = CheckSum;
2234  }
2235 
2236 Cleanup:
2237  /* Free buffer and return */
2239  return Status;
2240 }
2241 
2242 /*
2243  * @implemented
2244  */
2245 NTSTATUS
2246 NTAPI
2248  IN struct _DRIVE_LAYOUT_INFORMATION_EX** DriveLayout)
2249 {
2250  NTSTATUS Status;
2251  PDISK_INFORMATION Disk;
2252  PARTITION_STYLE PartitionStyle;
2253  PAGED_CODE();
2254 
2256  ASSERT(DriveLayout);
2257 
2258  /* First of all, allocate internal structure */
2260  if (!NT_SUCCESS(Status))
2261  {
2262  return Status;
2263  }
2264  ASSERT(Disk);
2265 
2266  /* Then, detect partition style (MBR? GTP/EFI? RAW?) */
2267  Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
2268  if (!NT_SUCCESS(Status))
2269  {
2271  return Status;
2272  }
2273 
2274  /* Here partition table is really read, depending on its style */
2275  switch (PartitionStyle)
2276  {
2277  case PARTITION_STYLE_MBR:
2278  case PARTITION_STYLE_RAW:
2279  Status = FstubReadPartitionTableMBR(Disk, FALSE, DriveLayout);
2280  break;
2281 
2282  case PARTITION_STYLE_GPT:
2283  /* Read primary table */
2284  Status = FstubReadPartitionTableEFI(Disk, FALSE, DriveLayout);
2285  /* If it failed, try reading backup table */
2286  if (!NT_SUCCESS(Status))
2287  {
2288  Status = FstubReadPartitionTableEFI(Disk, TRUE, DriveLayout);
2289  }
2290  break;
2291 
2292  default:
2293  DPRINT("Unknown partition type\n");
2295  }
2296 
2297  /* It's over, internal structure not needed anymore */
2299 
2300  /* In case of success, print data */
2301  if (NT_SUCCESS(Status))
2302  {
2303  FstubDbgPrintDriveLayoutEx(*DriveLayout);
2304  }
2305 
2306  return Status;
2307 }
2308 
2309 /*
2310  * @implemented
2311  */
2312 NTSTATUS
2313 NTAPI
2317 {
2318  NTSTATUS Status;
2319  PDISK_INFORMATION Disk;
2320  PARTITION_STYLE PartitionStyle;
2321  PAGED_CODE();
2322 
2325 
2326  /* Debug given modifications */
2328 
2329  /* Allocate internal structure */
2331  if (!NT_SUCCESS(Status))
2332  {
2333  return Status;
2334  }
2335 
2336  /* Get partition table style on disk */
2337  Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
2338  if (!NT_SUCCESS(Status))
2339  {
2341  return Status;
2342  }
2343 
2344  /* If it's not matching partition style given in modifications, give up */
2345  if (PartitionInfo->PartitionStyle != PartitionStyle)
2346  {
2348  return STATUS_INVALID_PARAMETER;
2349  }
2350 
2351  /* Finally, handle modifications using proper function */
2352  switch (PartitionStyle)
2353  {
2354  case PARTITION_STYLE_MBR:
2356  Disk->SectorSize,
2358  PartitionInfo->Mbr.PartitionType);
2359  break;
2360  case PARTITION_STYLE_GPT:
2363  &(PartitionInfo->Gpt));
2364  break;
2365  default:
2367  }
2368 
2369  /* Release internal structure and return */
2371  return Status;
2372 }
2373 
2374 /*
2375  * @implemented
2376  */
2377 NTSTATUS
2378 NTAPI
2381 {
2382  NTSTATUS Status;
2383  PDISK_INFORMATION Disk;
2384  PARTITION_STYLE PartitionStyle;
2385  PAGED_CODE();
2386 
2388 
2389  /* Allocate internal structure */
2391  if (!NT_SUCCESS(Status))
2392  {
2393  return Status;
2394  }
2395  ASSERT(Disk);
2396 
2397  /* Get partition table style on disk */
2398  Status = FstubDetectPartitionStyle(Disk, &PartitionStyle);
2399  if (!NT_SUCCESS(Status))
2400  {
2402  return Status;
2403  }
2404 
2405  /* Action will depend on partition style */
2406  switch (PartitionStyle)
2407  {
2408  /* For MBR, assume it's always OK */
2409  case PARTITION_STYLE_MBR:
2411  break;
2412  /* For GPT, call internal function */
2413  case PARTITION_STYLE_GPT:
2415  break;
2416  /* Otherwise, signal we can't work */
2417  default:
2419  }
2420 
2421  /* Release internal structure and return */
2423  return Status;
2424 }
2425 
2426 /*
2427  * @implemented
2428  */
2429 NTSTATUS
2430 NTAPI
2432  IN struct _DRIVE_LAYOUT_INFORMATION_EX* DriveLayout)
2433 {
2434  GUID DiskGuid;
2435  NTSTATUS Status;
2436  ULONG NumberOfEntries;
2437  PDISK_INFORMATION Disk;
2438  PEFI_PARTITION_HEADER EfiHeader;
2439  ULONGLONG SectorsForPartitions, FirstUsableLBA, LastUsableLBA;
2440  PAGED_CODE();
2441 
2443  ASSERT(DriveLayout);
2444 
2445  /* Debug partition table that must be written */
2446  FstubDbgPrintDriveLayoutEx(DriveLayout);
2447 
2448  /* Allocate internal structure */
2450  if (!NT_SUCCESS(Status))
2451  {
2452  return Status;
2453  }
2454  ASSERT(Disk);
2455 
2456  switch (DriveLayout->PartitionStyle)
2457  {
2458  case PARTITION_STYLE_MBR:
2459  Status = FstubWritePartitionTableMBR(Disk, DriveLayout);
2460  break;
2461 
2462  case PARTITION_STYLE_GPT:
2463  /* Read primary table header */
2464  Status = FstubReadHeaderEFI(Disk,
2465  FALSE,
2466  &EfiHeader);
2467  /* If it failed, try reading back table header */
2468  if (!NT_SUCCESS(Status))
2469  {
2470  Status = FstubReadHeaderEFI(Disk,
2471  TRUE,
2472  &EfiHeader);
2473  }
2474 
2475  /* We have a header! */
2476  if (NT_SUCCESS(Status))
2477  {
2478  /* Check if there are enough places for the partitions to be written */
2479  if (DriveLayout->PartitionCount <= EfiHeader->NumberOfEntries)
2480  {
2481  /* Backup data */
2482  NumberOfEntries = EfiHeader->NumberOfEntries;
2483  RtlCopyMemory(&DiskGuid, &EfiHeader->DiskGUID, sizeof(GUID));
2484  /* Count number of sectors needed to store partitions */
2485  SectorsForPartitions = ((ULONGLONG)NumberOfEntries * PARTITION_ENTRY_SIZE) / Disk->SectorSize;
2486  /* Set first usable LBA: Legacy MBR + GPT header + Partitions entries */
2487  FirstUsableLBA = SectorsForPartitions + 2;
2488  /* Set last usable LBA: Last sector - GPT header - Partitions entries */
2489  LastUsableLBA = Disk->SectorCount - SectorsForPartitions - 1;
2490  /* Write primary table */
2492  DiskGuid,
2493  NumberOfEntries,
2494  FirstUsableLBA,
2495  LastUsableLBA,
2496  FALSE,
2497  DriveLayout->PartitionCount,
2498  DriveLayout->PartitionEntry);
2499  /* If it succeed, also update backup table */
2500  if (NT_SUCCESS(Status))
2501  {
2503  DiskGuid,
2504  NumberOfEntries,
2505  FirstUsableLBA,
2506  LastUsableLBA,
2507  TRUE,
2508  DriveLayout->PartitionCount,
2509  DriveLayout->PartitionEntry);
2510  }
2511  }
2512  else
2513  {
2515  }
2516  }
2517  break;
2518 
2519  default:
2520  DPRINT("Unsupported partition style: %lu\n", DriveLayout->PartitionStyle);
2522  }
2523 
2524  /* It's over, internal structure not needed anymore */
2526 
2527  return Status;
2528 }
2529 
2530 /* EOF */
NTSTATUS NTAPI IoGetBootDiskInformation(IN OUT PBOOTDISK_INFORMATION BootDiskInformation, IN ULONG Size)
Definition: fstubex.c:1810
NTSTATUS NTAPI FstubVerifyPartitionTableEFI(IN PDISK_INFORMATION Disk, IN BOOLEAN FixErrors)
Definition: fstubex.c:1276
signed char * PCHAR
Definition: retypes.h:7
ULONG Signature
Definition: disk.h:75
#define IOCTL_DISK_GET_DRIVE_GEOMETRY_EX
Definition: ntddk_ex.h:208
#define IN
Definition: typedefs.h:38
USHORT MasterBootRecordMagic
Definition: disk.h:78
Definition: disk.h:53
#define TRUE
Definition: types.h:120
NTSYSAPI VOID NTAPI RtlCopyMemory(VOID UNALIGNED *Destination, CONST VOID UNALIGNED *Source, ULONG Length)
NTSTATUS NTAPI FstubSetPartitionInformationEFI(IN PDISK_INFORMATION Disk, IN ULONG PartitionNumber, IN SET_PARTITION_INFORMATION_GPT *PartitionInfo)
Definition: fstubex.c:1228
struct _DISK_INFORMATION DISK_INFORMATION
LARGE_INTEGER PartitionLength
Definition: ntdddisk.h:394
#define STATUS_INSUFFICIENT_RESOURCES
Definition: udferr_usr.h:158
PSTR ArcBootDeviceName
Definition: arc.h:503
NTSTATUS NTAPI FstubWriteBootSectorEFI(IN PDISK_INFORMATION Disk)
Definition: fstubex.c:1405
ULONG PartitionSectorCount
Definition: disk.h:65
_In_ PFCB _In_ LONGLONG StartingOffset
Definition: cdprocs.h:282
struct _Entry Entry
Definition: kefuncs.h:640
UCHAR StartSector
Definition: parttest.c:78
UCHAR EndCylinder
Definition: disk.h:63
PIRP NTAPI IoBuildSynchronousFsdRequest(IN ULONG MajorFunction, IN PDEVICE_OBJECT DeviceObject, IN PVOID Buffer, IN ULONG Length, IN PLARGE_INTEGER StartingOffset, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock)
Definition: irp.c:1069
NTSTATUS NTAPI IoReadDiskSignature(IN PDEVICE_OBJECT DeviceObject, IN ULONG BytesPerSector, OUT PDISK_SIGNATURE Signature)
Definition: fstubex.c:2141
PCONFIGURATION_INFORMATION NTAPI IoGetConfigurationInformation(VOID)
Definition: iorsrce.c:830
_In_ PIRP Irp
Definition: csq.h:116
VOID NTAPI FstubDbgPrintSetPartitionEx(IN PSET_PARTITION_INFORMATION_EX PartitionEntry, IN ULONG PartitionNumber)
Definition: fstubex.c:627
PCHAR ArcName
Definition: arc.h:210
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
UCHAR EndHead
Definition: parttest.c:81
UCHAR StartHead
Definition: disk.h:57
VOID NTAPI FstubFreeDiskInformation(IN PDISK_INFORMATION DiskBuffer)
Definition: fstubex.c:704
ULONG PartitionSectorCount
Definition: parttest.c:85
DISK_GEOMETRY_EX DiskGeometry
Definition: fstubex.c:21
unsigned char * PUCHAR
Definition: retypes.h:3
char CHAR
Definition: xmlstorage.h:175
PDRIVE_LAYOUT_INFORMATION NTAPI FstubConvertExtendedToLayout(IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx)
Definition: fstubex.c:266
UCHAR SystemIndicator
Definition: disk.h:60
LONG NTSTATUS
Definition: precomp.h:26
NTSTATUS NTAPI FstubCreateDiskMBR(IN PDEVICE_OBJECT DeviceObject, IN PCREATE_DISK_MBR DiskInfo)
Definition: fstubex.c:334
#define PARTITION_TABLE_OFFSET
Definition: hal.h:243
NTSTATUS NTAPI FstubReadHeaderEFI(IN PDISK_INFORMATION Disk, IN BOOLEAN ReadBackupTable, PEFI_PARTITION_HEADER *HeaderBuffer)
Definition: fstubex.c:811
_Inout_ __drv_aliasesMem PSLIST_ENTRY _Inout_ PSLIST_ENTRY _In_ ULONG Count
Definition: exfuncs.h:1015
NTSTATUS NTAPI FstubReadPartitionTableMBR(IN PDISK_INFORMATION Disk, IN BOOLEAN ReturnRecognizedPartitions, OUT struct _DRIVE_LAYOUT_INFORMATION_EX **ReturnedDriveLayout)
Definition: fstubex.c:1109
PDEVICE_OBJECT DeviceObject
Definition: fstubex.c:19
ULONGLONG EndingLBA
Definition: fstubex.c:51
NTSTATUS NTAPI IoGetDeviceObjectPointer(IN PUNICODE_STRING ObjectName, IN ACCESS_MASK DesiredAccess, OUT PFILE_OBJECT *FileObject, OUT PDEVICE_OBJECT *DeviceObject)
Definition: device.c:1434
NTSTATUS NTAPI FstubCreateDiskEFI(IN PDEVICE_OBJECT DeviceObject, IN PCREATE_DISK_GPT DiskInfo)
Definition: fstubex.c:380
ULONG BytesPerSector
Definition: ntdddisk.h:376
VOID NTAPI ObDereferenceObject(IN PVOID Object)
Definition: obref.c:375
static WCHAR String[]
Definition: stringtable.c:55
USHORT Reserved
Definition: disk.h:76
NTSTATUS NTAPI IoReadPartitionTableEx(IN PDEVICE_OBJECT DeviceObject, IN struct _DRIVE_LAYOUT_INFORMATION_EX **DriveLayout)
Definition: fstubex.c:2247
#define EFI_GUID_STRING_SIZE
Definition: fstubex.c:90
NTSTATUS NTAPI FstubReadPartitionTableEFI(IN PDISK_INFORMATION Disk, IN BOOLEAN ReadBackupTable, OUT struct _DRIVE_LAYOUT_INFORMATION_EX **DriveLayout)
Definition: fstubex.c:958
_In_ ULONG _In_ ULONG PartitionNumber
Definition: iofuncs.h:2056
ULONG SectorCountBeforePartition
Definition: parttest.c:84
NTSYSAPI BOOLEAN NTAPI RtlEqualString(PSTRING String1, PSTRING String2, BOOLEAN CaseInSensitive)
NTSTATUS NTAPI KeWaitForSingleObject(IN PVOID Object, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: wait.c:416
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
struct _PARTITION_TABLE_ENTRY * PPARTITION_TABLE_ENTRY
PARTITION_INFORMATION_MBR Mbr
Definition: imports.h:226
#define PAGED_CODE()
Definition: video.h:57
VOID NTAPI FstubDbgPrintDriveLayoutEx(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout)
Definition: fstubex.c:547
NTSYSAPI VOID NTAPI RtlInitAnsiString(PANSI_STRING DestinationString, PCSZ SourceString)
uint32_t ULONG_PTR
Definition: typedefs.h:63
LARGE_INTEGER DiskSize
Definition: ntdddisk.h:381
ULONG SectorSize
Definition: fstubex.c:20
UCHAR SystemIndicator
Definition: parttest.c:80
NTSTATUS NTAPI FstubDetectPartitionStyle(IN PDISK_INFORMATION Disk, IN PARTITION_STYLE *PartitionStyle)
Definition: fstubex.c:657
PARTITION_INFORMATION_GPT Gpt
Definition: imports.h:227
#define sprintf(buf, format,...)
Definition: sprintf.c:55
PARTITION_STYLE PartitionStyle
Definition: imports.h:220
NTSTATUS NTAPI FstubWriteSector(IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN ULONGLONG StartingSector OPTIONAL, IN PUSHORT Buffer)
Definition: fstubex.c:1723
ULONGLONG LastUsableLBA
Definition: fstubex.c:37
UCHAR StartSector
Definition: disk.h:58
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
NTSTATUS NTAPI FstubAllocateDiskInformation(IN PDEVICE_OBJECT DeviceObject, OUT PDISK_INFORMATION *DiskBuffer, PDISK_GEOMETRY_EX DiskGeometry OPTIONAL)
Definition: fstubex.c:204
ULONG SizeOfPartitionEntry
Definition: fstubex.c:41
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
UCHAR MasterBootRecordCodeAndData[0x1b8]
Definition: disk.h:74
_In_ ULONG _In_ ULONG Offset
Definition: ntddpcm.h:101
struct _PARTITION_TABLE_ENTRY PARTITION_TABLE_ENTRY
NTSTATUS NTAPI IoCreateDisk(IN PDEVICE_OBJECT DeviceObject, IN struct _CREATE_DISK *Disk)
Definition: fstubex.c:1781
struct _EFI_PARTITION_ENTRY EFI_PARTITION_ENTRY
#define EFI_HEADER_REVISION_1
Definition: fstubex.c:86
DISK_GEOMETRY Geometry
Definition: ntdddisk.h:380
_In_ PVOID _In_ ULONG Event
Definition: iotypes.h:434
unsigned char BOOLEAN
static GUID * Guid
Definition: apphelp.c:93
smooth NULL
Definition: ftsmooth.c:416
PARTITION_INFORMATION PartitionEntry[1]
Definition: ntdddisk.h:467
struct _BOOTDISK_INFORMATION_EX BOOTDISK_INFORMATION_EX
ULONGLONG AlternateLBA
Definition: fstubex.c:35
UCHAR EndHead
Definition: disk.h:61
#define SL_OVERRIDE_VERIFY_VOLUME
Definition: iotypes.h:1779
void DPRINT(...)
Definition: polytest.cpp:61
#define IS_VALID_DISK_INFO(Disk)
Definition: fstubex.c:92
Definition: bufpool.h:45
_Inout_ PFILE_OBJECT FileObject
Definition: cdprocs.h:593
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define ULL(a, b)
Definition: format_msg.c:27
ULONG SectorCountBeforePartition
Definition: disk.h:64
VOID NTAPI FstubAdjustPartitionCount(IN ULONG SectorSize, IN OUT PULONG PartitionCount)
Definition: fstubex.c:168
struct _MASTER_BOOT_RECORD MASTER_BOOT_RECORD
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
NTSTATUS NTAPI FstubWritePartitionTableEFI(IN PDISK_INFORMATION Disk, IN GUID DiskGUID, IN ULONG MaxPartitionCount, IN ULONGLONG FirstUsableLBA, IN ULONGLONG LastUsableLBA, IN BOOLEAN WriteBackupTable, IN ULONG PartitionCount, IN PPARTITION_INFORMATION_EX PartitionEntries OPTIONAL)
Definition: fstubex.c:1611
NTSTATUS NTAPI FstubReadSector(IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN ULONGLONG StartingSector OPTIONAL, OUT PUSHORT Buffer)
Definition: fstubex.c:1175
ULONGLONG FirstUsableLBA
Definition: fstubex.c:36
if(!(yy_init))
Definition: macro.lex.yy.c:714
#define BOOT_RECORD_SIGNATURE
Definition: parttest.c:17
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define STATUS_PENDING
Definition: ntstatus.h:82
LARGE_INTEGER StartingOffset
Definition: ntdddisk.h:393
DRIVE_LAYOUT_INFORMATION_MBR Mbr
Definition: ntdddisk.h:485
uint64_t ULONGLONG
Definition: typedefs.h:65
NTSTATUS NTAPI FstubCreateDiskRaw(IN PDEVICE_OBJECT DeviceObject)
Definition: fstubex.c:448
struct _PARTITION_DESCRIPTOR * PPARTITION_DESCRIPTOR
PARC_DISK_INFORMATION ArcDiskInformation
Definition: arc.h:509
Definition: parttest.c:75
_In_ ULONG _In_ struct _SET_PARTITION_INFORMATION_EX * PartitionInfo
Definition: iofuncs.h:2101
UCHAR EndCylinder
Definition: parttest.c:83
UCHAR BootIndicator
Definition: disk.h:55
#define for
Definition: utility.h:88
UCHAR CheckSum(LPSTR p, ULONG Len)
Definition: serial.c:197
GUID PartitionType
Definition: fstubex.c:48
NTSYSAPI VOID NTAPI RtlFreeUnicodeString(PUNICODE_STRING UnicodeString)
LARGE_INTEGER PartitionLength
Definition: imports.h:222
#define TAG_FSTUB
Definition: fstubex.c:80
struct _EFI_PARTITION_ENTRY * PEFI_PARTITION_ENTRY
#define EFI_HEADER_SIGNATURE
Definition: fstubex.c:84
NTSTATUS NTAPI IoSetPartitionInformationEx(IN PDEVICE_OBJECT DeviceObject, IN ULONG PartitionNumber, IN struct _SET_PARTITION_INFORMATION_EX *PartitionInfo)
Definition: fstubex.c:2314
* PFILE_OBJECT
Definition: iotypes.h:1954
PARTITION_TABLE_ENTRY PartitionTable[4]
Definition: disk.h:77
#define FILE_READ_ATTRIBUTES
Definition: nt_native.h:647
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
NTSTATUS NTAPI FstubGetDiskGeometry(IN PDEVICE_OBJECT DeviceObject, OUT PDISK_GEOMETRY_EX Geometry)
Definition: fstubex.c:718
#define ExAllocatePoolWithTag(hernya, size, tag)
Definition: env_spec_w32.h:350
BOOLEAN RewritePartition
Definition: ntdddisk.h:400
LARGE_INTEGER StartingOffset
Definition: imports.h:221
unsigned char UCHAR
Definition: xmlstorage.h:181
Definition: fstubex.c:46
#define PARTITION_ENTRY_SIZE
Definition: fstubex.c:82
NTSTATUS NTAPI IoVerifyPartitionTable(IN PDEVICE_OBJECT DeviceObject, IN BOOLEAN FixErrors)
Definition: fstubex.c:2379
NTSTATUS NTAPI FstubWriteEntryEFI(IN PDISK_INFORMATION Disk, IN ULONG PartitionsSizeSector, IN ULONG PartitionEntryNumber, IN PEFI_PARTITION_ENTRY PartitionEntry, IN BOOLEAN WriteBackupTable, IN BOOLEAN ForceWrite, OUT PULONG PartitionEntryCRC32 OPTIONAL)
Definition: fstubex.c:1456
_In_ ULONG _In_ BOOLEAN ReturnRecognizedPartitions
Definition: iofuncs.h:2046
enum _PARTITION_STYLE PARTITION_STYLE
#define BOOT_SIGNATURE_OFFSET
Definition: hal.h:244
Definition: typedefs.h:117
NTSTATUS NTAPI IoWritePartitionTableEx(IN PDEVICE_OBJECT DeviceObject, IN struct _DRIVE_LAYOUT_INFORMATION_EX *DriveLayout)
Definition: fstubex.c:2431
VOID NTAPI FstubDbgPrintPartitionEx(IN PPARTITION_INFORMATION_EX PartitionEntry, IN ULONG PartitionNumber)
Definition: fstubex.c:588
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
static const WCHAR Cleanup[]
Definition: register.c:80
__drv_aliasesMem FORCEINLINE PIO_STACK_LOCATION IoGetNextIrpStackLocation(_In_ PIRP Irp)
Definition: iofuncs.h:2647
ULONGLONG StartingLBA
Definition: fstubex.c:50
NTSTATUS FASTCALL IoReadPartitionTable(IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN BOOLEAN ReturnRecognizedPartitions, OUT PDRIVE_LAYOUT_INFORMATION *PartitionBuffer)
Definition: partition.c:310
PLOADER_PARAMETER_BLOCK IopLoaderBlock
Definition: iomgr.c:88
Status
Definition: gdiplustypes.h:24
UCHAR EndSector
Definition: disk.h:62
PUSHORT Buffer
Definition: fstubex.c:22
IN PDEVICE_OBJECT DeviceObject
Definition: fatprocs.h:1560
VOID NTAPI FstubCopyEntryEFI(OUT PEFI_PARTITION_ENTRY Entry, IN PPARTITION_INFORMATION_EX Partition, ULONG SectorSize)
Definition: fstubex.c:313
ULONGLONG Attributes
Definition: fstubex.c:52
PCHAR NTAPI FstubDbgGuidToString(IN PGUID Guid, OUT PCHAR String)
Definition: fstubex.c:525
BOOLEAN NTAPI IopVerifyDiskSignature(IN PDRIVE_LAYOUT_INFORMATION_EX DriveLayout, IN PARC_DISK_SIGNATURE ArcDiskSignature, OUT PULONG Signature)
Definition: arcname.c:945
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
NTSYSAPI ULONG NTAPI RtlComputeCrc32(_In_ ULONG InitialCrc, _In_ PUCHAR Buffer, _In_ ULONG Length)
unsigned short USHORT
Definition: pedump.c:61
LARGE_INTEGER StartingUsableOffset
Definition: ntdddisk.h:476
NTSYSAPI NTSTATUS NTAPI RtlAnsiStringToUnicodeString(PUNICODE_STRING DestinationString, PANSI_STRING SourceString, BOOLEAN AllocateDestinationString)
UCHAR StartCylinder
Definition: disk.h:59
#define STATUS_NO_MEMORY
Definition: ntstatus.h:246
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
struct _EFI_PARTITION_HEADER * PEFI_PARTITION_HEADER
unsigned int * PULONG
Definition: retypes.h:1
NTSTATUS NTAPI IoCallDriver(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)
Definition: irp.c:1218
struct _MASTER_BOOT_RECORD * PMASTER_BOOT_RECORD
BOOL FixErrors
Definition: chkdsk.c:69
PIRP NTAPI IoBuildDeviceIoControlRequest(IN ULONG IoControlCode, IN PDEVICE_OBJECT DeviceObject, IN PVOID InputBuffer, IN ULONG InputBufferLength, IN PVOID OutputBuffer, IN ULONG OutputBufferLength, IN BOOLEAN InternalDeviceIoControl, IN PKEVENT Event, IN PIO_STATUS_BLOCK IoStatusBlock)
Definition: irp.c:881
#define IRP_MJ_READ
Definition: rdpdr.c:46
ULONGLONG SectorCount
Definition: fstubex.c:23
PARTITION_INFORMATION_EX PartitionEntry[1]
Definition: ntdddisk.h:488
#define OUT
Definition: typedefs.h:39
NTSTATUS FASTCALL IoSetPartitionInformation(IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN ULONG PartitionNumber, IN ULONG PartitionType)
Definition: ntoskrnl.c:64
__GNU_EXTENSION typedef unsigned __int64 * PULONGLONG
Definition: ntbasedef.h:390
#define STATUS_DISK_CORRUPT_ERROR
Definition: udferr_usr.h:147
NTSTATUS NTAPI FstubWritePartitionTableMBR(IN PDISK_INFORMATION Disk, IN PDRIVE_LAYOUT_INFORMATION_EX LayoutEx)
Definition: fstubex.c:1692
LIST_ENTRY DiskSignatureListHead
Definition: arc.h:221
CHAR PartitionType
Definition: part_xbox.c:33
#define STATUS_NOT_SUPPORTED
Definition: ntstatus.h:409
unsigned int ULONG
Definition: retypes.h:1
#define EFI_PMBR_OSTYPE_EFI
Definition: fstubex.c:88
ULONGLONG MyLBA
Definition: fstubex.c:34
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
LARGE_INTEGER UsableLength
Definition: ntdddisk.h:477
NTSTATUS NTAPI FstubWriteHeaderEFI(IN PDISK_INFORMATION Disk, IN ULONG PartitionsSizeSector, IN GUID DiskGUID, IN ULONG NumberOfEntries, IN ULONGLONG FirstUsableLBA, IN ULONGLONG LastUsableLBA, IN ULONG PartitionEntryCRC32, IN BOOLEAN WriteBackupTable)
Definition: fstubex.c:1523
#define IRP_MJ_WRITE
Definition: rdpdr.c:47
struct _BOOTDISK_INFORMATION_EX * PBOOTDISK_INFORMATION_EX
BOOLEAN RecognizedPartition
Definition: ntdddisk.h:399
struct _EFI_PARTITION_HEADER EFI_PARTITION_HEADER
NTSTATUS FASTCALL IoWritePartitionTable(IN PDEVICE_OBJECT DeviceObject, IN ULONG SectorSize, IN ULONG SectorsPerTrack, IN ULONG NumberOfHeads, IN PDRIVE_LAYOUT_INFORMATION PartitionBuffer)
Definition: ntoskrnl.c:87
#define ExFreePoolWithTag(_P, _T)
Definition: module.h:1099
_In_ ULONG SectorSize
Definition: halfuncs.h:291
DRIVE_LAYOUT_INFORMATION_GPT Gpt
Definition: ntdddisk.h:486
IN BOOLEAN OUT PSTR Buffer
Definition: progress.h:34
GUID UniquePartition
Definition: fstubex.c:49
return STATUS_SUCCESS
Definition: btrfs.c:2725
ULONGLONG Signature
Definition: fstubex.c:29
static const WCHAR Signature[]
Definition: parser.c:141
UCHAR EndSector
Definition: parttest.c:82
ULONG PartitionEntryCRC32
Definition: fstubex.c:42
unsigned short * PUSHORT
Definition: retypes.h:2
#define STATUS_TOO_LATE
Definition: ntstatus.h:612
base of all file and directory entries
Definition: entries.h:82
WCHAR Name[0x24]
Definition: fstubex.c:53
#define ExFreePool(addr)
Definition: env_spec_w32.h:352
#define IOCTL_DISK_GET_DRIVE_GEOMETRY
Definition: cdrw_usr.h:169
ULONGLONG PartitionEntryLBA
Definition: fstubex.c:39
#define IOCTL_DISK_GET_PARTITION_INFO_EX
Definition: ntddk_ex.h:206
LONGLONG QuadPart
Definition: typedefs.h:112
struct _DISK_INFORMATION * PDISK_INFORMATION
#define STATUS_DEVICE_NOT_READY
Definition: shellext.h:65
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68