1 //====================================================================== 2 // 3 // Chkdskx 4 // 5 // Copyright (c) 1998 Mark Russinovich 6 // Systems Internals 7 // http://www.sysinternals.com 8 // 9 // Chkdsk clone that demonstrates the use of the FMIFS file system 10 // utility library. 11 // 12 // -------------------------------------------------------------------- 13 // 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. 18 // 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. 23 // 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. 28 // 29 // -------------------------------------------------------------------- 30 // 31 // 1999 February (Emanuele Aliberti) 32 // Adapted for ReactOS and lcc-win32. 33 // 34 // 1999 April (Emanuele Aliberti) 35 // Adapted for ReactOS and egcs. 36 // 37 // 2008 July (Aleksey Bragin) 38 // Cleanup, use ReactOS's fmifs.h 39 // 40 //====================================================================== 41 42 #include <stdio.h> 43 44 /* PSDK/NDK Headers */ 45 #define WIN32_NO_STATUS 46 #include <windef.h> 47 #include <winbase.h> 48 #include <wincon.h> 49 50 #include <conutils.h> 51 52 /* Resource header */ 53 #include "resource.h" 54 55 #define NTOS_MODE_USER 56 #include <ndk/ntndk.h> 57 58 /* FMIFS Public Header */ 59 #include <fmifs/fmifs.h> 60 61 #define FMIFS_IMPORT_DLL 62 63 // 64 // Globals 65 // 66 BOOL Error = FALSE; 67 68 // Switches 69 BOOL FixErrors = FALSE; 70 BOOL SkipClean = FALSE; 71 BOOL ScanSectors = FALSE; 72 BOOL Verbose = FALSE; 73 PWCHAR Drive = NULL; 74 WCHAR CurrentDirectory[1024]; 75 76 #ifndef FMIFS_IMPORT_DLL 77 // 78 // Functions in FMIFS.DLL 79 // 80 PCHKDSK Chkdsk; 81 #endif 82 83 84 //---------------------------------------------------------------------- 85 // 86 // PrintWin32Error 87 // 88 // Takes the win32 error code and prints the text version. 89 // 90 //---------------------------------------------------------------------- 91 static VOID PrintWin32Error(int Message, DWORD ErrorCode) 92 { 93 ConResPuts(StdErr, Message); 94 ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM, 95 NULL, ErrorCode, LANG_USER_DEFAULT); 96 ConPuts(StdErr, L"\n"); 97 } 98 99 100 //-------------------------------------------------------------------- 101 // 102 // CtrlCIntercept 103 // 104 // Intercepts Ctrl-C's so that the program can't be quit with the 105 // disk in an inconsistent state. 106 // 107 //-------------------------------------------------------------------- 108 BOOL 109 WINAPI 110 CtrlCIntercept(DWORD dwCtrlType) 111 { 112 // 113 // Handle the event so that the default handler doesn't 114 // 115 return TRUE; 116 } 117 118 119 //---------------------------------------------------------------------- 120 // 121 // Usage 122 // 123 // Tell the user how to use the program 124 // 125 //---------------------------------------------------------------------- 126 static VOID 127 Usage(PWCHAR ProgramName) 128 { 129 ConResPrintf(StdOut, IDS_USAGE, ProgramName); 130 } 131 132 133 //---------------------------------------------------------------------- 134 // 135 // ParseCommandLine 136 // 137 // Get the switches. 138 // 139 //---------------------------------------------------------------------- 140 static int 141 ParseCommandLine(int argc, WCHAR *argv[]) 142 { 143 int i; 144 BOOLEAN gotFix = FALSE; 145 BOOLEAN gotVerbose = FALSE; 146 BOOLEAN gotClean = FALSE; 147 // BOOLEAN gotScan = FALSE; 148 149 for (i = 1; i < argc; i++) 150 { 151 switch (argv[i][0]) 152 { 153 case L'-': case L'/': 154 155 switch (argv[i][1]) 156 { 157 // case L'?': 158 // Usage(argv[0]); 159 // return i; 160 161 case L'F': case L'f': 162 { 163 if (gotFix) return i; 164 FixErrors = TRUE; 165 gotFix = TRUE; 166 break; 167 } 168 169 case L'V': case L'v': 170 { 171 if (gotVerbose) return i; 172 Verbose = TRUE; 173 gotVerbose = TRUE; 174 break; 175 } 176 177 case L'R': case L'r': 178 { 179 if (gotFix) return i; 180 ScanSectors = TRUE; 181 gotFix = TRUE; 182 break; 183 } 184 185 case L'C': case L'c': 186 { 187 if (gotClean) return i; 188 SkipClean = TRUE; 189 gotClean = TRUE; 190 break; 191 } 192 193 default: 194 return i; 195 } 196 break; 197 198 default: 199 { 200 if (Drive) return i; 201 if (argv[i][1] != L':') return i; 202 203 Drive = argv[i]; 204 break; 205 } 206 } 207 } 208 return 0; 209 } 210 211 212 //---------------------------------------------------------------------- 213 // 214 // ChkdskCallback 215 // 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. 218 // 219 //---------------------------------------------------------------------- 220 BOOLEAN 221 WINAPI 222 ChkdskCallback( 223 CALLBACKCOMMAND Command, 224 DWORD Modifier, 225 PVOID Argument) 226 { 227 BOOLEAN Ret; 228 PDWORD percent; 229 PBOOLEAN status; 230 PTEXTOUTPUT output; 231 232 // 233 // We get other types of commands, 234 // but we don't have to pay attention to them 235 // 236 Ret = TRUE; 237 switch (Command) 238 { 239 case UNKNOWN2: 240 ConPuts(StdOut, L"UNKNOWN2\r"); 241 break; 242 243 case UNKNOWN3: 244 ConPuts(StdOut, L"UNKNOWN3\n"); 245 break; 246 247 case UNKNOWN4: 248 ConPuts(StdOut, L"UNKNOWN4\n"); 249 break; 250 251 case UNKNOWN5: 252 ConPuts(StdOut, L"UNKNOWN5\n"); 253 break; 254 255 case FSNOTSUPPORTED: 256 ConPuts(StdOut, L"FSNOTSUPPORTED\n"); 257 break; 258 259 case VOLUMEINUSE: 260 ConResPuts(StdOut, IDS_VOLUME_IN_USE); 261 Ret = FALSE; 262 break; 263 264 case UNKNOWN9: 265 ConPuts(StdOut, L"UNKNOWN9\n"); 266 break; 267 268 case UNKNOWNA: 269 ConPuts(StdOut, L"UNKNOWNA\n"); 270 break; 271 272 case UNKNOWNC: 273 ConPuts(StdOut, L"UNKNOWNC\n"); 274 break; 275 276 case UNKNOWND: 277 ConPuts(StdOut, L"UNKNOWND\n"); 278 break; 279 280 case INSUFFICIENTRIGHTS: 281 ConPuts(StdOut, L"INSUFFICIENTRIGHTS\n"); 282 break; 283 284 case STRUCTUREPROGRESS: 285 ConPuts(StdOut, L"STRUCTUREPROGRESS\n"); 286 break; 287 288 case DONEWITHSTRUCTURE: 289 ConPuts(StdOut, L"DONEWITHSTRUCTURE\n"); 290 break; 291 292 case CLUSTERSIZETOOSMALL: 293 ConPuts(StdOut, L"CLUSTERSIZETOOSMALL\n"); 294 break; 295 296 case PROGRESS: 297 percent = (PDWORD)Argument; 298 ConResPrintf(StdOut, IDS_PERCENT_COMPL, *percent); 299 break; 300 301 case OUTPUT: 302 output = (PTEXTOUTPUT)Argument; 303 ConPrintf(StdOut, L"%S", output->Output); 304 break; 305 306 case DONE: 307 status = (PBOOLEAN)Argument; 308 if (*status == FALSE) 309 { 310 ConResPuts(StdOut, IDS_CHKDSK_FAIL); 311 Error = TRUE; 312 } 313 break; 314 } 315 return Ret; 316 } 317 318 #ifndef FMIFS_IMPORT_DLL 319 //---------------------------------------------------------------------- 320 // 321 // LoadFMIFSEntryPoints 322 // 323 // Loads FMIFS.DLL and locates the entry point(s) we are going to use 324 // 325 //---------------------------------------------------------------------- 326 static BOOLEAN 327 LoadFMIFSEntryPoints(VOID) 328 { 329 HMODULE hFmifs = LoadLibraryW(L"fmifs.dll"); 330 if (hFmifs == NULL) 331 return FALSE; 332 333 Chkdsk = (PCHKDSK)GetProcAddress(hFmifs, "Chkdsk"); 334 if (!Chkdsk) 335 { 336 FreeLibrary(hFmifs); 337 return FALSE; 338 } 339 340 return TRUE; 341 } 342 #endif 343 344 345 //---------------------------------------------------------------------- 346 // 347 // WMain 348 // 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. 352 // 353 // We do this in UNICODE because the chkdsk command expects PWCHAR 354 // arguments. 355 // 356 //---------------------------------------------------------------------- 357 int 358 wmain(int argc, WCHAR *argv[]) 359 { 360 int badArg; 361 HANDLE volumeHandle; 362 WCHAR fileSystem[1024]; 363 WCHAR volumeName[1024]; 364 DWORD serialNumber; 365 DWORD flags, maxComponent; 366 367 /* Initialize the Console Standard Streams */ 368 ConInitStdStreams(); 369 370 ConResPuts(StdOut, IDS_ABOUT); 371 372 #ifndef FMIFS_IMPORT_DLL 373 // 374 // Get function pointers 375 // 376 if (!LoadFMIFSEntryPoints()) 377 { 378 ConResPuts(StdErr, IDS_NO_ENTRY_POINT); 379 return -1; 380 } 381 #endif 382 383 // 384 // Parse command line 385 // 386 badArg = ParseCommandLine(argc, argv); 387 if (badArg) 388 { 389 ConResPrintf(StdOut, IDS_BAD_ARGUMENT, argv[badArg]); 390 Usage(argv[0]); 391 return -1; 392 } 393 394 // 395 // Get the drive's format 396 // 397 if (!Drive) 398 { 399 if (!GetCurrentDirectoryW(ARRAYSIZE(CurrentDirectory), CurrentDirectory)) 400 { 401 PrintWin32Error(IDS_NO_CURRENT_DIR, GetLastError()); 402 return -1; 403 } 404 } 405 else 406 { 407 wcscpy(CurrentDirectory, Drive); 408 } 409 CurrentDirectory[2] = L'\\'; 410 CurrentDirectory[3] = L'\0'; 411 Drive = CurrentDirectory; 412 413 // 414 // Determine the drive's file system format, which we need to 415 // tell chkdsk 416 // 417 if (!GetVolumeInformationW(Drive, 418 volumeName, 419 ARRAYSIZE(volumeName), 420 &serialNumber, 421 &maxComponent, 422 &flags, 423 fileSystem, 424 ARRAYSIZE(fileSystem))) 425 { 426 PrintWin32Error(IDS_NO_QUERY_VOL, GetLastError()); 427 return -1; 428 } 429 430 // 431 // If they want to fix, we need to have access to the drive 432 // 433 if (FixErrors) 434 { 435 swprintf(volumeName, L"\\\\.\\%C:", Drive[0]); 436 volumeHandle = CreateFileW(volumeName, 437 GENERIC_WRITE, 438 0, 439 NULL, 440 OPEN_EXISTING, 441 0, 442 0); 443 if (volumeHandle == INVALID_HANDLE_VALUE) 444 { 445 ConResPuts(StdErr, IDS_VOLUME_IN_USE_PROC); 446 return -1; 447 } 448 CloseHandle(volumeHandle); 449 450 // 451 // Can't let the user break out of a chkdsk that can modify the drive 452 // 453 SetConsoleCtrlHandler(CtrlCIntercept, TRUE); 454 } 455 456 // 457 // Just do it 458 // 459 ConResPrintf(StdOut, IDS_FILE_SYSTEM, fileSystem); 460 Chkdsk(Drive, 461 fileSystem, 462 FixErrors, 463 Verbose, 464 SkipClean, 465 ScanSectors, 466 NULL, 467 NULL, 468 ChkdskCallback); 469 470 if (Error) return -1; 471 return 0; 472 } 473 474 /* EOF */ 475