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