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
11 /* INCLUDES *****************************************************************/
14 #define WIN32_NO_STATUS
17 #define NTOS_MODE_USER
18 #include <ndk/exfuncs.h>
19 #include <ndk/iofuncs.h>
20 #include <ndk/obfuncs.h>
21 #include <ndk/psfuncs.h>
22 #include <ndk/rtlfuncs.h>
23 #include <ndk/umfuncs.h>
24 #include <fmifs/fmifs.h>
29 /* DEFINES ******************************************************************/
31 #define FS_ATTRIBUTE_BUFFER_SIZE (MAX_PATH * sizeof(WCHAR) + sizeof(FILE_FS_ATTRIBUTE_INFORMATION))
34 /* FUNCTIONS ****************************************************************/
40 PrintString(char* fmt
,...)
44 UNICODE_STRING UnicodeString
;
45 ANSI_STRING AnsiString
;
48 vsprintf(buffer
, fmt
, ap
);
51 RtlInitAnsiString(&AnsiString
, buffer
);
52 RtlAnsiStringToUnicodeString(&UnicodeString
,
55 NtDisplayString(&UnicodeString
);
56 RtlFreeUnicodeString(&UnicodeString
);
59 // this func is taken from kernel32/file/volume.c
65 UNICODE_STRING NtPathU
;
66 OBJECT_ATTRIBUTES ObjectAttributes
;
68 IO_STATUS_BLOCK IoStatusBlock
;
71 if (!RtlDosPathNameToNtPathName_U(DirName
,
76 DPRINT1("Invalid path!\n");
77 return INVALID_HANDLE_VALUE
;
80 InitializeObjectAttributes(
87 Status
= NtCreateFile(
89 Write
? FILE_GENERIC_WRITE
: FILE_GENERIC_READ
,
94 FILE_SHARE_READ
|FILE_SHARE_WRITE
,
100 RtlFreeHeap(RtlGetProcessHeap(), 0, NtPathU
.Buffer
);
102 if (!NT_SUCCESS(Status
))
104 return INVALID_HANDLE_VALUE
;
113 IN OUT LPWSTR FileSystemName
,
114 IN SIZE_T FileSystemNameSize
)
118 IO_STATUS_BLOCK IoStatusBlock
;
119 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
120 UCHAR Buffer
[FS_ATTRIBUTE_BUFFER_SIZE
];
122 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
124 FileHandle
= OpenDirectory(Drive
, FALSE
);
125 if (FileHandle
== INVALID_HANDLE_VALUE
)
126 return STATUS_INVALID_PARAMETER
;
128 Status
= NtQueryVolumeInformationFile(FileHandle
,
131 FS_ATTRIBUTE_BUFFER_SIZE
,
132 FileFsAttributeInformation
);
135 if (NT_SUCCESS(Status
))
137 if (FileSystemNameSize
* sizeof(WCHAR
) >= FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
139 CopyMemory(FileSystemName
,
140 FileFsAttribute
->FileSystemName
,
141 FileFsAttribute
->FileSystemNameLength
);
142 FileSystemName
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = 0;
145 return STATUS_BUFFER_TOO_SMALL
;
150 return STATUS_SUCCESS
;
153 // This is based on SysInternal's ChkDsk app
156 IN CALLBACKCOMMAND Command
,
165 // We get other types of commands,
166 // but we don't have to pay attention to them
171 DPRINT("UNKNOWN2\n");
175 DPRINT("UNKNOWN3\n");
179 DPRINT("UNKNOWN4\n");
183 DPRINT("UNKNOWN5\n");
187 DPRINT("UNKNOWN9\n");
191 DPRINT("UNKNOWNA\n");
195 DPRINT("UNKNOWNC\n");
199 DPRINT("UNKNOWND\n");
202 case INSUFFICIENTRIGHTS
:
203 DPRINT("INSUFFICIENTRIGHTS\n");
207 DPRINT("FSNOTSUPPORTED\n");
211 DPRINT("VOLUMEINUSE\n");
214 case STRUCTUREPROGRESS
:
215 DPRINT("STRUCTUREPROGRESS\n");
218 case DONEWITHSTRUCTURE
:
219 DPRINT("DONEWITHSTRUCTURE\n");
222 case CLUSTERSIZETOOSMALL
:
223 DPRINT("CLUSTERSIZETOOSMALL\n");
227 Percent
= (PDWORD
) Argument
;
228 PrintString("%d percent completed.\r", *Percent
);
232 Output
= (PTEXTOUTPUT
) Argument
;
233 PrintString("%s", Output
->Output
);
237 Status
= (PBOOLEAN
)Argument
;
240 PrintString("Autochk was unable to complete successfully.\r\n\r\n");
248 /* Load the provider associated with this file system */
251 IN PWCHAR FileSystem
)
253 UNICODE_STRING ProviderDll
;
257 /* FIXME: add more providers here */
259 if (wcscmp(FileSystem
, L
"NTFS") == 0)
261 RtlInitUnicodeString(&ProviderDll
, L
"untfs.dll");
263 else if (wcscmp(FileSystem
, L
"FAT") == 0
264 || wcscmp(FileSystem
, L
"FAT32") == 0)
266 RtlInitUnicodeString(&ProviderDll
, L
"ufat.dll");
268 else if (wcscmp(FileSystem
, L
"EXT2") == 0
269 || wcscmp(FileSystem
, L
"EXT3") == 0
270 || wcscmp(FileSystem
, L
"EXT4") == 0)
272 RtlInitUnicodeString(&ProviderDll
, L
"uext2.dll");
274 else if (wcscmp(FileSystem
, L
"Btrfs") == 0)
276 RtlInitUnicodeString(&ProviderDll
, L
"ubtrfs.dll");
278 else if (wcscmp(FileSystem
, L
"RFSD") == 0)
280 RtlInitUnicodeString(&ProviderDll
, L
"ureiserfs.dll");
287 Status
= LdrLoadDll(NULL
, NULL
, &ProviderDll
, &BaseAddress
);
288 if (!NT_SUCCESS(Status
))
297 WCHAR FileSystem
[128];
298 ANSI_STRING ChkdskFunctionName
= RTL_CONSTANT_STRING("ChkdskEx");
301 WCHAR NtDrivePath
[64];
302 UNICODE_STRING DrivePathU
;
305 /* Get the file system */
306 Status
= GetFileSystem(DrivePath
,
308 ARRAYSIZE(FileSystem
));
309 if (!NT_SUCCESS(Status
))
311 DPRINT1("GetFileSystem() failed with status 0x%08lx\n", Status
);
312 PrintString(" Unable to get file system of %S\r\n", DrivePath
);
316 /* Load the provider which will do the chkdsk */
317 Provider
= LoadProvider(FileSystem
);
318 if (Provider
== NULL
)
320 DPRINT1("LoadProvider() failed\n");
321 PrintString(" Unable to verify a %S volume\r\n", FileSystem
);
322 return STATUS_DLL_NOT_FOUND
;
325 /* Get the Chkdsk function address */
326 Status
= LdrGetProcedureAddress(Provider
,
329 (PVOID
*)&ChkdskFunc
);
330 if (!NT_SUCCESS(Status
))
332 DPRINT1("LdrGetProcedureAddress() failed with status 0x%08lx\n", Status
);
333 PrintString(" Unable to verify a %S volume\r\n", FileSystem
);
334 LdrUnloadDll(Provider
);
339 // PrintString(" Verifying volume %S\r\n", DrivePath);
340 swprintf(NtDrivePath
, L
"\\??\\");
341 wcscat(NtDrivePath
, DrivePath
);
342 NtDrivePath
[wcslen(NtDrivePath
)-1] = 0;
343 RtlInitUnicodeString(&DrivePathU
, NtDrivePath
);
345 DPRINT1("AUTOCHK: Checking %wZ\n", &DrivePathU
);
346 Status
= ChkdskFunc(&DrivePathU
,
349 TRUE
, // CheckOnlyIfDirty
353 LdrUnloadDll(Provider
);
357 /* Native image's entry point */
365 PROCESS_DEVICEMAP_INFORMATION DeviceMap
;
368 WCHAR DrivePath
[128];
370 // Win2003 passes the only param - "*". Probably means to check all drives
372 DPRINT("Got %d params\n", argc);
373 for (i=0; i<argc; i++)
374 DPRINT("Param %d: %s\n", i, argv[i]);
377 /* FIXME: We should probably use here the mount manager to be
378 * able to check volumes which don't have a drive letter.
381 Status
= NtQueryInformationProcess(NtCurrentProcess(),
384 sizeof(DeviceMap
.Query
),
386 if (!NT_SUCCESS(Status
))
388 DPRINT1("NtQueryInformationProcess() failed with status 0x%08lx\n",
393 for (i
= 0; i
< 26; i
++)
395 if ((DeviceMap
.Query
.DriveMap
& (1 << i
))
396 && (DeviceMap
.Query
.DriveType
[i
] == DOSDEVICE_DRIVE_FIXED
))
398 swprintf(DrivePath
, L
"%c:\\", L
'A'+i
);
399 CheckVolume(DrivePath
);
402 // PrintString(" Done\r\n\r\n");