1 //======================================================================
5 // Copyright (c) 1998 Mark Russinovich
7 // http://www.sysinternals.com
9 // Chkdsk clone that demonstrates the use of the FMIFS file system
12 // --------------------------------------------------------------------
14 // This software is free software; you can redistribute it and/or
15 // modify it under the terms of the GNU Library General Public License as
16 // published by the Free Software Foundation; either version 2 of the
17 // License, or (at your option) any later version.
19 // This software is distributed in the hope that it will be useful,
20 // but WITHOUT ANY WARRANTY; without even the implied warranty of
21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
22 // Library General Public License for more details.
24 // You should have received a copy of the GNU Library General Public
25 // License along with this software; see the file COPYING.LIB. If
26 // not, write to the Free Software Foundation, Inc., 675 Mass Ave,
27 // Cambridge, MA 02139, USA.
29 // --------------------------------------------------------------------
31 // 1999 February (Emanuele Aliberti)
32 // Adapted for ReactOS and lcc-win32.
34 // 1999 April (Emanuele Aliberti)
35 // Adapted for ReactOS and egcs.
37 // 2008 July (Aleksey Bragin)
38 // Cleanup, use ReactOS's fmifs.h
40 //======================================================================
44 /* PSDK/NDK Headers */
45 #define WIN32_NO_STATUS
52 #define NTOS_MODE_USER
53 #include <ndk/ntndk.h>
55 /* FMIFS Public Header */
56 #include <fmifs/fmifs.h>
58 #define FMIFS_IMPORT_DLL
66 BOOL FixErrors
= FALSE
;
67 BOOL SkipClean
= FALSE
;
68 BOOL ScanSectors
= FALSE
;
71 WCHAR CurrentDirectory
[1024];
73 #ifndef FMIFS_IMPORT_DLL
75 // Functions in FMIFS.DLL
81 //----------------------------------------------------------------------
85 // Takes the win32 error code and prints the text version.
87 //----------------------------------------------------------------------
88 static VOID
PrintWin32Error(LPWSTR Message
, DWORD ErrorCode
)
90 ConPrintf(StdErr
, L
"%s: ", Message
);
91 ConMsgPuts(StdErr
, FORMAT_MESSAGE_FROM_SYSTEM
,
92 NULL
, ErrorCode
, LANG_USER_DEFAULT
);
93 ConPuts(StdErr
, L
"\n");
97 //--------------------------------------------------------------------
101 // Intercepts Ctrl-C's so that the program can't be quit with the
102 // disk in an inconsistent state.
104 //--------------------------------------------------------------------
107 CtrlCIntercept(DWORD dwCtrlType
)
110 // Handle the event so that the default handler doesn't
116 //----------------------------------------------------------------------
120 // Tell the user how to use the program
122 //----------------------------------------------------------------------
124 Usage(PWCHAR ProgramName
)
127 L
"Usage: %s [drive:] [-F] [-V] [-R] [-C]\n\n"
128 L
"[drive:] Specifies the drive to check.\n"
129 L
"-F Fixes errors on the disk.\n"
130 L
"-V Displays the full path of every file on the disk.\n"
131 L
"-R Locates bad sectors and recovers readable information.\n"
132 L
"-C Checks the drive only if it is dirty.\n\n",
137 //----------------------------------------------------------------------
143 //----------------------------------------------------------------------
145 ParseCommandLine(int argc
, WCHAR
*argv
[])
148 BOOLEAN gotFix
= FALSE
;
149 BOOLEAN gotVerbose
= FALSE
;
150 BOOLEAN gotClean
= FALSE
;
151 // BOOLEAN gotScan = FALSE;
153 for (i
= 1; i
< argc
; i
++)
157 case L
'-': case L
'/':
165 case L
'F': case L
'f':
167 if (gotFix
) return i
;
173 case L
'V': case L
'v':
175 if (gotVerbose
) return i
;
181 case L
'R': case L
'r':
183 if (gotFix
) return i
;
189 case L
'C': case L
'c':
191 if (gotClean
) return i
;
205 if (argv
[i
][1] != L
':') return i
;
216 //----------------------------------------------------------------------
220 // The file system library will call us back with commands that we
221 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
223 //----------------------------------------------------------------------
227 CALLBACKCOMMAND Command
,
236 // We get other types of commands,
237 // but we don't have to pay attention to them
242 ConPuts(StdOut
, L
"UNKNOWN2\r");
246 ConPuts(StdOut
, L
"UNKNOWN3\n");
250 ConPuts(StdOut
, L
"UNKNOWN4\n");
254 ConPuts(StdOut
, L
"UNKNOWN5\n");
258 ConPuts(StdOut
, L
"FSNOTSUPPORTED\n");
262 ConPuts(StdOut
, L
"VOLUMEINUSE\n");
266 ConPuts(StdOut
, L
"UNKNOWN9\n");
270 ConPuts(StdOut
, L
"UNKNOWNA\n");
274 ConPuts(StdOut
, L
"UNKNOWNC\n");
278 ConPuts(StdOut
, L
"UNKNOWND\n");
281 case INSUFFICIENTRIGHTS
:
282 ConPuts(StdOut
, L
"INSUFFICIENTRIGHTS\n");
285 case STRUCTUREPROGRESS
:
286 ConPuts(StdOut
, L
"STRUCTUREPROGRESS\n");
289 case DONEWITHSTRUCTURE
:
290 ConPuts(StdOut
, L
"DONEWITHSTRUCTURE\n");
293 case CLUSTERSIZETOOSMALL
:
294 ConPuts(StdOut
, L
"CLUSTERSIZETOOSMALL\n");
298 percent
= (PDWORD
)Argument
;
299 ConPrintf(StdOut
, L
"%d percent completed.\r", *percent
);
303 output
= (PTEXTOUTPUT
)Argument
;
304 ConPrintf(StdOut
, L
"%S", output
->Output
);
308 status
= (PBOOLEAN
)Argument
;
309 if (*status
== FALSE
)
311 ConPuts(StdOut
, L
"Chkdsk was unable to complete successfully.\n\n");
319 #ifndef FMIFS_IMPORT_DLL
320 //----------------------------------------------------------------------
322 // LoadFMIFSEntryPoints
324 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
326 //----------------------------------------------------------------------
328 LoadFMIFSEntryPoints(VOID
)
330 HMODULE hFmifs
= LoadLibraryW(L
"fmifs.dll");
334 Chkdsk
= (PCHKDSK
)GetProcAddress(hFmifs
, "Chkdsk");
346 //----------------------------------------------------------------------
350 // Engine. Just get command line switches and fire off a chkdsk. This
351 // could also be done in a GUI like Explorer does when you select a
352 // drive and run a check on it.
354 // We do this in UNICODE because the chkdsk command expects PWCHAR
357 //----------------------------------------------------------------------
359 wmain(int argc
, WCHAR
*argv
[])
363 WCHAR fileSystem
[1024];
364 WCHAR volumeName
[1024];
366 DWORD flags
, maxComponent
;
368 /* Initialize the Console Standard Streams */
373 L
"Chkdskx v1.0.1 by Mark Russinovich\n"
374 L
"Systems Internals - http://www.sysinternals.com\n"
375 L
"ReactOS adaptation 1999 by Emanuele Aliberti\n\n");
377 #ifndef FMIFS_IMPORT_DLL
379 // Get function pointers
381 if (!LoadFMIFSEntryPoints())
383 ConPuts(StdErr
, L
"Could not located FMIFS entry points.\n\n");
389 // Parse command line
391 badArg
= ParseCommandLine(argc
, argv
);
394 ConPrintf(StdOut
, L
"Unknown argument: %s\n", argv
[badArg
]);
400 // Get the drive's format
404 if (!GetCurrentDirectoryW(ARRAYSIZE(CurrentDirectory
), CurrentDirectory
))
406 PrintWin32Error(L
"Could not get current directory", GetLastError());
412 wcscpy(CurrentDirectory
, Drive
);
414 CurrentDirectory
[2] = L
'\\';
415 CurrentDirectory
[3] = L
'\0';
416 Drive
= CurrentDirectory
;
419 // Determine the drive's file system format, which we need to
422 if (!GetVolumeInformationW(Drive
,
424 ARRAYSIZE(volumeName
),
429 ARRAYSIZE(fileSystem
)))
431 PrintWin32Error(L
"Could not query volume", GetLastError());
436 // If they want to fix, we need to have access to the drive
440 swprintf(volumeName
, L
"\\\\.\\%C:", Drive
[0]);
441 volumeHandle
= CreateFileW(volumeName
,
448 if (volumeHandle
== INVALID_HANDLE_VALUE
)
450 ConPuts(StdErr
, L
"Chkdsk cannot run because the volume is in use by another process.\n\n");
453 CloseHandle(volumeHandle
);
456 // Can't let the user break out of a chkdsk that can modify the drive
458 SetConsoleCtrlHandler(CtrlCIntercept
, TRUE
);
464 ConPrintf(StdOut
, L
"The type of file system is %s.\n", fileSystem
);
475 if (Error
) return -1;