bf15c55e8c419fb64aebb30d41e346199a7df101
[reactos.git] / rosapps / applications / sysutils / chkdsk / chkdsk.c
1 //======================================================================
2 //
3 // $Id$
4 //
5 // Chkdskx
6 //
7 // Copyright (c) 1998 Mark Russinovich
8 // Systems Internals
9 // http://www.sysinternals.com/
10 //
11 // --------------------------------------------------------------------
12 //
13 // This software is free software; you can redistribute it and/or
14 // modify it under the terms of the GNU Library General Public License as
15 // published by the Free Software Foundation; either version 2 of the
16 // License, or (at your option) any later version.
17 //
18 // This software is distributed in the hope that it will be useful,
19 // but WITHOUT ANY WARRANTY; without even the implied warranty of
20 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 // Library General Public License for more details.
22 //
23 // You should have received a copy of the GNU Library General Public
24 // License along with this software; see the file COPYING.LIB. If
25 // not, write to the Free Software Foundation, Inc., 675 Mass Ave,
26 // Cambridge, MA 02139, USA.
27 //
28 // --------------------------------------------------------------------
29 //
30 // Chkdsk clone that demonstrates the use of the FMIFS file system
31 // utility library.
32 //
33 // 1999 February (Emanuele Aliberti)
34 // Adapted for ReactOS and lcc-win32.
35 //
36 // 1999 April (Emanuele Aliberti)
37 // Adapted for ReactOS and egcs.
38 //
39 // 2008 July (Aleksey Bragin)
40 // Cleanup, use ReactOS's fmifs.h
41 //
42 //======================================================================
43 #define WIN32_NO_STATUS
44 #define NTOS_MODE_USER
45 #define UNICODE
46 #include <windows.h>
47 #include <stdio.h>
48 #include <ndk/ntndk.h>
49 #include <fmifs/fmifs.h>
50 #define _UNICODE 1
51 #include <tchar.h>
52 #include "config.h"
53 #include "win32err.h"
54
55 //
56 // Globals
57 //
58 BOOL Error = FALSE;
59
60 // switches
61 BOOL FixErrors = FALSE;
62 BOOL SkipClean = FALSE;
63 BOOL ScanSectors = FALSE;
64 BOOL Verbose = FALSE;
65 PWCHAR Drive = NULL;
66 WCHAR CurrentDirectory[1024];
67
68 #ifndef FMIFS_IMPORT_DLL
69 //
70 // FMIFS function
71 //
72 //PCHKDSK Chkdsk;
73 #endif /* ndef FMIFS_IMPORT_DLL */
74
75
76 //--------------------------------------------------------------------
77 //
78 // CtrlCIntercept
79 //
80 // Intercepts Ctrl-C's so that the program can't be quit with the
81 // disk in an inconsistent state.
82 //
83 //--------------------------------------------------------------------
84 BOOL
85 WINAPI
86 CtrlCIntercept( DWORD dwCtrlType )
87 {
88 //
89 // Handle the event so that the default handler doesn't
90 //
91 return TRUE;
92 }
93
94
95 //----------------------------------------------------------------------
96 //
97 // Usage
98 //
99 // Tell the user how to use the program
100 //
101 // 19990216 EA Missing printf %s argument
102 //----------------------------------------------------------------------
103 VOID
104 Usage( PWCHAR ProgramName )
105 {
106 _tprintf(
107 L"\
108 Usage: %s [drive:] [-F] [-V] [-R] [-C]\n\n\
109 [drive:] Specifies the drive to check.\n\
110 -F Fixes errors on the disk.\n\
111 -V Displays the full path of every file on the disk.\n\
112 -R Locates bad sectors and recovers readable information.\n\
113 -C Checks the drive only if it is dirty.\n\n",
114 ProgramName
115 );
116 }
117
118
119 //----------------------------------------------------------------------
120 //
121 // ParseCommandLine
122 //
123 // Get the switches.
124 //
125 //----------------------------------------------------------------------
126 int
127 ParseCommandLine(
128 int argc,
129 WCHAR *argv []
130 )
131 {
132 int i;
133 BOOLEAN gotFix = FALSE;
134 BOOLEAN gotVerbose = FALSE;
135 BOOLEAN gotClean = FALSE;
136 /*BOOLEAN gotScan = FALSE;*/
137
138
139 for ( i = 1;
140 (i < argc);
141 i++
142 ) {
143 switch( argv[i][0] )
144 {
145 case L'-':
146 case L'/':
147
148 switch( argv[i][1] )
149 {
150 case L'F':
151 case L'f':
152
153 if( gotFix ) return i;
154 FixErrors = TRUE;
155 gotFix = TRUE;
156 break;
157
158 case L'V':
159 case L'v':
160
161 if( gotVerbose) return i;
162 Verbose = TRUE;
163 gotVerbose = TRUE;
164 break;
165
166 case L'R':
167 case L'r':
168
169 if( gotFix ) return i;
170 ScanSectors = TRUE;
171 gotFix = TRUE;
172 break;
173
174 case L'C':
175 case L'c':
176
177 if( gotClean ) return i;
178 SkipClean = TRUE;
179 gotClean = TRUE;
180 break;
181
182 default:
183 return i;
184 }
185 break;
186
187 default:
188
189 if( Drive ) return i;
190 if( argv[i][1] != L':' ) return i;
191
192 Drive = argv[i];
193 break;
194 }
195 }
196 return 0;
197 }
198
199
200 //----------------------------------------------------------------------
201 //
202 // ChkdskCallback
203 //
204 // The file system library will call us back with commands that we
205 // can interpret. If we wanted to halt the chkdsk we could return FALSE.
206 //
207 //----------------------------------------------------------------------
208 BOOLEAN
209 STDCALL
210 ChkdskCallback(
211 CALLBACKCOMMAND Command,
212 DWORD Modifier,
213 PVOID Argument
214 )
215 {
216 PDWORD percent;
217 PBOOLEAN status;
218 PTEXTOUTPUT output;
219
220 //
221 // We get other types of commands,
222 // but we don't have to pay attention to them
223 //
224 switch( Command )
225 {
226 case UNKNOWN2:
227 wprintf(L"UNKNOWN2\r");
228 break;
229
230 case UNKNOWN3:
231 wprintf(L"UNKNOWN3\r");
232 break;
233
234 case UNKNOWN4:
235 wprintf(L"UNKNOWN4\r");
236 break;
237
238 case UNKNOWN5:
239 wprintf(L"UNKNOWN5\r");
240 break;
241
242 case FSNOTSUPPORTED:
243 wprintf(L"FSNOTSUPPORTED\r");
244 break;
245
246 case VOLUMEINUSE:
247 wprintf(L"VOLUMEINUSE\r");
248 break;
249
250 case UNKNOWN9:
251 wprintf(L"UNKNOWN9\r");
252 break;
253
254 case UNKNOWNA:
255 wprintf(L"UNKNOWNA\r");
256 break;
257
258 case UNKNOWNC:
259 wprintf(L"UNKNOWNC\r");
260 break;
261
262 case UNKNOWND:
263 wprintf(L"UNKNOWND\r");
264 break;
265
266 case INSUFFICIENTRIGHTS:
267 wprintf(L"INSUFFICIENTRIGHTS\r");
268 break;
269
270 case STRUCTUREPROGRESS:
271 wprintf(L"STRUCTUREPROGRESS\r");
272 break;
273
274 case DONEWITHSTRUCTURE:
275 wprintf(L"DONEWITHSTRUCTURE\r");
276 break;
277
278 case CLUSTERSIZETOOSMALL:
279 wprintf(L"CLUSTERSIZETOOSMALL\r");
280 break;
281
282 case PROGRESS:
283 percent = (PDWORD) Argument;
284 wprintf(L"%d percent completed.\r", *percent);
285 break;
286
287 case OUTPUT:
288 output = (PTEXTOUTPUT) Argument;
289 fwprintf(stdout, L"%s", output->Output);
290 break;
291
292 case DONE:
293 status = (PBOOLEAN) Argument;
294 if ( *status == TRUE )
295 {
296 wprintf(L"Chkdsk was unable to complete successfully.\n\n");
297 Error = TRUE;
298 }
299 break;
300 }
301 return TRUE;
302 }
303
304 #ifndef FMIFS_IMPORT_DLL
305 //----------------------------------------------------------------------
306 //
307 // LoadFMIFSEntryPoints
308 //
309 // Loads FMIFS.DLL and locates the entry point(s) we are going to use
310 //
311 // 19990216 EA Used wide functions
312 //
313 //----------------------------------------------------------------------
314 BOOLEAN
315 LoadFMIFSEntryPoints(VOID)
316 {
317 LoadLibraryW( L"fmifs.dll" );
318
319 if( !(Chkdsk =
320 (void *) GetProcAddress(
321 GetModuleHandleW(L"fmifs.dll"),
322 "Chkdsk" ))
323 )
324 {
325 return FALSE;
326 }
327 return TRUE;
328 }
329 #endif /* ndef FMIFS_IMPORT_DLL */
330
331
332 //----------------------------------------------------------------------
333 //
334 // WMain
335 //
336 // Engine. Just get command line switches and fire off a chkdsk. This
337 // could also be done in a GUI like Explorer does when you select a
338 // drive and run a check on it.
339 //
340 // We do this in UNICODE because the chkdsk command expects PWCHAR
341 // arguments.
342 //
343 //----------------------------------------------------------------------
344 int
345 wmain( int argc, WCHAR *argv[] )
346 {
347 int badArg;
348 HANDLE volumeHandle;
349 WCHAR fileSystem [1024];
350 WCHAR volumeName [1024];
351 DWORD serialNumber;
352 DWORD flags,
353 maxComponent;
354
355 wprintf(
356 L"\n\
357 Chkdskx v1.0.1 by Mark Russinovich\n\
358 Systems Internals - http://www.sysinternals.com/\n\
359 ReactOS adaptation 1999 by Emanuele Aliberti\n\n"
360 );
361 #ifndef FMIFS_IMPORT_DLL
362 //
363 // Get function pointers
364 //
365 if( !LoadFMIFSEntryPoints())
366 {
367 wprintf(L"Could not located FMIFS entry points.\n\n");
368 return -1;
369 }
370 #endif /* ndef FMIFS_IMPORT_DLL */
371 //
372 // Parse command line
373 //
374 if( (badArg = ParseCommandLine( argc, argv )))
375 {
376 wprintf(
377 L"Unknown argument: %s\n",
378 argv[badArg]
379 );
380
381 Usage(argv[0]);
382 return -1;
383 }
384
385 //
386 // Get the drive's format
387 //
388 if( !Drive )
389 {
390 if( !GetCurrentDirectoryW(
391 sizeof(CurrentDirectory),
392 CurrentDirectory
393 )
394 ) {
395
396 PrintWin32Error(
397 L"Could not get current directory",
398 GetLastError()
399 );
400 return -1;
401 }
402
403 } else {
404
405 wcscpy( CurrentDirectory, Drive );
406 }
407 CurrentDirectory[2] = L'\\';
408 CurrentDirectory[3] = L'\0';
409 Drive = CurrentDirectory;
410
411 //
412 // Determine the drive's file system format, which we need to
413 // tell chkdsk
414 //
415 if( !GetVolumeInformationW(
416 Drive,
417 volumeName,
418 sizeof volumeName,
419 & serialNumber,
420 & maxComponent,
421 & flags,
422 fileSystem,
423 sizeof fileSystem
424 )
425 ) {
426 PrintWin32Error(
427 L"Could not query volume",
428 GetLastError()
429 );
430 return -1;
431 }
432
433 //
434 // If they want to fix, we need to have access to the drive
435 //
436 if ( FixErrors )
437 {
438 swprintf(
439 volumeName,
440 L"\\\\.\\%C:",
441 Drive[0]
442 );
443 volumeHandle = CreateFileW(
444 volumeName,
445 GENERIC_WRITE,
446 0,
447 NULL,
448 OPEN_EXISTING,
449 0,
450 0
451 );
452 if( volumeHandle == INVALID_HANDLE_VALUE )
453 {
454 wprintf(L"Chdskx cannot run because the volume is in use by another process.\n\n");
455 return -1;
456 }
457 CloseHandle( volumeHandle );
458
459 //
460 // Can't let the user break out of a chkdsk that can modify the drive
461 //
462 SetConsoleCtrlHandler( CtrlCIntercept, TRUE );
463 }
464
465 //
466 // Just do it
467 //
468 wprintf(
469 L"The type of file system is %s.\n",
470 fileSystem
471 );
472 Chkdsk(
473 Drive,
474 fileSystem,
475 FixErrors,
476 Verbose,
477 SkipClean,
478 ScanSectors,
479 NULL,
480 NULL,
481 ChkdskCallback
482 );
483
484 if ( Error ) return -1;
485 return 0;
486 }
487
488 /* EOF */