Various improvements and hardcoded directory creation.
[reactos.git] / reactos / subsys / system / usetup / partlist.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: subsys/system/usetup/partlist.c
23 * PURPOSE: Partition list functions
24 * PROGRAMMER: Eric Kohl
25 */
26
27 #include <ddk/ntddk.h>
28 #include <ddk/ntddscsi.h>
29
30 #include <ntdll/rtl.h>
31
32 #include <ntos/minmax.h>
33
34 #include "usetup.h"
35 #include "console.h"
36 #include "partlist.h"
37
38
39 /* FUNCTIONS ****************************************************************/
40
41 PPARTLIST
42 CreatePartitionList(SHORT Left,
43 SHORT Top,
44 SHORT Right,
45 SHORT Bottom)
46 {
47 PPARTLIST List;
48 OBJECT_ATTRIBUTES ObjectAttributes;
49 SYSTEM_DEVICE_INFORMATION Sdi;
50 DISK_GEOMETRY DiskGeometry;
51 ULONG ReturnSize;
52 NTSTATUS Status;
53 ULONG DiskCount;
54 IO_STATUS_BLOCK Iosb;
55 WCHAR Buffer[MAX_PATH];
56 UNICODE_STRING Name;
57 HANDLE FileHandle;
58 DRIVE_LAYOUT_INFORMATION *LayoutBuffer;
59 SCSI_ADDRESS ScsiAddress;
60 ULONG i;
61
62 List = (PPARTLIST)RtlAllocateHeap(ProcessHeap, 0, sizeof(PARTLIST));
63 if (List == NULL)
64 return(NULL);
65
66 List->Left = Left;
67 List->Top = Top;
68 List->Right = Right;
69 List->Bottom = Bottom;
70
71 List->Line = 0;
72
73 List->TopDisk = (ULONG)-1;
74 List->TopPartition = (ULONG)-1;
75
76 List->CurrentDisk = (ULONG)-1;
77 List->CurrentPartition = (ULONG)-1;
78
79 List->DiskCount = 0;
80 List->DiskArray = NULL;
81
82
83 Status = NtQuerySystemInformation(SystemDeviceInformation,
84 &Sdi,
85 sizeof(SYSTEM_DEVICE_INFORMATION),
86 &ReturnSize);
87 if (!NT_SUCCESS(Status))
88 {
89 RtlFreeHeap(ProcessHeap, 0, List);
90 return(NULL);
91 }
92
93 List->DiskArray = (PDISKENTRY)RtlAllocateHeap(ProcessHeap,
94 0,
95 Sdi.NumberOfDisks * sizeof(DISKENTRY));
96 List->DiskCount = Sdi.NumberOfDisks;
97
98 for (DiskCount = 0; DiskCount < Sdi.NumberOfDisks; DiskCount++)
99 {
100 swprintf(Buffer,
101 L"\\Device\\Harddisk%d\\Partition0",
102 DiskCount);
103 RtlInitUnicodeString(&Name,
104 Buffer);
105
106 InitializeObjectAttributes(&ObjectAttributes,
107 &Name,
108 0,
109 NULL,
110 NULL);
111
112 Status = NtOpenFile(&FileHandle,
113 0x10001,
114 &ObjectAttributes,
115 &Iosb,
116 1,
117 FILE_SYNCHRONOUS_IO_NONALERT);
118 if (NT_SUCCESS(Status))
119 {
120 Status = NtDeviceIoControlFile(FileHandle,
121 NULL,
122 NULL,
123 NULL,
124 &Iosb,
125 IOCTL_DISK_GET_DRIVE_GEOMETRY,
126 NULL,
127 0,
128 &DiskGeometry,
129 sizeof(DISK_GEOMETRY));
130 if (NT_SUCCESS(Status))
131 {
132 if (DiskGeometry.MediaType == FixedMedia)
133 {
134 Status = NtDeviceIoControlFile(FileHandle,
135 NULL,
136 NULL,
137 NULL,
138 &Iosb,
139 IOCTL_SCSI_GET_ADDRESS,
140 NULL,
141 0,
142 &ScsiAddress,
143 sizeof(SCSI_ADDRESS));
144
145
146 List->DiskArray[DiskCount].DiskSize =
147 DiskGeometry.Cylinders.QuadPart *
148 (ULONGLONG)DiskGeometry.TracksPerCylinder *
149 (ULONGLONG)DiskGeometry.SectorsPerTrack *
150 (ULONGLONG)DiskGeometry.BytesPerSector;
151 List->DiskArray[DiskCount].DiskNumber = DiskCount;
152 List->DiskArray[DiskCount].Port = ScsiAddress.PortNumber;
153 List->DiskArray[DiskCount].Bus = ScsiAddress.PathId;
154 List->DiskArray[DiskCount].Id = ScsiAddress.TargetId;
155
156 List->DiskArray[DiskCount].FixedDisk = TRUE;
157
158
159 LayoutBuffer = (DRIVE_LAYOUT_INFORMATION*)RtlAllocateHeap(ProcessHeap, 0, 8192);
160
161 Status = NtDeviceIoControlFile(FileHandle,
162 NULL,
163 NULL,
164 NULL,
165 &Iosb,
166 IOCTL_DISK_GET_DRIVE_LAYOUT,
167 NULL,
168 0,
169 LayoutBuffer,
170 8192);
171 if (NT_SUCCESS(Status))
172 {
173
174 List->DiskArray[DiskCount].PartArray = (PPARTENTRY)RtlAllocateHeap(ProcessHeap,
175 0,
176 LayoutBuffer->PartitionCount * sizeof(PARTENTRY));
177 List->DiskArray[DiskCount].PartCount = LayoutBuffer->PartitionCount;
178
179 for (i = 0; i < LayoutBuffer->PartitionCount; i++)
180 {
181 if ((LayoutBuffer->PartitionEntry[i].PartitionType != PARTITION_ENTRY_UNUSED) &&
182 !IsContainerPartition(LayoutBuffer->PartitionEntry[i].PartitionType))
183 {
184 List->DiskArray[DiskCount].PartArray[i].PartSize = LayoutBuffer->PartitionEntry[i].PartitionLength.QuadPart;
185 List->DiskArray[DiskCount].PartArray[i].PartNumber = LayoutBuffer->PartitionEntry[i].PartitionNumber,
186 List->DiskArray[DiskCount].PartArray[i].PartType = LayoutBuffer->PartitionEntry[i].PartitionType;
187 List->DiskArray[DiskCount].PartArray[i].Used = TRUE;
188 }
189 else
190 {
191 List->DiskArray[DiskCount].PartArray[i].Used = FALSE;
192 }
193 }
194 }
195
196 RtlFreeHeap(ProcessHeap, 0, LayoutBuffer);
197 }
198 else
199 {
200 /* mark removable disk entry */
201 List->DiskArray[DiskCount].FixedDisk = FALSE;
202 List->DiskArray[DiskCount].PartCount = 0;
203 List->DiskArray[DiskCount].PartArray = NULL;
204 }
205 }
206
207 NtClose(FileHandle);
208 }
209 }
210
211 List->TopDisk = 0;
212 List->TopPartition = 0;
213
214 /* FIXME: search for first usable disk and partition */
215 List->CurrentDisk = 0;
216 List->CurrentPartition = 0;
217
218 DrawPartitionList(List);
219
220 return(List);
221 }
222
223
224 VOID
225 DestroyPartitionList(PPARTLIST List)
226 {
227 ULONG i;
228 #if 0
229 COORD coPos;
230 USHORT Width;
231
232 /* clear occupied screen area */
233 coPos.X = List->Left;
234 Width = List->Right - List->Left + 1;
235 for (coPos.Y = List->Top; coPos.Y <= List->Bottom; coPos.Y++)
236 {
237 FillConsoleOutputAttribute(0x17,
238 Width,
239 coPos,
240 &i);
241
242 FillConsoleOutputCharacter(' ',
243 Width,
244 coPos,
245 &i);
246 }
247 #endif
248
249 /* free disk and partition info */
250 if (List->DiskArray != NULL)
251 {
252 /* free partition arrays */
253 for (i = 0; i < List->DiskCount; i++)
254 {
255 if (List->DiskArray[i].PartArray != NULL)
256 {
257 RtlFreeHeap(ProcessHeap, 0, List->DiskArray[i].PartArray);
258 List->DiskArray[i].PartCount = 0;
259 List->DiskArray[i].PartArray = NULL;
260 }
261 }
262
263 /* free disk array */
264 RtlFreeHeap(ProcessHeap, 0, List->DiskArray);
265 List->DiskCount = 0;
266 List->DiskArray = NULL;
267 }
268
269 /* free list head */
270 RtlFreeHeap(ProcessHeap, 0, List);
271 }
272
273
274 static VOID
275 PrintEmptyLine(PPARTLIST List)
276 {
277 COORD coPos;
278 ULONG Written;
279 USHORT Width;
280 USHORT Height;
281
282 Width = List->Right - List->Left - 1;
283 Height = List->Bottom - List->Top - 1;
284
285 if (List->Line < 0 || List->Line > Height)
286 return;
287
288 coPos.X = List->Left + 1;
289 coPos.Y = List->Top + 1 + List->Line;
290
291 FillConsoleOutputAttribute(0x17,
292 Width,
293 coPos,
294 &Written);
295
296 FillConsoleOutputCharacter(' ',
297 Width,
298 coPos,
299 &Written);
300
301 List->Line++;
302 }
303
304
305 static VOID
306 PrintPartitionData(PPARTLIST List,
307 SHORT DiskIndex,
308 SHORT PartIndex)
309 {
310 PPARTENTRY PartEntry;
311 CHAR LineBuffer[128];
312 COORD coPos;
313 ULONG Written;
314 USHORT Width;
315 USHORT Height;
316
317 ULONGLONG PartSize;
318 PCHAR Unit;
319 PCHAR PartType;
320 UCHAR Attribute;
321
322
323 Width = List->Right - List->Left - 1;
324 Height = List->Bottom - List->Top - 1;
325
326 if (List->Line < 0 || List->Line > Height)
327 return;
328
329 coPos.X = List->Left + 1;
330 coPos.Y = List->Top + 1 + List->Line;
331
332 PartEntry = &List->DiskArray[DiskIndex].PartArray[PartIndex];
333
334 if ((PartEntry->PartType == PARTITION_FAT_12) ||
335 (PartEntry->PartType == PARTITION_FAT_16) ||
336 (PartEntry->PartType == PARTITION_HUGE) ||
337 (PartEntry->PartType == PARTITION_XINT13))
338 {
339 PartType = "FAT";
340 }
341 else if ((PartEntry->PartType == PARTITION_FAT32) ||
342 (PartEntry->PartType == PARTITION_FAT32_XINT13))
343 {
344 PartType = "FAT32";
345 }
346 else if (PartEntry->PartType == PARTITION_IFS)
347 {
348 PartType = "NTFS"; /* FIXME: Not quite correct! */
349 }
350 else
351 {
352 PartType = "Unknown";
353 }
354
355 if (PartEntry->PartSize >= 0x280000000ULL) /* 10 GB */
356 {
357 PartSize = (PartEntry->PartSize + (1 << 29)) >> 30;
358 Unit = "GB";
359 }
360 else if (PartEntry->PartSize >= 0xA00000ULL) /* 10 MB */
361 {
362 PartSize = (PartEntry->PartSize + (1 << 19)) >> 20;
363 Unit = "MB";
364 }
365 else
366 {
367 PartSize = (PartEntry->PartSize + (1 << 9)) >> 10;
368 Unit = "kB";
369 }
370
371 sprintf(LineBuffer,
372 "%d: nr: %d type: %x (%s) %I64u %s",
373 PartIndex,
374 PartEntry->PartNumber,
375 PartEntry->PartType,
376 PartType,
377 PartSize,
378 Unit);
379
380
381 Attribute = (List->CurrentDisk == DiskIndex &&
382 List->CurrentPartition == PartIndex) ? 0x71 : 0x17;
383
384 FillConsoleOutputCharacter(' ',
385 Width,
386 coPos,
387 &Written);
388
389 coPos.X += 4;
390 Width -= 8;
391 FillConsoleOutputAttribute(Attribute,
392 Width,
393 coPos,
394 &Written);
395
396 coPos.X++;
397 Width -= 2;
398 WriteConsoleOutputCharacters(LineBuffer,
399 min(strlen(LineBuffer), Width),
400 coPos);
401
402 List->Line++;
403 }
404
405
406 static VOID
407 PrintDiskData(PPARTLIST List,
408 SHORT DiskIndex)
409 {
410 PDISKENTRY DiskEntry;
411 CHAR LineBuffer[128];
412 COORD coPos;
413 ULONG Written;
414 USHORT Width;
415 USHORT Height;
416 ULONGLONG DiskSize;
417 PCHAR Unit;
418 SHORT PartIndex;
419 BOOL PartPrinted;
420
421 DiskEntry = &List->DiskArray[DiskIndex];
422
423 Width = List->Right - List->Left - 1;
424 Height = List->Bottom - List->Top - 1;
425
426 if (List->Line < 0 || List->Line > Height)
427 return;
428
429 coPos.X = List->Left + 1;
430 coPos.Y = List->Top + 1 + List->Line;
431
432 if (DiskEntry->DiskSize >= 0x280000000ULL) /* 10 GB */
433 {
434 DiskSize = (DiskEntry->DiskSize + (1 << 29)) >> 30;
435 Unit = "GB";
436 }
437 else if (DiskEntry->DiskSize >= 0xA00000ULL) /* 10 MB */
438 {
439 DiskSize = (DiskEntry->DiskSize + (1 << 19)) >> 20;
440 Unit = "MB";
441 }
442 else
443 {
444 DiskSize = (DiskEntry->DiskSize + (1 << 9)) >> 10;
445 Unit = "kB";
446 }
447
448 sprintf(LineBuffer,
449 "%I64u %s Harddisk %lu (Port=%hu, Bus=%hu, Id=%hu)",
450 DiskSize,
451 Unit,
452 DiskEntry->DiskNumber,
453 DiskEntry->Port,
454 DiskEntry->Bus,
455 DiskEntry->Id);
456
457 FillConsoleOutputAttribute(0x17,
458 Width,
459 coPos,
460 &Written);
461
462 FillConsoleOutputCharacter(' ',
463 Width,
464 coPos,
465 &Written);
466
467 coPos.X++;
468 WriteConsoleOutputCharacters(LineBuffer,
469 min(strlen(LineBuffer), Width - 2),
470 coPos);
471
472 List->Line++;
473
474 /* Print separator line */
475 PrintEmptyLine(List);
476
477
478 PartPrinted = FALSE;
479
480 /* Print partition lines*/
481 for (PartIndex = 0; PartIndex < List->DiskArray[DiskIndex].PartCount; PartIndex++)
482 {
483 if (List->DiskArray[DiskIndex].PartArray[PartIndex].Used == TRUE)
484 {
485 PrintPartitionData(List,
486 DiskIndex,
487 PartIndex);
488 PartPrinted = TRUE;
489 }
490 }
491
492 /* Print separator line */
493 if (PartPrinted == TRUE)
494 {
495 PrintEmptyLine(List);
496 }
497 }
498
499
500 VOID
501 DrawPartitionList(PPARTLIST List)
502 {
503 CHAR LineBuffer[128];
504 COORD coPos;
505 ULONG Written;
506 SHORT i;
507 SHORT DiskIndex;
508
509 /* draw upper left corner */
510 coPos.X = List->Left;
511 coPos.Y = List->Top;
512 FillConsoleOutputCharacter(0xDA, // '+',
513 1,
514 coPos,
515 &Written);
516
517 /* draw upper edge */
518 coPos.X = List->Left + 1;
519 coPos.Y = List->Top;
520 FillConsoleOutputCharacter(0xC4, // '-',
521 List->Right - List->Left - 1,
522 coPos,
523 &Written);
524
525 /* draw upper right corner */
526 coPos.X = List->Right;
527 coPos.Y = List->Top;
528 FillConsoleOutputCharacter(0xBF, // '+',
529 1,
530 coPos,
531 &Written);
532
533 /* draw left and right edge */
534 for (i = List->Top + 1; i < List->Bottom; i++)
535 {
536 coPos.X = List->Left;
537 coPos.Y = i;
538 FillConsoleOutputCharacter(0xB3, // '|',
539 1,
540 coPos,
541 &Written);
542
543 coPos.X = List->Right;
544 FillConsoleOutputCharacter(0xB3, //'|',
545 1,
546 coPos,
547 &Written);
548 }
549
550 /* draw lower left corner */
551 coPos.X = List->Left;
552 coPos.Y = List->Bottom;
553 FillConsoleOutputCharacter(0xC0, // '+',
554 1,
555 coPos,
556 &Written);
557
558 /* draw lower edge */
559 coPos.X = List->Left + 1;
560 coPos.Y = List->Bottom;
561 FillConsoleOutputCharacter(0xC4, // '-',
562 List->Right - List->Left - 1,
563 coPos,
564 &Written);
565
566 /* draw upper right corner */
567 coPos.X = List->Right;
568 coPos.Y = List->Bottom;
569 FillConsoleOutputCharacter(0xD9, // '+',
570 1,
571 coPos,
572 &Written);
573
574 /* print list entries */
575 List->Line = 0;
576 for (DiskIndex = 0; DiskIndex < List->DiskCount; DiskIndex++)
577 {
578 if (List->DiskArray[DiskIndex].FixedDisk == TRUE)
579 {
580 /* Print disk entry */
581 PrintDiskData(List,
582 DiskIndex);
583 }
584 }
585 }
586
587
588 VOID
589 ScrollDownPartitionList(PPARTLIST List)
590 {
591 ULONG i;
592 ULONG j;
593
594 /* check for available disks */
595 if (List->DiskCount == 0)
596 return;
597
598 /* check for next usable entry on current disk */
599 for (i = List->CurrentPartition + 1; i < List->DiskArray[List->CurrentDisk].PartCount; i++)
600 {
601 if (List->DiskArray[List->CurrentDisk].PartArray[i].Used == TRUE)
602 {
603 List->CurrentPartition = i;
604 DrawPartitionList(List);
605 return;
606 }
607 }
608
609 /* check for first usable entry on next disk */
610 for (j = List->CurrentDisk + 1; j < List->DiskCount; j++)
611 {
612 for (i = 0; i < List->DiskArray[j].PartCount; i++)
613 {
614 if (List->DiskArray[j].PartArray[i].Used == TRUE)
615 {
616 List->CurrentDisk = j;
617 List->CurrentPartition = i;
618 DrawPartitionList(List);
619 return;
620 }
621 }
622 }
623 }
624
625
626 VOID
627 ScrollUpPartitionList(PPARTLIST List)
628 {
629 ULONG i;
630 ULONG j;
631
632 /* check for available disks */
633 if (List->DiskCount == 0)
634 return;
635
636 /* check for previous usable entry on current disk */
637 for (i = List->CurrentPartition - 1; i != (ULONG)-1; i--)
638 {
639 if (List->DiskArray[List->CurrentDisk].PartArray[i].Used == TRUE)
640 {
641 List->CurrentPartition = i;
642 DrawPartitionList(List);
643 return;
644 }
645 }
646
647 /* check for last usable entry on previous disk */
648 for (j = List->CurrentDisk - 1; j != (ULONG)-1; j--)
649 {
650 for (i = List->DiskArray[j].PartCount - 1; i != (ULONG)-1; i--)
651 {
652 if (List->DiskArray[j].PartArray[i].Used == TRUE)
653 {
654 List->CurrentDisk = j;
655 List->CurrentPartition = i;
656 DrawPartitionList(List);
657 return;
658 }
659 }
660 }
661 }
662
663
664 BOOL
665 GetPartitionData(PPARTLIST List,
666 PPARTDATA Data)
667 {
668 if (List->CurrentDisk >= List->DiskCount)
669 return(FALSE);
670
671 if (List->DiskArray[List->CurrentDisk].FixedDisk == FALSE)
672 return(FALSE);
673
674 if (List->CurrentPartition >= List->DiskArray[List->CurrentDisk].PartCount)
675 return(FALSE);
676
677 if (List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].Used == FALSE)
678 return(FALSE);
679
680 Data->DiskSize = List->DiskArray[List->CurrentDisk].DiskSize;
681 Data->DiskNumber = List->DiskArray[List->CurrentDisk].DiskNumber;
682 Data->Port = List->DiskArray[List->CurrentDisk].Port;
683 Data->Bus = List->DiskArray[List->CurrentDisk].Bus;
684 Data->Id = List->DiskArray[List->CurrentDisk].Id;
685
686 Data->PartSize = List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].PartSize;
687 Data->PartNumber = List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].PartNumber;
688 Data->PartType = List->DiskArray[List->CurrentDisk].PartArray[List->CurrentPartition].PartType;
689
690 return(TRUE);
691 }
692
693 /* EOF */