xref: /reactos/base/system/diskpart/clean.c (revision 2be7af18)
1 /*
2  * PROJECT:         ReactOS DiskPart
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            base/system/diskpart/clean.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
clean_main(_In_ INT argc,_In_ PWSTR * argv)16 clean_main(
17     _In_ INT argc,
18     _In_ PWSTR *argv)
19 {
20     PLIST_ENTRY Entry;
21     PPARTENTRY PartEntry;
22     PVOLENTRY VolumeEntry;
23     BOOL bAll = FALSE;
24     PUCHAR SectorsBuffer = NULL;
25     ULONG LayoutBufferSize, Size;
26     INT i;
27     WCHAR Buffer[MAX_PATH];
28     UNICODE_STRING Name;
29     OBJECT_ATTRIBUTES ObjectAttributes;
30     IO_STATUS_BLOCK IoStatusBlock;
31     HANDLE FileHandle = NULL;
32     LARGE_INTEGER Offset, Count, MaxCount;
33     NTSTATUS Status;
34 
35     DPRINT("Clean()\n");
36 
37     if (CurrentDisk == NULL)
38     {
39         ConResPuts(StdOut, IDS_SELECT_NO_DISK);
40         return TRUE;
41     }
42 
43     /* Do not allow to clean the boot disk */
44     if ((CurrentDisk->BiosFound == TRUE) &&
45         (CurrentDisk->BiosDiskNumber == 0))
46     {
47         ConResPuts(StdOut, IDS_CLEAN_SYSTEM);
48         return TRUE;
49     }
50 
51     for (i = 1; i < argc; i++)
52     {
53         if (_wcsicmp(argv[1], L"all") == 0)
54         {
55             bAll = TRUE;
56         }
57     }
58 
59     /* Dismount and remove all logical partitions */
60     while (!IsListEmpty(&CurrentDisk->LogicalPartListHead))
61     {
62         Entry = RemoveHeadList(&CurrentDisk->LogicalPartListHead);
63         PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
64 
65         /* Dismount the logical partition */
66         if (PartEntry->PartitionType != 0)
67         {
68             DismountVolume(PartEntry);
69             VolumeEntry = GetVolumeFromPartition(PartEntry);
70             if (VolumeEntry)
71                 RemoveVolume(VolumeEntry);
72         }
73 
74         /* Delete it */
75         RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry);
76     }
77 
78     /* Dismount and remove all primary partitions */
79     while (!IsListEmpty(&CurrentDisk->PrimaryPartListHead))
80     {
81         Entry = RemoveHeadList(&CurrentDisk->PrimaryPartListHead);
82         PartEntry = CONTAINING_RECORD(Entry, PARTENTRY, ListEntry);
83 
84         /* Dismount the primary partition */
85         if ((PartEntry->PartitionType != 0) &&
86             (IsContainerPartition(PartEntry->PartitionType) == FALSE))
87         {
88             DismountVolume(PartEntry);
89             VolumeEntry = GetVolumeFromPartition(PartEntry);
90             if (VolumeEntry)
91                 RemoveVolume(VolumeEntry);
92         }
93 
94         /* Delete it */
95         RtlFreeHeap(RtlGetProcessHeap(), 0, PartEntry);
96     }
97 
98     /* Initialize the disk entry */
99     CurrentDisk->ExtendedPartition = NULL;
100     CurrentDisk->Dirty = FALSE;
101     CurrentDisk->NewDisk = TRUE;
102     CurrentDisk->NoMbr = TRUE;
103 
104     /* Wipe the layout buffer */
105     RtlFreeHeap(RtlGetProcessHeap(), 0, CurrentDisk->LayoutBuffer);
106 
107     LayoutBufferSize = sizeof(DRIVE_LAYOUT_INFORMATION) +
108                        ((4 - ANYSIZE_ARRAY) * sizeof(PARTITION_INFORMATION));
109     CurrentDisk->LayoutBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
110                                                 HEAP_ZERO_MEMORY,
111                                                 LayoutBufferSize);
112     if (CurrentDisk->LayoutBuffer == NULL)
113     {
114         DPRINT1("Failed to allocate the disk layout buffer!\n");
115         return TRUE;
116     }
117 
118     /* Allocate a 1MB sectors buffer */
119     SectorsBuffer = RtlAllocateHeap(RtlGetProcessHeap(),
120                                     HEAP_ZERO_MEMORY,
121                                     1024 * 1024);
122     if (SectorsBuffer == NULL)
123     {
124         DPRINT1("Failed to allocate the sectors buffer!\n");
125         goto done;
126     }
127 
128     /* Open the disk for writing */
129     StringCchPrintfW(Buffer, ARRAYSIZE(Buffer),
130                      L"\\Device\\Harddisk%d\\Partition0",
131                      CurrentDisk->DiskNumber);
132 
133     RtlInitUnicodeString(&Name, Buffer);
134 
135     InitializeObjectAttributes(&ObjectAttributes,
136                                &Name,
137                                OBJ_CASE_INSENSITIVE,
138                                NULL,
139                                NULL);
140 
141     Status = NtOpenFile(&FileHandle,
142                         GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
143                         &ObjectAttributes,
144                         &IoStatusBlock,
145                         0,
146                         FILE_SYNCHRONOUS_IO_NONALERT);
147     if (!NT_SUCCESS(Status))
148     {
149         DPRINT1("Failed to open the disk! (Status 0x%08lx)\n", Status);
150         ConResPuts(StdOut, IDS_CLEAN_FAIL);
151         goto done;
152     }
153 
154     /* Clean sectors */
155     if (bAll)
156     {
157         MaxCount.QuadPart = (CurrentDisk->SectorCount.QuadPart * CurrentDisk->BytesPerSector) / (1024 * 1024);
158         for (Count.QuadPart = 0; Count.QuadPart < MaxCount.QuadPart; Count.QuadPart++)
159         {
160             Offset.QuadPart = Count.QuadPart * (1024 * 1024);
161             Status = NtWriteFile(FileHandle,
162                                  NULL,
163                                  NULL,
164                                  NULL,
165                                  &IoStatusBlock,
166                                  SectorsBuffer,
167                                  1024 * 1024,
168                                  &Offset,
169                                  NULL);
170             if (!NT_SUCCESS(Status))
171             {
172                 DPRINT1("Failed to write MB! (Status 0x%08lx)\n", Status);
173                 ConResPuts(StdOut, IDS_CLEAN_FAIL);
174                 goto done;
175             }
176         }
177 
178         Size = (ULONG)(CurrentDisk->SectorCount.QuadPart * CurrentDisk->BytesPerSector) % (1024 * 1024);
179         if (Size != 0)
180         {
181             Offset.QuadPart += (1024 * 1024);
182             Status = NtWriteFile(FileHandle,
183                                  NULL,
184                                  NULL,
185                                  NULL,
186                                  &IoStatusBlock,
187                                  SectorsBuffer,
188                                  Size,
189                                  &Offset,
190                                  NULL);
191             if (!NT_SUCCESS(Status))
192             {
193                 DPRINT1("Failed to write the last part! (Status 0x%08lx)\n", Status);
194                 ConResPuts(StdOut, IDS_CLEAN_FAIL);
195                 goto done;
196             }
197         }
198     }
199     else
200     {
201         /* Clean the first MB */
202         Offset.QuadPart = 0;
203         Status = NtWriteFile(FileHandle,
204                              NULL,
205                              NULL,
206                              NULL,
207                              &IoStatusBlock,
208                              SectorsBuffer,
209                              1024 * 1024,
210                              &Offset,
211                              NULL);
212         if (!NT_SUCCESS(Status))
213         {
214             DPRINT1("Failed to write the first MB! (Status 0x%08lx)\n", Status);
215             ConResPuts(StdOut, IDS_CLEAN_FAIL);
216             goto done;
217         }
218 
219         /* Clean the last MB */
220         Offset.QuadPart = (CurrentDisk->SectorCount.QuadPart * CurrentDisk->BytesPerSector) - (1024 * 1024);
221         Status = NtWriteFile(FileHandle,
222                              NULL,
223                              NULL,
224                              NULL,
225                              &IoStatusBlock,
226                              SectorsBuffer,
227                              1024 * 1024,
228                              &Offset,
229                              NULL);
230         if (!NT_SUCCESS(Status))
231         {
232             DPRINT1("Failed to write the last MB! (Status 0x%08lx)\n", Status);
233             ConResPuts(StdOut, IDS_CLEAN_FAIL);
234             goto done;
235         }
236     }
237 
238     ConResPuts(StdOut, IDS_CLEAN_SUCCESS);
239 
240 done:
241     if (FileHandle != NULL)
242         NtClose(FileHandle);
243 
244     if (SectorsBuffer != NULL)
245         RtlFreeHeap(RtlGetProcessHeap(), 0, SectorsBuffer);
246 
247     return TRUE;
248 }
249