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
55 #define NTOS_MODE_USER
56 #include <ndk/ntndk.h>
58 /* FMIFS Public Header */
59 #include <fmifs/fmifs.h>
61 #define FMIFS_IMPORT_DLL
69 BOOL FixErrors
= FALSE
;
70 BOOL SkipClean
= FALSE
;
71 BOOL ScanSectors
= FALSE
;
74 WCHAR CurrentDirectory
[1024];
76 #ifndef FMIFS_IMPORT_DLL
78 // Functions in FMIFS.DLL
84 //----------------------------------------------------------------------
88 // Takes the win32 error code and prints the text version.
90 //----------------------------------------------------------------------
91 static VOID
PrintWin32Error(int Message
, DWORD ErrorCode
)
93 ConResPuts(StdErr
, Message
);
94 ConMsgPuts(StdErr
, FORMAT_MESSAGE_FROM_SYSTEM
,
95 NULL
, ErrorCode
, LANG_USER_DEFAULT
);
96 ConPuts(StdErr
, L
"\n");
100 //--------------------------------------------------------------------
104 // Intercepts Ctrl-C's so that the program can't be quit with the
105 // disk in an inconsistent state.
107 //--------------------------------------------------------------------
110 CtrlCIntercept(DWORD dwCtrlType
)
113 // Handle the event so that the default handler doesn't
119 //----------------------------------------------------------------------
123 // Tell the user how to use the program
125 //----------------------------------------------------------------------
127 Usage(PWCHAR ProgramName
)
129 ConResPrintf(StdOut
, IDS_USAGE
, ProgramName
);
133 //----------------------------------------------------------------------
139 //----------------------------------------------------------------------
141 ParseCommandLine(int argc
, WCHAR
*argv
[])
144 BOOLEAN gotFix
= FALSE
;
145 BOOLEAN gotVerbose
= FALSE
;
146 BOOLEAN gotClean
= FALSE
;
147 // BOOLEAN gotScan = FALSE;
149 for (i
= 1; i
< argc
; i
++)
153 case L
'-': case L
'/':
161 case L
'F': case L
'f':
163 if (gotFix
) return i
;
169 case L
'V': case L
'v':
171 if (gotVerbose
) return i
;
177 case L
'R': case L
'r':
179 if (gotFix
) return i
;
185 case L
'C': case L
'c':
187 if (gotClean
) return i
;
201 if (argv
[i
][1] != L
':') return i
;
212 //----------------------------------------------------------------------
216 // The file system library will call us back with commands that we
217 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
219 //----------------------------------------------------------------------
223 CALLBACKCOMMAND Command
,
233 // We get other types of commands,
234 // but we don't have to pay attention to them
240 ConPuts(StdOut
, L
"UNKNOWN2\r");
244 ConPuts(StdOut
, L
"UNKNOWN3\n");
248 ConPuts(StdOut
, L
"UNKNOWN4\n");
252 ConPuts(StdOut
, L
"UNKNOWN5\n");
256 ConPuts(StdOut
, L
"FSNOTSUPPORTED\n");
260 ConResPuts(StdOut
, IDS_VOLUME_IN_USE
);
265 ConPuts(StdOut
, L
"UNKNOWN9\n");
269 ConPuts(StdOut
, L
"UNKNOWNA\n");
273 ConPuts(StdOut
, L
"UNKNOWNC\n");
277 ConPuts(StdOut
, L
"UNKNOWND\n");
280 case INSUFFICIENTRIGHTS
:
281 ConPuts(StdOut
, L
"INSUFFICIENTRIGHTS\n");
284 case STRUCTUREPROGRESS
:
285 ConPuts(StdOut
, L
"STRUCTUREPROGRESS\n");
288 case DONEWITHSTRUCTURE
:
289 ConPuts(StdOut
, L
"DONEWITHSTRUCTURE\n");
292 case CLUSTERSIZETOOSMALL
:
293 ConPuts(StdOut
, L
"CLUSTERSIZETOOSMALL\n");
297 percent
= (PDWORD
)Argument
;
298 ConResPrintf(StdOut
, IDS_PERCENT_COMPL
, *percent
);
302 output
= (PTEXTOUTPUT
)Argument
;
303 ConPrintf(StdOut
, L
"%S", output
->Output
);
307 status
= (PBOOLEAN
)Argument
;
308 if (*status
== FALSE
)
310 ConResPuts(StdOut
, IDS_CHKDSK_FAIL
);
318 #ifndef FMIFS_IMPORT_DLL
319 //----------------------------------------------------------------------
321 // LoadFMIFSEntryPoints
323 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
325 //----------------------------------------------------------------------
327 LoadFMIFSEntryPoints(VOID
)
329 HMODULE hFmifs
= LoadLibraryW(L
"fmifs.dll");
333 Chkdsk
= (PCHKDSK
)GetProcAddress(hFmifs
, "Chkdsk");
345 //----------------------------------------------------------------------
349 // Engine. Just get command line switches and fire off a chkdsk. This
350 // could also be done in a GUI like Explorer does when you select a
351 // drive and run a check on it.
353 // We do this in UNICODE because the chkdsk command expects PWCHAR
356 //----------------------------------------------------------------------
358 wmain(int argc
, WCHAR
*argv
[])
362 WCHAR fileSystem
[1024];
363 WCHAR volumeName
[1024];
365 DWORD flags
, maxComponent
;
367 /* Initialize the Console Standard Streams */
370 ConResPuts(StdOut
, IDS_ABOUT
);
372 #ifndef FMIFS_IMPORT_DLL
374 // Get function pointers
376 if (!LoadFMIFSEntryPoints())
378 ConResPuts(StdErr
, IDS_NO_ENTRY_POINT
);
384 // Parse command line
386 badArg
= ParseCommandLine(argc
, argv
);
389 ConResPrintf(StdOut
, IDS_BAD_ARGUMENT
, argv
[badArg
]);
395 // Get the drive's format
399 if (!GetCurrentDirectoryW(ARRAYSIZE(CurrentDirectory
), CurrentDirectory
))
401 PrintWin32Error(IDS_NO_CURRENT_DIR
, GetLastError());
407 wcscpy(CurrentDirectory
, Drive
);
409 CurrentDirectory
[2] = L
'\\';
410 CurrentDirectory
[3] = L
'\0';
411 Drive
= CurrentDirectory
;
414 // Determine the drive's file system format, which we need to
417 if (!GetVolumeInformationW(Drive
,
419 ARRAYSIZE(volumeName
),
424 ARRAYSIZE(fileSystem
)))
426 PrintWin32Error(IDS_NO_QUERY_VOL
, GetLastError());
431 // If they want to fix, we need to have access to the drive
435 swprintf(volumeName
, L
"\\\\.\\%C:", Drive
[0]);
436 volumeHandle
= CreateFileW(volumeName
,
443 if (volumeHandle
== INVALID_HANDLE_VALUE
)
445 ConResPuts(StdErr
, IDS_VOLUME_IN_USE_PROC
);
448 CloseHandle(volumeHandle
);
451 // Can't let the user break out of a chkdsk that can modify the drive
453 SetConsoleCtrlHandler(CtrlCIntercept
, TRUE
);
459 ConResPrintf(StdOut
, IDS_FILE_SYSTEM
, fileSystem
);
470 if (Error
) return -1;