Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

577 lines
16 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. efichk.cxx
  5. Abstract:
  6. This is the main program for the eficheck version of chkdsk.
  7. --*/
  8. #pragma warning(disable: 4091)
  9. #include "ulib.hxx"
  10. #include "wstring.hxx"
  11. #include "fatvol.hxx"
  12. #include "efickmsg.hxx"
  13. #include "error.hxx"
  14. #include "ifssys.hxx"
  15. #include "rtmsg.h"
  16. #include "rcache.hxx"
  17. #include "ifsserv.hxx"
  18. #include "efiwintypes.hxx"
  19. extern "C" BOOLEAN
  20. InitializeUfat(
  21. PVOID DllHandle,
  22. ULONG Reason,
  23. PCONTEXT Context
  24. );
  25. extern "C" BOOLEAN
  26. InitializeIfsUtil(
  27. PVOID DllHandle,
  28. ULONG Reason,
  29. PCONTEXT Context
  30. );
  31. USHORT
  32. InvokeAutoChk (
  33. IN PWSTRING DriveLetter,
  34. IN PWSTRING VolumeName,
  35. IN ULONG ChkdskFlags,
  36. IN BOOLEAN RemoveRegistry,
  37. IN BOOLEAN SetupMode,
  38. IN BOOLEAN Extend,
  39. IN ULONG LogfileSize,
  40. IN INT ArgCount,
  41. IN WCHAR **ArgArray,
  42. IN OUT PMESSAGE Msg,
  43. OUT PULONG ExitStatus
  44. );
  45. int __cdecl
  46. main(
  47. int argc,
  48. WCHAR** argv,
  49. WCHAR** envp
  50. );
  51. extern "C" {
  52. #include "efi.h"
  53. #include "efilib.h"
  54. }
  55. int argc;
  56. WCHAR ** argv;
  57. #if defined(EFI_DEBUG)
  58. VOID
  59. PrintLoadedImageInfo (
  60. IN EFI_LOADED_IMAGE *LoadedImage
  61. );
  62. #endif
  63. VOID
  64. InvokeAutochkMain (
  65. IN EFI_HANDLE ImageHandle,
  66. IN EFI_LOADED_IMAGE *LoadedImage
  67. );
  68. extern "C" {
  69. EFI_STATUS
  70. __declspec(dllexport)
  71. InitializeEfiChkApplication(
  72. IN EFI_HANDLE ImageHandle,
  73. IN EFI_SYSTEM_TABLE *SystemTable
  74. )
  75. {
  76. EFI_LOADED_IMAGE *LoadedImage;
  77. /*
  78. * Initialize the Library. Set BS, RT, &ST globals
  79. * BS = Boot Services RT = RunTime Services
  80. * ST = System Table
  81. */
  82. InitializeLib (ImageHandle, SystemTable);
  83. InitializeShellApplication( ImageHandle, SystemTable );
  84. Print(TEXT("EFI Check Disk Version 0.2\n"));
  85. Print(TEXT("Based on EFI Core "));
  86. Print(TEXT("Version %d.%d.%d.%d\n"),
  87. EFI_SPECIFICATION_MAJOR_REVISION,
  88. EFI_SPECIFICATION_MINOR_REVISION,
  89. EFI_FIRMWARE_MAJOR_REVISION,
  90. EFI_FIRMWARE_MINOR_REVISION
  91. );
  92. DEBUG((D_INFO,(CHAR8*)"EFICHK application started\n"));
  93. BS->HandleProtocol (ImageHandle, &LoadedImageProtocol, (VOID**)&LoadedImage);
  94. #if 0
  95. PrintLoadedImageInfo (LoadedImage);
  96. #endif
  97. // call into autochk.
  98. InvokeAutochkMain (ImageHandle, LoadedImage);
  99. #if 0
  100. EfiWaitForKey();
  101. ST->ConOut->OutputString (ST->ConOut, TEXT("\n\n"));
  102. #endif
  103. return EFI_SUCCESS;
  104. }
  105. } // extern "C"
  106. UINT16 *MemoryType[] = {
  107. TEXT("reserved "),
  108. TEXT("LoaderCode"),
  109. TEXT("LoaderData"),
  110. TEXT("BS_code "),
  111. TEXT("BS_data "),
  112. TEXT("RT_code "),
  113. TEXT("RT_data "),
  114. TEXT("available "),
  115. TEXT("Unusable "),
  116. TEXT("ACPI_recl "),
  117. TEXT("ACPI_NVS "),
  118. TEXT("MemMapIO "),
  119. TEXT("MemPortIO "),
  120. TEXT("PAL_code "),
  121. TEXT("BUG:BUG: MaxMemoryType")
  122. };
  123. VOID
  124. InvokeAutochkMain (
  125. IN EFI_HANDLE ImageHandle,
  126. IN EFI_LOADED_IMAGE *LoadedImage
  127. )
  128. {
  129. EFI_LOADED_IMAGE *ParentImage;
  130. if (!LoadedImage->ParentHandle) {
  131. /*
  132. * If you are loaded from the EFI boot manager the ParentHandle
  133. * is Null. Thus a pure EFI application will not have a parrent.
  134. */
  135. DEBUG((D_INFO,(CHAR8*)"\n%HImage was loaded from EFI Boot Manager%N\n"));
  136. return;
  137. }
  138. BS->HandleProtocol (LoadedImage->ParentHandle, &LoadedImageProtocol, (VOID**)&ParentImage);
  139. {
  140. argc = SI->Argc;
  141. argv = SI->Argv;
  142. DEBUG((D_INFO,(CHAR8*)"Launching main...\n"));
  143. // call main.
  144. main(argc,argv,NULL);
  145. DEBUG((D_INFO,(CHAR8*)"Returned from main...\n"));
  146. }
  147. }
  148. #if defined(EFI_DEBUG)
  149. VOID
  150. PrintLoadedImageInfo (
  151. IN EFI_LOADED_IMAGE *LoadedImage
  152. )
  153. {
  154. EFI_STATUS Status;
  155. EFI_DEVICE_PATH *DevicePath;
  156. Print( TEXT("\n%HImage was loaded from file %N%s\n"), DevicePathToStr (LoadedImage->FilePath));
  157. BS->HandleProtocol (LoadedImage->DeviceHandle, &DevicePathProtocol, (VOID**)&DevicePath);
  158. if (DevicePath) {
  159. Print( TEXT("%HImage was loaded from this device %N%s\n"), DevicePathToStr (DevicePath));
  160. }
  161. Print( TEXT("\n Image Base is %X"), LoadedImage->ImageBase);
  162. Print( TEXT("\n Image Size is %X"), LoadedImage->ImageSize);
  163. Print( TEXT("\n Image Code Type %s"), MemoryType[LoadedImage->ImageCodeType]);
  164. Print( TEXT("\n Image Data Type %s"), MemoryType[LoadedImage->ImageDataType]);
  165. Print( TEXT("\n %d Bytes of Options passed to this Image\n"), LoadedImage->LoadOptionsSize);
  166. if (LoadedImage->ParentHandle) {
  167. Status = BS->HandleProtocol (LoadedImage->ParentHandle, &DevicePathProtocol, (VOID**)&DevicePath);
  168. if (Status == EFI_SUCCESS && DevicePath) {
  169. Print( TEXT("Images parent is %s\n\n"), DevicePathToStr (DevicePath));
  170. }
  171. }
  172. }
  173. #endif
  174. BOOLEAN force = FALSE;
  175. BOOLEAN readonly = TRUE;
  176. int __cdecl
  177. main(
  178. int argc,
  179. WCHAR** argv,
  180. WCHAR** envp
  181. )
  182. /*++
  183. Routine Description:
  184. This routine is the main program for autocheck FAT chkdsk.
  185. Arguments:
  186. argc, argv - Supplies the fully qualified NT path name of the
  187. the drive to check.
  188. Return Value:
  189. 0 - Success.
  190. 1 - Failure.
  191. --*/
  192. {
  193. DEBUG( (D_INFO,(CHAR8*)"\nInit Libs...\n"));
  194. if (!InitializeUlib( NULL, !DLL_PROCESS_DETACH, NULL ) ||
  195. !InitializeIfsUtil(NULL,0,NULL) ||
  196. !InitializeUfat(NULL,0,NULL)) {
  197. return 1;
  198. }
  199. DEBUG( (D_INFO,(CHAR8*)"Init Libs Successful.\n"));
  200. //
  201. // The declarations must come after these initialization functions.
  202. //
  203. DSTRING dos_drive_name;
  204. DSTRING volume_name;
  205. DSTRING drive_letter;
  206. EFICHECK_MESSAGE *msg = NULL;
  207. BOOLEAN onlyifdirty = TRUE;
  208. BOOLEAN recover = FALSE;
  209. BOOLEAN extend = FALSE;
  210. BOOLEAN remove_registry = FALSE;
  211. ULONG ArgOffset = 1;
  212. BOOLEAN SetupOutput = FALSE;
  213. BOOLEAN SetupTextMode = FALSE;
  214. BOOLEAN SetupSpecialFixLevel = FALSE;
  215. ULONG exit_status = 0;
  216. BOOLEAN SuppressOutput = TRUE; // dots only by default
  217. BOOLEAN all_drives = FALSE;
  218. BOOLEAN resize_logfile = FALSE;
  219. BOOLEAN skip_index_scan = FALSE;
  220. BOOLEAN skip_cycle_scan = FALSE;
  221. BOOLEAN showhelp = FALSE;
  222. BOOLEAN drive_already_specified = FALSE;
  223. LONG logfile_size = 0;
  224. USHORT rtncode;
  225. ULONG chkdsk_flags;
  226. if (!drive_letter.Initialize() ||
  227. !volume_name.Initialize()) {
  228. DEBUG((D_ERROR,(CHAR8*)"Out of memory.\n"));
  229. return 1;
  230. }
  231. force = FALSE;
  232. onlyifdirty = FALSE;
  233. // Parse the arguments--the accepted arguments are:
  234. //
  235. // efichk [/f] [/r] device-name
  236. //
  237. // /f - fix errors
  238. // /r - recover; implies /f
  239. //
  240. msg = NEW EFICHECK_MESSAGE;
  241. if (NULL == msg || !msg->Initialize()) {
  242. return 1;
  243. }
  244. DEBUG( (D_INFO,(CHAR8*)"\nParse Options\n"));
  245. for (ArgOffset = 1; ArgOffset < (ULONG)argc; ++ArgOffset) {
  246. if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  247. (argv[ArgOffset][1] == 'r' || argv[ArgOffset][1] == 'R') &&
  248. (argv[ArgOffset][2] == 0) ) {
  249. // Note that /r implies /f.
  250. //
  251. recover = TRUE;
  252. readonly = FALSE;
  253. } else if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  254. (argv[ArgOffset][1] == 'f' || argv[ArgOffset][1] == 'F') &&
  255. (argv[ArgOffset][2] == 0) ) {
  256. // Note that /r implies /p.
  257. //
  258. readonly = FALSE;
  259. } else if ((argv[ArgOffset][0] != '/' && argv[ArgOffset][0] != '-')) {
  260. // we assume this refers to a device
  261. if (!volume_name.Initialize(argv[ArgOffset])) {
  262. return 1;
  263. }
  264. drive_already_specified = TRUE;
  265. } else if( (argv[ArgOffset][0] == '/' || argv[ArgOffset][0] == '-') &&
  266. (argv[ArgOffset][1] == '?') &&
  267. (argv[ArgOffset][2] == 0) ) {
  268. // show some usage help
  269. showhelp = TRUE;
  270. } else if ( strcmp(argv[ArgOffset], TEXT("/FORCE")) == 0 ) {
  271. // have a /FORCE switch to allow efichk to check really messed up volumes.
  272. force = TRUE;
  273. } else {
  274. // this is a switch we don't know of
  275. msg->Set(MSG_INVALID_PARAMETER);
  276. msg->Display("%ws",argv[ArgOffset]);
  277. msg->Set(MSG_BLANK_LINE);
  278. msg->Display();
  279. showhelp = TRUE;
  280. }
  281. }
  282. SuppressOutput = FALSE;
  283. if(showhelp || !drive_already_specified) {
  284. msg->Set(MSG_CHK_USAGE_HEADER);
  285. msg->Display();
  286. msg->Set(MSG_BLANK_LINE);
  287. msg->Display();
  288. msg->Set(MSG_CHK_COMMAND_LINE);
  289. msg->Display();
  290. msg->Set(MSG_CHK_DRIVE);
  291. msg->Display();
  292. msg->Set(MSG_CHK_F_SWITCH);
  293. msg->Display();
  294. msg->Set(MSG_CHK_V_SWITCH);
  295. msg->Display();
  296. return 1;
  297. }
  298. // make drive letter the same as volume name
  299. if (!drive_letter.Initialize(&volume_name)) {
  300. return 1;
  301. }
  302. DEBUG( (D_INFO,(CHAR8*)"\nParsed Args\n"));
  303. chkdsk_flags = 0;
  304. chkdsk_flags = (onlyifdirty ? CHKDSK_CHECK_IF_DIRTY : 0);
  305. chkdsk_flags |= ((recover || extend) ? CHKDSK_RECOVER_FREE_SPACE : 0);
  306. chkdsk_flags |= (recover ? CHKDSK_RECOVER_ALLOC_SPACE : 0);
  307. DEBUG((D_INFO,(CHAR8*)"Invoking chkdsk.\n"));
  308. rtncode = InvokeAutoChk(&drive_letter,
  309. &volume_name,
  310. chkdsk_flags,
  311. remove_registry,
  312. SetupOutput || SetupTextMode,
  313. extend,
  314. logfile_size,
  315. argc,
  316. argv,
  317. msg,
  318. &exit_status);
  319. DEBUG((D_INFO,(CHAR8*)"Back from chkdsk.\n"));
  320. #if 0
  321. switch( exit_status ) {
  322. case 0:
  323. msg->Set(MSG_CHK_AUTOCHK_COMPLETE);
  324. break;
  325. case 1:
  326. case 2:
  327. msg->Set(MSG_CHK_ERRORS_FIXED);
  328. break;
  329. case 3:
  330. msg->Set(MSG_CHK_ERRORS_NOT_FIXED);
  331. break;
  332. default:
  333. msg->Set(MSG_CHK_AUTOCHK_COMPLETE);
  334. break;
  335. }
  336. msg->Display();
  337. #endif
  338. DELETE(msg);
  339. DEBUG((D_ERROR,(CHAR8*)"EFICHK: Exit Status %d\n", exit_status));
  340. return exit_status;
  341. }
  342. USHORT
  343. InvokeAutoChk (
  344. IN PWSTRING DriveLetter,
  345. IN PWSTRING VolumeName,
  346. IN ULONG ChkdskFlags,
  347. IN BOOLEAN RemoveRegistry,
  348. IN BOOLEAN SetupMode,
  349. IN BOOLEAN Extend,
  350. IN ULONG LogfileSize,
  351. IN INT ArgCount,
  352. IN WCHAR **ArgArray,
  353. IN OUT PMESSAGE Msg,
  354. OUT PULONG ExitStatus
  355. )
  356. /*++
  357. Routine Description:
  358. This is the core of efichk. It checks the specified drive.
  359. Arguments:
  360. DriveLetter - Supplies the drive letter of the drive
  361. (can be empty string)
  362. VolumeName - Supplies the guid volume name of the drive
  363. ChkdskFlags - Supplies the chkdsk control flags
  364. RemoveRegistry - Supplies TRUE if registry entry is to be removed
  365. SetupMode - Supplies TRUE if invoked through setup
  366. Extend - Supplies TRUE if extending the volume (obsolete)
  367. LogfileSize - Supplies the size of the logfile
  368. ArgCount - Supplies the number of arguments given to autochk.
  369. ArgArray - Supplies the arguments given to autochk.
  370. Msg - Supplies the outlet of messages
  371. ExitStatus - Retrieves the exit status of chkdsk
  372. Return Value:
  373. 0 - Success
  374. 1 - Fatal error
  375. 2 - Volume specific error
  376. --*/
  377. {
  378. DSTRING fsname;
  379. DSTRING fsNameAndVersion;
  380. PFAT_VOL fatvol = NULL;
  381. PVOL_LIODPDRV vol;
  382. BOOLEAN SetupSpecialFixLevel = FALSE;
  383. PREAD_CACHE read_cache;
  384. DSTRING boot_execute_log_file_name;
  385. FSTRING boot_ex_temp;
  386. HMEM logged_message_mem;
  387. NTSTATUS result;
  388. DSTRING fatname;
  389. DSTRING fat32name;
  390. DSTRING rawname;
  391. DSTRING ntfsname;
  392. *ExitStatus = CHKDSK_EXIT_COULD_NOT_FIX;
  393. if (!fatname.Initialize("FAT") ||
  394. !rawname.Initialize("RAW") ||
  395. !fat32name.Initialize("FAT32")) {
  396. return 1;
  397. }
  398. if (VolumeName->QueryChCount() == 0) {
  399. DEBUG((D_ERROR,(CHAR8*)"EFICHK: Volume name is missing.\n"));
  400. return 2; // continue if all_drives are enabled
  401. }
  402. if (DriveLetter->QueryChCount() == 0) {
  403. // unable to map VolumeName to a drive letter so do the default
  404. if (!IFS_SYSTEM::NtDriveNameToDosDriveName(VolumeName, DriveLetter)) {
  405. DEBUG((D_ERROR,(CHAR8*)"Out of memory.\n"));
  406. return 1;
  407. }
  408. }
  409. if (!IFS_SYSTEM::QueryFileSystemName(VolumeName, &fsname,
  410. &result, &fsNameAndVersion)) {
  411. Msg->Set( MSG_FS_NOT_DETERMINED );
  412. Msg->Display( "%W", VolumeName );
  413. if(result != 0 ){
  414. Msg->Set(MSG_CANT_DASD);
  415. Msg->Display();
  416. }
  417. return 2;
  418. }
  419. // Msg->SetLoggingEnabled();
  420. Msg->Set(MSG_CHK_RUNNING);
  421. Msg->Display("%W", DriveLetter);
  422. Msg->Set(MSG_FILE_SYSTEM_TYPE);
  423. Msg->Display("%W", &fsname);
  424. if (fsname == fatname || fsname == fat32name || force) {
  425. if (!(fatvol = NEW FAT_VOL)) {
  426. DEBUG((D_ERROR,(CHAR8*)"Out of memory.\n"));
  427. return 1;
  428. }
  429. if (NoError != fatvol->Initialize(Msg,
  430. VolumeName,
  431. (BOOLEAN)(ChkdskFlags & CHKDSK_CHECK_IF_DIRTY))) {
  432. DELETE(fatvol);
  433. return 2;
  434. }
  435. if ((read_cache = NEW READ_CACHE) &&
  436. read_cache->Initialize(fatvol, 75)) {
  437. fatvol->SetCache(read_cache);
  438. } else {
  439. DELETE(read_cache);
  440. }
  441. vol = fatvol;
  442. } else {
  443. Msg->Set( MSG_FS_NOT_SUPPORTED );
  444. Msg->Display( "%s%W", "EFICHK", &fsname );
  445. return 2;
  446. }
  447. // Invoke chkdsk.
  448. if (!vol->ChkDsk(readonly ? CheckOnly : TotalFix,
  449. Msg,
  450. ChkdskFlags,
  451. LogfileSize,
  452. ExitStatus,
  453. DriveLetter)) {
  454. DELETE(vol);
  455. DEBUG((D_ERROR,(CHAR8*)"EFICHK: ChkDsk failure\n"));
  456. return 2;
  457. }
  458. DELETE(vol);
  459. return 0;
  460. }