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