xref: /reactos/base/system/diskpart/create.c (revision 886670e9)
1 /*
2  * PROJECT:         ReactOS DiskPart
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            base/system/diskpart/create.c
5  * PURPOSE:         Manages all the partitions of the OS in an interactive way.
6  * PROGRAMMERS:     Lee Schroeder
7  */
8 
9 #include "diskpart.h"
10 
11 #define NDEBUG
12 #include <debug.h>
13 
14 
15 BOOL
16 CreateExtendedPartition(
17     _In_ INT argc,
18     _In_ PWSTR *argv)
19 {
20     PPARTENTRY PartEntry, NewPartEntry;
21     PLIST_ENTRY ListEntry;
22     ULONGLONG ullSize = 0ULL;
23     ULONGLONG ullSectorCount;
24 #if 0
25     ULONGLONG ullOffset = 0ULL;
26     BOOL bNoErr = FALSE;
27 #endif
28     INT i;
29     PWSTR pszSuffix = NULL;
30     NTSTATUS Status;
31 
32     if (CurrentDisk == NULL)
33     {
34         ConResPuts(StdOut, IDS_SELECT_NO_DISK);
35         return TRUE;
36     }
37 
38     for (i = 3; i < argc; i++)
39     {
40         if (HasPrefix(argv[i], L"size=", &pszSuffix))
41         {
42             /* size=<N> (MB) */
43             DPRINT("Size : %s\n", pszSuffix);
44 
45             ullSize = _wcstoui64(pszSuffix, NULL, 10);
46             if ((ullSize == 0) && (errno == ERANGE))
47             {
48                 ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
49                 return TRUE;
50             }
51         }
52         else if (HasPrefix(argv[i], L"offset=", &pszSuffix))
53         {
54             /* offset=<N> (KB) */
55             DPRINT("Offset : %s\n", pszSuffix);
56             ConPuts(StdOut, L"The OFFSET option is not supported yet!\n");
57 #if 0
58             ullOffset = _wcstoui64(pszSuffix, NULL, 10);
59             if ((ullOffset == 0) && (errno == ERANGE))
60             {
61                 ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
62                 return TRUE;
63             }
64 #endif
65         }
66         else if (HasPrefix(argv[i], L"align=", &pszSuffix))
67         {
68             /* align=<N> */
69             DPRINT("Align : %s\n", pszSuffix);
70             ConPuts(StdOut, L"The ALIGN option is not supported yet!\n");
71 #if 0
72             bAlign = TRUE;
73 #endif
74         }
75         else if (_wcsicmp(argv[i], L"noerr") == 0)
76         {
77             /* noerr */
78             DPRINT("NoErr\n", pszSuffix);
79             ConPuts(StdOut, L"The NOERR option is not supported yet!\n");
80 #if 0
81             bNoErr = TRUE;
82 #endif
83         }
84         else
85         {
86             ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
87             return TRUE;
88         }
89     }
90 
91     DPRINT1("Size: %I64u\n", ullSize);
92 #if 0
93     DPRINT1("Offset: %I64u\n", ullOffset);
94 #endif
95 
96     if (GetPrimaryPartitionCount(CurrentDisk) >= 4)
97     {
98         ConPuts(StdOut, L"No space left for an extended partition!\n");
99         return TRUE;
100     }
101 
102     if (CurrentDisk->ExtendedPartition != NULL)
103     {
104         ConPuts(StdOut, L"We already have an extended partition on this disk!\n");
105         return TRUE;
106     }
107 
108     if (ullSize != 0)
109         ullSectorCount = (ullSize * 1024 * 1024) / CurrentDisk->BytesPerSector;
110     else
111         ullSectorCount = 0;
112 
113     DPRINT1("SectorCount: %I64u\n", ullSectorCount);
114 
115     ListEntry = CurrentDisk->PrimaryPartListHead.Blink;
116 
117     PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
118     if (PartEntry->IsPartitioned)
119     {
120         ConPuts(StdOut, L"No disk space left for an extended partition!\n");
121         return TRUE;
122     }
123 
124     if (ullSectorCount == 0)
125     {
126         PartEntry->IsPartitioned = TRUE;
127         PartEntry->New = TRUE;
128         PartEntry->PartitionType = PARTITION_EXTENDED;
129         PartEntry->FormatState = Unformatted;
130         PartEntry->FileSystemName[0] = L'\0';
131 
132         CurrentPartition = PartEntry;
133         CurrentDisk->Dirty = TRUE;
134     }
135     else
136     {
137         if (PartEntry->SectorCount.QuadPart == ullSectorCount)
138         {
139             PartEntry->IsPartitioned = TRUE;
140             PartEntry->New = TRUE;
141             PartEntry->PartitionType = PARTITION_EXTENDED;
142             PartEntry->FormatState = Unformatted;
143             PartEntry->FileSystemName[0] = L'\0';
144 
145             CurrentPartition = PartEntry;
146             CurrentDisk->Dirty = TRUE;
147         }
148         else if (PartEntry->SectorCount.QuadPart > ullSectorCount)
149         {
150             NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PPARTENTRY));
151             if (NewPartEntry == NULL)
152             {
153                 ConPuts(StdOut, L"Memory allocation failed!\n");
154                 return TRUE;
155             }
156 
157             NewPartEntry->DiskEntry = PartEntry->DiskEntry;
158 
159             NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
160             NewPartEntry->SectorCount.QuadPart = ullSectorCount;
161 
162             NewPartEntry->LogicalPartition = FALSE;
163             NewPartEntry->IsPartitioned = TRUE;
164             NewPartEntry->New = TRUE;
165             NewPartEntry->PartitionType = PARTITION_EXTENDED;
166             NewPartEntry->FormatState = Unformatted;
167             NewPartEntry->FileSystemName[0] = L'\0';
168 
169             PartEntry->StartSector.QuadPart += ullSectorCount;
170             PartEntry->SectorCount.QuadPart -= ullSectorCount;
171 
172             InsertTailList(ListEntry, &NewPartEntry->ListEntry);
173 
174             CurrentPartition = NewPartEntry;
175             CurrentDisk->Dirty = TRUE;
176         }
177     }
178 
179     UpdateDiskLayout(CurrentDisk);
180     Status = WritePartitions(CurrentDisk);
181     if (!NT_SUCCESS(Status))
182     {
183         ConResPuts(StdOut, IDS_CREATE_PARTITION_FAIL);
184         CurrentPartition = NULL;
185         return TRUE;
186     }
187 
188     ConResPuts(StdOut, IDS_CREATE_PARTITION_SUCCESS);
189 
190     return TRUE;
191 }
192 
193 
194 BOOL
195 CreateLogicalPartition(
196     _In_ INT argc,
197     _In_ PWSTR *argv)
198 {
199     PPARTENTRY PartEntry, NewPartEntry;
200     PLIST_ENTRY ListEntry;
201     ULONGLONG ullSize = 0ULL;
202     ULONGLONG ullSectorCount;
203 #if 0
204     ULONGLONG ullOffset = 0ULL;
205     BOOL bNoErr = FALSE;
206 #endif
207     UCHAR PartitionType = PARTITION_HUGE;
208     INT i, length;
209     PWSTR pszSuffix = NULL;
210     NTSTATUS Status;
211 
212     if (CurrentDisk == NULL)
213     {
214         ConResPuts(StdOut, IDS_SELECT_NO_DISK);
215         return TRUE;
216     }
217 
218     for (i = 3; i < argc; i++)
219     {
220         if (HasPrefix(argv[i], L"size=", &pszSuffix))
221         {
222             /* size=<N> (MB) */
223             DPRINT("Size : %s\n", pszSuffix);
224 
225             ullSize = _wcstoui64(pszSuffix, NULL, 10);
226             if ((ullSize == 0) && (errno == ERANGE))
227             {
228                 ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
229                 return TRUE;
230             }
231         }
232         else if (HasPrefix(argv[i], L"offset=", &pszSuffix))
233         {
234             /* offset=<N> (KB) */
235             DPRINT("Offset : %s\n", pszSuffix);
236             ConPuts(StdOut, L"The OFFSET option is not supported yet!\n");
237 #if 0
238             ullOffset = _wcstoui64(pszSuffix, NULL, 10);
239             if ((ullOffset == 0) && (errno == ERANGE))
240             {
241                 ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
242                 return TRUE;
243             }
244 #endif
245         }
246         else if (HasPrefix(argv[i], L"id=", &pszSuffix))
247         {
248             /* id=<Byte>|<GUID> */
249             DPRINT("Id : %s\n", pszSuffix);
250 
251             length = wcslen(pszSuffix);
252             if ((length == 1) || (length == 2))
253             {
254                 /* Byte */
255                 PartitionType = (UCHAR)wcstoul(pszSuffix, NULL, 16);
256                 if ((PartitionType == 0) && (errno == ERANGE))
257                 {
258                     ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
259                     return TRUE;
260                 }
261             }
262 #if 0
263             else if ()
264             {
265                 /* GUID */
266             }
267 #endif
268             else
269             {
270                 ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
271                 return TRUE;
272             }
273         }
274         else if (HasPrefix(argv[i], L"align=", &pszSuffix))
275         {
276             /* align=<N> */
277             DPRINT("Align : %s\n", pszSuffix);
278             ConPuts(StdOut, L"The ALIGN option is not supported yet!\n");
279 #if 0
280             bAlign = TRUE;
281 #endif
282         }
283         else if (_wcsicmp(argv[i], L"noerr") == 0)
284         {
285             /* noerr */
286             DPRINT("NoErr\n", pszSuffix);
287             ConPuts(StdOut, L"The NOERR option is not supported yet!\n");
288 #if 0
289             bNoErr = TRUE;
290 #endif
291         }
292         else
293         {
294             ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
295             return TRUE;
296         }
297     }
298 
299     DPRINT1("Size: %I64u\n", ullSize);
300 #if 0
301     DPRINT1("Offset: %I64u\n", ullOffset);
302 #endif
303     DPRINT1("Partition Type: %hx\n", PartitionType);
304 
305     if (ullSize != 0)
306         ullSectorCount = (ullSize * 1024 * 1024) / CurrentDisk->BytesPerSector;
307     else
308         ullSectorCount = 0;
309 
310     DPRINT1("SectorCount: %I64u\n", ullSectorCount);
311 
312     for (ListEntry = CurrentDisk->LogicalPartListHead.Flink;
313          ListEntry != &CurrentDisk->LogicalPartListHead;
314          ListEntry = ListEntry->Flink)
315     {
316         PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
317         if (PartEntry->IsPartitioned)
318             continue;
319 
320         if (ullSectorCount == 0)
321         {
322             PartEntry->IsPartitioned = TRUE;
323             PartEntry->New = TRUE;
324             PartEntry->PartitionType = PartitionType;
325             PartEntry->FormatState = Unformatted;
326             PartEntry->FileSystemName[0] = L'\0';
327 
328             CurrentPartition = PartEntry;
329             CurrentDisk->Dirty = TRUE;
330             break;
331         }
332         else
333         {
334             if (PartEntry->SectorCount.QuadPart == ullSectorCount)
335             {
336                 PartEntry->IsPartitioned = TRUE;
337                 PartEntry->New = TRUE;
338                 PartEntry->PartitionType = PartitionType;
339                 PartEntry->FormatState = Unformatted;
340                 PartEntry->FileSystemName[0] = L'\0';
341 
342                 CurrentPartition = PartEntry;
343                 CurrentDisk->Dirty = TRUE;
344                 break;
345             }
346             else if (PartEntry->SectorCount.QuadPart > ullSectorCount)
347             {
348                 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PPARTENTRY));
349                 if (NewPartEntry == NULL)
350                 {
351                     ConPuts(StdOut, L"Memory allocation failed!\n");
352                     return TRUE;
353                 }
354 
355                 NewPartEntry->DiskEntry = PartEntry->DiskEntry;
356 
357                 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
358                 NewPartEntry->SectorCount.QuadPart = ullSectorCount;
359 
360                 NewPartEntry->LogicalPartition = TRUE;
361                 NewPartEntry->IsPartitioned = TRUE;
362                 NewPartEntry->New = TRUE;
363                 NewPartEntry->PartitionType = PartitionType;
364                 NewPartEntry->FormatState = Unformatted;
365                 NewPartEntry->FileSystemName[0] = L'\0';
366 
367                 PartEntry->StartSector.QuadPart += ullSectorCount;
368                 PartEntry->SectorCount.QuadPart -= ullSectorCount;
369 
370                 InsertTailList(ListEntry, &NewPartEntry->ListEntry);
371 
372                 CurrentPartition = NewPartEntry;
373                 CurrentDisk->Dirty = TRUE;
374                 break;
375             }
376         }
377     }
378 
379     UpdateDiskLayout(CurrentDisk);
380     Status = WritePartitions(CurrentDisk);
381     if (!NT_SUCCESS(Status))
382     {
383         ConResPuts(StdOut, IDS_CREATE_PARTITION_FAIL);
384         CurrentPartition = NULL;
385         return TRUE;
386     }
387 
388     ConResPuts(StdOut, IDS_CREATE_PARTITION_SUCCESS);
389 
390     return TRUE;
391 }
392 
393 
394 BOOL
395 CreatePrimaryPartition(
396     _In_ INT argc,
397     _In_ PWSTR *argv)
398 {
399     PPARTENTRY PartEntry, NewPartEntry;
400     PLIST_ENTRY ListEntry;
401     ULONGLONG ullSize = 0ULL;
402     ULONGLONG ullSectorCount;
403 #if 0
404     ULONGLONG ullOffset = 0ULL;
405     BOOL bNoErr = FALSE;
406 #endif
407     UCHAR PartitionType = PARTITION_HUGE;
408     INT i, length;
409     PWSTR pszSuffix = NULL;
410     NTSTATUS Status;
411 
412     if (CurrentDisk == NULL)
413     {
414         ConResPuts(StdOut, IDS_SELECT_NO_DISK);
415         return TRUE;
416     }
417 
418     for (i = 3; i < argc; i++)
419     {
420         if (HasPrefix(argv[i], L"size=", &pszSuffix))
421         {
422             /* size=<N> (MB) */
423             DPRINT("Size : %s\n", pszSuffix);
424 
425             ullSize = _wcstoui64(pszSuffix, NULL, 10);
426             if ((ullSize == 0) && (errno == ERANGE))
427             {
428                 ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
429                 return TRUE;
430             }
431         }
432         else if (HasPrefix(argv[i], L"offset=", &pszSuffix))
433         {
434             /* offset=<N> (KB) */
435             DPRINT("Offset : %s\n", pszSuffix);
436             ConPuts(StdOut, L"The OFFSET option is not supported yet!\n");
437 #if 0
438             ullOffset = _wcstoui64(pszSuffix, NULL, 10);
439             if ((ullOffset == 0) && (errno == ERANGE))
440             {
441                 ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
442                 return TRUE;
443             }
444 #endif
445         }
446         else if (HasPrefix(argv[i], L"id=", &pszSuffix))
447         {
448             /* id=<Byte>|<GUID> */
449             DPRINT("Id : %s\n", pszSuffix);
450 
451             length = wcslen(pszSuffix);
452             if ((length == 1) || (length == 2))
453             {
454                 /* Byte */
455                 PartitionType = (UCHAR)wcstoul(pszSuffix, NULL, 16);
456                 if ((PartitionType == 0) && (errno == ERANGE))
457                 {
458                     ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
459                     return TRUE;
460                 }
461             }
462 #if 0
463             else if ()
464             {
465                 /* GUID */
466             }
467 #endif
468             else
469             {
470                 ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
471                 return TRUE;
472             }
473         }
474         else if (HasPrefix(argv[i], L"align=", &pszSuffix))
475         {
476             /* align=<N> */
477             DPRINT("Align : %s\n", pszSuffix);
478             ConPuts(StdOut, L"The ALIGN option is not supported yet!\n");
479 #if 0
480             bAlign = TRUE;
481 #endif
482         }
483         else if (_wcsicmp(argv[i], L"noerr") == 0)
484         {
485             /* noerr */
486             DPRINT("NoErr\n", pszSuffix);
487             ConPuts(StdOut, L"The NOERR option is not supported yet!\n");
488 #if 0
489             bNoErr = TRUE;
490 #endif
491         }
492         else
493         {
494             ConResPuts(StdErr, IDS_ERROR_INVALID_ARGS);
495             return TRUE;
496         }
497     }
498 
499     DPRINT1("Size: %I64u\n", ullSize);
500 #if 0
501     DPRINT1("Offset: %I64u\n", ullOffset);
502 #endif
503     DPRINT1("Partition Type: %hx\n", PartitionType);
504 
505     if (GetPrimaryPartitionCount(CurrentDisk) >= 4)
506     {
507         ConPuts(StdOut, L"No space left for another primary partition!\n");
508         return TRUE;
509     }
510 
511     if (ullSize != 0)
512         ullSectorCount = (ullSize * 1024 * 1024) / CurrentDisk->BytesPerSector;
513     else
514         ullSectorCount = 0;
515 
516     DPRINT1("SectorCount: %I64u\n", ullSectorCount);
517 
518     for (ListEntry = CurrentDisk->PrimaryPartListHead.Flink;
519          ListEntry != &CurrentDisk->PrimaryPartListHead;
520          ListEntry = ListEntry->Flink)
521     {
522         PartEntry = CONTAINING_RECORD(ListEntry, PARTENTRY, ListEntry);
523         if (PartEntry->IsPartitioned)
524             continue;
525 
526         if (ullSectorCount == 0)
527         {
528             PartEntry->IsPartitioned = TRUE;
529             PartEntry->New = TRUE;
530             PartEntry->PartitionType = PartitionType;
531             PartEntry->FormatState = Unformatted;
532             PartEntry->FileSystemName[0] = L'\0';
533 
534             CurrentPartition = PartEntry;
535             CurrentDisk->Dirty = TRUE;
536             break;
537         }
538         else
539         {
540             if (PartEntry->SectorCount.QuadPart == ullSectorCount)
541             {
542                 PartEntry->IsPartitioned = TRUE;
543                 PartEntry->New = TRUE;
544                 PartEntry->PartitionType = PartitionType;
545                 PartEntry->FormatState = Unformatted;
546                 PartEntry->FileSystemName[0] = L'\0';
547 
548                 CurrentPartition = PartEntry;
549                 CurrentDisk->Dirty = TRUE;
550                 break;
551             }
552             else if (PartEntry->SectorCount.QuadPart > ullSectorCount)
553             {
554                 NewPartEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(PPARTENTRY));
555                 if (NewPartEntry == NULL)
556                 {
557                     ConPuts(StdOut, L"Memory allocation failed!\n");
558                     return TRUE;
559                 }
560 
561                 NewPartEntry->DiskEntry = PartEntry->DiskEntry;
562 
563                 NewPartEntry->StartSector.QuadPart = PartEntry->StartSector.QuadPart;
564                 NewPartEntry->SectorCount.QuadPart = ullSectorCount;
565 
566                 NewPartEntry->LogicalPartition = FALSE;
567                 NewPartEntry->IsPartitioned = TRUE;
568                 NewPartEntry->New = TRUE;
569                 NewPartEntry->PartitionType = PartitionType;
570                 NewPartEntry->FormatState = Unformatted;
571                 NewPartEntry->FileSystemName[0] = L'\0';
572 
573                 PartEntry->StartSector.QuadPart += ullSectorCount;
574                 PartEntry->SectorCount.QuadPart -= ullSectorCount;
575 
576                 InsertTailList(ListEntry, &NewPartEntry->ListEntry);
577 
578                 CurrentPartition = NewPartEntry;
579                 CurrentDisk->Dirty = TRUE;
580                 break;
581             }
582         }
583     }
584 
585     UpdateDiskLayout(CurrentDisk);
586     Status = WritePartitions(CurrentDisk);
587     if (!NT_SUCCESS(Status))
588     {
589         ConResPuts(StdOut, IDS_CREATE_PARTITION_FAIL);
590         CurrentPartition = NULL;
591         return TRUE;
592     }
593 
594     ConResPuts(StdOut, IDS_CREATE_PARTITION_SUCCESS);
595 
596     return TRUE;
597 }
598