Minor changes for ATAPI Srb Functions
[reactos.git] / base / system / diskpart / partlist.c
1 /*
2 * PROJECT: ReactOS DiskPart
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/diskpart/partlist.c
5 * PURPOSE: Manages all the partitions of the OS in an interactive way
6 * PROGRAMMERS: Eric Kohl
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include "diskpart.h"
12
13 #include <stdlib.h>
14 #include <winbase.h>
15 #include <wincon.h>
16 #include <winuser.h>
17
18 #include <ntddscsi.h>
19
20 #define NDEBUG
21 #include <debug.h>
22
23 #define InsertAscendingList(ListHead, NewEntry, Type, ListEntryField, SortField)\
24 {\
25 PLIST_ENTRY current;\
26 \
27 current = (ListHead)->Flink;\
28 while (current != (ListHead))\
29 {\
30 if (CONTAINING_RECORD(current, Type, ListEntryField)->SortField >=\
31 (NewEntry)->SortField)\
32 {\
33 break;\
34 }\
35 current = current->Flink;\
36 }\
37 \
38 InsertTailList(current, &((NewEntry)->ListEntryField));\
39 }
40
41 /* We have to define it there, because it is not in the MS DDK */
42 #define PARTITION_EXT2 0x83
43
44 #define PARTITION_TBL_SIZE 4
45
46 #include <pshpack1.h>
47
48 typedef struct _PARTITION
49 {
50 unsigned char BootFlags; /* bootable? 0=no, 128=yes */
51 unsigned char StartingHead; /* beginning head number */
52 unsigned char StartingSector; /* beginning sector number */
53 unsigned char StartingCylinder; /* 10 bit nmbr, with high 2 bits put in begsect */
54 unsigned char PartitionType; /* Operating System type indicator code */
55 unsigned char EndingHead; /* ending head number */
56 unsigned char EndingSector; /* ending sector number */
57 unsigned char EndingCylinder; /* also a 10 bit nmbr, with same high 2 bit trick */
58 unsigned int StartingBlock; /* first sector relative to start of disk */
59 unsigned int SectorCount; /* number of sectors in partition */
60 } PARTITION, *PPARTITION;
61
62 typedef struct _PARTITION_SECTOR
63 {
64 UCHAR BootCode[440]; /* 0x000 */
65 ULONG Signature; /* 0x1B8 */
66 UCHAR Reserved[2]; /* 0x1BC */
67 PARTITION Partition[PARTITION_TBL_SIZE]; /* 0x1BE */
68 USHORT Magic; /* 0x1FE */
69 } PARTITION_SECTOR, *PPARTITION_SECTOR;
70
71 #include <poppack.h>
72
73
74 /* GLOBALS ********************************************************************/
75
76 LIST_ENTRY DiskListHead;
77 LIST_ENTRY BiosDiskListHead;
78
79 PDISKENTRY CurrentDisk = NULL;
80 PPARTENTRY CurrentPartition = NULL;
81
82
83 /* FUNCTIONS ******************************************************************/
84
85 ULONGLONG
86 AlignDown(
87 IN ULONGLONG Value,
88 IN ULONG Alignment)
89 {
90 ULONGLONG Temp;
91
92 Temp = Value / Alignment;
93
94 return Temp * Alignment;
95 }
96
97 static
98 VOID
99 GetDriverName(
100 PDISKENTRY DiskEntry)
101 {
102 RTL_QUERY_REGISTRY_TABLE QueryTable[2];
103 WCHAR KeyName[32];
104 NTSTATUS Status;
105
106 RtlInitUnicodeString(&DiskEntry->DriverName,
107 NULL);
108
109 swprintf(KeyName,
110 L"\\Scsi\\Scsi Port %lu",
111 DiskEntry->Port);
112
113 RtlZeroMemory(&QueryTable,
114 sizeof(QueryTable));
115
116 QueryTable[0].Name = L"Driver";
117 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT;
118 QueryTable[0].EntryContext = &DiskEntry->DriverName;
119
120 Status = RtlQueryRegistryValues(RTL_REGISTRY_DEVICEMAP,
121 KeyName,
122 QueryTable,
123 NULL,
124 NULL);
125 if (!NT_SUCCESS(Status))
126 {
127 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status);
128 }
129 }
130
131 static
132 NTSTATUS
133 NTAPI
134 DiskIdentifierQueryRoutine(
135 PWSTR ValueName,
136 ULONG ValueType,
137 PVOID ValueData,
138 ULONG ValueLength,
139 PVOID Context,
140 PVOID EntryContext)
141 {
142 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
143 UNICODE_STRING NameU;
144
145 if (ValueType == REG_SZ &&
146 ValueLength == 20 * sizeof(WCHAR))
147 {
148 NameU.Buffer = (PWCHAR)ValueData;
149 NameU.Length = NameU.MaximumLength = 8 * sizeof(WCHAR);
150 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Checksum);
151
152 NameU.Buffer = (PWCHAR)ValueData + 9;
153 RtlUnicodeStringToInteger(&NameU, 16, &BiosDiskEntry->Signature);
154
155 return STATUS_SUCCESS;
156 }
157
158 return STATUS_UNSUCCESSFUL;
159 }
160
161 static
162 NTSTATUS
163 NTAPI
164 DiskConfigurationDataQueryRoutine(
165 PWSTR ValueName,
166 ULONG ValueType,
167 PVOID ValueData,
168 ULONG ValueLength,
169 PVOID Context,
170 PVOID EntryContext)
171 {
172 PBIOSDISKENTRY BiosDiskEntry = (PBIOSDISKENTRY)Context;
173 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
174 PCM_DISK_GEOMETRY_DEVICE_DATA DiskGeometry;
175 ULONG i;
176
177 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
178 ValueLength < sizeof(CM_FULL_RESOURCE_DESCRIPTOR))
179 return STATUS_UNSUCCESSFUL;
180
181 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
182
183 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
184 #if 0
185 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
186 FullResourceDescriptor->PartialResourceList.Revision != 1)
187 return STATUS_UNSUCCESSFUL;
188 #endif
189
190 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
191 {
192 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
193 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize != sizeof(CM_DISK_GEOMETRY_DEVICE_DATA))
194 continue;
195
196 DiskGeometry = (PCM_DISK_GEOMETRY_DEVICE_DATA)&FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1];
197 BiosDiskEntry->DiskGeometry = *DiskGeometry;
198
199 return STATUS_SUCCESS;
200 }
201
202 return STATUS_UNSUCCESSFUL;
203 }
204
205 static
206 NTSTATUS
207 NTAPI
208 SystemConfigurationDataQueryRoutine(
209 PWSTR ValueName,
210 ULONG ValueType,
211 PVOID ValueData,
212 ULONG ValueLength,
213 PVOID Context,
214 PVOID EntryContext)
215 {
216 PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor;
217 PCM_INT13_DRIVE_PARAMETER* Int13Drives = (PCM_INT13_DRIVE_PARAMETER*)Context;
218 ULONG i;
219
220 if (ValueType != REG_FULL_RESOURCE_DESCRIPTOR ||
221 ValueLength < sizeof (CM_FULL_RESOURCE_DESCRIPTOR))
222 return STATUS_UNSUCCESSFUL;
223
224 FullResourceDescriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)ValueData;
225
226 /* Hm. Version and Revision are not set on Microsoft Windows XP... */
227 #if 0
228 if (FullResourceDescriptor->PartialResourceList.Version != 1 ||
229 FullResourceDescriptor->PartialResourceList.Revision != 1)
230 return STATUS_UNSUCCESSFUL;
231 #endif
232
233 for (i = 0; i < FullResourceDescriptor->PartialResourceList.Count; i++)
234 {
235 if (FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].Type != CmResourceTypeDeviceSpecific ||
236 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize % sizeof(CM_INT13_DRIVE_PARAMETER) != 0)
237 continue;
238
239 *Int13Drives = (CM_INT13_DRIVE_PARAMETER*)RtlAllocateHeap(RtlGetProcessHeap(), 0,
240 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
241 if (*Int13Drives == NULL)
242 return STATUS_NO_MEMORY;
243
244 memcpy(*Int13Drives,
245 &FullResourceDescriptor->PartialResourceList.PartialDescriptors[i + 1],
246 FullResourceDescriptor->PartialResourceList.PartialDescriptors[i].u.DeviceSpecificData.DataSize);
247 return STATUS_SUCCESS;
248 }
249
250 return STATUS_UNSUCCESSFUL;
251 }
252
253
254 #define ROOT_NAME L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System\\MultifunctionAdapter"
255
256 static
257 VOID
258 EnumerateBiosDiskEntries(VOID)
259 {
260 RTL_QUERY_REGISTRY_TABLE QueryTable[3];
261 WCHAR Name[120];
262 ULONG AdapterCount;
263 ULONG DiskCount;
264 NTSTATUS Status;
265 PCM_INT13_DRIVE_PARAMETER Int13Drives;
266 PBIOSDISKENTRY BiosDiskEntry;
267
268 memset(QueryTable, 0, sizeof(QueryTable));
269
270 QueryTable[1].Name = L"Configuration Data";
271 QueryTable[1].QueryRoutine = SystemConfigurationDataQueryRoutine;
272 Int13Drives = NULL;
273 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
274 L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System",
275 &QueryTable[1],
276 (PVOID)&Int13Drives,
277 NULL);
278 if (!NT_SUCCESS(Status))
279 {
280 DPRINT1("Unable to query the 'Configuration Data' key in '\\Registry\\Machine\\HARDWARE\\DESCRIPTION\\System', status=%lx\n", Status);
281 return;
282 }
283
284 AdapterCount = 0;
285 while (1)
286 {
287 swprintf(Name, L"%s\\%lu", ROOT_NAME, AdapterCount);
288 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
289 Name,
290 &QueryTable[2],
291 NULL,
292 NULL);
293 if (!NT_SUCCESS(Status))
294 {
295 break;
296 }
297
298 swprintf(Name, L"%s\\%lu\\DiskController", ROOT_NAME, AdapterCount);
299 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
300 Name,
301 &QueryTable[2],
302 NULL,
303 NULL);
304 if (NT_SUCCESS(Status))
305 {
306 while (1)
307 {
308 swprintf(Name, L"%s\\%lu\\DiskController\\0", ROOT_NAME, AdapterCount);
309 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
310 Name,
311 &QueryTable[2],
312 NULL,
313 NULL);
314 if (!NT_SUCCESS(Status))
315 {
316 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
317 return;
318 }
319
320 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral", ROOT_NAME, AdapterCount);
321 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
322 Name,
323 &QueryTable[2],
324 NULL,
325 NULL);
326 if (NT_SUCCESS(Status))
327 {
328 QueryTable[0].Name = L"Identifier";
329 QueryTable[0].QueryRoutine = DiskIdentifierQueryRoutine;
330 QueryTable[1].Name = L"Configuration Data";
331 QueryTable[1].QueryRoutine = DiskConfigurationDataQueryRoutine;
332
333 DiskCount = 0;
334 while (1)
335 {
336 BiosDiskEntry = (BIOSDISKENTRY*)RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(BIOSDISKENTRY));
337 if (BiosDiskEntry == NULL)
338 {
339 break;
340 }
341
342 swprintf(Name, L"%s\\%lu\\DiskController\\0\\DiskPeripheral\\%lu", ROOT_NAME, AdapterCount, DiskCount);
343 Status = RtlQueryRegistryValues(RTL_REGISTRY_ABSOLUTE,
344 Name,
345 QueryTable,
346 (PVOID)BiosDiskEntry,
347 NULL);
348 if (!NT_SUCCESS(Status))
349 {
350 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry);
351 break;
352 }
353
354 BiosDiskEntry->DiskNumber = DiskCount;
355 BiosDiskEntry->Recognized = FALSE;
356
357 if (DiskCount < Int13Drives[0].NumberDrives)
358 {
359 BiosDiskEntry->Int13DiskData = Int13Drives[DiskCount];
360 }
361 else
362 {
363 DPRINT1("Didn't find int13 drive datas for disk %u\n", DiskCount);
364 }
365
366 InsertTailList(&BiosDiskListHead, &BiosDiskEntry->ListEntry);
367
368 DPRINT("DiskNumber: %lu\n", BiosDiskEntry->DiskNumber);
369 DPRINT("Signature: %08lx\n", BiosDiskEntry->Signature);
370 DPRINT("Checksum: %08lx\n", BiosDiskEntry->Checksum);
371 DPRINT("BytesPerSector: %lu\n", BiosDiskEntry->DiskGeometry.BytesPerSector);
372 DPRINT("NumberOfCylinders: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfCylinders);
373 DPRINT("NumberOfHeads: %lu\n", BiosDiskEntry->DiskGeometry.NumberOfHeads);
374 DPRINT("DriveSelect: %02x\n", BiosDiskEntry->Int13DiskData.DriveSelect);
375 DPRINT("MaxCylinders: %lu\n", BiosDiskEntry->Int13DiskData.MaxCylinders);
376 DPRINT("SectorsPerTrack: %d\n", BiosDiskEntry->Int13DiskData.SectorsPerTrack);
377 DPRINT("MaxHeads: %d\n", BiosDiskEntry->Int13DiskData.MaxHeads);
378 DPRINT("NumberDrives: %d\n", BiosDiskEntry->Int13DiskData.NumberDrives);
379
380 DiskCount++;
381 }
382 }
383
384 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
385 return;
386 }
387 }
388
389 AdapterCount++;
390 }
391
392 RtlFreeHeap(RtlGetProcessHeap(), 0, Int13Drives);
393 }
394
395
396 static
397 VOID
398 AddPartitionToDisk(
399 ULONG DiskNumber,
400 PDISKENTRY DiskEntry,
401 ULONG PartitionIndex,
402 BOOLEAN LogicalPartition)
403 {
404 PPARTITION_INFORMATION PartitionInfo;
405 PPARTENTRY PartEntry;
406
407 PartitionInfo = &DiskEntry->LayoutBuffer->PartitionEntry[PartitionIndex];
408 if (PartitionInfo->PartitionType == 0 ||
409 (LogicalPartition == TRUE && IsContainerPartition(PartitionInfo->PartitionType)))
410 return;
411
412 PartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
413 HEAP_ZERO_MEMORY,
414 sizeof(PARTENTRY));
415 if (PartEntry == NULL)
416 {
417 return;
418 }
419
420 PartEntry->DiskEntry = DiskEntry;
421
422 PartEntry->StartSector.QuadPart = (ULONGLONG)PartitionInfo->StartingOffset.QuadPart / DiskEntry->BytesPerSector;
423 PartEntry->SectorCount.QuadPart = (ULONGLONG)PartitionInfo->PartitionLength.QuadPart / DiskEntry->BytesPerSector;
424
425 PartEntry->BootIndicator = PartitionInfo->BootIndicator;
426 PartEntry->PartitionType = PartitionInfo->PartitionType;
427 PartEntry->HiddenSectors = PartitionInfo->HiddenSectors;
428
429 PartEntry->LogicalPartition = LogicalPartition;
430 PartEntry->IsPartitioned = TRUE;
431 PartEntry->PartitionNumber = PartitionInfo->PartitionNumber;
432 PartEntry->PartitionIndex = PartitionIndex;
433
434 if (IsContainerPartition(PartEntry->PartitionType))
435 {
436 PartEntry->FormatState = Unformatted;
437
438 if (LogicalPartition == FALSE && DiskEntry->ExtendedPartition == NULL)
439 DiskEntry->ExtendedPartition = PartEntry;
440 }
441 else if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
442 (PartEntry->PartitionType == PARTITION_FAT_16) ||
443 (PartEntry->PartitionType == PARTITION_HUGE) ||
444 (PartEntry->PartitionType == PARTITION_XINT13) ||
445 (PartEntry->PartitionType == PARTITION_FAT32) ||
446 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
447 {
448 #if 0
449 if (CheckFatFormat())
450 {
451 PartEntry->FormatState = Preformatted;
452 }
453 else
454 {
455 PartEntry->FormatState = Unformatted;
456 }
457 #endif
458 PartEntry->FormatState = Preformatted;
459 }
460 else if (PartEntry->PartitionType == PARTITION_EXT2)
461 {
462 #if 0
463 if (CheckExt2Format())
464 {
465 PartEntry->FormatState = Preformatted;
466 }
467 else
468 {
469 PartEntry->FormatState = Unformatted;
470 }
471 #endif
472 PartEntry->FormatState = Preformatted;
473 }
474 else if (PartEntry->PartitionType == PARTITION_IFS)
475 {
476 #if 0
477 if (CheckNtfsFormat())
478 {
479 PartEntry->FormatState = Preformatted;
480 }
481 else if (CheckHpfsFormat())
482 {
483 PartEntry->FormatState = Preformatted;
484 }
485 else
486 {
487 PartEntry->FormatState = Unformatted;
488 }
489 #endif
490 PartEntry->FormatState = Preformatted;
491 }
492 else
493 {
494 PartEntry->FormatState = UnknownFormat;
495 }
496
497 if (LogicalPartition)
498 InsertTailList(&DiskEntry->LogicalPartListHead,
499 &PartEntry->ListEntry);
500 else
501 InsertTailList(&DiskEntry->PrimaryPartListHead,
502 &PartEntry->ListEntry);
503 }
504
505
506 static
507 VOID
508 ScanForUnpartitionedDiskSpace(
509 PDISKENTRY DiskEntry)
510 {
511 ULONGLONG LastStartSector;
512 ULONGLONG LastSectorCount;
513 ULONGLONG LastUnusedSectorCount;
514 PPARTENTRY PartEntry;
515 PPARTENTRY NewPartEntry;
516 PLIST_ENTRY Entry;
517
518 DPRINT("ScanForUnpartitionedDiskSpace()\n");
519
520 if (IsListEmpty(&DiskEntry->PrimaryPartListHead))
521 {
522 DPRINT1("No primary partition!\n");
523
524 /* Create a partition table that represents the empty disk */
525 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
526 HEAP_ZERO_MEMORY,
527 sizeof(PARTENTRY));
528 if (NewPartEntry == NULL)
529 return;
530
531 NewPartEntry->DiskEntry = DiskEntry;
532
533 NewPartEntry->IsPartitioned = FALSE;
534 NewPartEntry->StartSector.QuadPart = (ULONGLONG)DiskEntry->SectorAlignment;
535 NewPartEntry->SectorCount.QuadPart = AlignDown(DiskEntry->SectorCount.QuadPart, DiskEntry->SectorAlignment) -
536 NewPartEntry->StartSector.QuadPart;
537
538 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
539 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
540 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
541
542 NewPartEntry->FormatState = Unformatted;
543
544 InsertTailList(&DiskEntry->PrimaryPartListHead,
545 &NewPartEntry->ListEntry);
546
547 return;
548 }
549
550 /* Start partition at head 1, cylinder 0 */
551 LastStartSector = DiskEntry->SectorAlignment;
552 LastSectorCount = 0ULL;
553 LastUnusedSectorCount = 0ULL;
554
555 Entry = DiskEntry->PrimaryPartListHead.Flink;
556 while (Entry != &DiskEntry->PrimaryPartListHead)
557 {
558 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
559
560 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
561 PartEntry->SectorCount.QuadPart != 0ULL)
562 {
563 LastUnusedSectorCount =
564 PartEntry->StartSector.QuadPart - (LastStartSector + LastSectorCount);
565
566 if (PartEntry->StartSector.QuadPart > (LastStartSector + LastSectorCount) &&
567 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
568 {
569 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
570
571 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
572 HEAP_ZERO_MEMORY,
573 sizeof(PARTENTRY));
574 if (NewPartEntry == NULL)
575 return;
576
577 NewPartEntry->DiskEntry = DiskEntry;
578
579 NewPartEntry->IsPartitioned = FALSE;
580 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
581 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
582 NewPartEntry->StartSector.QuadPart;
583
584 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
585 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
586 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
587
588 NewPartEntry->FormatState = Unformatted;
589
590 /* Insert the table into the list */
591 InsertTailList(&PartEntry->ListEntry,
592 &NewPartEntry->ListEntry);
593 }
594
595 LastStartSector = PartEntry->StartSector.QuadPart;
596 LastSectorCount = PartEntry->SectorCount.QuadPart;
597 }
598
599 Entry = Entry->Flink;
600 }
601
602 /* Check for trailing unpartitioned disk space */
603 if ((LastStartSector + LastSectorCount) < DiskEntry->SectorCount.QuadPart)
604 {
605 LastUnusedSectorCount = AlignDown(DiskEntry->SectorCount.QuadPart - (LastStartSector + LastSectorCount), DiskEntry->SectorAlignment);
606
607 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
608 {
609 DPRINT1("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
610
611 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
612 HEAP_ZERO_MEMORY,
613 sizeof(PARTENTRY));
614 if (NewPartEntry == NULL)
615 return;
616
617 NewPartEntry->DiskEntry = DiskEntry;
618
619 NewPartEntry->IsPartitioned = FALSE;
620 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
621 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
622 NewPartEntry->StartSector.QuadPart;
623
624 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
625 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
626 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
627
628 NewPartEntry->FormatState = Unformatted;
629
630 /* Append the table to the list */
631 InsertTailList(&DiskEntry->PrimaryPartListHead,
632 &NewPartEntry->ListEntry);
633 }
634 }
635
636 if (DiskEntry->ExtendedPartition != NULL)
637 {
638 if (IsListEmpty(&DiskEntry->LogicalPartListHead))
639 {
640 DPRINT1("No logical partition!\n");
641
642 /* Create a partition table entry that represents the empty extended partition */
643 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
644 HEAP_ZERO_MEMORY,
645 sizeof(PARTENTRY));
646 if (NewPartEntry == NULL)
647 return;
648
649 NewPartEntry->DiskEntry = DiskEntry;
650 NewPartEntry->LogicalPartition = TRUE;
651
652 NewPartEntry->IsPartitioned = FALSE;
653 NewPartEntry->StartSector.QuadPart = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
654 NewPartEntry->SectorCount.QuadPart = DiskEntry->ExtendedPartition->SectorCount.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment;
655
656 DPRINT1("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
657 DPRINT1("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
658 DPRINT1("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
659
660 NewPartEntry->FormatState = Unformatted;
661
662 InsertTailList(&DiskEntry->LogicalPartListHead,
663 &NewPartEntry->ListEntry);
664
665 return;
666 }
667
668 /* Start partition at head 1, cylinder 0 */
669 LastStartSector = DiskEntry->ExtendedPartition->StartSector.QuadPart + (ULONGLONG)DiskEntry->SectorAlignment;
670 LastSectorCount = 0ULL;
671 LastUnusedSectorCount = 0ULL;
672
673 Entry = DiskEntry->LogicalPartListHead.Flink;
674 while (Entry != &DiskEntry->LogicalPartListHead)
675 {
676 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
677
678 if (PartEntry->PartitionType != PARTITION_ENTRY_UNUSED ||
679 PartEntry->SectorCount.QuadPart != 0ULL)
680 {
681 LastUnusedSectorCount =
682 PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment - (LastStartSector + LastSectorCount);
683
684 if ((PartEntry->StartSector.QuadPart - (ULONGLONG)DiskEntry->SectorAlignment) > (LastStartSector + LastSectorCount) &&
685 LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
686 {
687 DPRINT("Unpartitioned disk space %I64u sectors\n", LastUnusedSectorCount);
688
689 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
690 HEAP_ZERO_MEMORY,
691 sizeof(PARTENTRY));
692 if (NewPartEntry == NULL)
693 return;
694
695 NewPartEntry->DiskEntry = DiskEntry;
696 NewPartEntry->LogicalPartition = TRUE;
697
698 NewPartEntry->IsPartitioned = FALSE;
699 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
700 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
701 NewPartEntry->StartSector.QuadPart;
702
703 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
704 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
705 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
706
707 NewPartEntry->FormatState = Unformatted;
708
709 /* Insert the table into the list */
710 InsertTailList(&PartEntry->ListEntry,
711 &NewPartEntry->ListEntry);
712 }
713
714 LastStartSector = PartEntry->StartSector.QuadPart;
715 LastSectorCount = PartEntry->SectorCount.QuadPart;
716 }
717
718 Entry = Entry->Flink;
719 }
720
721 /* Check for trailing unpartitioned disk space */
722 if ((LastStartSector + LastSectorCount) < DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart)
723 {
724 LastUnusedSectorCount = AlignDown(DiskEntry->ExtendedPartition->StartSector.QuadPart + DiskEntry->ExtendedPartition->SectorCount.QuadPart - (LastStartSector + LastSectorCount),
725 DiskEntry->SectorAlignment);
726
727 if (LastUnusedSectorCount >= (ULONGLONG)DiskEntry->SectorAlignment)
728 {
729 DPRINT("Unpartitioned disk space: %I64u sectors\n", LastUnusedSectorCount);
730
731 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(),
732 HEAP_ZERO_MEMORY,
733 sizeof(PARTENTRY));
734 if (NewPartEntry == NULL)
735 return;
736
737 NewPartEntry->DiskEntry = DiskEntry;
738 NewPartEntry->LogicalPartition = TRUE;
739
740 NewPartEntry->IsPartitioned = FALSE;
741 NewPartEntry->StartSector.QuadPart = LastStartSector + LastSectorCount;
742 NewPartEntry->SectorCount.QuadPart = AlignDown(NewPartEntry->StartSector.QuadPart + LastUnusedSectorCount, DiskEntry->SectorAlignment) -
743 NewPartEntry->StartSector.QuadPart;
744
745 DPRINT("First Sector: %I64u\n", NewPartEntry->StartSector.QuadPart);
746 DPRINT("Last Sector: %I64u\n", NewPartEntry->StartSector.QuadPart + NewPartEntry->SectorCount.QuadPart - 1);
747 DPRINT("Total Sectors: %I64u\n", NewPartEntry->SectorCount.QuadPart);
748
749 NewPartEntry->FormatState = Unformatted;
750
751 /* Append the table to the list */
752 InsertTailList(&DiskEntry->LogicalPartListHead,
753 &NewPartEntry->ListEntry);
754 }
755 }
756 }
757
758 DPRINT("ScanForUnpartitionedDiskSpace() done\n");
759 }
760
761
762 static
763 VOID
764 AddDiskToList(
765 HANDLE FileHandle,
766 ULONG DiskNumber)
767 {
768 DISK_GEOMETRY DiskGeometry;
769 SCSI_ADDRESS ScsiAddress;
770 PDISKENTRY DiskEntry;
771 IO_STATUS_BLOCK Iosb;
772 NTSTATUS Status;
773 PPARTITION_SECTOR Mbr;
774 PULONG Buffer;
775 LARGE_INTEGER FileOffset;
776 WCHAR Identifier[20];
777 ULONG Checksum;
778 ULONG Signature;
779 ULONG i;
780 PLIST_ENTRY ListEntry;
781 PBIOSDISKENTRY BiosDiskEntry;
782 ULONG LayoutBufferSize;
783 PDRIVE_LAYOUT_INFORMATION NewLayoutBuffer;
784
785 Status = NtDeviceIoControlFile(FileHandle,
786 NULL,
787 NULL,
788 NULL,
789 &Iosb,
790 IOCTL_DISK_GET_DRIVE_GEOMETRY,
791 NULL,
792 0,
793 &DiskGeometry,
794 sizeof(DISK_GEOMETRY));
795 if (!NT_SUCCESS(Status))
796 {
797 return;
798 }
799
800 if (DiskGeometry.MediaType != FixedMedia &&
801 DiskGeometry.MediaType != RemovableMedia)
802 {
803 return;
804 }
805
806 Status = NtDeviceIoControlFile(FileHandle,
807 NULL,
808 NULL,
809 NULL,
810 &Iosb,
811 IOCTL_SCSI_GET_ADDRESS,
812 NULL,
813 0,
814 &ScsiAddress,
815 sizeof(SCSI_ADDRESS));
816 if (!NT_SUCCESS(Status))
817 {
818 return;
819 }
820
821 Mbr = (PARTITION_SECTOR*)RtlAllocateHeap(RtlGetProcessHeap(),
822 0,
823 DiskGeometry.BytesPerSector);
824 if (Mbr == NULL)
825 {
826 return;
827 }
828
829 FileOffset.QuadPart = 0;
830 Status = NtReadFile(FileHandle,
831 NULL,
832 NULL,
833 NULL,
834 &Iosb,
835 (PVOID)Mbr,
836 DiskGeometry.BytesPerSector,
837 &FileOffset,
838 NULL);
839 if (!NT_SUCCESS(Status))
840 {
841 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr);
842 DPRINT1("NtReadFile failed, status=%x\n", Status);
843 return;
844 }
845 Signature = Mbr->Signature;
846
847 /* Calculate the MBR checksum */
848 Checksum = 0;
849 Buffer = (PULONG)Mbr;
850 for (i = 0; i < 128; i++)
851 {
852 Checksum += Buffer[i];
853 }
854 Checksum = ~Checksum + 1;
855
856 swprintf(Identifier, L"%08x-%08x-A", Checksum, Signature);
857 DPRINT("Identifier: %S\n", Identifier);
858
859 DiskEntry = RtlAllocateHeap(RtlGetProcessHeap(),
860 HEAP_ZERO_MEMORY,
861 sizeof(DISKENTRY));
862 if (DiskEntry == NULL)
863 {
864 return;
865 }
866
867 // DiskEntry->Checksum = Checksum;
868 // DiskEntry->Signature = Signature;
869 DiskEntry->BiosFound = FALSE;
870
871 /* Check if this disk has a valid MBR */
872 if (Mbr->BootCode[0] == 0 && Mbr->BootCode[1] == 0)
873 DiskEntry->NoMbr = TRUE;
874 else
875 DiskEntry->NoMbr = FALSE;
876
877 /* Free Mbr sector buffer */
878 RtlFreeHeap(RtlGetProcessHeap(), 0, Mbr);
879
880 ListEntry = BiosDiskListHead.Flink;
881 while (ListEntry != &BiosDiskListHead)
882 {
883 BiosDiskEntry = CONTAINING_RECORD(ListEntry, BIOSDISKENTRY, ListEntry);
884 /* FIXME:
885 * Compare the size from bios and the reported size from driver.
886 * If we have more than one disk with a zero or with the same signatur
887 * we must create new signatures and reboot. After the reboot,
888 * it is possible to identify the disks.
889 */
890 if (BiosDiskEntry->Signature == Signature &&
891 BiosDiskEntry->Checksum == Checksum &&
892 !BiosDiskEntry->Recognized)
893 {
894 if (!DiskEntry->BiosFound)
895 {
896 DiskEntry->BiosDiskNumber = BiosDiskEntry->DiskNumber;
897 DiskEntry->BiosFound = TRUE;
898 BiosDiskEntry->Recognized = TRUE;
899 }
900 else
901 {
902 }
903 }
904 ListEntry = ListEntry->Flink;
905 }
906
907 if (!DiskEntry->BiosFound)
908 {
909 #if 0
910 RtlFreeHeap(ProcessHeap, 0, DiskEntry);
911 return;
912 #else
913 DPRINT1("WARNING: Setup could not find a matching BIOS disk entry. Disk %d is not be bootable by the BIOS!\n", DiskNumber);
914 #endif
915 }
916
917 InitializeListHead(&DiskEntry->PrimaryPartListHead);
918 InitializeListHead(&DiskEntry->LogicalPartListHead);
919
920 DiskEntry->Cylinders = DiskGeometry.Cylinders.QuadPart;
921 DiskEntry->TracksPerCylinder = DiskGeometry.TracksPerCylinder;
922 DiskEntry->SectorsPerTrack = DiskGeometry.SectorsPerTrack;
923 DiskEntry->BytesPerSector = DiskGeometry.BytesPerSector;
924
925 DPRINT("Cylinders %I64u\n", DiskEntry->Cylinders);
926 DPRINT("TracksPerCylinder %I64u\n", DiskEntry->TracksPerCylinder);
927 DPRINT("SectorsPerTrack %I64u\n", DiskEntry->SectorsPerTrack);
928 DPRINT("BytesPerSector %I64u\n", DiskEntry->BytesPerSector);
929
930 DiskEntry->SectorCount.QuadPart = DiskGeometry.Cylinders.QuadPart *
931 (ULONGLONG)DiskGeometry.TracksPerCylinder *
932 (ULONGLONG)DiskGeometry.SectorsPerTrack;
933
934 DiskEntry->SectorAlignment = DiskGeometry.SectorsPerTrack;
935 DiskEntry->CylinderAlignment = DiskGeometry.SectorsPerTrack * DiskGeometry.TracksPerCylinder;
936
937 DPRINT1("SectorCount: %I64u\n", DiskEntry->SectorCount);
938 DPRINT1("SectorAlignment: %lu\n", DiskEntry->SectorAlignment);
939 DPRINT1("CylinderAlignment: %lu\n", DiskEntry->CylinderAlignment);
940
941 DiskEntry->DiskNumber = DiskNumber;
942 DiskEntry->Port = ScsiAddress.PortNumber;
943 DiskEntry->Bus = ScsiAddress.PathId;
944 DiskEntry->Id = ScsiAddress.TargetId;
945
946 GetDriverName(DiskEntry);
947
948 InsertAscendingList(&DiskListHead, DiskEntry, DISKENTRY, ListEntry, DiskNumber);
949
950 /* Allocate a layout buffer with 4 partition entries first */
951 LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
952 ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
953 DiskEntry->LayoutBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
954 HEAP_ZERO_MEMORY,
955 LayoutBufferSize);
956 if (DiskEntry->LayoutBuffer == NULL)
957 {
958 DPRINT1("Failed to allocate the disk layout buffer!\n");
959 return;
960 }
961
962 for (;;)
963 {
964 DPRINT1("Buffer size: %lu\n", LayoutBufferSize);
965 Status = NtDeviceIoControlFile(FileHandle,
966 NULL,
967 NULL,
968 NULL,
969 &Iosb,
970 IOCTL_DISK_GET_DRIVE_LAYOUT,
971 NULL,
972 0,
973 DiskEntry->LayoutBuffer,
974 LayoutBufferSize);
975 if (NT_SUCCESS(Status))
976 break;
977
978 if (Status != STATUS_BUFFER_TOO_SMALL)
979 {
980 DPRINT1("NtDeviceIoControlFile() failed (Status: 0x%08lx)\n", Status);
981 return;
982 }
983
984 LayoutBufferSize += 4 * sizeof(PARTITION_INFORMATION);
985 NewLayoutBuffer = RtlReAllocateHeap(RtlGetProcessHeap(),
986 HEAP_ZERO_MEMORY,
987 DiskEntry->LayoutBuffer,
988 LayoutBufferSize);
989 if (NewLayoutBuffer == NULL)
990 {
991 DPRINT1("Failed to reallocate the disk layout buffer!\n");
992 return;
993 }
994
995 DiskEntry->LayoutBuffer = NewLayoutBuffer;
996 }
997
998 DPRINT1("PartitionCount: %lu\n", DiskEntry->LayoutBuffer->PartitionCount);
999
1000 #ifdef DUMP_PARTITION_TABLE
1001 DumpPartitionTable(DiskEntry);
1002 #endif
1003
1004 if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart != 0 &&
1005 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionLength.QuadPart != 0 &&
1006 DiskEntry->LayoutBuffer->PartitionEntry[0].PartitionType != 0)
1007 {
1008 if ((DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart / DiskEntry->BytesPerSector) % DiskEntry->SectorsPerTrack == 0)
1009 {
1010 DPRINT("Use %lu Sector alignment!\n", DiskEntry->SectorsPerTrack);
1011 }
1012 else if (DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart % (1024 * 1024) == 0)
1013 {
1014 DPRINT1("Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1015 }
1016 else
1017 {
1018 DPRINT1("No matching aligment found! Partition 1 starts at %I64u\n", DiskEntry->LayoutBuffer->PartitionEntry[0].StartingOffset.QuadPart);
1019 }
1020 }
1021 else
1022 {
1023 DPRINT1("No valid partition table found! Use megabyte (%lu Sectors) alignment!\n", (1024 * 1024) / DiskEntry->BytesPerSector);
1024 }
1025
1026
1027 if (DiskEntry->LayoutBuffer->PartitionCount == 0)
1028 {
1029 DiskEntry->NewDisk = TRUE;
1030 DiskEntry->LayoutBuffer->PartitionCount = 4;
1031
1032 for (i = 0; i < 4; i++)
1033 DiskEntry->LayoutBuffer->PartitionEntry[i].RewritePartition = TRUE;
1034 }
1035 else
1036 {
1037 for (i = 0; i < 4; i++)
1038 {
1039 AddPartitionToDisk(DiskNumber, DiskEntry, i, FALSE);
1040 }
1041
1042 for (i = 4; i < DiskEntry->LayoutBuffer->PartitionCount; i += 4)
1043 {
1044 AddPartitionToDisk(DiskNumber, DiskEntry, i, TRUE);
1045 }
1046 }
1047
1048 ScanForUnpartitionedDiskSpace(DiskEntry);
1049 }
1050
1051
1052 NTSTATUS
1053 CreatePartitionList(VOID)
1054 {
1055 OBJECT_ATTRIBUTES ObjectAttributes;
1056 SYSTEM_DEVICE_INFORMATION Sdi;
1057 IO_STATUS_BLOCK Iosb;
1058 ULONG ReturnSize;
1059 NTSTATUS Status;
1060 ULONG DiskNumber;
1061 WCHAR Buffer[MAX_PATH];
1062 UNICODE_STRING Name;
1063 HANDLE FileHandle;
1064
1065 CurrentDisk = NULL;
1066 CurrentPartition = NULL;
1067
1068 // BootDisk = NULL;
1069 // BootPartition = NULL;
1070
1071 // TempDisk = NULL;
1072 // TempPartition = NULL;
1073 // FormatState = Start;
1074
1075 InitializeListHead(&DiskListHead);
1076 InitializeListHead(&BiosDiskListHead);
1077
1078 EnumerateBiosDiskEntries();
1079
1080 Status = NtQuerySystemInformation(SystemDeviceInformation,
1081 &Sdi,
1082 sizeof(SYSTEM_DEVICE_INFORMATION),
1083 &ReturnSize);
1084 if (!NT_SUCCESS(Status))
1085 {
1086 return Status;
1087 }
1088
1089 for (DiskNumber = 0; DiskNumber < Sdi.NumberOfDisks; DiskNumber++)
1090 {
1091 swprintf(Buffer,
1092 L"\\Device\\Harddisk%d\\Partition0",
1093 DiskNumber);
1094 RtlInitUnicodeString(&Name,
1095 Buffer);
1096
1097 InitializeObjectAttributes(&ObjectAttributes,
1098 &Name,
1099 0,
1100 NULL,
1101 NULL);
1102
1103 Status = NtOpenFile(&FileHandle,
1104 FILE_READ_DATA | FILE_READ_ATTRIBUTES | SYNCHRONIZE,
1105 &ObjectAttributes,
1106 &Iosb,
1107 FILE_SHARE_READ,
1108 FILE_SYNCHRONOUS_IO_NONALERT);
1109 if (NT_SUCCESS(Status))
1110 {
1111 AddDiskToList(FileHandle, DiskNumber);
1112
1113 NtClose(FileHandle);
1114 }
1115 }
1116
1117 // UpdateDiskSignatures(List);
1118
1119 // AssignDriveLetters(List);
1120
1121 return STATUS_SUCCESS;
1122 }
1123
1124
1125 VOID
1126 DestroyPartitionList(VOID)
1127 {
1128 PDISKENTRY DiskEntry;
1129 PBIOSDISKENTRY BiosDiskEntry;
1130 PPARTENTRY PartEntry;
1131 PLIST_ENTRY Entry;
1132
1133 CurrentDisk = NULL;
1134 CurrentPartition = NULL;
1135
1136 /* Release disk and partition info */
1137 while (!IsListEmpty(&DiskListHead))
1138 {
1139 Entry = RemoveHeadList(&DiskListHead);
1140 DiskEntry = CONTAINING_RECORD(Entry, DISKENTRY, ListEntry);
1141
1142 /* Release driver name */
1143 RtlFreeUnicodeString(&DiskEntry->DriverName);
1144
1145 /* Release primary partition list */
1146 while (!IsListEmpty(&DiskEntry->PrimaryPartListHead))
1147 {
1148 Entry = RemoveHeadList(&DiskEntry->PrimaryPartListHead);
1149 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1150
1151 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry);
1152 }
1153
1154 /* Release logical partition list */
1155 while (!IsListEmpty(&DiskEntry->LogicalPartListHead))
1156 {
1157 Entry = RemoveHeadList(&DiskEntry->LogicalPartListHead);
1158 PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
1159
1160 RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry);
1161 }
1162
1163 /* Release layout buffer */
1164 if (DiskEntry->LayoutBuffer != NULL)
1165 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry->LayoutBuffer);
1166
1167
1168 /* Release disk entry */
1169 RtlFreeHeap(RtlGetProcessHeap(), 0, DiskEntry);
1170 }
1171
1172 /* Release the bios disk info */
1173 while (!IsListEmpty(&BiosDiskListHead))
1174 {
1175 Entry = RemoveHeadList(&BiosDiskListHead);
1176 BiosDiskEntry = CONTAINING_RECORD(Entry, BIOSDISKENTRY, ListEntry);
1177
1178 RtlFreeHeap(RtlGetProcessHeap(), 0, BiosDiskEntry);
1179 }
1180 }
1181
1182 /* EOF */