[AUTOCHK][CMD][TASKMGR]
[reactos.git] / reactos / base / system / autochk / autochk.c
1 /* PROJECT: ReactOS Kernel
2 * LICENSE: GPL - See COPYING in the top level directory
3 * FILE: base/system/autochk/autochk.c
4 * PURPOSE: Filesystem checker
5 * PROGRAMMERS: Aleksey Bragin
6 * Eric Kohl
7 * Hervé Poussineau
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include <stdio.h>
13 #define WIN32_NO_STATUS
14 #include <windows.h>
15 #define NTOS_MODE_USER
16 #include <ndk/exfuncs.h>
17 #include <ndk/iofuncs.h>
18 #include <ndk/obtypes.h>
19 #include <ndk/obfuncs.h>
20 #include <ndk/pstypes.h>
21 #include <ndk/psfuncs.h>
22 #include <ndk/rtlfuncs.h>
23 #include <ndk/umfuncs.h>
24 #include <fmifs/fmifs.h>
25
26 #define NDEBUG
27 #include <debug.h>
28
29 /* DEFINES ******************************************************************/
30
31 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
32
33
34 /* FUNCTIONS ****************************************************************/
35 //
36 // FMIFS function
37 //
38
39 static VOID
40 PrintString(char* fmt,...)
41 {
42 char buffer[512];
43 va_list ap;
44 UNICODE_STRING UnicodeString;
45 ANSI_STRING AnsiString;
46
47 va_start(ap, fmt);
48 vsprintf(buffer, fmt, ap);
49 va_end(ap);
50
51 RtlInitAnsiString(&AnsiString, buffer);
52 RtlAnsiStringToUnicodeString(&UnicodeString,
53 &AnsiString,
54 TRUE);
55 NtDisplayString(&UnicodeString);
56 RtlFreeUnicodeString(&UnicodeString);
57 }
58
59 // this func is taken from kernel32/file/volume.c
60 static HANDLE
61 OpenDirectory(
62 IN LPCWSTR DirName,
63 IN BOOLEAN Write)
64 {
65 UNICODE_STRING NtPathU;
66 OBJECT_ATTRIBUTES ObjectAttributes;
67 NTSTATUS Status;
68 IO_STATUS_BLOCK IoStatusBlock;
69 HANDLE hFile;
70
71 if (!RtlDosPathNameToNtPathName_U(DirName,
72 &NtPathU,
73 NULL,
74 NULL))
75 {
76 DPRINT1("Invalid path!\n");
77 return INVALID_HANDLE_VALUE;
78 }
79
80 InitializeObjectAttributes(
81 &ObjectAttributes,
82 &NtPathU,
83 OBJ_CASE_INSENSITIVE,
84 NULL,
85 NULL);
86
87 Status = NtCreateFile(
88 &hFile,
89 Write ? FILE_GENERIC_WRITE : FILE_GENERIC_READ,
90 &ObjectAttributes,
91 &IoStatusBlock,
92 NULL,
93 0,
94 FILE_SHARE_READ|FILE_SHARE_WRITE,
95 FILE_OPEN,
96 0,
97 NULL,
98 0);
99
100 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU.Buffer);
101
102 if (!NT_SUCCESS(Status))
103 {
104 return INVALID_HANDLE_VALUE;
105 }
106
107 return hFile;
108 }
109
110 static NTSTATUS
111 GetFileSystem(
112 IN LPCWSTR Drive,
113 IN OUT LPWSTR FileSystemName,
114 IN SIZE_T FileSystemNameSize)
115 {
116 HANDLE FileHandle;
117 NTSTATUS Status;
118 IO_STATUS_BLOCK IoStatusBlock;
119 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
120 UCHAR Buffer[FS_ATTRIBUTE_BUFFER_SIZE];
121
122 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
123
124 FileHandle = OpenDirectory(Drive, FALSE);
125 if (FileHandle == INVALID_HANDLE_VALUE)
126 return STATUS_INVALID_PARAMETER;
127
128 Status = NtQueryVolumeInformationFile(FileHandle,
129 &IoStatusBlock,
130 FileFsAttribute,
131 FS_ATTRIBUTE_BUFFER_SIZE,
132 FileFsAttributeInformation);
133 NtClose(FileHandle);
134
135 if (NT_SUCCESS(Status))
136 {
137 if (FileSystemNameSize * sizeof(WCHAR) >= FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
138 {
139 CopyMemory(FileSystemName,
140 FileFsAttribute->FileSystemName,
141 FileFsAttribute->FileSystemNameLength);
142 FileSystemName[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = 0;
143 }
144 else
145 return STATUS_BUFFER_TOO_SMALL;
146 }
147 else
148 return Status;
149
150 return STATUS_SUCCESS;
151 }
152
153 // This is based on SysInternal's ChkDsk app
154 static BOOLEAN NTAPI
155 ChkdskCallback(
156 IN CALLBACKCOMMAND Command,
157 IN ULONG Modifier,
158 IN PVOID Argument)
159 {
160 PDWORD Percent;
161 PBOOLEAN Status;
162 PTEXTOUTPUT Output;
163
164 //
165 // We get other types of commands,
166 // but we don't have to pay attention to them
167 //
168 switch(Command)
169 {
170 case UNKNOWN2:
171 DPRINT("UNKNOWN2\r");
172 break;
173
174 case UNKNOWN3:
175 DPRINT("UNKNOWN3\r");
176 break;
177
178 case UNKNOWN4:
179 DPRINT("UNKNOWN4\r");
180 break;
181
182 case UNKNOWN5:
183 DPRINT("UNKNOWN5\r");
184 break;
185
186 case UNKNOWN9:
187 DPRINT("UNKNOWN9\r");
188 break;
189
190 case UNKNOWNA:
191 DPRINT("UNKNOWNA\r");
192 break;
193
194 case UNKNOWNC:
195 DPRINT("UNKNOWNC\r");
196 break;
197
198 case UNKNOWND:
199 DPRINT("UNKNOWND\r");
200 break;
201
202 case INSUFFICIENTRIGHTS:
203 DPRINT("INSUFFICIENTRIGHTS\r");
204 break;
205
206 case FSNOTSUPPORTED:
207 DPRINT("FSNOTSUPPORTED\r");
208 break;
209
210 case VOLUMEINUSE:
211 DPRINT("VOLUMEINUSE\r");
212 break;
213
214 case STRUCTUREPROGRESS:
215 DPRINT("STRUCTUREPROGRESS\r");
216 break;
217
218 case DONEWITHSTRUCTURE:
219 DPRINT("DONEWITHSTRUCTURE\r");
220 break;
221
222 case CLUSTERSIZETOOSMALL:
223 DPRINT("CLUSTERSIZETOOSMALL\r");
224 break;
225
226 case PROGRESS:
227 Percent = (PDWORD) Argument;
228 PrintString("%d percent completed.\r", *Percent);
229 break;
230
231 case OUTPUT:
232 Output = (PTEXTOUTPUT) Argument;
233 PrintString("%s", Output->Output);
234 break;
235
236 case DONE:
237 Status = (PBOOLEAN)Argument;
238 if (*Status == TRUE)
239 {
240 PrintString("Autochk was unable to complete successfully.\n\n");
241 //Error = TRUE;
242 }
243 break;
244 }
245 return TRUE;
246 }
247
248 /* Load the provider associated with this file system */
249 static PVOID
250 LoadProvider(
251 IN PWCHAR FileSystem)
252 {
253 UNICODE_STRING ProviderDll;
254 PVOID BaseAddress;
255 NTSTATUS Status;
256
257 /* FIXME: add more providers here */
258
259 if (wcscmp(FileSystem, L"NTFS") == 0)
260 {
261 RtlInitUnicodeString(&ProviderDll, L"untfs.dll");
262 }
263 else if (wcscmp(FileSystem, L"FAT") == 0
264 || wcscmp(FileSystem, L"FAT32") == 0)
265 {
266 RtlInitUnicodeString(&ProviderDll, L"ufat.dll");
267 }
268 else
269 {
270 return NULL;
271 }
272
273 Status = LdrLoadDll(NULL, NULL, &ProviderDll, &BaseAddress);
274 if (!NT_SUCCESS(Status))
275 return NULL;
276 return BaseAddress;
277 }
278
279 static NTSTATUS
280 CheckVolume(
281 IN PWCHAR DrivePath)
282 {
283 WCHAR FileSystem[128];
284 ANSI_STRING ChkdskFunctionName = RTL_CONSTANT_STRING("ChkdskEx");
285 PVOID Provider;
286 CHKDSKEX ChkdskFunc;
287 WCHAR NtDrivePath[64];
288 UNICODE_STRING DrivePathU;
289 NTSTATUS Status;
290
291 /* Get the file system */
292 Status = GetFileSystem(DrivePath,
293 FileSystem,
294 sizeof(FileSystem) / sizeof(FileSystem[0]));
295 if (!NT_SUCCESS(Status))
296 {
297 DPRINT1("GetFileSystem() failed with status 0x%08lx\n", Status);
298 PrintString(" Unable to get file system of %S\n", DrivePath);
299 return Status;
300 }
301
302 /* Load the provider which will do the chkdsk */
303 Provider = LoadProvider(FileSystem);
304 if (Provider == NULL)
305 {
306 DPRINT1("LoadProvider() failed\n");
307 PrintString(" Unable to verify a %S volume\n", FileSystem);
308 return STATUS_DLL_NOT_FOUND;
309 }
310
311 /* Get the Chkdsk function address */
312 Status = LdrGetProcedureAddress(Provider,
313 &ChkdskFunctionName,
314 0,
315 (PVOID*)&ChkdskFunc);
316 if (!NT_SUCCESS(Status))
317 {
318 DPRINT1("LdrGetProcedureAddress() failed with status 0x%08lx\n", Status);
319 PrintString(" Unable to verify a %S volume\n", FileSystem);
320 LdrUnloadDll(Provider);
321 return Status;
322 }
323
324 /* Call provider */
325 //PrintString(" Verifying volume %S\n", DrivePath);
326 swprintf(NtDrivePath, L"\\??\\");
327 wcscat(NtDrivePath, DrivePath);
328 NtDrivePath[wcslen(NtDrivePath)-1] = 0;
329 RtlInitUnicodeString(&DrivePathU, NtDrivePath);
330
331 Status = ChkdskFunc(&DrivePathU,
332 TRUE, // FixErrors
333 TRUE, // Verbose
334 TRUE, // CheckOnlyIfDirty
335 FALSE,// ScanDrive
336 ChkdskCallback);
337
338 LdrUnloadDll(Provider);
339 return Status;
340 }
341
342 /* Native image's entry point */
343 int
344 _cdecl
345 _main(int argc,
346 char *argv[],
347 char *envp[],
348 int DebugFlag)
349 {
350 PROCESS_DEVICEMAP_INFORMATION DeviceMap;
351 ULONG i;
352 NTSTATUS Status;
353 WCHAR DrivePath[128];
354
355 // Win2003 passes the only param - "*". Probably means to check all drives
356 /*
357 DPRINT("Got %d params\n", argc);
358 for (i=0; i<argc; i++)
359 DPRINT("Param %d: %s\n", i, argv[i]);
360 */
361
362 /* FIXME: We should probably use here the mount manager to be
363 * able to check volumes which don't have a drive letter.
364 */
365
366 Status = NtQueryInformationProcess(NtCurrentProcess(),
367 ProcessDeviceMap,
368 &DeviceMap.Query,
369 sizeof(DeviceMap.Query),
370 NULL);
371 if (!NT_SUCCESS(Status))
372 {
373 DPRINT1("NtQueryInformationProcess() failed with status 0x%08lx\n",
374 Status);
375 return 1;
376 }
377
378 for (i = 0; i < 26; i++)
379 {
380 if ((DeviceMap.Query.DriveMap & (1 << i))
381 && (DeviceMap.Query.DriveType[i] == DOSDEVICE_DRIVE_FIXED))
382 {
383 swprintf(DrivePath, L"%c:\\", L'A'+i);
384 CheckVolume(DrivePath);
385 }
386 }
387 //PrintString(" Done\n\n");
388 return 0;
389 }
390
391 /* EOF */