Source code of Windows XP (NT5)
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.

1664 lines
51 KiB

  1. //=============================================================================*
  2. // COPYRIGHT� 2001 Microsoft Corporation and Executive Software International, Inc.
  3. //=============================================================================*
  4. // File: Defrag.cpp
  5. //=============================================================================*
  6. #include "stdafx.h"
  7. extern "C" {
  8. #include "SysStruc.h"
  9. }
  10. #include "AdminPrivs.h"
  11. #include "DataIo.h"
  12. #include "DataIoCl.h"
  13. #include "DfrgCmn.h"
  14. #include "DfrgRes.h"
  15. #include "ErrMacro.h"
  16. #include "GetDfrgRes.h"
  17. #include "TextBlock.h"
  18. #include "Defrag.h"
  19. #include "resource.h"
  20. #include "UiCommon.h"
  21. #include <stdio.h>
  22. #include <comdef.h>
  23. #include <atlconv.h>
  24. #include <locale.h>
  25. #include <winnlsp.h> // in public\internal\base\inc
  26. #include "secattr.h"
  27. // return code
  28. static int RetCode = 0;
  29. // resource DLL
  30. static HINSTANCE resdll = NULL;
  31. // force defrag flag
  32. static BOOL ForceDefrag = FALSE;
  33. // analyse vs defrag flag
  34. BOOL AnalyzeOnly = FALSE;
  35. // verbose vs concise output flag
  36. BOOL VerboseOutput = FALSE;
  37. // force Boot Optimize flag
  38. static BOOL BootOptimize = FALSE;
  39. // event engine signals to tell us it is finished
  40. static HANDLE hEngineDoneEvent = NULL;
  41. // semaphore to prevent multiple defraggers (command line or UI)
  42. static HANDLE hIsOkToRunSemaphore = NULL;
  43. // name of program
  44. static PTCHAR prog;
  45. WCHAR g_szTempBuffer[1024];
  46. // prototypes
  47. static void DisplayHelp(PTCHAR prog);
  48. static int Defrag(PTCHAR cDriveGUIDString, PTCHAR fileSystem, HANDLE stopEvent);
  49. static int GetMISemaphore();
  50. static void ReleaseMISemaphore();
  51. BOOL
  52. PrintOnConsole(
  53. IN LPCWSTR wszStr,
  54. IN HANDLE hConsoleOutput,
  55. IN BOOL bIsTrueConsoleOutput
  56. )
  57. {
  58. DWORD dwCharsOutput = 0;
  59. if (bIsTrueConsoleOutput) {
  60. //
  61. // Output to the console
  62. //
  63. if (!WriteConsoleW(hConsoleOutput,
  64. (PVOID)wszStr,
  65. (DWORD)wcslen(wszStr),
  66. &dwCharsOutput,
  67. NULL)
  68. ) {
  69. return FALSE;
  70. }
  71. }
  72. else {
  73. //
  74. // Output being redirected. WriteConsoleW doesn't work for redirected output. Convert
  75. // UNICODE to the current output CP multibyte charset.
  76. //
  77. LPSTR lpszTmpBuffer;
  78. DWORD dwByteCount;
  79. //
  80. // Get size of temp buffer needed for the conversion.
  81. //
  82. dwByteCount = WideCharToMultiByte(
  83. GetConsoleOutputCP(),
  84. 0,
  85. wszStr,
  86. -1,
  87. NULL,
  88. 0,
  89. NULL,
  90. NULL
  91. );
  92. if (0 == dwByteCount) {
  93. return FALSE;
  94. }
  95. lpszTmpBuffer = (LPSTR)malloc(dwByteCount);
  96. if (NULL == lpszTmpBuffer ) {
  97. return FALSE;
  98. }
  99. //
  100. // Now convert it.
  101. //
  102. dwByteCount = WideCharToMultiByte(
  103. GetConsoleOutputCP(),
  104. 0,
  105. wszStr,
  106. -1,
  107. lpszTmpBuffer,
  108. dwByteCount,
  109. NULL,
  110. NULL
  111. );
  112. if (0 == dwByteCount) {
  113. free(lpszTmpBuffer);
  114. return FALSE;
  115. }
  116. // Finally output it.
  117. if (!WriteFile(
  118. hConsoleOutput,
  119. lpszTmpBuffer,
  120. dwByteCount - 1, // Get rid of the trailing NULL char
  121. &dwCharsOutput,
  122. NULL)
  123. ) {
  124. free(lpszTmpBuffer);
  125. return FALSE;
  126. }
  127. free(lpszTmpBuffer);
  128. }
  129. return TRUE;
  130. }
  131. BOOL
  132. PrintOnStdOut(
  133. IN LPCWSTR wszStr
  134. )
  135. {
  136. static BOOL bIsTrueConsoleOutput = TRUE;
  137. static HANDLE hConsoleOutput = INVALID_HANDLE_VALUE;
  138. DWORD fdwMode = 0;
  139. if (INVALID_HANDLE_VALUE == hConsoleOutput) {
  140. hConsoleOutput = GetStdHandle(STD_OUTPUT_HANDLE);
  141. if (INVALID_HANDLE_VALUE == hConsoleOutput) {
  142. return FALSE;
  143. }
  144. //
  145. // Stash away the results in static vars. bIsTrueConsoleOutput is TRUE when the
  146. // standard output handle is pointing to a console character device.
  147. //
  148. bIsTrueConsoleOutput = (GetFileType( hConsoleOutput ) & FILE_TYPE_CHAR ) &&
  149. GetConsoleMode( hConsoleOutput, &fdwMode );
  150. }
  151. if (NULL == wszStr) {
  152. return FALSE;
  153. }
  154. return PrintOnConsole(wszStr, hConsoleOutput, bIsTrueConsoleOutput);
  155. }
  156. BOOL
  157. PrintOnStdErr(
  158. IN LPCWSTR wszStr
  159. )
  160. {
  161. static BOOL bIsTrueConsoleOutput = TRUE;
  162. static HANDLE hConsoleOutput = INVALID_HANDLE_VALUE;
  163. DWORD fdwMode = 0;
  164. if (INVALID_HANDLE_VALUE == hConsoleOutput) {
  165. hConsoleOutput = GetStdHandle(STD_ERROR_HANDLE);
  166. if (INVALID_HANDLE_VALUE == hConsoleOutput) {
  167. return FALSE;
  168. }
  169. //
  170. // Stash away the results in static vars. bIsTrueConsoleOutput is TRUE when the
  171. // standard output handle is pointing to a console character device.
  172. //
  173. bIsTrueConsoleOutput = (GetFileType( hConsoleOutput ) & FILE_TYPE_CHAR ) &&
  174. GetConsoleMode( hConsoleOutput, &fdwMode );
  175. }
  176. if (NULL == wszStr) {
  177. return FALSE;
  178. }
  179. return PrintOnConsole(wszStr, hConsoleOutput, bIsTrueConsoleOutput);
  180. }
  181. //-------------------------------------------------------------------*
  182. // function: main
  183. //
  184. // returns: 0 if all is well, otherwise error code
  185. // note:
  186. //-------------------------------------------------------------------*
  187. extern "C" int __cdecl _tmain(int argc, TCHAR* argv[])
  188. {
  189. int ret = 0;
  190. int ii;
  191. DWORD_PTR dwParams[10];
  192. DWORD dLastError = 0;
  193. BOOL bDriveEntered = FALSE;
  194. TCHAR fileSystem[10];
  195. WCHAR buf[400];
  196. UINT lenbuf = sizeof(buf)/sizeof(WCHAR); //135977 pass number of characters not number of bytes
  197. WCHAR msg[400];
  198. UINT lenmsg = sizeof(msg)/sizeof(WCHAR); //135977 pass number of characters not number of bytes
  199. DWORD len;
  200. HANDLE parentProcessHandle = NULL;
  201. HANDLE stopEventHandle = NULL;
  202. HANDLE stopEventSourceHandle;
  203. DWORD parentProcessId;
  204. BOOL stopEventSpecified = FALSE;
  205. BOOL parentProcessSpecified = FALSE;
  206. BOOL success;
  207. TCHAR cDriveGUIDString[GUID_LENGTH];
  208. VString tmpVolumeArg;
  209. HRESULT hr = E_FAIL;
  210. // Use the OEM code page ...
  211. setlocale(LC_ALL, ".OCP");
  212. // Use the console UI language
  213. SetThreadUILanguage( 0 );
  214. CoInitializeEx(NULL, COINIT_MULTITHREADED);
  215. /*
  216. // Initialize COM security
  217. hr = CoInitializeSecurity(
  218. NULL,
  219. -1, // IN LONG cAuthSvc,
  220. NULL, // IN SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
  221. NULL, // IN void *pReserved1,
  222. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // IN DWORD dwAuthnLevel,
  223. RPC_C_IMP_LEVEL_IDENTIFY, // IN DWORD dwImpLevel,
  224. NULL, // IN void *pAuthList,
  225. (EOAC_SECURE_REFS | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL ),
  226. NULL // IN void *pReserved3
  227. );
  228. if(FAILED(hr)) {
  229. return 0;
  230. }
  231. */
  232. // load resource DLL
  233. resdll = GetDfrgResHandle();
  234. if (resdll == NULL) {
  235. PrintOnStdErr(L"Error: cannot load resource DLL.\r\nContact system administrator.\r\n");
  236. RetCode = ENGERR_SYSTEM;
  237. CoUninitialize();
  238. return RetCode;
  239. }
  240. // must be an administrator to run this
  241. if (!CheckForAdminPrivs()) {
  242. LoadString(resdll, IDS_NEED_ADMIN_PRIVS, buf, lenbuf);
  243. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  244. PrintOnStdErr(g_szTempBuffer);
  245. RetCode = ENGERR_SYSTEM;
  246. CoUninitialize();
  247. return RetCode;
  248. }
  249. // check for multiple instances
  250. if (GetMISemaphore() != 0)
  251. {
  252. RetCode = 1;
  253. CoUninitialize();
  254. return RetCode;
  255. }
  256. // strip off path from prog name
  257. prog = _tcsrchr(argv[0], TEXT('\\'));
  258. if (prog == NULL)
  259. {
  260. prog = argv[0];
  261. }
  262. else
  263. {
  264. prog++;
  265. }
  266. //
  267. dwParams[0] = (DWORD_PTR) prog;
  268. dwParams[1] = NULL;
  269. // process command line
  270. for (ii = 1; ii < argc; ii++)
  271. {
  272. // command line switches start with a dash or slash
  273. if (argv[ii][0] == TEXT('-') || argv[ii][0] == TEXT('/'))
  274. {
  275. // process command line switches
  276. switch (argv[ii][1])
  277. {
  278. // Analyse only
  279. case TEXT('A'):
  280. case TEXT('a'):
  281. AnalyzeOnly = TRUE;
  282. break;
  283. // force boot optimize only
  284. case TEXT('B'):
  285. case TEXT('b'):
  286. BootOptimize = TRUE;
  287. break;
  288. // force defragmentation, even if too little free space
  289. case TEXT('F'):
  290. case TEXT('f'):
  291. ForceDefrag = TRUE;
  292. break;
  293. // help request
  294. case TEXT('H'):
  295. case TEXT('h'):
  296. case TEXT('?'):
  297. DisplayHelp(prog);
  298. RetCode = ENGERR_BAD_PARAM;
  299. CoUninitialize();
  300. return RetCode;
  301. break;
  302. // parent process
  303. case TEXT('P'):
  304. case TEXT('p'):
  305. ii++;
  306. if (ii < argc) {
  307. if (0 == _stscanf(argv[ii], TEXT("%x"), &parentProcessId)) {
  308. RetCode = ENGERR_BAD_PARAM;
  309. CoUninitialize();
  310. return RetCode;
  311. }
  312. parentProcessSpecified = TRUE;
  313. }
  314. break;
  315. // stop event
  316. case TEXT('S'):
  317. case TEXT('s'):
  318. ii++;
  319. if (ii < argc) {
  320. if (0 == _stscanf(argv[ii], TEXT("%p"), &stopEventSourceHandle)) {
  321. RetCode = ENGERR_BAD_PARAM;
  322. CoUninitialize();
  323. return RetCode;
  324. }
  325. stopEventSpecified = TRUE;
  326. }
  327. break;
  328. // verbose output (full report)
  329. case TEXT('V'):
  330. case TEXT('v'):
  331. VerboseOutput = TRUE;
  332. break;
  333. // unknown option
  334. default:
  335. dwParams[0] = (DWORD_PTR) argv[ii];
  336. dwParams[1] = NULL;
  337. if(!BootOptimize)
  338. {
  339. LoadString(resdll, IDS_ERR_BAD_OPTION, buf, lenbuf);
  340. assert(wcslen(buf) < lenbuf);
  341. len = FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  342. buf, 0, 0, msg, lenmsg, (va_list*) dwParams);
  343. assert(wcslen(msg) < lenmsg);
  344. PrintOnStdErr(msg);
  345. DisplayHelp(prog);
  346. }
  347. RetCode = ENGERR_BAD_PARAM;
  348. CoUninitialize();
  349. return RetCode;
  350. break;
  351. }
  352. }
  353. // otherwise, assume it is a drive letter or mount point
  354. else
  355. {
  356. // check to make sure we don't already have a volume
  357. if (bDriveEntered) // error
  358. {
  359. if(!BootOptimize)
  360. {
  361. // multiple drive error
  362. LoadString(resdll, IDS_ERR_2_DRIVES, buf, lenbuf);
  363. wsprintf(g_szTempBuffer, L"\r\n%s\r\n\r\n", buf);
  364. PrintOnStdErr(g_szTempBuffer);
  365. DisplayHelp(prog);
  366. }
  367. RetCode = ENGERR_BAD_PARAM;
  368. CoUninitialize();
  369. return RetCode;
  370. }
  371. // get a copy of the parameter
  372. tmpVolumeArg = argv[ii];
  373. // make sure it has a trailing backslash
  374. len = tmpVolumeArg.GetLength();
  375. if (tmpVolumeArg.operator [](len - 1) != TEXT('\\'))
  376. {
  377. if (!tmpVolumeArg.AddChar(TEXT('\\'))) {
  378. RetCode = ENGERR_BAD_PARAM;
  379. CoUninitialize();
  380. return RetCode;
  381. }
  382. }
  383. // get GUID from system
  384. if (!GetVolumeNameForVolumeMountPoint(tmpVolumeArg.GetBuffer(), cDriveGUIDString, GUID_LENGTH))
  385. {
  386. if(!BootOptimize)
  387. {
  388. // bad drive error
  389. LoadString(resdll, IDS_CMDLINE_BAD_VOL, buf, lenbuf);
  390. wsprintf(g_szTempBuffer, L"\r\n%s\r\n\r\n", buf);
  391. PrintOnStdErr(g_szTempBuffer);
  392. DisplayHelp(prog);
  393. }
  394. RetCode = ENGERR_BAD_PARAM;
  395. CoUninitialize();
  396. return RetCode;
  397. }
  398. bDriveEntered = TRUE;
  399. }
  400. }
  401. if(!BootOptimize)
  402. {
  403. LoadString(resdll, IDS_COMMANDLINE_DESCRIPTION, buf, lenbuf);
  404. assert(wcslen(buf) < lenbuf);
  405. PrintOnStdOut(buf);
  406. }
  407. // no drive letter = help request
  408. if (bDriveEntered == FALSE)
  409. {
  410. DisplayHelp(prog);
  411. RetCode = ENGERR_BAD_PARAM;
  412. CoUninitialize();
  413. return RetCode;
  414. }
  415. // error if not a valid volume
  416. if (IsValidVolume(cDriveGUIDString, NULL, fileSystem) == FALSE)
  417. {
  418. if(!BootOptimize)
  419. {
  420. LoadString(resdll, IDS_VOLUME_TYPE_NOT_SUPPORTED, buf, lenbuf);
  421. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  422. PrintOnStdErr(g_szTempBuffer);
  423. }
  424. RetCode = ENGERR_BAD_PARAM;
  425. CoUninitialize();
  426. return RetCode;
  427. }
  428. // error if non-writeable device
  429. //sks bug#205674 disk full error
  430. if (IsVolumeWriteable(cDriveGUIDString, &dLastError) == FALSE)
  431. {
  432. if(!BootOptimize)
  433. {
  434. if(dLastError == ERROR_HANDLE_DISK_FULL)
  435. {
  436. LoadString(resdll, IDS_DISK_FULL, buf, lenbuf);
  437. wsprintf(g_szTempBuffer, L"\r\n%s.\r\n", buf);
  438. PrintOnStdErr(g_szTempBuffer);
  439. } else
  440. {
  441. LoadString(resdll, IDS_READONLY_VOLUME, buf, lenbuf);
  442. wsprintf(g_szTempBuffer, L"\r\n%s.\r\n", buf);
  443. PrintOnStdErr(g_szTempBuffer);
  444. }
  445. }
  446. RetCode = ENGERR_BAD_PARAM;
  447. CoUninitialize();
  448. return RetCode;
  449. }
  450. // if both a parent process and a stop event has been specified, open
  451. // the parent process and duplicate the handle to the event that it
  452. // may signal to stop/cancel us.
  453. if (parentProcessSpecified && stopEventSpecified)
  454. {
  455. // open the parent process.
  456. parentProcessHandle = OpenProcess(PROCESS_DUP_HANDLE,
  457. FALSE,
  458. parentProcessId);
  459. if (!parentProcessHandle)
  460. {
  461. RetCode = ENGERR_BAD_PARAM;
  462. CoUninitialize();
  463. return RetCode;
  464. }
  465. // duplicate the stop event.
  466. success = DuplicateHandle(parentProcessHandle,
  467. stopEventSourceHandle,
  468. GetCurrentProcess(),
  469. &stopEventHandle,
  470. 0,
  471. FALSE,
  472. DUPLICATE_SAME_ACCESS);
  473. CloseHandle(parentProcessHandle);
  474. if (!success)
  475. {
  476. RetCode = ENGERR_BAD_PARAM;
  477. CoUninitialize();
  478. return RetCode;
  479. }
  480. }
  481. // defrag
  482. ret = Defrag(cDriveGUIDString, fileSystem, stopEventHandle);
  483. // if parent process passed in a stop event, close it.
  484. if (stopEventHandle) {
  485. CloseHandle(stopEventHandle);
  486. }
  487. #ifdef _DEBUG
  488. if (RetCode == 0)
  489. {
  490. if(!BootOptimize)
  491. {
  492. LoadString(resdll, IDS_LABEL_DEFRAG_COMPLETE, buf, lenbuf);
  493. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  494. PrintOnStdOut(g_szTempBuffer);
  495. }
  496. }
  497. if(!BootOptimize)
  498. {
  499. wsprintf(g_szTempBuffer, L"ret code=%d\r\n", RetCode);
  500. PrintOnStdOut(g_szTempBuffer);
  501. }
  502. #endif
  503. // unload resource DLL
  504. ::FreeLibrary(resdll);
  505. // free multi instance semaphore
  506. ReleaseMISemaphore();
  507. CoUninitialize();
  508. return RetCode;
  509. }
  510. //-------------------------------------------------------------------*
  511. // function: DisplayHelp
  512. //
  513. // returns:
  514. // note:
  515. //-------------------------------------------------------------------*
  516. static void DisplayHelp(PTCHAR prog)
  517. {
  518. WCHAR buf[400];
  519. UINT lenbuf = sizeof(buf)/sizeof(WCHAR); //135977 pass number of characters not number of bytes
  520. WCHAR msg[400];
  521. UINT lenmsg = sizeof(msg)/sizeof(WCHAR); //135977 pass number of characters not number of bytes
  522. DWORD_PTR dwParams[10];
  523. DWORD len;
  524. dwParams[0] = (DWORD_PTR) prog;
  525. dwParams[1] = NULL;
  526. if(!BootOptimize)
  527. {
  528. LoadString(resdll, IDS_CMDLINE_USAGE, buf, lenbuf);
  529. assert(wcslen(buf) < lenbuf);
  530. len = FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  531. buf,
  532. 0,
  533. 0,
  534. msg,
  535. lenmsg,
  536. (va_list*) dwParams);
  537. assert(wslen(msg) < lenmsg);
  538. PrintOnStdOut(msg);
  539. }
  540. }
  541. //-------------------------------------------------------------------*
  542. // function: ConsoleCtrlHandler
  543. //
  544. // returns: TRUE if handled, FALSE otherwise
  545. // note:
  546. //-------------------------------------------------------------------*
  547. BOOL WINAPI ConsoleCtrlHandler(DWORD CtrlType)
  548. {
  549. BOOL ret = FALSE;
  550. WCHAR buf[400];
  551. UINT lenbuf = sizeof(buf)/sizeof(WCHAR); //135975 pass number of characters not number of bytes
  552. switch(CtrlType)
  553. {
  554. case CTRL_C_EVENT:
  555. case CTRL_BREAK_EVENT:
  556. // on these cases we want to acknowledge the user cancelled
  557. if(!BootOptimize)
  558. {
  559. // Use the OEM code page ...
  560. setlocale(LC_ALL, ".OCP");
  561. // Use the console UI language
  562. SetThreadUILanguage( 0 );
  563. LoadString(resdll, IDS_USER_CANCELLED, buf, lenbuf);
  564. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  565. PrintOnStdErr(g_szTempBuffer);
  566. }
  567. // fall through on purpose
  568. case CTRL_CLOSE_EVENT:
  569. case CTRL_LOGOFF_EVENT:
  570. case CTRL_SHUTDOWN_EVENT:
  571. SetEvent(hEngineDoneEvent);
  572. RetCode = ENG_USER_CANCELLED;
  573. ret = TRUE;
  574. break;
  575. }
  576. return ret;
  577. }
  578. //-------------------------------------------------------------------*
  579. // function: GetMISemaphore
  580. //
  581. // returns:
  582. // note:
  583. //-------------------------------------------------------------------*
  584. static int GetMISemaphore()
  585. {
  586. int ret = 1;
  587. WCHAR buf[400];
  588. UINT lenbuf = sizeof(buf)/sizeof(WCHAR); //135974 pass number of characters not number of bytes
  589. SECURITY_ATTRIBUTES saSecurityAttributes;
  590. SECURITY_DESCRIPTOR sdSecurityDescriptor;
  591. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  592. saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
  593. saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
  594. saSecurityAttributes.bInheritHandle = FALSE;
  595. if (!ConstructSecurityAttributes(&saSecurityAttributes, esatSemaphore, FALSE)) {
  596. return 1;
  597. }
  598. #if 1
  599. hIsOkToRunSemaphore = CreateSemaphore(&saSecurityAttributes, 1, 1, IS_OK_TO_RUN_SEMAPHORE_NAME);
  600. CleanupSecurityAttributes(&saSecurityAttributes);
  601. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  602. if (hIsOkToRunSemaphore != NULL)
  603. {
  604. // is the semaphore signaled?
  605. DWORD retValue = WaitForSingleObject(hIsOkToRunSemaphore, 10);
  606. // if so, this process is the only one, and the semaphore count is decremented to 0
  607. if (retValue == WAIT_OBJECT_0)
  608. {
  609. ret = 0;
  610. }
  611. }
  612. if (ret != 0)
  613. {
  614. if(!BootOptimize)
  615. {
  616. LoadString(resdll, IDS_CMDLINE_MULTI_INSTANCE, buf, lenbuf);
  617. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  618. PrintOnStdErr(g_szTempBuffer);
  619. }
  620. }
  621. #else
  622. // try to create the multiple instance semaphore
  623. hIsOkToRunSemaphore = CreateSemaphore(&saSecurityAttributes, 0, 1, IS_OK_TO_RUN_SEMAPHORE_NAME);
  624. // check if someone else has it
  625. if (hIsOkToRunSemaphore != NULL && GetLastError() == ERROR_ALREADY_EXISTS)
  626. {
  627. if(!BootOptimize)
  628. {
  629. LoadString(resdll, IDS_CMDLINE_MULTI_INSTANCE, buf, lenbuf);
  630. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  631. PrintOnStdErr(g_szTempBuffer);
  632. }
  633. ret = 1;
  634. }
  635. #endif
  636. return ret;
  637. }
  638. //-------------------------------------------------------------------*
  639. // function: ReleaseMISemaphore
  640. //
  641. // returns:
  642. // note:
  643. //-------------------------------------------------------------------*
  644. static void ReleaseMISemaphore()
  645. {
  646. // if the semaphore was created, nuke it
  647. if (hIsOkToRunSemaphore != NULL)
  648. {
  649. ReleaseSemaphore(hIsOkToRunSemaphore, 1, NULL);
  650. CloseHandle(hIsOkToRunSemaphore);
  651. hIsOkToRunSemaphore = NULL;
  652. }
  653. }
  654. //-------------------------------------------------------------------*
  655. // function: Defrag
  656. //
  657. // returns: 0 if all is well, otherwise error code
  658. // note:
  659. //-------------------------------------------------------------------*
  660. static int Defrag(PTCHAR cDriveGUIDString, PTCHAR fileSystem, HANDLE hStopEvent)
  661. {
  662. int ret = 0;
  663. TCHAR cmd[200];
  664. LPDATAOBJECT pDefragEngine = NULL;
  665. WCHAR buf[400];
  666. UINT lenbuf = sizeof(buf)/sizeof(WCHAR); //135976 pass number of characters not number of bytes
  667. NOT_DATA NotData = {0};
  668. BOOL bReturn;
  669. ULONG numEvents;
  670. HANDLE hEvents[2];
  671. SECURITY_ATTRIBUTES saSecurityAttributes;
  672. SECURITY_DESCRIPTOR sdSecurityDescriptor;
  673. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  674. saSecurityAttributes.nLength = sizeof (saSecurityAttributes);
  675. saSecurityAttributes.lpSecurityDescriptor = &sdSecurityDescriptor;
  676. saSecurityAttributes.bInheritHandle = FALSE;
  677. if (!ConstructSecurityAttributes(&saSecurityAttributes, esatEvent, FALSE)) {
  678. RetCode = ENGERR_SYSTEM;
  679. return RetCode;
  680. }
  681. hEngineDoneEvent = CreateEvent(&saSecurityAttributes, TRUE, FALSE, DEFRAG_COMPLETE_EVENT_NAME);
  682. // create event
  683. if ((hEngineDoneEvent == NULL) || (ERROR_ALREADY_EXISTS == GetLastError())) {
  684. if(!BootOptimize)
  685. {
  686. LoadString(resdll, IDS_ERR_CREATE_EVENT, buf, lenbuf);
  687. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  688. PrintOnStdErr(g_szTempBuffer);
  689. }
  690. CleanupSecurityAttributes(&saSecurityAttributes);
  691. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  692. RetCode = ENGERR_SYSTEM;
  693. return RetCode;
  694. }
  695. CleanupSecurityAttributes(&saSecurityAttributes);
  696. ZeroMemory(&sdSecurityDescriptor, sizeof(SECURITY_DESCRIPTOR));
  697. // initialize
  698. DWORD dwInstanceRegister = InitializeDataIo(CLSID_DfrgCtlDataIo, REGCLS_MULTIPLEUSE);
  699. // build command string
  700. // is this an NTFS volume?
  701. if (_tcscmp(fileSystem, TEXT("NTFS")) == MATCH)
  702. {
  703. // start the NTFS command string
  704. _tcscpy(cmd, TEXT("DfrgNtfs "));
  705. }
  706. // is this a FAT or FAT32 volume?
  707. else if (_tcscmp(fileSystem, TEXT("FAT")) == MATCH ||
  708. _tcscmp(fileSystem, TEXT("FAT32")) == MATCH)
  709. {
  710. // start the FAT command string
  711. _tcscpy(cmd, TEXT("DfrgFat "));
  712. }
  713. else
  714. {
  715. if(!BootOptimize)
  716. {
  717. LoadString(resdll, IDS_VOLUME_TYPE_NOT_SUPPORTED, buf, lenbuf);
  718. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  719. PrintOnStdErr(g_szTempBuffer);
  720. }
  721. RetCode = ENGERR_BAD_PARAM;
  722. return RetCode;
  723. }
  724. // finish command line
  725. _tcscat(cmd, cDriveGUIDString);
  726. if (AnalyzeOnly) {
  727. _tcscat(cmd, TEXT(" ANALYZE CMDLINE"));
  728. }
  729. else {
  730. _tcscat(cmd, TEXT(" DEFRAG CMDLINE"));
  731. }
  732. // add boot optimize flag
  733. if (BootOptimize)
  734. {
  735. _tcscat(cmd, TEXT(" BOOT"));
  736. } else
  737. { // add force flag
  738. if (ForceDefrag)
  739. {
  740. _tcscat(cmd, TEXT(" FORCE"));
  741. }
  742. }
  743. #ifdef _DEBUG
  744. if(!BootOptimize)
  745. {
  746. wsprintf(g_szTempBuffer, L"command line: %s\r\n\r\n", cmd);
  747. PrintOnStdOut(g_szTempBuffer);
  748. }
  749. #endif
  750. // Start the volume-oriented communication. Create a guid for communication first.
  751. CLSID volumeID;
  752. if (!SUCCEEDED(CoCreateGuid(&volumeID)))
  753. {
  754. if(!BootOptimize)
  755. {
  756. LoadString(resdll, IDS_ERR_CONNECT_ENGINE, buf, lenbuf);
  757. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  758. PrintOnStdErr(g_szTempBuffer);
  759. }
  760. RetCode = ENGERR_SYSTEM;
  761. return RetCode;
  762. }
  763. USES_CONVERSION;
  764. COleStr VolID;
  765. StringFromCLSID(volumeID, VolID);
  766. InitializeDataIo(volumeID, REGCLS_MULTIPLEUSE);
  767. // clear the event
  768. if (!ResetEvent(hEngineDoneEvent))
  769. {
  770. if(!BootOptimize)
  771. {
  772. LoadString(resdll, IDS_ERR_CREATE_EVENT, buf, lenbuf);
  773. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  774. PrintOnStdErr(g_szTempBuffer);
  775. }
  776. RetCode = ENGERR_SYSTEM;
  777. return RetCode;
  778. }
  779. // install handler to make sure engine shuts down if we get killed
  780. BOOL ok = SetConsoleCtrlHandler(ConsoleCtrlHandler, TRUE);
  781. // is this an NTFS volume?
  782. if (_tcscmp(fileSystem, TEXT("NTFS")) == MATCH)
  783. {
  784. // get a pointer to the NTFS engine
  785. if (!InitializeDataIoClient(CLSID_DfrgNtfs, NULL, &pDefragEngine))
  786. {
  787. if(!BootOptimize)
  788. {
  789. LoadString(resdll, IDS_ERR_CONNECT_ENGINE, buf, lenbuf);
  790. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  791. PrintOnStdErr(g_szTempBuffer);
  792. }
  793. RetCode = ENGERR_SYSTEM;
  794. return RetCode;
  795. }
  796. }
  797. // is this a FAT or FAT32 volume?
  798. else
  799. {
  800. // get a pointer to the FAT engine
  801. if (!InitializeDataIoClient(CLSID_DfrgFat, NULL, &pDefragEngine))
  802. {
  803. if(!BootOptimize)
  804. {
  805. LoadString(resdll, IDS_ERR_CONNECT_ENGINE, buf, lenbuf);
  806. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  807. PrintOnStdErr(g_szTempBuffer);
  808. }
  809. RetCode = ENGERR_SYSTEM;
  810. return RetCode;
  811. }
  812. }
  813. // defrag
  814. //
  815. // send the generated clsid to the engine
  816. DataIoClientSetData(ID_INIT_VOLUME_COMM,
  817. OLE2T(VolID),
  818. VolID.GetLength() * sizeof(TCHAR),
  819. pDefragEngine);
  820. // send the command request to the Dfrg engine
  821. DataIoClientSetData(ID_INITIALIZE_DRIVE,
  822. cmd,
  823. _tcslen(cmd) * sizeof(TCHAR),
  824. pDefragEngine);
  825. // wait for engine to signal it is finished
  826. BOOL bEngineNotDone = TRUE; // not done yet flag
  827. const DWORD dwWaitMilliSecs = 5000; // milli-seconds to wait
  828. // setup the events that may be signaled to stop us.
  829. numEvents = 0;
  830. hEvents[numEvents] = hEngineDoneEvent;
  831. numEvents++;
  832. if (hStopEvent) {
  833. hEvents[numEvents] = hStopEvent;
  834. numEvents++;
  835. }
  836. while (bEngineNotDone)
  837. {
  838. // wait for engine to signal it is done, but timeout
  839. DWORD status = WaitForMultipleObjects(numEvents,
  840. hEvents,
  841. FALSE,
  842. dwWaitMilliSecs);
  843. switch (status)
  844. {
  845. case WAIT_TIMEOUT: // wait timed out
  846. // ping engine to see if it is running still
  847. bReturn = DataIoClientSetData(ID_PING, (PTCHAR) &NotData, sizeof(NOT_DATA), pDefragEngine);
  848. // if we cannot ping it, assume it is dead
  849. if (!bReturn)
  850. {
  851. // to avoid a race condition, check the done event again.
  852. if (WAIT_OBJECT_0 == WaitForSingleObject(hEngineDoneEvent, 0))
  853. {
  854. // engine signaled event and exit just when we timed out.
  855. // loop and fall through to the "engine done" code path.
  856. break;
  857. }
  858. if (RetCode == 0)
  859. {
  860. RetCode = ENGERR_UNKNOWN;
  861. }
  862. // error message
  863. if ((ENGERR_UNKNOWN == RetCode) && (!BootOptimize)) {
  864. LoadString(resdll, IDS_CMDLINE_UNKNOWN_ERR, buf, lenbuf);
  865. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  866. PrintOnStdErr(g_szTempBuffer);
  867. DisplayHelp(prog);
  868. }
  869. bEngineNotDone = FALSE;
  870. }
  871. break;
  872. case WAIT_OBJECT_0: // engine signaled it is done
  873. bEngineNotDone = FALSE;
  874. break;
  875. case WAIT_OBJECT_0 + 1: // parent process asked us to stop
  876. bEngineNotDone = FALSE;
  877. RetCode = ENG_USER_CANCELLED;
  878. break;
  879. case WAIT_ABANDONED: // engine died
  880. // error message
  881. if(!BootOptimize)
  882. {
  883. LoadString(resdll, IDS_CMDLINE_UNKNOWN_ERR, buf, lenbuf);
  884. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  885. PrintOnStdErr(g_szTempBuffer);
  886. DisplayHelp(prog);
  887. }
  888. RetCode = ENGERR_UNKNOWN;
  889. bEngineNotDone = FALSE;
  890. break;
  891. }
  892. }
  893. // kill engine
  894. BOOL bNoGui = TRUE;
  895. DataIoClientSetData(ID_ABORT, (PTCHAR) &bNoGui, sizeof(BOOL), pDefragEngine);
  896. // clean up
  897. ok = ExitDataIoClient(&pDefragEngine);
  898. pDefragEngine = NULL;
  899. #ifdef _DEBUG
  900. if (!ok)
  901. {
  902. if(!BootOptimize)
  903. {
  904. LoadString(resdll, IDS_ERR_RELEASE_ENGINE, buf, lenbuf);
  905. wsprintf(g_szTempBuffer, L"\r\n%s\r\n", buf);
  906. PrintOnStdErr(g_szTempBuffer);
  907. }
  908. }
  909. #endif
  910. // don't need event any more
  911. CloseHandle(hEngineDoneEvent);
  912. return RetCode;
  913. }
  914. TCHAR*
  915. InsertCommaIntoText(
  916. IN TCHAR* stringBuffer
  917. )
  918. {
  919. TCHAR targetString[256];
  920. TCHAR sourceString[256];
  921. TCHAR tcThousandsSep[2] = {TEXT(','), 0};
  922. _tcscpy(sourceString, stringBuffer);
  923. if(_tcslen(sourceString) == 0) {
  924. return TEXT("");
  925. }
  926. struct lconv *locals = localeconv();
  927. if (*(locals->thousands_sep) != 0) {
  928. _stprintf(tcThousandsSep, TEXT("%C"), *(locals->thousands_sep));
  929. }
  930. UINT uGrouping = atoi(locals->grouping);
  931. if(uGrouping == 0) {
  932. uGrouping = 3; //default value if its not supported
  933. }
  934. // point the source pointer at the null terminator
  935. PTCHAR pSource = sourceString + _tcslen(sourceString);
  936. // put the target pointer at the end of the target buffer
  937. PTCHAR pTarget = targetString + sizeof(targetString) / sizeof(TCHAR) - 1;
  938. // write the null terminator
  939. *pTarget = NULL;
  940. for (UINT i=0; i<_tcslen(sourceString); i++){
  941. if (i>0 && i%uGrouping == 0){
  942. pTarget--;
  943. *pTarget = tcThousandsSep[0];
  944. }
  945. pTarget--;
  946. pSource--;
  947. *pTarget = *pSource;
  948. }
  949. // if (stringBufferLength > _tcslen(pTarget)){
  950. _tcscpy(stringBuffer, pTarget);
  951. // }
  952. // else{
  953. // _tcscpy(stringBuffer, TEXT(""));
  954. // }
  955. return stringBuffer;
  956. }
  957. LONGLONG checkForNegativeValues(LONGLONG lldatavalue)
  958. {
  959. return ((lldatavalue > 0) ? lldatavalue : 0);
  960. }
  961. VOID
  962. PrintToStdOut(
  963. IN UINT resourceIDText,
  964. IN UINT resourceIDSeperator,
  965. IN TCHAR* pTextStr,
  966. BOOL bIndentText,
  967. IN UINT resourceIDPercent = 0
  968. )
  969. {
  970. TCHAR buffer[256];
  971. TCHAR tempBuffer[270];
  972. TCHAR buffer2[8];
  973. //load the resourceIDText
  974. LoadString(GetDfrgResHandle(), resourceIDText, buffer, sizeof(buffer)/sizeof(TCHAR));
  975. if(bIndentText) {
  976. _stprintf(tempBuffer, TEXT(" %s"), buffer);
  977. }
  978. else {
  979. _stprintf(tempBuffer, TEXT("\r\n%s"), buffer);
  980. }
  981. //
  982. // Add spaces so that this part occupies at least 35 chars
  983. //
  984. int uExtraStrLen = 35 - _tcslen(tempBuffer);
  985. if (uExtraStrLen > 0) {
  986. int i = 0;
  987. for(i=0;i<uExtraStrLen;i++) {
  988. _tcscat(tempBuffer, TEXT(" "));
  989. }
  990. }
  991. //load the resourceIDSeperator
  992. LoadString(GetDfrgResHandle(), resourceIDSeperator, buffer, sizeof(buffer)/sizeof(TCHAR));
  993. if (resourceIDPercent) {
  994. LoadString(GetDfrgResHandle(), resourceIDPercent, buffer2, sizeof(buffer2)/sizeof(TCHAR));
  995. wsprintf(g_szTempBuffer, L"%s \t%s %s %s\r\n", tempBuffer, buffer, pTextStr, buffer2);
  996. PrintOnStdOut(g_szTempBuffer);
  997. }
  998. else {
  999. wsprintf(g_szTempBuffer, L"%s \t%s %s\r\n", tempBuffer, buffer, pTextStr);
  1000. PrintOnStdOut(g_szTempBuffer);
  1001. }
  1002. }
  1003. VOID
  1004. WriteTextReportToStdOut(
  1005. IN TEXT_DATA *pTextData
  1006. )
  1007. {
  1008. TCHAR buffer[256];
  1009. TCHAR tempBuffer[256];
  1010. static int count = 0;
  1011. // Use the OEM code page ...
  1012. setlocale(LC_ALL, ".OCP");
  1013. // Use the console UI language
  1014. SetThreadUILanguage( 0 );
  1015. // check all the values of textdata to make sure no negative values
  1016. //to fix bug number 35764
  1017. pTextData->DiskSize = checkForNegativeValues(pTextData->DiskSize);
  1018. pTextData->BytesPerCluster = checkForNegativeValues(pTextData->BytesPerCluster);
  1019. pTextData->UsedSpace = checkForNegativeValues(pTextData->UsedSpace);
  1020. pTextData->FreeSpace = checkForNegativeValues(pTextData->FreeSpace);
  1021. pTextData->FreeSpacePercent = checkForNegativeValues(pTextData->FreeSpacePercent);
  1022. pTextData->UsableFreeSpace = checkForNegativeValues(pTextData->UsableFreeSpace);
  1023. pTextData->UsableFreeSpacePercent = checkForNegativeValues(pTextData->UsableFreeSpacePercent);
  1024. pTextData->PagefileBytes = checkForNegativeValues(pTextData->PagefileBytes);
  1025. pTextData->PagefileFrags = checkForNegativeValues(pTextData->PagefileFrags);
  1026. pTextData->TotalDirectories = checkForNegativeValues(pTextData->TotalDirectories);
  1027. pTextData->FragmentedDirectories = checkForNegativeValues(pTextData->FragmentedDirectories);
  1028. pTextData->ExcessDirFrags = checkForNegativeValues(pTextData->ExcessDirFrags);
  1029. pTextData->TotalFiles = checkForNegativeValues(pTextData->TotalFiles);
  1030. pTextData->AvgFileSize = checkForNegativeValues(pTextData->AvgFileSize);
  1031. pTextData->NumFraggedFiles = checkForNegativeValues(pTextData->NumFraggedFiles);
  1032. pTextData->NumExcessFrags = checkForNegativeValues(pTextData->NumExcessFrags);
  1033. pTextData->PercentDiskFragged = checkForNegativeValues(pTextData->PercentDiskFragged);
  1034. pTextData->AvgFragsPerFile = checkForNegativeValues(pTextData->AvgFragsPerFile);
  1035. pTextData->MFTBytes = checkForNegativeValues(pTextData->MFTBytes);
  1036. pTextData->InUseMFTRecords = checkForNegativeValues(pTextData->InUseMFTRecords);
  1037. pTextData->TotalMFTRecords = checkForNegativeValues(pTextData->TotalMFTRecords);
  1038. pTextData->MFTExtents = checkForNegativeValues(pTextData->MFTExtents);
  1039. pTextData->FreeSpaceFragPercent = checkForNegativeValues(pTextData->FreeSpaceFragPercent);
  1040. if (!VerboseOutput) {
  1041. TCHAR buffer1[24];
  1042. if (AnalyzeOnly || !count) {
  1043. PrintToStdOut(IDS_ANALYSIS_REPORT_TITLE, NULL, TEXT(""), FALSE);
  1044. }
  1045. else {
  1046. PrintToStdOut(IDS_DEFRAG_REPORT_TITLE, NULL, TEXT(""), FALSE);
  1047. }
  1048. ++count;
  1049. LoadString(GetDfrgResHandle(), IDS_CONCISE_OUTPUT_FORMAT, buffer, sizeof(buffer)/sizeof(TCHAR));
  1050. // Volume Size
  1051. _stprintf(buffer1, TEXT("%I64d"), pTextData->DiskSize);
  1052. InsertCommaIntoText(buffer1);
  1053. FormatNumber(GetDfrgResHandle(), pTextData->DiskSize, buffer1);
  1054. // Free Space
  1055. _stprintf(tempBuffer, TEXT("%I64d"), pTextData->FreeSpace);
  1056. InsertCommaIntoText(tempBuffer);
  1057. FormatNumber(GetDfrgResHandle(), pTextData->FreeSpace, tempBuffer);
  1058. wsprintf(g_szTempBuffer,
  1059. buffer,
  1060. buffer1,
  1061. tempBuffer,
  1062. pTextData->FreeSpacePercent,
  1063. ((pTextData->PercentDiskFragged + pTextData->FreeSpaceFragPercent) / 2),
  1064. pTextData->PercentDiskFragged
  1065. );
  1066. PrintOnStdOut(g_szTempBuffer);
  1067. if (AnalyzeOnly) {
  1068. if(((pTextData->PercentDiskFragged + pTextData->FreeSpaceFragPercent) / 2) > 10){
  1069. //If the fragmentation on the disk exceeds 10% fragmentation, then recommend defragging.
  1070. PrintToStdOut(IDS_LABEL_CHOOSE_DEFRAGMENT, NULL, TEXT(""), FALSE);
  1071. }
  1072. else{
  1073. //Otherwise tell the user he doesn't need to defragment at this time.
  1074. PrintToStdOut(IDS_LABEL_NO_CHOOSE_DEFRAGMENT, NULL, TEXT(""), FALSE);
  1075. }
  1076. }
  1077. return;
  1078. }
  1079. if (AnalyzeOnly || !count) {
  1080. PrintToStdOut(IDS_ANALYSIS_REPORT_TITLE, NULL, TEXT("\r\n"), FALSE);
  1081. }
  1082. else {
  1083. PrintOnStdOut(L"\r\n\r\n");
  1084. PrintToStdOut(IDS_DEFRAG_REPORT_TITLE, NULL, TEXT("\r\n"), FALSE);
  1085. }
  1086. ++count;
  1087. ///////////////////////////////////////////////////////////////////////////
  1088. // Volume Size
  1089. _stprintf(buffer, TEXT("%I64d"), pTextData->DiskSize);
  1090. InsertCommaIntoText(buffer);
  1091. FormatNumber(GetDfrgResHandle(), pTextData->DiskSize, buffer);
  1092. PrintToStdOut(IDS_LABEL_VOLUME_SIZE,IDS_LABEL_EQUAL_SIGN,
  1093. buffer,TRUE);
  1094. // Cluster Size
  1095. _stprintf(buffer, TEXT("%I64d"), pTextData->BytesPerCluster);
  1096. InsertCommaIntoText(buffer);
  1097. FormatNumber(GetDfrgResHandle(), pTextData->BytesPerCluster, buffer);
  1098. PrintToStdOut(IDS_LABEL_CLUSTER_SIZE,IDS_LABEL_EQUAL_SIGN,
  1099. buffer,TRUE);
  1100. // Used Space
  1101. _stprintf(buffer, TEXT("%I64d"), pTextData->UsedSpace);
  1102. InsertCommaIntoText(buffer);
  1103. FormatNumber(GetDfrgResHandle(), pTextData->UsedSpace, buffer);
  1104. PrintToStdOut(IDS_LABEL_USED_SPACE,IDS_LABEL_EQUAL_SIGN,
  1105. buffer,TRUE);
  1106. // Free Space
  1107. _stprintf(buffer, TEXT("%I64d"), pTextData->FreeSpace);
  1108. InsertCommaIntoText(buffer);
  1109. FormatNumber(GetDfrgResHandle(), pTextData->FreeSpace, buffer);
  1110. PrintToStdOut(IDS_LABEL_FREE_SPACE,IDS_LABEL_EQUAL_SIGN,
  1111. buffer,TRUE);
  1112. // % Free Space
  1113. _stprintf(buffer, TEXT("%I64d"), pTextData->FreeSpacePercent);
  1114. PrintToStdOut(IDS_LABEL_PERCENT_FREE_SPACE,
  1115. IDS_LABEL_EQUAL_SIGN,buffer,TRUE,IDS_LABEL_PERCENT_SIGN);
  1116. // Volume Fragmentation Header
  1117. PrintToStdOut(IDS_LABEL_VOLUME_FRAGMENTATION_HEADING,NULL,TEXT(""),FALSE);
  1118. // % Total Fragmentation
  1119. _stprintf(buffer, TEXT("%I64d"), (pTextData->PercentDiskFragged + pTextData->FreeSpaceFragPercent) / 2);
  1120. PrintToStdOut(IDS_LABEL_TOTAL_FRAGMENTATION,
  1121. IDS_LABEL_EQUAL_SIGN,buffer,TRUE,IDS_LABEL_PERCENT_SIGN);
  1122. // % File Fragmentation
  1123. _stprintf(buffer, TEXT("%I64d"), pTextData->PercentDiskFragged);
  1124. PrintToStdOut(IDS_LABEL_FILE_FRAGMENTATION,
  1125. IDS_LABEL_EQUAL_SIGN,buffer,TRUE,IDS_LABEL_PERCENT_SIGN);
  1126. // % Free Space Fragmentation
  1127. _stprintf(buffer, TEXT("%I64d"), pTextData->FreeSpaceFragPercent);
  1128. PrintToStdOut(IDS_LABEL_FREE_SPACE_FRAGMENTATION,
  1129. IDS_LABEL_EQUAL_SIGN,buffer,TRUE,IDS_LABEL_PERCENT_SIGN);
  1130. // File Fragmentation Header
  1131. PrintToStdOut(IDS_LABEL_FILE_FRAGMENTATION_HEADING ,NULL,TEXT(""),FALSE);
  1132. // Total Files
  1133. _stprintf(buffer, TEXT("%I64d"), pTextData->TotalFiles);
  1134. InsertCommaIntoText(buffer);
  1135. PrintToStdOut(IDS_LABEL_TOTAL_FILES ,IDS_LABEL_EQUAL_SIGN,buffer,TRUE);
  1136. // Average Files Size
  1137. _stprintf(buffer, TEXT("%I64d"), pTextData->AvgFileSize);
  1138. InsertCommaIntoText(buffer);
  1139. FormatNumber(GetDfrgResHandle(), pTextData->AvgFileSize, buffer);
  1140. PrintToStdOut(IDS_LABEL_AVERAGE_FILE_SIZE, IDS_LABEL_EQUAL_SIGN,buffer,TRUE);
  1141. // Total fragmented files
  1142. _stprintf(buffer, TEXT("%I64d"), pTextData->NumFraggedFiles);
  1143. PrintToStdOut(IDS_LABEL_TOTAL_FRAGMENTED_FILES, IDS_LABEL_EQUAL_SIGN,InsertCommaIntoText(buffer),TRUE);
  1144. // Total excess fragments
  1145. _stprintf(buffer, TEXT("%I64d"), pTextData->NumExcessFrags);
  1146. PrintToStdOut(IDS_LABEL_TOTAL_EXCESS_FRAGMENTS, IDS_LABEL_EQUAL_SIGN,InsertCommaIntoText(buffer),TRUE);
  1147. // Average Fragments per File
  1148. struct lconv *locals = localeconv();
  1149. _stprintf(buffer, TEXT("%d%c%02d"), (UINT)pTextData->AvgFragsPerFile/100,
  1150. ((locals && (locals->decimal_point)) ? *(locals->decimal_point) : '.'),
  1151. (UINT)pTextData->AvgFragsPerFile%100);
  1152. PrintToStdOut(IDS_LABEL_AVERAGE_FRAGMENTS_PER_FILE, IDS_LABEL_EQUAL_SIGN,buffer,TRUE);
  1153. // Pagefile Fragmentation Header
  1154. PrintToStdOut(IDS_LABEL_PAGEFILE_FRAGMENTATION_HEADING, NULL,TEXT(""),FALSE);
  1155. // Pagefile Size
  1156. _stprintf(buffer, TEXT("%I64d"), pTextData->PagefileBytes);
  1157. InsertCommaIntoText(buffer);
  1158. FormatNumber(GetDfrgResHandle(), pTextData->PagefileBytes, buffer);
  1159. PrintToStdOut(IDS_LABEL_PAGEFILE_SIZE, IDS_LABEL_EQUAL_SIGN,buffer,TRUE);
  1160. // Total Fragments
  1161. _stprintf(buffer, TEXT("%I64d"), pTextData->PagefileFrags);
  1162. PrintToStdOut(IDS_LABEL_TOTAL_FRAGMENTS, IDS_LABEL_EQUAL_SIGN,InsertCommaIntoText(buffer),TRUE);
  1163. // Directory Fragmentation Header
  1164. PrintToStdOut(IDS_LABEL_DIRECTORY_FRAGMENTATION_HEADING,NULL,TEXT(""),FALSE);
  1165. // Total Directories
  1166. _stprintf(buffer, TEXT("%I64d"), pTextData->TotalDirectories);
  1167. PrintToStdOut(IDS_LABEL_TOTAL_DIRECTORIES,
  1168. IDS_LABEL_EQUAL_SIGN,InsertCommaIntoText(buffer),TRUE);
  1169. // Fragmented Directories
  1170. _stprintf(buffer, TEXT("%I64d"), pTextData->FragmentedDirectories);
  1171. PrintToStdOut(IDS_LABEL_FRAGMENTED_DIRECTORIES,
  1172. IDS_LABEL_EQUAL_SIGN,InsertCommaIntoText(buffer),TRUE);
  1173. // Excess directory fragments
  1174. _stprintf(buffer, TEXT("%I64d"), pTextData->ExcessDirFrags);
  1175. PrintToStdOut(IDS_LABEL_EXCESS_DIRECTORY_FRAGMENTS, IDS_LABEL_EQUAL_SIGN,
  1176. InsertCommaIntoText(buffer), TRUE);
  1177. //Only display MFT data if this is an NTFS drive.
  1178. if(_tcscmp(pTextData->cFileSystem, TEXT("NTFS")) == 0) {
  1179. // MFT Fragmentation Header
  1180. PrintToStdOut(IDS_LABEL_MFT_FRAGMENTATION_HEADING, NULL, TEXT(""), FALSE);
  1181. // Total MFT Size
  1182. _stprintf(buffer, TEXT("%I64d"), pTextData->MFTBytes);
  1183. InsertCommaIntoText(buffer);
  1184. FormatNumber(GetDfrgResHandle(), pTextData->MFTBytes, buffer);
  1185. PrintToStdOut(IDS_LABEL_TOTAL_MFT_SIZE, IDS_LABEL_EQUAL_SIGN,
  1186. buffer, TRUE);
  1187. // Number of MFT records
  1188. _stprintf(buffer, TEXT("%I64d"), pTextData->InUseMFTRecords);
  1189. PrintToStdOut(IDS_LABEL_MFT_RECORD_COUNT, IDS_LABEL_EQUAL_SIGN,
  1190. InsertCommaIntoText(buffer), TRUE);
  1191. // Percent of MFT in use
  1192. _stprintf(buffer, TEXT("%I64d"), 100*pTextData->InUseMFTRecords/pTextData->TotalMFTRecords);
  1193. PrintToStdOut(IDS_LABEL_PERCENT_MFT_IN_USE, IDS_LABEL_EQUAL_SIGN,
  1194. buffer, TRUE);
  1195. // Total MFT fragments
  1196. _stprintf(buffer, TEXT("%I64d"), pTextData->MFTExtents);
  1197. PrintToStdOut(IDS_LABEL_TOTAL_MFT_FRAGMENTS, IDS_LABEL_EQUAL_SIGN,
  1198. InsertCommaIntoText(buffer),TRUE);
  1199. }
  1200. if (AnalyzeOnly) {
  1201. if(((pTextData->PercentDiskFragged + pTextData->FreeSpaceFragPercent) / 2) > 10){
  1202. //If the fragmentation on the disk exceeds 10% fragmentation, then recommend defragging.
  1203. PrintToStdOut(IDS_LABEL_CHOOSE_DEFRAGMENT, NULL, TEXT(""), FALSE);
  1204. }
  1205. else{
  1206. //Otherwise tell the user he doesn't need to defragment at this time.
  1207. PrintToStdOut(IDS_LABEL_NO_CHOOSE_DEFRAGMENT, NULL, TEXT(""), FALSE);
  1208. }
  1209. }
  1210. /* // if there are >1 mount points, print them all out
  1211. // yes, this will duplicate the same as the display label
  1212. // refresh the mount point list
  1213. #ifndef VER4
  1214. pLocalVolume->GetVolumeMountPointList();
  1215. if (pLocalVolume->MountPointCount() > 1){
  1216. for (UINT i=0; i<pLocalVolume->MountPointCount(); i++){
  1217. LoadString(GetDfrgResHandle(), IDS_MOUNTED_VOLUME, tempBuffer, sizeof(tempBuffer)/sizeof(TCHAR));
  1218. _stprintf(buffer, TEXT("%s %s"), tempBuffer, pLocalVolume->MountPoint(i));
  1219. PrintToStdOut(buffer,
  1220. NULL,TEXT(""),FALSE);
  1221. }
  1222. }
  1223. #endif
  1224. // write out the display label (usually the drive letter/label)
  1225. LoadString(GetDfrgResHandle(), IDS_LABEL_VOLUME, tempBuffer, sizeof(tempBuffer)/sizeof(TCHAR));
  1226. _stprintf(buffer, TEXT("%s %s"), tempBuffer,pLocalVolume->DisplayLabel());
  1227. PrintToStdOut(buffer
  1228. ,NULL,TEXT(""),FALSE);
  1229. */
  1230. // PrintToStdOut(IDS_PRODUCT_NAME,NULL,TEXT(""),FALSE);
  1231. }
  1232. /*-------------------------------------------------------------------*
  1233. ROUTINE DESCRIPTION:
  1234. This routines handles the 're-routed' window posted command messages. The general DataIo (DCOM)
  1235. routines that we use would normally call the PostMessage() routine to handle incoming data requests.
  1236. But for console applications, there is NO windows application to handle the PostMessage() commands,
  1237. so in DataIo.cpp (SetData() routine), it was modified to call a locally define PostMessageConsole()
  1238. routine instead if the user defines "ConsoleApplication" at build time.
  1239. GLOBAL DATA:
  1240. None
  1241. INPUT:
  1242. hWnd - Handle to the window - always NULL
  1243. uMsg - The message.
  1244. wParam - The word parameter for the message.
  1245. lParam - the long parameter for the message.
  1246. Note: These are the same inputs that the WndProc() routine would handle for PostMessage() commands.
  1247. RETURN:
  1248. TRUE
  1249. REVISION HISTORY:
  1250. 0.0E00 23 September 1997 - Andy Staffer - modified for the DfrgSnap
  1251. 0.0E00 15 July 1997 - Gary Quan - Created
  1252. ---------------------------------------------------------------------*/
  1253. BOOL PostMessageLocal (
  1254. IN HWND hWnd,
  1255. IN UINT Msg,
  1256. IN WPARAM wParam,
  1257. IN LPARAM lParam
  1258. )
  1259. {
  1260. DATA_IO* pDataIo;
  1261. switch (LOWORD(wParam))
  1262. {
  1263. // says that the engine is instantiated, but not defragging or analyzing
  1264. case ID_ENGINE_START:
  1265. {
  1266. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1267. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1268. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1269. break;
  1270. }
  1271. // defrag has actually started
  1272. case ID_BEGIN_SCAN:
  1273. {
  1274. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1275. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1276. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1277. break;
  1278. }
  1279. // defrag has ended
  1280. case ID_END_SCAN:
  1281. {
  1282. END_SCAN_DATA* pEndScanData;
  1283. // Get a pointer to the data sent via DCOM.
  1284. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1285. pEndScanData = (END_SCAN_DATA*)&(pDataIo->cData);
  1286. // Make sure this is a valid size packet.
  1287. EF_ASSERT(pDataIo->ulDataSize >= sizeof(END_SCAN_DATA));
  1288. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1289. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1290. break;
  1291. }
  1292. // engine died
  1293. case ID_TERMINATING:
  1294. {
  1295. NOT_DATA* pNotData;
  1296. // Get a pointer to the data sent via DCOM.
  1297. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1298. pNotData = (NOT_DATA*)&(pDataIo->cData);
  1299. // Make sure this is a valid size packet.
  1300. EF_ASSERT(pDataIo->ulDataSize >= sizeof(NOT_DATA));
  1301. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1302. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1303. break;
  1304. }
  1305. // engine error data
  1306. case ID_ERROR:
  1307. {
  1308. ERROR_DATA* pErrorData;
  1309. // Get a pointer to the data sent via DCOM.
  1310. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1311. pErrorData = (ERROR_DATA*)&(pDataIo->cData);
  1312. // Make sure this is a valid size packet.
  1313. EF_ASSERT(pDataIo->ulDataSize >= sizeof(ERROR_DATA));
  1314. // Save error code
  1315. RetCode = pErrorData->dwErrCode;
  1316. if(!BootOptimize)
  1317. {
  1318. wsprintf(g_szTempBuffer, L"\r\n%s\r\n\r\n", pErrorData->cErrText);
  1319. PrintOnStdErr(g_szTempBuffer);
  1320. }
  1321. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1322. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1323. break;
  1324. }
  1325. // sends the progress bar setting and the status that is
  1326. // displayed in the list view
  1327. case ID_STATUS:
  1328. {
  1329. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1330. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1331. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1332. break;
  1333. }
  1334. // sends the list of most fragged files
  1335. case ID_FRAGGED_DATA:
  1336. {
  1337. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1338. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1339. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1340. break;
  1341. }
  1342. // sends the data displayed in the graphic wells (cluster maps)
  1343. case ID_DISP_DATA:
  1344. {
  1345. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1346. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1347. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1348. break;
  1349. }
  1350. // sends the text data that is displayed on the report
  1351. case ID_REPORT_TEXT_DATA:
  1352. {
  1353. TEXT_DATA* pTextData = NULL;
  1354. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1355. pTextData = (TEXT_DATA*)&(pDataIo->cData);
  1356. EF_ASSERT(pDataIo->ulDataSize >= sizeof(TEXT_DATA));
  1357. WriteTextReportToStdOut(pTextData);
  1358. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1359. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1360. break;
  1361. }
  1362. case ID_PING:
  1363. // Do nothing.
  1364. // This is just a ping sent by the engine to make sure the UI is still up.
  1365. {
  1366. NOT_DATA* pNotData;
  1367. // Get a pointer to the data sent via DCOM.
  1368. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  1369. pNotData = (NOT_DATA*)&(pDataIo->cData);
  1370. // Make sure this is a valid size packet.
  1371. EF_ASSERT(pDataIo->ulDataSize >= sizeof(NOT_DATA));
  1372. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  1373. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  1374. break;
  1375. }
  1376. default:
  1377. EF_ASSERT(FALSE);
  1378. break;
  1379. }
  1380. return TRUE;
  1381. }