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