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.

3631 lines
118 KiB

  1. /*****************************************************************************************************************
  2. FILENAME: DfrgFat.cpp
  3. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  4. Scan Disk and/or defragment engine for FAT volumes.
  5. If Analyze is specified on the command line, this will execute an analysis of the disk.
  6. If Defragment is specified on the command line, this will execute an analysis of the disk
  7. and then defragment it.
  8. */
  9. #ifndef INC_OLE2
  10. #define INC_OLE2
  11. #endif
  12. #include "stdafx.h"
  13. #define GLOBAL_DATAHOME
  14. #include <windows.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <commctrl.h>
  18. #include <winioctl.h>
  19. #include <shlobj.h> // for SHGetSpecialFolderLocation()
  20. #include "DataIo.h"
  21. #include "DataIoCl.h"
  22. extern "C" {
  23. #include "SysStruc.h"
  24. }
  25. #include "ErrMacro.h"
  26. #include "Message.h"
  27. #include "ErrLog.h"
  28. #include "Event.h"
  29. #include "DfrgCmn.h"
  30. #include "DfrgEngn.h"
  31. #include "DfrgRes.h"
  32. #include "Extents.h"
  33. #include "FreeSpace.h"
  34. #include "FastFat2.h"
  35. #include "FatSubs.h"
  36. #include "FsSubs.h"
  37. #include "MoveFile.h"
  38. #include "Alloc.h"
  39. #include "DiskView.h"
  40. #include "Exclude.h"
  41. #include "GetReg.h"
  42. #include "GetTime.h"
  43. #include "IntFuncs.h"
  44. #include "Logging.h"
  45. #include "ErrMsg.h"
  46. #include "Expand.h"
  47. #include "LogFile.h"
  48. #include "GetDfrgRes.h"
  49. #include "FraggedFileList.h"
  50. extern "C" {
  51. #include "Priority.h"
  52. }
  53. #include "DfrgFat.h"
  54. #include "resource.h"
  55. #include "VString.hpp"
  56. #include <atlconv.h>
  57. #include "BootOptimizeFat.h"
  58. #include "defragcommon.h"
  59. static UINT DiskViewInterval = 1000; // default to 1 sec
  60. LONGLONG EnumeratedFatFiles = 0;
  61. static HANDLE hDefragCompleteEvent = NULL;
  62. // This is set to terminate until the initialize has been successfully run.
  63. BOOL bTerminate = TRUE;
  64. BOOL bOCXIsDead = FALSE;
  65. BOOL bCommandLineUsed = FALSE;
  66. BOOL bLogFile = FALSE;
  67. BOOL bCommandLineMode = FALSE;
  68. BOOL bCommandLineForceFlag = FALSE;
  69. BOOL bCommandLineBootOptimizeFlag = FALSE;
  70. //acs bug #101862//
  71. static UINT uPass = 0;
  72. static UINT uPercentDone = 0;
  73. static UINT uEngineState = DEFRAG_STATE_NONE;
  74. //acs//
  75. static DWORD dwMoveFlags = MOVE_FRAGMENTED|MOVE_CONTIGUOUS;
  76. LPDATAOBJECT pdataDfrgCtl = NULL;
  77. TCHAR cWindow[100];
  78. static const DISKVIEW_TIMER_ID = 1;
  79. static const PING_TIMER_ID = 2;
  80. DiskView AnalyzeView;
  81. DiskView DefragView;
  82. /*****************************************************************************************************************
  83. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  84. ROUTINE DESCRIPTION:
  85. This is the WinMain function for the FAT defragmention engine.
  86. INPUT + OUTPUT:
  87. IN GetDfrgResHandle()ance - The handle to this instance.
  88. IN hPrevInstance - The handle to the previous instance.
  89. IN lpCmdLine - The command line which was passed in.
  90. IN nCmdShow - Whether the window should be minimized or not.
  91. GLOBALS:
  92. OUT AnalyzeOrDefrag - Tells whether were supposed to to an analyze or an analyze and a defrag.
  93. OUT VolData.cDrive - The drive letter with a colon after it.
  94. RETURN:
  95. FALSE - Failure to initilize.
  96. other - Various values can return at exit.
  97. */
  98. int APIENTRY
  99. WinMain(
  100. HINSTANCE hInstance,
  101. HINSTANCE hPrevInstance,
  102. IN LPSTR lpCmdLine,
  103. IN int nCmdShow
  104. )
  105. {
  106. TCHAR cWindow[100];
  107. WNDCLASSEX wc;
  108. MSG Message;
  109. HRESULT hr = E_FAIL;
  110. // Before we start using VolData, zero it out.
  111. ZeroMemory(&VolData, sizeof(VOL_DATA));
  112. CoInitializeEx(NULL, COINIT_MULTITHREADED);
  113. /*
  114. Commenting this call out to minimise registry changes for XP SP 1.
  115. // Initialize COM security
  116. hr = CoInitializeSecurity(
  117. (PVOID)&CLSID_DfrgFat, // IN PSECURITY_DESCRIPTOR pSecDesc,
  118. -1, // IN LONG cAuthSvc,
  119. NULL, // IN SOLE_AUTHENTICATION_SERVICE *asAuthSvc,
  120. NULL, // IN void *pReserved1,
  121. RPC_C_AUTHN_LEVEL_PKT_PRIVACY, // IN DWORD dwAuthnLevel,
  122. RPC_C_IMP_LEVEL_IDENTIFY, // IN DWORD dwImpLevel,
  123. NULL, // IN void *pAuthList,
  124. (EOAC_SECURE_REFS | EOAC_DISABLE_AAA | EOAC_NO_CUSTOM_MARSHAL | EOAC_APPID),
  125. NULL // IN void *pReserved3
  126. );
  127. if(FAILED(hr)) {
  128. return 0;
  129. }
  130. */
  131. #ifndef VER4
  132. OSVERSIONINFO Ver;
  133. //This should only work on version 5 or later. Do a check.
  134. Ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  135. EF(GetVersionEx(&Ver));
  136. if(Ver.dwMajorVersion < 5){
  137. //took out the display error message stuff from here because we needed to
  138. //not display error dialogs for the commandline, but here is the problem...
  139. //we have not got the information from InitializeDrive yet, so we don't
  140. //know what mode we are in, so we can't either write to a log or display
  141. //a message box. The likelyhood that this call will fail is very small, so
  142. //not doing anything is not a problem. One other problem exist here that
  143. //I am not even going to try and solve, and that is when this call fails,
  144. //since the COM server is not set up correctly, we go off into never never
  145. //land and cause a server busy dialog to be displayed by the system, not
  146. //from defrag. Scott K. Sipe
  147. return FALSE;
  148. }
  149. #endif
  150. // Build the window name from the drive letter.
  151. lstrcpy(cWindow, DFRGFAT_WINDOW);
  152. // Initialize the window class.
  153. wc.style = CS_OWNDC;
  154. wc.lpfnWndProc = (WNDPROC) MainWndProc;
  155. wc.cbClsExtra = 0;
  156. wc.cbWndExtra = sizeof(PVOID);
  157. wc.hInstance = hInstance;
  158. wc.hIcon = NULL;
  159. wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  160. wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  161. wc.lpszMenuName = NULL;
  162. wc.lpszClassName = DFRGFAT_CLASS;
  163. wc.cbSize = sizeof(WNDCLASSEX);
  164. wc.hIconSm = NULL;
  165. // Register the window class.
  166. if(!RegisterClassEx(&wc)){
  167. //took out the display error message stuff from here because we needed to
  168. //not display error dialogs for the commandline, but here is the problem...
  169. //we have not got the information from InitializeDrive yet, so we don't
  170. //know what mode we are in, so we can't either write to a log or display
  171. //a message box. The likelyhood that this call will fail is very small, so
  172. //not doing anything is not a problem. One other problem exist here that
  173. //I am not even going to try and solve, and that is when this call fails,
  174. //since the COM server is not set up correctly, we go off into never never
  175. //land and cause a server busy dialog to be displayed by the system, not
  176. //from defrag. Scott K. Sipe
  177. return FALSE;
  178. }
  179. // Create the window.
  180. if((hwndMain = CreateWindow(DFRGFAT_CLASS,
  181. cWindow,
  182. WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL | WS_MINIMIZE,
  183. CW_USEDEFAULT,
  184. CW_USEDEFAULT,
  185. CW_USEDEFAULT,
  186. CW_USEDEFAULT,
  187. NULL,
  188. NULL,
  189. hInstance,
  190. (LPVOID)IntToPtr(NULL))) == NULL){
  191. //took out the display error message stuff from here because we needed to
  192. //not display error dialogs for the commandline, but here is the problem...
  193. //we have not got the information from InitializeDrive yet, so we don't
  194. //know what mode we are in, so we can't either write to a log or display
  195. //a message box. The likelyhood that this call will fail is very small, so
  196. //not doing anything is not a problem. One other problem exist here that
  197. //I am not even going to try and solve, and that is when this call fails,
  198. //since the COM server is not set up correctly, we go off into never never
  199. //land and cause a server busy dialog to be displayed by the system, not
  200. //from defrag. Scott K. Sipe
  201. return FALSE;
  202. }
  203. // Make that window visible.
  204. #ifdef VisibleWindow
  205. ShowWindow(hwndMain, nCmdShow);
  206. UpdateWindow(hwndMain);
  207. #endif
  208. // PostMessage for ID_INITALIZE which will get data about the volume, etc.
  209. SendMessage (hwndMain, WM_COMMAND, ID_INITIALIZE, 0);
  210. // Pass any posted messages on to MainWndProc.
  211. while(GetMessage(&Message, NULL, 0, 0)){
  212. TranslateMessage(&Message);
  213. DispatchMessage(&Message);
  214. }
  215. return (int) Message.wParam;
  216. }
  217. /*****************************************************************************************************************
  218. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  219. ROUTINE DESCRIPTION:
  220. This is the WndProc function for the FAT defragmentaion engine.
  221. INPUT + OUTPUT:
  222. IN hWnd - Handle to the window.
  223. IN uMsg - The message.
  224. IN wParam - The word parameter for the message.
  225. IN lParam - the long parameter for the message.
  226. GLOBALS:
  227. IN AnalyzeOrDefrag - Used to determine whether this is an analysis or defragment run.
  228. IN OUT hThread - Handle for the worker thread (either analyze or defragment).
  229. RETURN:
  230. various.
  231. */
  232. LRESULT CALLBACK
  233. MainWndProc(
  234. IN HWND hWnd,
  235. IN UINT uMsg,
  236. IN WPARAM wParam,
  237. IN LPARAM lParam
  238. )
  239. {
  240. DATA_IO* pDataIo;
  241. switch(uMsg){
  242. case WM_COMMAND:
  243. switch(LOWORD(wParam)){
  244. case ID_INIT_VOLUME_COMM:
  245. {
  246. USES_CONVERSION;
  247. CLSID clsidVolume;
  248. HRESULT hr;
  249. //
  250. // Get the volume comm id out of the given data.
  251. //
  252. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  253. EB_ASSERT( pDataIo );
  254. hr = CLSIDFromString( T2OLE( (PTCHAR) &pDataIo->cData ), &clsidVolume );
  255. EB_ASSERT( SUCCEEDED( hr ) );
  256. //
  257. // Initialize the upstream communication given the
  258. // guid.
  259. //
  260. InitializeDataIoClient( clsidVolume, NULL, &pdataDfrgCtl);
  261. break;
  262. }
  263. case ID_INITIALIZE:
  264. {
  265. Message(TEXT("ID_INITIALIZE"), -1, NULL);
  266. Initialize();
  267. Message(TEXT("calling GetCommandLine()"), -1, NULL);
  268. #ifdef CMDLINE
  269. #pragma message ("Information: CMDLINE defined.")
  270. // Get the command line passed in.
  271. PTCHAR pCommandLine = GetCommandLine();
  272. Message(TEXT("CMDLINE defined"), -1, NULL);
  273. Message(pCommandLine, -1, NULL);
  274. // if "-Embed..." is NOT found in the string, then this was a command line
  275. // submitted by the user and NOT by the OCX. Package it up and send it to the
  276. // message pump. If -Embed was found, the OCX will send the command line in
  277. // a ID_INITIALIZE_DRIVE message.
  278. if (_tcsstr(pCommandLine, TEXT("-Embed")) == NULL){
  279. HANDLE hCommandLine = NULL;
  280. DATA_IO* pCmdLine = NULL;
  281. //If this is not called by the MMC, use the command line typed in from the DOS window.
  282. bCommandLineUsed = TRUE;
  283. AllocateMemory((lstrlen(pCommandLine)+1)*sizeof(TCHAR)+sizeof(DATA_IO), &hCommandLine, (void**)&pCmdLine);
  284. lstrcpy(&pCmdLine->cData, pCommandLine);
  285. GlobalUnlock(hCommandLine);
  286. PostMessage(hWnd, WM_COMMAND, ID_INITIALIZE_DRIVE, (LPARAM)hCommandLine);
  287. }
  288. #else
  289. #pragma message ("Information: CMDLINE not defined.")
  290. // Get the command line passed in.
  291. PTCHAR pCommandLine = GetCommandLine();
  292. Message(TEXT("CMDLINE not defined"), -1, NULL);
  293. Message(pCommandLine, -1, NULL);
  294. // if "-Embed..." is NOT found in the string, then this was a command line
  295. // submitted by the user and NOT by the OCX and that is not supported.
  296. // Raise an error dialog and send an ABORT to the engine
  297. if (_tcsstr(pCommandLine, TEXT("-Embed")) == NULL){
  298. VString msg(IDS_CMD_LINE_OFF, GetDfrgResHandle());
  299. VString title(IDS_DK_TITLE, GetDfrgResHandle());
  300. MessageBox(NULL, msg.GetBuffer(), title.GetBuffer(), MB_OK|MB_ICONSTOP);
  301. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  302. }
  303. #endif
  304. Message(TEXT("ID_INITIALIZE done"), -1, NULL);
  305. break;
  306. }
  307. case ID_INITIALIZE_DRIVE:
  308. Message(TEXT("ID_INITIALIZE_DRIVE"), -1, NULL);
  309. pDataIo = (DATA_IO*)GlobalLock((void*)lParam);
  310. if(!InitializeDrive((PTCHAR)&pDataIo->cData)){
  311. // If initialize failed, pop up a message box, log an abort, and trigger an abort.
  312. //IDS_SCANNTFS_INIT_ABORT - "ScanFAT: Initialize Aborted - Fatal Error"
  313. VString msg(IDS_SCANFAT_INIT_ABORT, GetDfrgResHandle());
  314. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  315. // Log an abort in the event log.
  316. EF(LogEvent(MSG_ENGINE_ERROR, msg.GetBuffer()));
  317. // Trigger an abort.
  318. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  319. // set the event to signaled, allowing the UI to proceed
  320. if (hDefragCompleteEvent){
  321. SetEvent(hDefragCompleteEvent);
  322. }
  323. }
  324. EH_ASSERT(GlobalUnlock((void*)lParam) == FALSE);
  325. EH_ASSERT(GlobalFree((void*)lParam) == NULL);
  326. break;
  327. case ID_ANALYZE:
  328. // Create an analyze thread.
  329. {
  330. DWORD ThreadId;
  331. EB_ASSERT((hThread = CreateThread(NULL,
  332. 0,
  333. (LPTHREAD_START_ROUTINE)AnalyzeThread,
  334. NULL,
  335. 0,
  336. &ThreadId)) != NULL);
  337. }
  338. break;
  339. case ID_DEFRAG:
  340. // Create a defrag thread.
  341. {
  342. DWORD ThreadId;
  343. EB_ASSERT((hThread = CreateThread(NULL,
  344. 0,
  345. (LPTHREAD_START_ROUTINE)DefragThread,
  346. NULL,
  347. 0,
  348. &ThreadId)) != NULL);
  349. }
  350. break;
  351. case ID_STOP:
  352. Message(TEXT("ID_STOP"), -1, NULL);
  353. //Tell the worker thread to terminate.
  354. VolData.EngineState = TERMINATE;
  355. //Send status data to the UI.
  356. SendStatusData();
  357. break;
  358. case ID_PAUSE_ON_SNAPSHOT:
  359. {
  360. #ifndef NOTIMER
  361. KillTimer(hwndMain, PING_TIMER_ID);
  362. #endif
  363. NOT_DATA NotData;
  364. wcscpy(NotData.cVolumeName, VolData.cVolumeName);
  365. Message(TEXT("ID_PAUSE_ON_SNAPSHOT"), -1, NULL);
  366. VolData.EngineState = PAUSED;
  367. //Tell the UI we've paused.
  368. DataIoClientSetData(ID_PAUSE_ON_SNAPSHOT, (PTCHAR)&NotData, sizeof(NOT_DATA), pdataDfrgCtl);
  369. break;
  370. }
  371. case ID_PAUSE:
  372. {
  373. #ifndef NOTIMER
  374. KillTimer(hwndMain, PING_TIMER_ID);
  375. #endif
  376. NOT_DATA NotData;
  377. wcscpy(NotData.cVolumeName, VolData.cVolumeName);
  378. Message(TEXT("ID_PAUSE"), -1, NULL);
  379. VolData.EngineState = PAUSED;
  380. //Tell the UI we've paused.
  381. DataIoClientSetData(ID_PAUSE, (PTCHAR)&NotData, sizeof(NOT_DATA), pdataDfrgCtl);
  382. break;
  383. }
  384. case ID_CONTINUE:
  385. {
  386. #ifndef NOTIMER
  387. EF_ASSERT(SetTimer(hwndMain, PING_TIMER_ID, PINGTIMER, NULL) != 0);
  388. #endif
  389. NOT_DATA NotData;
  390. wcscpy(NotData.cVolumeName, VolData.cVolumeName);
  391. Message(TEXT("ID_CONTINUE"), -1, NULL);
  392. VolData.EngineState = RUNNING;
  393. //Tell the UI we've continued.
  394. DataIoClientSetData(ID_CONTINUE, (PTCHAR)&NotData, sizeof(NOT_DATA), pdataDfrgCtl);
  395. break;
  396. }
  397. case ID_ABORT_ON_SNAPSHOT:
  398. if (hDefragCompleteEvent){
  399. SetEvent(hDefragCompleteEvent);
  400. }
  401. // fall through;
  402. case ID_ABORT:
  403. {
  404. Message(TEXT("ID_ABORT"), -1, NULL);
  405. pDataIo = (DATA_IO*)GlobalLock((HANDLE)lParam);
  406. if (pDataIo){
  407. bOCXIsDead = *(BOOL *) &pDataIo->cData;
  408. }
  409. // Terminate this engine.
  410. bTerminate = TRUE;
  411. VolData.EngineState = TERMINATE;
  412. PostMessage(hwndMain, WM_CLOSE, 0, 0);
  413. break;
  414. }
  415. case ID_PING:
  416. //Do nothing. This is just a ping sent by the UI to make sure the engine is still up.
  417. break;
  418. case ID_SETDISPDIMENSIONS:
  419. {
  420. pDataIo = (DATA_IO*)GlobalLock((HANDLE)lParam);
  421. BOOL bSendData = TRUE;
  422. //Make sure this is a valid size packet.
  423. EF_ASSERT(pDataIo->ulDataSize == sizeof(SET_DISP_DATA));
  424. SET_DISP_DATA *pSetDispData = (SET_DISP_DATA *) &pDataIo->cData;
  425. AnalyzeView.SetNumLines(pSetDispData->AnalyzeLineCount);
  426. if (pSetDispData->bSendGraphicsUpdate == FALSE && AnalyzeView.IsDataSent() == TRUE){
  427. bSendData = FALSE;
  428. }
  429. DefragView.SetNumLines(pSetDispData->DefragLineCount);
  430. if (pSetDispData->bSendGraphicsUpdate == FALSE && DefragView.IsDataSent() == TRUE){
  431. bSendData = FALSE;
  432. }
  433. EH_ASSERT(GlobalUnlock((HANDLE)lParam) == FALSE);
  434. EH_ASSERT(GlobalFree((HANDLE)lParam) == NULL);
  435. // if the UI wants a graphics update, send data
  436. if (bSendData) {
  437. SendGraphicsData();
  438. }
  439. break;
  440. }
  441. default:
  442. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  443. }
  444. break;
  445. case WM_TIMER:
  446. //
  447. // If we're running on battery power, make sure it isn't low, critical
  448. // or unknown
  449. //
  450. SYSTEM_POWER_STATUS SystemPowerStatus;
  451. if ( GetSystemPowerStatus(&SystemPowerStatus) ){
  452. if ((STATUS_AC_POWER_OFFLINE == SystemPowerStatus.ACLineStatus) &&
  453. ((STATUS_BATTERY_POWER_LOW & SystemPowerStatus.BatteryFlag) ||
  454. (STATUS_BATTERY_POWER_CRITICAL & SystemPowerStatus.BatteryFlag)
  455. )) {
  456. // abort all engines
  457. TCHAR buf[256];
  458. TCHAR buf2[256];
  459. UINT buflen = 0;
  460. DWORD_PTR dwParams[1];
  461. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  462. dwParams[0] = (DWORD_PTR) VolData.cDisplayLabel;
  463. LoadString(GetDfrgResHandle(), IDS_APM_FAILED_ENGINE, buf, sizeof(buf) / sizeof(TCHAR));
  464. if (!FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  465. buf, 0, 0, buf2, 256, (va_list*) dwParams)) {
  466. break;
  467. }
  468. SendErrData(buf2, ENGERR_GENERAL);
  469. }
  470. }
  471. if(wParam == DISKVIEW_TIMER_ID){ // graphics data
  472. //Send the graphical data to the UI.
  473. SendGraphicsData();
  474. }
  475. else if(wParam == PING_TIMER_ID && !bCommandLineUsed){
  476. #ifndef NOTIMER
  477. NOT_DATA NotData;
  478. wcscpy(NotData.cVolumeName, VolData.cVolumeName);
  479. // Kill the timer until it's been processed so we don't get a backlog of timers.
  480. KillTimer(hwndMain, PING_TIMER_ID);
  481. // Ping the UI.
  482. Message(TEXT("ID_PING sent from FAT engine"), -1, NULL);
  483. if(!DataIoClientSetData(ID_PING, (PTCHAR)&NotData, sizeof(NOT_DATA), pdataDfrgCtl)){
  484. //If the UI isn't there, abort.
  485. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  486. break;
  487. }
  488. // Set the timer for the next ping.
  489. EF_ASSERT(SetTimer(hwndMain, PING_TIMER_ID, PINGTIMER, NULL) != 0);
  490. #endif
  491. }
  492. break;
  493. case WM_CLOSE:
  494. END_SCAN_DATA EndScanData;
  495. NOT_DATA NotData;
  496. ZeroMemory(&EndScanData, sizeof(ENGINE_START_DATA));
  497. wcscpy(EndScanData.cVolumeName, VolData.cVolumeName);
  498. EndScanData.dwAnalyzeOrDefrag = AnalyzeOrDefrag;
  499. if (VolData.bFragmented) {
  500. EndScanData.dwAnalyzeOrDefrag |= DEFRAG_FAILED;
  501. }
  502. if(VolData.FileSystem == FS_FAT){
  503. lstrcpy(EndScanData.cFileSystem, TEXT("FAT"));
  504. }
  505. else if(VolData.FileSystem == FS_FAT32){
  506. lstrcpy(EndScanData.cFileSystem, TEXT("FAT32"));
  507. }
  508. // Cleanup and nuke the window.
  509. if(bMessageWindowActive && !bCommandLineUsed){
  510. if(!bTerminate){
  511. //Tell the gui that the analyze and/or defrag are done.
  512. DataIoClientSetData(ID_END_SCAN, (PTCHAR)&EndScanData, sizeof(END_SCAN_DATA), pdataDfrgCtl);
  513. break;
  514. }
  515. }
  516. wcscpy(NotData.cVolumeName, VolData.cVolumeName);
  517. //Tell the gui that the engine is terminating. (unless it is DEAD!)
  518. if (!bOCXIsDead){
  519. DataIoClientSetData(ID_TERMINATING, (PTCHAR)&NotData, sizeof(NOT_DATA), pdataDfrgCtl);
  520. }
  521. Exit();
  522. DestroyWindow(hWnd);
  523. break;
  524. case WM_DESTROY:
  525. // Nuke the thread.
  526. PostQuitMessage(0);
  527. break;
  528. default:
  529. return DefWindowProc(hWnd, uMsg, wParam, lParam);
  530. }
  531. return 0;
  532. }
  533. /*****************************************************************************************************************
  534. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  535. ROUTINE DESCRIPTION:
  536. This module carries out all initialization before the Analyze or Defrag threads start.
  537. INPUT + OUTPUT:
  538. None.
  539. GLOBALS:
  540. IN hwndMain - Handle to the main window.
  541. OUT hPageFileNames - The memory that holds the list of names of active pagefiles on this drive.
  542. OUT pPageFileNames - The pointer.
  543. IN VolData.TotalClusters - The total number of clusters on the disk -- can be used to determine if this is a FAT12 drive.
  544. OUT VolData.StartTime - The time the engine is considered to have started.
  545. OUT VolData.AveFragsPerFile - Set to 1 fragment per file initially.
  546. OUT VolData.hExtentList - The memory for the buffer that holds the extent list for files as they are worked on.
  547. OUT VolData.pExtentList - The pointer.
  548. OUT VolData.ExtentListBytes - The size of the memory currently allocated for VolData.hExtentList.
  549. OUT VolData.cNodeName - The name of the computer this is working on.
  550. RETURN:
  551. TRUE - Success.
  552. FALSE - Fatal Error.
  553. */
  554. BOOL
  555. Initialize(
  556. )
  557. {
  558. // Note EF's before this point will not work if they are routed to Message
  559. // Initialize a message window.
  560. InitCommonControls(); // todo Help file says this function is obsolete
  561. // Initialize DCOM DataIo communication.
  562. InitializeDataIo(CLSID_DfrgFat, REGCLS_SINGLEUSE);
  563. Message(TEXT("Initialize"), S_OK, NULL);
  564. Message(TEXT(""), -1, NULL);
  565. return TRUE;
  566. }
  567. /*****************************************************************************************************************
  568. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  569. ROUTINE DESCRIPTION:
  570. This module carries out all initialization before the Analyze or Defrag threads start.
  571. INPUT + OUTPUT:
  572. None.
  573. GLOBALS:
  574. OUT hPageFileNames - Handle to the memory used to hold the names of all the pagefiles active on this drive.
  575. OUT pPageFileNames - The pointer.
  576. IN OUT Various VolData fields.
  577. RETURN:
  578. TRUE - Success.
  579. FALSE - Fatal Error.
  580. */
  581. BOOL
  582. InitializeDrive(
  583. IN PTCHAR pCommandLine
  584. )
  585. {
  586. UCHAR* pUchar = NULL;
  587. DWORD dwComputerNameSize = MAX_COMPUTERNAME_LENGTH + 1;
  588. TCHAR cLoggerIdentifier[256];
  589. TCHAR pParam0[100];
  590. TCHAR pParam1[100];
  591. TCHAR pParam2[100];
  592. TCHAR pParam3[100];
  593. TCHAR pParam4[100];
  594. HKEY hValue = NULL;
  595. TCHAR cRegValue[MAX_PATH];
  596. DWORD dwRegValueSize = sizeof(cRegValue);
  597. Message(pCommandLine, -1, NULL);
  598. // Parse the command line.
  599. pParam0[0] = 0;
  600. pParam1[0] = 0;
  601. pParam2[0] = 0;
  602. pParam3[0] = 0;
  603. pParam4[0] = 0;
  604. swscanf(pCommandLine, TEXT("%99s %99s %99s %99s %99s"), pParam0, pParam1, pParam2, pParam3, pParam4);
  605. // Get the drive letter from the first parameter.
  606. // check for a x: format, sanity check on second character
  607. if (wcslen(pParam1) == 2 && pParam1[1] == L':'){
  608. wsprintf(VolData.cVolumeName, L"\\\\.\\%c:", pParam1[0]); // UNC format
  609. VolData.cDrive = pParam1[0];
  610. // Get a handle to the volume and fill in data
  611. EF(GetFatVolumeStats());
  612. // Format the VolData.DisplayLabel
  613. FormatDisplayString(VolData.cDrive, VolData.cVolumeLabel, VolData.cDisplayLabel);
  614. // create the tag
  615. wsprintf(VolData.cVolumeTag, L"%c", pParam1[0]); // the drive letter only
  616. }
  617. // check for \\.\x:\, sanity check on third character
  618. else if (wcslen(pParam1) == 7 && pParam1[2] == L'.'){
  619. wcscpy(VolData.cVolumeName, pParam1); // UNC format, copy it over
  620. VolData.cVolumeName[6] = (TCHAR) NULL; // get rid of trailing backslash
  621. VolData.cDrive = pParam1[4];
  622. // Get a handle to the volume and fill in data
  623. EF(GetFatVolumeStats());
  624. // Format the VolData.DisplayLabel
  625. FormatDisplayString(VolData.cDrive, VolData.cVolumeLabel, VolData.cDisplayLabel);
  626. // create the tag
  627. wsprintf(VolData.cVolumeTag, L"%c", pParam1[4]); // the drive letter only
  628. }
  629. #ifndef VER4 // NT5 only:
  630. // check for \\?\Volume{12a926c3-3f85-11d2-aa0e-000000000000}\,
  631. // sanity check on third character
  632. else if (wcslen(pParam1) == 49 && pParam1[2] == L'?'){
  633. wcscpy(VolData.cVolumeName, pParam1); // GUID format, copy it over
  634. VolData.cVolumeName[48] = (TCHAR) NULL; // get rid of trailing backslash
  635. // Get a handle to the volume and fill in data
  636. EF(GetFatVolumeStats());
  637. VString mountPointList[MAX_MOUNT_POINTS];
  638. UINT mountPointCount = 0;
  639. // get the drive letter
  640. if (!GetDriveLetterByGUID(VolData.cVolumeName, VolData.cDrive)){
  641. // if we didn't get a drive letter, get the mount point list
  642. // cause we need the list to create the DisplayLabel
  643. GetVolumeMountPointList(
  644. VolData.cVolumeName,
  645. mountPointList,
  646. mountPointCount);
  647. }
  648. // Format the VolData.DisplayLabel
  649. FormatDisplayString(
  650. VolData.cDrive,
  651. VolData.cVolumeLabel,
  652. mountPointList,
  653. mountPointCount,
  654. VolData.cDisplayLabel);
  655. // create the tag
  656. for (UINT i=0, j=0; i<wcslen(VolData.cVolumeName); i++){
  657. if (iswctype(VolData.cVolumeName[i],_HEX)){
  658. VolData.cVolumeTag[j++] = VolData.cVolumeName[i];
  659. }
  660. }
  661. VolData.cVolumeTag[j] = (TCHAR) NULL;
  662. }
  663. #endif
  664. else {
  665. // invalid drive on command line
  666. VString msg(IDS_INVALID_CMDLINE_DRIVE, GetDfrgResHandle());
  667. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  668. return FALSE;
  669. }
  670. // Check to see if this is anything other than FAT or FAT32, and if so, bail out.
  671. if(VolData.FileSystem != FS_FAT && VolData.FileSystem != FS_FAT32){
  672. VString msg(IDMSG_ERR_NOT_FAT_PARTITION, GetDfrgResHandle());
  673. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  674. return FALSE;
  675. }
  676. // calculate the graphics refresh interval
  677. LONGLONG DiskSize = VolData.TotalClusters * VolData.BytesPerCluster;
  678. LONGLONG GigSize = 1024 * 1024 * 1024;
  679. if (DiskSize <= GigSize * 4) {
  680. DiskViewInterval = 2000;
  681. }
  682. else if (DiskSize <= GigSize * 9) {
  683. DiskViewInterval = 5000;
  684. }
  685. else if (DiskSize <= GigSize * 100) {
  686. DiskViewInterval = 10000;
  687. }
  688. else {
  689. DiskViewInterval = 30000;
  690. }
  691. // Get whether this is analyze or defrag from the second parameter
  692. if(wcscmp(pParam2, L"ANALYZE") == 0){
  693. AnalyzeOrDefrag = ANALYZE;
  694. }
  695. else if(wcscmp(pParam2, L"DEFRAG") == 0){
  696. AnalyzeOrDefrag = DEFRAG;
  697. }
  698. else{
  699. // Print out an error if neither analyze nor defrag were passed in.
  700. VString msg(IDS_INVALID_CMDLINE_OPERATION, GetDfrgResHandle());
  701. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  702. return FALSE;
  703. }
  704. //0.0E00 The third or fourth parameters might be set to Command Line
  705. // which would mean this was launched from the Command Line
  706. // I did the compare not case sensitive
  707. if(wcslen(pParam3)){
  708. if(_wcsicmp(TEXT("CMDLINE"), pParam3) == 0){
  709. bCommandLineMode = TRUE;
  710. if(wcslen(pParam4)){ //Force flag check
  711. if(_wcsicmp(TEXT("BOOT"), pParam4) == 0){
  712. bCommandLineBootOptimizeFlag = TRUE;
  713. } else
  714. {
  715. bCommandLineBootOptimizeFlag = FALSE;
  716. }
  717. if(_wcsicmp(TEXT("FORCE"), pParam4) == 0){
  718. bCommandLineForceFlag = TRUE;
  719. } else
  720. {
  721. bCommandLineForceFlag = FALSE;
  722. }
  723. }
  724. } else
  725. {
  726. bCommandLineMode = FALSE;
  727. }
  728. }
  729. // open the event that was created by the UI.
  730. // this is only used for command line operation.
  731. // if this fails, that means there is no other process that is
  732. // trying to sync with the engine.
  733. Message(TEXT("Opening Event..."), -1, NULL);
  734. if (bCommandLineMode) {
  735. hDefragCompleteEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, DEFRAG_COMPLETE_EVENT_NAME);
  736. if (!hDefragCompleteEvent){
  737. Message(DEFRAG_COMPLETE_EVENT_NAME, GetLastError(), NULL);
  738. }
  739. }
  740. // Get the path name.
  741. dwRegValueSize = sizeof(cRegValue);
  742. if(GetRegValue(&hValue,
  743. TEXT("SOFTWARE\\Microsoft\\Dfrg"),
  744. TEXT("PathName"),
  745. cRegValue,
  746. &dwRegValueSize) != ERROR_SUCCESS){
  747. VString msg(IDS_CANT_CREATE_RESOURCE, GetDfrgResHandle());
  748. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  749. return FALSE;
  750. }
  751. if(RegCloseKey(hValue)!=ERROR_SUCCESS){
  752. VString msg(IDS_CANT_CREATE_RESOURCE, GetDfrgResHandle());
  753. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  754. return FALSE;
  755. }
  756. hValue = NULL;
  757. //Translate any environment variables in the string.
  758. if(!ExpandEnvVars(cRegValue)){
  759. VString msg(IDS_CANT_CREATE_RESOURCE, GetDfrgResHandle());
  760. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  761. return FALSE;
  762. }
  763. // get the My Documents path
  764. TCHAR cLogPath[300];
  765. LPITEMIDLIST pidl ;
  766. // this will get the path to My Documents for the current user
  767. SHGetSpecialFolderLocation(NULL, CSIDL_PERSONAL, &pidl);
  768. SHGetPathFromIDList(pidl, cLogPath);
  769. // initialize the log files
  770. TCHAR cErrLogName[300];
  771. // put error log in My Docs folder
  772. _tcscpy(cErrLogName, cLogPath);
  773. _tcscat(cErrLogName, TEXT("\\DfrgError.log"));
  774. _stprintf(cLoggerIdentifier, TEXT("DfrgFat on Drive %s"), VolData.cDisplayLabel);
  775. #ifdef _DEBUG
  776. InitializeErrorLog(cErrLogName, cLoggerIdentifier);
  777. #endif
  778. // check registry setting for the stats log
  779. BOOL bStatLog = FALSE;
  780. dwRegValueSize = sizeof(cRegValue);
  781. if(GetRegValue(&hValue,
  782. TEXT("SOFTWARE\\Microsoft\\Dfrg"),
  783. TEXT("CreateLogFile"),
  784. cRegValue,
  785. &dwRegValueSize) == ERROR_SUCCESS){
  786. RegCloseKey(hValue);
  787. if(_tcscmp(cRegValue, TEXT("1")) == MATCH){
  788. bStatLog = TRUE;
  789. }
  790. }
  791. // if we want to log statistics to a file.
  792. if(bStatLog){
  793. // put error log in My Docs folder
  794. _tcscpy(cErrLogName, cLogPath);
  795. _tcscat(cErrLogName, TEXT("\\DfrgFATStats.log"));
  796. // initialize the log which will be used to tell variation success status to dfrgtest.
  797. if (InitializeLogFile(cErrLogName)){
  798. bLogFile = TRUE;
  799. }
  800. }
  801. // Default to 1 frag per file
  802. VolData.AveFragsPerFile = 100;
  803. // Initialize event logging.
  804. EF(InitLogging(TEXT("Diskeeper")));
  805. // Allocate an initial buffer to hold a file's extent list.
  806. VolData.ExtentListAlloced = INITIAL_EXTENT_LIST_BYTES;
  807. EF(AllocateMemory((DWORD)VolData.ExtentListAlloced, &VolData.hExtentList, (void**)&VolData.pExtentList));
  808. // Check for 12-bit FAT.
  809. if(VolData.TotalClusters < 4087){
  810. TCHAR cString[256];
  811. TCHAR szMsg[300];
  812. DWORD_PTR dwParams[2];
  813. // IDMSG_BITFAT_ERROR - "Error - Volume %s: has a 12-bit FAT.
  814. // Diskeeper does not support 12-bit FAT partitions."
  815. dwParams[0] = (DWORD_PTR)VolData.cDisplayLabel; // this error will not happen for mounted volumes
  816. dwParams[1] = 0;
  817. LoadString(GetDfrgResHandle(), IDMSG_BITFAT_ERROR, cString, sizeof(cString) / sizeof(TCHAR));
  818. if (!FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ARGUMENT_ARRAY,
  819. cString, 0, 0, szMsg, 300, (va_list*) dwParams)) {
  820. GetLastError();
  821. return FALSE;
  822. }
  823. SendErrData(szMsg, ENGERR_GENERAL);
  824. EF(LogEvent(MSG_ENGINE_ERROR, cString));
  825. return FALSE;
  826. }
  827. // Get this computer's name.
  828. EF(GetComputerName(VolData.NodeName, &dwComputerNameSize));
  829. // Get the pagefile names.
  830. EF(GetPagefileNames(VolData.cDrive, &hPageFileNames, &pPageFileNames));
  831. EF(GetFatBootSector());
  832. //If this is a FAT32 volume and the disk version is greater than 0,
  833. //then bail out, because we don't support this version.
  834. if((VolData.FileSystem == FS_FAT32) && VolData.FatVersion){
  835. VString msg(IDS_UNSUPPORTED_FAT_VERSION, GetDfrgResHandle());
  836. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  837. return FALSE;
  838. }
  839. // Allocate buffer to hold the volume bitmap - don't lock
  840. EF(AllocateMemory((DWORD)(sizeof(VOLUME_BITMAP_BUFFER) + (VolData.BitmapSize / 8)),
  841. &VolData.hVolumeBitmap,
  842. NULL));
  843. //1.0E00 Load the volume bitmap.
  844. EF(GetVolumeBitmap());
  845. // Set the timer for updating the DiskView.
  846. EF(SetTimer(hwndMain, DISKVIEW_TIMER_ID, DiskViewInterval, NULL) != 0);
  847. // Set the timer that will ping the UI.
  848. // DO NOT set this timer is this is the command line version 'cause the engine will kill itself
  849. #ifndef NOTIMER
  850. if (!bCommandLineMode){
  851. EF(SetTimer(hwndMain, PING_TIMER_ID, PINGTIMER, NULL) != 0);
  852. }
  853. #endif
  854. //Ok don't terminate before closing the display window.
  855. bTerminate = FALSE;
  856. //Set the engine state to running.
  857. VolData.EngineState = RUNNING;
  858. //Send a message to the UI telling it that the process has started
  859. //and what type of pass this is.
  860. ENGINE_START_DATA EngineStartData = {0};
  861. wcscpy(EngineStartData.cVolumeName, VolData.cVolumeName);
  862. EngineStartData.dwAnalyzeOrDefrag = AnalyzeOrDefrag;
  863. if(VolData.FileSystem == FS_FAT){
  864. lstrcpy(EngineStartData.cFileSystem, TEXT("FAT"));
  865. }
  866. else if(VolData.FileSystem == FS_FAT32){
  867. lstrcpy(EngineStartData.cFileSystem, TEXT("FAT32"));
  868. }
  869. DataIoClientSetData(ID_ENGINE_START, (PTCHAR)&EngineStartData, sizeof(ENGINE_START_DATA), pdataDfrgCtl);
  870. Message(TEXT("Initialize"), S_OK, NULL);
  871. Message(TEXT(""), -1, NULL);
  872. // After Initialize, determine whether this is an analyze or defrag run,
  873. // and start the approriate one.
  874. switch(AnalyzeOrDefrag){
  875. case ANALYZE:
  876. PostMessage(hwndMain, WM_COMMAND, ID_ANALYZE, 0);
  877. break;
  878. case DEFRAG:
  879. PostMessage(hwndMain, WM_COMMAND, ID_DEFRAG, 0);
  880. break;
  881. default:
  882. EF(FALSE);
  883. }
  884. return TRUE;
  885. }
  886. /*****************************************************************************************************************
  887. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  888. ROUTINE DESCRIPTION:
  889. This module carries out initialization specific to defrag before the defrag thread starts.
  890. INPUT + OUTPUT:
  891. None.
  892. GLOBALS:
  893. OUT VolData.hVolumeBitmap - Memory filled with the volume bitmap. (Will be filled upon return.)
  894. OUT VolData.hExcludeList - Memory holding the exclusion list.
  895. RETURN:
  896. TRUE - Success.
  897. FALSE - Fatal Error.
  898. */
  899. BOOL
  900. InitializeDefrag(
  901. )
  902. {
  903. // Load the volume bitmap.
  904. EF(GetVolumeBitmap());
  905. // Get the exclude list if any.
  906. TCHAR cExcludeFile[100];
  907. wsprintf(cExcludeFile, TEXT("Exclude%s.dat"), VolData.cVolumeTag);
  908. GetExcludeFile(cExcludeFile, &VolData.hExcludeList);
  909. // Copy the analyze cluster array (DiskView class)
  910. DefragView = AnalyzeView;
  911. SendGraphicsData();
  912. BEGIN_SCAN_INFO ScanInfo = {0};
  913. wcscpy(ScanInfo.cVolumeName, VolData.cVolumeName);
  914. wcscpy(ScanInfo.cDisplayLabel, VolData.cDisplayLabel);
  915. if(VolData.FileSystem == FS_FAT){
  916. lstrcpy(ScanInfo.cFileSystem, TEXT("FAT"));
  917. }
  918. else if(VolData.FileSystem == FS_FAT32){
  919. lstrcpy(ScanInfo.cFileSystem, TEXT("FAT32"));
  920. }
  921. //The defrag fields will equal zero since the structure is zero memoried above. This means we're not sending defrag data.
  922. // Tell the UI that we're beginning the scan.
  923. DataIoClientSetData(ID_BEGIN_SCAN, (PTCHAR)&ScanInfo, sizeof(BEGIN_SCAN_INFO), pdataDfrgCtl);
  924. return TRUE;
  925. }
  926. /*****************************************************************************************************************
  927. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  928. ROUTINE DESCRIPTION:
  929. Thread routine for analysis.
  930. INPUT + OUTPUT:
  931. None.
  932. GLOBALS:
  933. OUT VolData.EngineState - To tell the main thread whether the prescan and scan are running.
  934. RETURN:
  935. TRUE - Success.
  936. FALSE - Fatal Error.
  937. */
  938. BOOL
  939. AnalyzeThread(
  940. )
  941. {
  942. CoInitializeEx(NULL, COINIT_MULTITHREADED);
  943. // Get the time that the engine started.
  944. GetLocalTime(&VolData.StartTime);
  945. AcquirePrivilege(SE_BACKUP_NAME);
  946. // Do the Prescan.
  947. uPercentDone = 10;
  948. uPass = 0;
  949. uEngineState = DEFRAG_STATE_ANALYZING;
  950. SendStatusData();
  951. if(!PreScanFat()){
  952. // IDMSG_SCANFAT_PRESCAN_ABORT - "ScanFat: PreScan Aborted - Fatal Error - File:"
  953. VString msg(IDMSG_SCANFAT_PRESCAN_ABORT, GetDfrgResHandle());
  954. msg.AddChar(L' ');
  955. PWSTR Temp = VolData.vFileName.GetBuffer();
  956. if (StartsWithVolumeGuid(Temp)) {
  957. if ((VolData.cDrive >= L'C') &&
  958. (VolData.cDrive <= L'Z')) {
  959. msg.AddChar(VolData.cDrive);
  960. msg.AddChar(L':');
  961. }
  962. msg += (PWSTR)(Temp + 48);
  963. }
  964. else {
  965. msg += VolData.vFileName;
  966. }
  967. // send error info to client
  968. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  969. // Log this into the EventLog.
  970. LogEvent(MSG_ENGINE_ERROR, msg.GetBuffer());
  971. // Trigger an abort.
  972. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  973. // set the event to signaled, allowing the UI to proceed
  974. if (hDefragCompleteEvent){
  975. SetEvent(hDefragCompleteEvent);
  976. }
  977. ExitThread(0);
  978. return FALSE;
  979. }
  980. if(VolData.EngineState == TERMINATE){
  981. //1.0E00 We're done, close down now.
  982. PostMessage(hwndMain, WM_CLOSE, 0, 0);
  983. // Kill the thread.
  984. ExitThread(0);
  985. }
  986. //1.0E00 Allocate memory for the file lists.
  987. uPercentDone = 20; //acs bug #101862//
  988. SendStatusData();
  989. if (!AllocateFileLists()) {
  990. VString msg(IDS_OUT_OF_MEMORY, GetDfrgResHandle());
  991. msg += TEXT("\r\n");
  992. VString line2(IDS_SCANFAT_INIT_ABORT, GetDfrgResHandle());
  993. msg += line2;
  994. // send error info to client
  995. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  996. // Log this into the EventLog.
  997. LogEvent(MSG_ENGINE_ERROR, msg.GetBuffer());
  998. // Trigger an abort.
  999. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1000. // set the event to signaled, allowing the UI to proceed
  1001. if (hDefragCompleteEvent){
  1002. SetEvent(hDefragCompleteEvent);
  1003. }
  1004. ExitThread(0);
  1005. return FALSE;
  1006. }
  1007. // Do the Scan.
  1008. if(!ScanFat()){
  1009. // IDMSG_SCANFAT_SCAN_ABORT - "ScanFAT: Scan Aborted - Fatal Error - File:"
  1010. VString msg(IDMSG_SCANFAT_SCAN_ABORT, GetDfrgResHandle());
  1011. msg.AddChar(L' ');
  1012. PWSTR Temp = VolData.vFileName.GetBuffer();
  1013. if (StartsWithVolumeGuid(Temp)) {
  1014. if ((VolData.cDrive >= L'C') &&
  1015. (VolData.cDrive <= L'Z')) {
  1016. msg.AddChar(VolData.cDrive);
  1017. msg.AddChar(L':');
  1018. }
  1019. msg += (PWSTR)(Temp + 48);
  1020. }
  1021. else {
  1022. msg += VolData.vFileName;
  1023. }
  1024. // send error info to client
  1025. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  1026. // Log this into the EventLog.
  1027. LogEvent(MSG_ENGINE_ERROR, msg.GetBuffer());
  1028. // Trigger an abort.
  1029. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1030. // set the event to signaled, allowing the UI to proceed
  1031. if (hDefragCompleteEvent){
  1032. SetEvent(hDefragCompleteEvent);
  1033. }
  1034. ExitThread(0);
  1035. return FALSE;
  1036. }
  1037. // If this engine has a visible window, write the basic statistics for this drive to the screen.
  1038. //uPercentDone = 60; //acs bug #101862//
  1039. SendStatusData();
  1040. // Note the end time for that pass.
  1041. GetLocalTime(&VolData.EndTime);
  1042. DisplayFatVolumeStats();
  1043. //Send status data to the UI.
  1044. uPercentDone = 100;
  1045. uEngineState = DEFRAG_STATE_ANALYZED;
  1046. SendStatusData();
  1047. //Send the graphical data to the UI.
  1048. SendGraphicsData();
  1049. //Send the report text data to the UI.
  1050. SendReportData();
  1051. //Send the most fragged list to the UI.
  1052. SendMostFraggedList();
  1053. //1.0E00 We're done, close down now.
  1054. PostMessage(hwndMain, WM_CLOSE, 0, 0);
  1055. // set the event to signaled, allowing the UI to proceed
  1056. if (hDefragCompleteEvent){
  1057. SetEvent(hDefragCompleteEvent);
  1058. }
  1059. // Kill the thread.
  1060. ExitThread(0);
  1061. return TRUE;
  1062. }
  1063. /*****************************************************************************************************************
  1064. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  1065. ROUTINE DESCRIPTION:
  1066. Scan the volume to determine the amount of memory which will be required for the file lists.
  1067. INPUT + OUTPUT:
  1068. None.
  1069. GLOBALS:
  1070. IN OUT Multiple VolData fields are used by PreScanFat and the functions is calls. There are to many to practically enumerate here.
  1071. RETURN:
  1072. TRUE - Success.
  1073. FALSE - Fatal Error.
  1074. */
  1075. BOOL
  1076. PreScanFat(
  1077. )
  1078. {
  1079. ULONG NumDirs = 0;
  1080. ULONG NumFiles = 0;
  1081. ULONG NumMoveableFiles = 0;
  1082. ULONG SmallFiles = 0;
  1083. Message(TEXT("PreScanFat"), -1, NULL);
  1084. EnumeratedFatFiles = 0;
  1085. while(TRUE){
  1086. // Sleep if paused.
  1087. while(VolData.EngineState == PAUSED){
  1088. Sleep(1000);
  1089. }
  1090. // Terminate if told to stop by the controller - this is not an error.
  1091. if(VolData.EngineState == TERMINATE){
  1092. EH(PostMessage(hwndMain, WM_CLOSE, 0, 0));
  1093. return TRUE;
  1094. }
  1095. // Get the next file to check.
  1096. EF(NextFatFile());
  1097. ++EnumeratedFatFiles;
  1098. // Check to see if we have run out of files.
  1099. if(VolData.vFileName.GetLength() == 0){
  1100. break;
  1101. }
  1102. // Check to see if this is the pagefile.
  1103. EF(CheckForPagefileFat());
  1104. if(VolData.bPageFile){
  1105. // If this is a pagefile, then set this var to FALSE so we don't automatically think
  1106. //the next file is a pagefile too.
  1107. VolData.bPageFile = FALSE;
  1108. // Keep track of the total number of pagefiles.
  1109. VolData.NumPagefiles++;
  1110. // Don't process this file in this routine.
  1111. continue;
  1112. }
  1113. if (!OpenFatFile()){
  1114. continue;
  1115. }
  1116. // Handle dirs
  1117. if(VolData.bDirectory){
  1118. NumDirs++; //Count that we found a dir.
  1119. }
  1120. else{
  1121. if(VolData.FileSize){
  1122. NumFiles++; //Count that we found a file.
  1123. }
  1124. else {
  1125. // Catch small files (don't do anything more than count them).
  1126. // Don't deal with directories here because some directories
  1127. // are marked in their root entry as zero length when in fact they are not.
  1128. // We must get the extent list before we can know for sure about directories.
  1129. SmallFiles++;
  1130. continue;
  1131. }
  1132. }
  1133. //This, of course, also inclues moveable directories.
  1134. NumMoveableFiles++;
  1135. // Increase the size of the list that will hold the names of all files and directories.
  1136. VolData.NameListSize += (VolData.vFileName.GetLength() + 1) * sizeof(TCHAR);
  1137. }
  1138. //Note the total number of files on the disk for statistics purposes.
  1139. VolData.TotalFiles = NumFiles;
  1140. //Note the total number of dirs on the disk for statistics purposes.
  1141. VolData.TotalDirs = NumDirs;
  1142. // We've gone through every file on the disk, now compute the file list memory requirements
  1143. VolData.MoveableFileListEntries = NumMoveableFiles;
  1144. VolData.PagefileListEntries = (ULONG)VolData.NumPagefiles;
  1145. //Now determine the sizes of each of the file list buffers.
  1146. VolData.PagefileListSize = (ULONG)VolData.NumPagefiles*sizeof(FILE_LIST_ENTRY);
  1147. // Pad MoveableFileListSize by 1000 entries. This covers the contingency that someone might add files between the end of this pass and the
  1148. // beginning of the next.
  1149. VolData.MoveableFileListSize = (NumMoveableFiles+1000)*sizeof(FILE_LIST_ENTRY);
  1150. // Determine the size the volume bitmap must be.
  1151. EF_ASSERT(VolData.BitmapSize);
  1152. // The name list size has already been determined directly,
  1153. // but add 100 new file name spaces in case files are added.
  1154. // Since this is * MAX_PATH it will actually go farther than 100 extra entries.
  1155. // todo max_path - Does this get really huge? Look at this method
  1156. VolData.NameListSize += (100 * MAX_PATH);
  1157. return TRUE;
  1158. }
  1159. /*****************************************************************************************************************
  1160. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  1161. ROUTINE DESCRIPTION:
  1162. Do the scan of he volume, filling in the file lists with the extent data for each file on the volume.
  1163. INPUT + OUTPUT:
  1164. None.
  1165. GLOBALS:
  1166. IN OUT Multiple VolData fields are used by PreScanFat and the functions is calls. There are to many to practically enumerate here.
  1167. RETURN:
  1168. TRUE - Success.
  1169. FALSE - Fatal Error.
  1170. */
  1171. BOOL
  1172. ScanFat(
  1173. )
  1174. {
  1175. //acs bug #101862//
  1176. double dFileRecordNumber = 0;
  1177. UINT uPercentDoneMem = 0;
  1178. uPass = 1;
  1179. TCHAR* pNameList = VolData.pNameList;
  1180. BEGIN_SCAN_INFO ScanInfo = {0};
  1181. Message(TEXT("ScanFat"), -1, NULL);
  1182. // Zero the memory buffers.
  1183. if (VolData.MoveableFileListSize){
  1184. ZeroMemory(VolData.pMoveableFileList, VolData.MoveableFileListSize);
  1185. }
  1186. if (VolData.NameListSize){
  1187. ZeroMemory(VolData.pNameList, VolData.NameListSize);
  1188. }
  1189. // Reset the dir scanner for NextFatFile
  1190. EF(GetFatBootSector());
  1191. // Create a DiskView class cluster array for this volume
  1192. AnalyzeView.SetClusterCount((int)VolData.TotalClusters);
  1193. //1.0E00 Create a buffer to hold extent updates for DiskView.
  1194. EF(CreateExtentBuffer());
  1195. _tcscpy(ScanInfo.cVolumeName, VolData.cVolumeName);
  1196. _tcscpy(ScanInfo.cDisplayLabel, VolData.cDisplayLabel);
  1197. if(VolData.FileSystem == FS_FAT){
  1198. _tcscpy(ScanInfo.cFileSystem, TEXT("FAT"));
  1199. }
  1200. else if(VolData.FileSystem == FS_FAT32){
  1201. _tcscpy(ScanInfo.cFileSystem, TEXT("FAT32"));
  1202. }
  1203. // The defrag fields will equal zero since the structure is zero memoried above.
  1204. // This means we're not sending defrag data.
  1205. // Tell the UI that we're beginning the scan.
  1206. DataIoClientSetData(ID_BEGIN_SCAN, (PTCHAR)&ScanInfo, sizeof(BEGIN_SCAN_INFO), pdataDfrgCtl);
  1207. // Scan the disk for fragmented files, directories & pagefiles.
  1208. while(TRUE){
  1209. // Sleep if paused.
  1210. while(VolData.EngineState == PAUSED){
  1211. Sleep(1000);
  1212. }
  1213. // Terminate if told to stop by the controller - this is not an error.
  1214. if(VolData.EngineState == TERMINATE){
  1215. EH(PostMessage(hwndMain, WM_CLOSE, 0, 0));
  1216. return TRUE;
  1217. }
  1218. // Get the next file to check.
  1219. EF(NextFatFile());
  1220. // Exit if done.
  1221. if(VolData.vFileName.GetLength() == 0){
  1222. break;
  1223. }
  1224. //acs bug #101862// Send progress bar status - max = 98%.
  1225. dFileRecordNumber++;
  1226. //acs// Upadate Percent done & progress bar.
  1227. if(EnumeratedFatFiles != 0) {
  1228. //acs bug #101862// Add 20% as we already got that from the prescan.
  1229. uPercentDone = UINT(((dFileRecordNumber / EnumeratedFatFiles) *78)+20);
  1230. //acs bug #101862// Only send it if there is a change - don't overload the SendStatusData
  1231. if(uPercentDone > uPercentDoneMem) {
  1232. SendStatusData();
  1233. uPercentDoneMem = uPercentDone;
  1234. }
  1235. }
  1236. // Check if this is a pagefile.
  1237. EF(CheckForPagefileFat());
  1238. if(VolData.bPageFile){
  1239. // Reset this variable so the next file isn't automatically considered a pagefile.
  1240. VolData.bPageFile = FALSE;
  1241. // If this is the pagefile, set the pagefile stats.
  1242. VolData.PagefileSize += VolData.FileSize;
  1243. FILE_EXTENT_HEADER* pFileExtentHeader = (FILE_EXTENT_HEADER*)VolData.pExtentList;
  1244. VolData.PagefileFrags += pFileExtentHeader->ExcessExtents + 1;
  1245. // Put the pagefile's extents into shared memory
  1246. EC(AddFileToListFat(
  1247. VolData.pPagefileList,
  1248. &VolData.PagefileListIndex,
  1249. VolData.PagefileListSize,
  1250. VolData.pExtentList));
  1251. //Now add the file to the disk view map of disk clusters.
  1252. EF(AddExtents(PageFileColor));
  1253. #ifndef DKMS // don't count the pagefile in the stats for the DKMS version
  1254. //0.0E00 Keep track of fragged statistics.
  1255. if (VolData.bFragmented){
  1256. VolData.FraggedSpace += VolData.NumberOfClusters * VolData.BytesPerCluster;
  1257. VolData.NumFraggedFiles++;
  1258. VolData.NumExcessFrags += VolData.NumberOfFragments - 1;
  1259. }
  1260. #endif
  1261. continue;
  1262. }
  1263. // Get name, dir/file & size of next file
  1264. if (!OpenFatFile()){
  1265. continue;
  1266. }
  1267. // Check this BEFORE you get the extent list to save some time.
  1268. // Catch small files (don't do anything with them in the scan).
  1269. // Don't deal with directories here because some directories are marked in their root entry
  1270. // as zero length when in fact they are not. We must get the extent list before we can know for
  1271. // sure about directories.
  1272. if(VolData.FileSize == 0 && !VolData.bDirectory){
  1273. continue;
  1274. }
  1275. // Get the file's extent list.
  1276. EF(GetExtentList(DEFAULT_STREAMS, NULL));
  1277. if (VolData.bDirectory){ // this is a directory.
  1278. // If it's a small directory, don't do anything with it.
  1279. if(VolData.FileSize == 0){
  1280. continue;
  1281. }
  1282. //Now add the dir to the disk view map of disk clusters.
  1283. EF(AddExtents(DirectoryColor));
  1284. // If fragmented, update the appropriate statistics.
  1285. if(VolData.bFragmented == TRUE){
  1286. VolData.FraggedSpace += VolData.NumberOfClusters * VolData.BytesPerCluster;
  1287. VolData.NumFraggedDirs++;
  1288. VolData.NumExcessDirFrags += VolData.NumberOfFragments - 1;
  1289. }
  1290. }
  1291. else { // Process files
  1292. // Keep track of the total number of files so far.
  1293. VolData.CurrentFile++;
  1294. // Keep track of how many bytes there are in all files we've processed.
  1295. VolData.TotalFileSpace += VolData.NumberOfClusters * VolData.BytesPerCluster;
  1296. VolData.TotalFileBytes += VolData.FileSize;
  1297. if(VolData.bFragmented) {
  1298. EF(AddExtents(FragmentColor));
  1299. // Keep track of the total amount of space on the disk containing fragmented files.
  1300. VolData.FraggedSpace += VolData.NumberOfClusters * VolData.BytesPerCluster;
  1301. // Keep track of the number of excess fragments.
  1302. VolData.NumExcessFrags += VolData.NumberOfFragments - 1;
  1303. // Keep track of the number of fragmented files.
  1304. VolData.NumFraggedFiles ++;
  1305. }
  1306. else{ // NOT fragmented
  1307. EF(AddExtents(UsedSpaceColor));
  1308. }
  1309. }
  1310. // Add moveable files to the moveable file list.
  1311. // we really can't move these, but put them there anyway, we filter them out later
  1312. EF(AddFileToListFat(VolData.pMoveableFileList, &VolData.MoveableFileListIndex, VolData.MoveableFileListSize, VolData.pExtentList));
  1313. // update cluster array
  1314. PurgeExtentBuffer();
  1315. }
  1316. // Keep track of the average file size.
  1317. if(VolData.CurrentFile != 0){
  1318. VolData.AveFileSize = VolData.TotalFileBytes / VolData.CurrentFile;
  1319. }
  1320. // Make final computation of what percentage of the disk is fragmented.
  1321. if (VolData.UsedSpace != 0) {
  1322. VolData.PercentDiskFragged = 100 * VolData.FraggedSpace / VolData.UsedSpace;
  1323. }
  1324. else if (VolData.UsedClusters != 0 && VolData.BytesPerCluster != 0) {
  1325. VolData.PercentDiskFragged = (100 * VolData.FraggedSpace) /
  1326. (VolData.UsedClusters * VolData.BytesPerCluster);
  1327. }
  1328. // Make final computation of the average fragments per file on the volume.
  1329. if (VolData.NumFraggedFiles && VolData.CurrentFile){
  1330. VolData.AveFragsPerFile = ((VolData.NumExcessFrags + VolData.CurrentFile) * 100) / VolData.CurrentFile;
  1331. }
  1332. //Send status data to the UI.
  1333. SendStatusData();
  1334. //Send the graphical data.
  1335. SendGraphicsData();
  1336. return TRUE;
  1337. }
  1338. DWORD
  1339. HandleBootOptimize()
  1340. {
  1341. DWORD LayoutErrCode;
  1342. LayoutErrCode = BootOptimize(VolData.hVolume, VolData.BitmapSize, VolData.BytesPerSector,
  1343. VolData.TotalClusters, FALSE, 0,
  1344. 0, VolData.cDrive);
  1345. VolData.BootOptimizeBeginClusterExclude = 0;
  1346. VolData.BootOptimizeEndClusterExclude = 0;
  1347. if (IsBootVolume(VolData.cDrive)) {
  1348. //update the voldata values for the new registry entries
  1349. HKEY hValue = NULL;
  1350. DWORD dwRegValueSize = 0;
  1351. long ret = 0;
  1352. TCHAR cRegValue[100];
  1353. // get Boot Optimize Begin Cluster Exclude from registry
  1354. dwRegValueSize = sizeof(cRegValue);
  1355. ret = GetRegValue(
  1356. &hValue,
  1357. BOOT_OPTIMIZE_REGISTRY_PATH,
  1358. BOOT_OPTIMIZE_REGISTRY_LCNSTARTLOCATION,
  1359. cRegValue,
  1360. &dwRegValueSize);
  1361. RegCloseKey(hValue);
  1362. //check to see if the key exists, else exit from routine
  1363. if (ret == ERROR_SUCCESS) {
  1364. VolData.BootOptimizeBeginClusterExclude = _ttoi(cRegValue);
  1365. }
  1366. // get Boot Optimize End Cluster Exclude from registry
  1367. hValue = NULL;
  1368. dwRegValueSize = sizeof(cRegValue);
  1369. ret = GetRegValue(
  1370. &hValue,
  1371. BOOT_OPTIMIZE_REGISTRY_PATH,
  1372. BOOT_OPTIMIZE_REGISTRY_LCNENDLOCATION,
  1373. cRegValue,
  1374. &dwRegValueSize);
  1375. RegCloseKey(hValue);
  1376. //check to see if the key exists, else exit from routine
  1377. if (ret == ERROR_SUCCESS) {
  1378. VolData.BootOptimizeEndClusterExclude = _ttoi(cRegValue);
  1379. }
  1380. }
  1381. return LayoutErrCode;
  1382. }
  1383. /*****************************************************************************************************************
  1384. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  1385. ROUTINE DESCRIPTION:
  1386. Thread routine for defragmentation.
  1387. INPUT + OUTPUT:
  1388. None.
  1389. GLOBALS:
  1390. None.
  1391. RETURN:
  1392. TRUE - Success.
  1393. FALSE - Fatal Error.
  1394. */
  1395. BOOL
  1396. DefragThread(
  1397. )
  1398. {
  1399. CoInitializeEx(NULL, COINIT_MULTITHREADED);
  1400. // Get the time that the engine started.
  1401. GetLocalTime(&VolData.StartTime);
  1402. AcquirePrivilege(SE_BACKUP_NAME);
  1403. // Do the Prescan.
  1404. uEngineState = DEFRAG_STATE_REANALYZING;
  1405. uPercentDone = 1;
  1406. SendStatusData();
  1407. if(!PreScanFat()){
  1408. // IDMSG_SCANFAT_PRESCAN_ABORT - "ScanFAT: PreScan Aborted - Fatal Error - File "
  1409. VString msg(IDMSG_SCANFAT_PRESCAN_ABORT, GetDfrgResHandle());
  1410. msg.AddChar(L' ');
  1411. PWSTR Temp = VolData.vFileName.GetBuffer();
  1412. if (StartsWithVolumeGuid(Temp)) {
  1413. if ((VolData.cDrive >= L'C') &&
  1414. (VolData.cDrive <= L'Z')) {
  1415. msg.AddChar(VolData.cDrive);
  1416. msg.AddChar(L':');
  1417. }
  1418. msg += (PWSTR)(Temp + 48);
  1419. }
  1420. else {
  1421. msg += VolData.vFileName;
  1422. }
  1423. // send error info to client
  1424. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  1425. // Log this into the EventLog.
  1426. LogEvent(MSG_ENGINE_ERROR, msg.GetBuffer());
  1427. // Trigger an abort.
  1428. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1429. // set the event to signaled, allowing the UI to proceed
  1430. if (hDefragCompleteEvent){
  1431. SetEvent(hDefragCompleteEvent);
  1432. }
  1433. ExitThread(0);
  1434. return FALSE;
  1435. }
  1436. if(VolData.EngineState == TERMINATE){
  1437. //1.0E00 We're done, close down now.
  1438. PostMessage(hwndMain, WM_CLOSE, 0, 0);
  1439. // Kill the thread.
  1440. ExitThread(0);
  1441. }
  1442. //
  1443. // Note whether updating the optimal layout was successful. Any errors
  1444. // will be ignored if we did not get launched just to optimize the layout.
  1445. //
  1446. // If command line was boot optimize -b /b, just do the boot optimize
  1447. if(bCommandLineBootOptimizeFlag)
  1448. {
  1449. DWORD LayoutErrCode = HandleBootOptimize();
  1450. //if we failed layout optimization, tell the client.
  1451. if (LayoutErrCode != ENG_NOERR)
  1452. {
  1453. SendErrData(TEXT(""), LayoutErrCode);
  1454. }
  1455. //signal the client that we are done.
  1456. if (hDefragCompleteEvent){
  1457. SetEvent(hDefragCompleteEvent);
  1458. }
  1459. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1460. ExitThread(0);
  1461. return TRUE;
  1462. }
  1463. // Allocate memory for the file lists.
  1464. if (!AllocateFileLists()) {
  1465. VString msg(IDS_OUT_OF_MEMORY, GetDfrgResHandle());
  1466. msg += TEXT("\r\n");
  1467. VString line2(IDS_SCANFAT_INIT_ABORT, GetDfrgResHandle());
  1468. msg += line2;
  1469. // send error info to client
  1470. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  1471. // Log this into the EventLog.
  1472. LogEvent(MSG_ENGINE_ERROR, msg.GetBuffer());
  1473. // Trigger an abort.
  1474. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1475. // set the event to signaled, allowing the UI to proceed
  1476. if (hDefragCompleteEvent){
  1477. SetEvent(hDefragCompleteEvent);
  1478. }
  1479. ExitThread(0);
  1480. return FALSE;
  1481. }
  1482. // Do the Scan.
  1483. if(!ScanFat()){
  1484. // IDMSG_SCANFAT_SCAN_ABORT - "ScanFAT: Scan Aborted - Fatal Error - File:"
  1485. VString msg(IDMSG_SCANFAT_SCAN_ABORT, GetDfrgResHandle());
  1486. msg.AddChar(L' ');
  1487. PWSTR Temp = VolData.vFileName.GetBuffer();
  1488. if (StartsWithVolumeGuid(Temp)) {
  1489. if ((VolData.cDrive >= L'C') &&
  1490. (VolData.cDrive <= L'Z')) {
  1491. msg.AddChar(VolData.cDrive);
  1492. msg.AddChar(L':');
  1493. }
  1494. msg += (PWSTR)(Temp + 48);
  1495. }
  1496. else {
  1497. msg += VolData.vFileName;
  1498. }
  1499. // send error info to client
  1500. SendErrData(msg.GetBuffer(), ENGERR_GENERAL);
  1501. // Log this into the EventLog.
  1502. LogEvent(MSG_ENGINE_ERROR, msg.GetBuffer());
  1503. // Trigger an abort.
  1504. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1505. // set the event to signaled, allowing the UI to proceed
  1506. if (hDefragCompleteEvent){
  1507. SetEvent(hDefragCompleteEvent);
  1508. }
  1509. ExitThread(0);
  1510. return FALSE;
  1511. }
  1512. if(VolData.EngineState == TERMINATE){
  1513. //1.0E00 We're done, close down now.
  1514. PostMessage(hwndMain, WM_CLOSE, 0, 0);
  1515. // Kill the thread.
  1516. ExitThread(0);
  1517. }
  1518. //Send the report text data to the UI.
  1519. SendReportData();
  1520. // Defragment the Drive.
  1521. uEngineState = DEFRAG_STATE_BOOT_OPTIMIZING;
  1522. uPercentDone = 1;
  1523. SendStatusData();
  1524. HandleBootOptimize();
  1525. //I moved this piece of code down here so that SendReportData() is executed
  1526. //before ValidateFreeSpace() so that VolData is populated, else not all the
  1527. //calculations work. I hope this doesn't cause any problems
  1528. //add in the check for force flag in command line mode
  1529. if(bCommandLineMode && !bCommandLineForceFlag)
  1530. {
  1531. TCHAR msg[800];
  1532. VolData.UsableFreeSpace = VolData.FreeSpace = (VolData.TotalClusters - VolData.UsedClusters) *
  1533. VolData.BytesPerCluster;
  1534. if(!ValidateFreeSpace(bCommandLineMode, VolData.FreeSpace, VolData.UsableFreeSpace,
  1535. (VolData.TotalClusters * VolData.BytesPerCluster),
  1536. VolData.cDisplayLabel, msg, sizeof(msg) / sizeof(TCHAR)))
  1537. {
  1538. //0.0E00 Log this into the EventLog.
  1539. LogEvent(MSG_ENGINE_ERROR, msg);
  1540. // send error info to client
  1541. SendErrData(msg, ENGERR_LOW_FREESPACE);
  1542. //0.0E00 Trigger an abort.
  1543. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1544. // set the event to signaled, allowing the UI to proceed
  1545. if (hDefragCompleteEvent){
  1546. SetEvent(hDefragCompleteEvent);
  1547. }
  1548. ExitThread(0);
  1549. return TRUE;
  1550. }
  1551. }
  1552. // Prepare to defragment.
  1553. if (!InitializeDefrag()) {
  1554. VString msg(IDS_SCANFAT_INIT_ABORT, GetDfrgResHandle());
  1555. VString title(IDS_DK_TITLE, GetDfrgResHandle());
  1556. ErrorMessageBox(msg.GetBuffer(), title.GetBuffer());
  1557. // Trigger an abort.
  1558. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1559. ExitThread(0);
  1560. return FALSE;
  1561. }
  1562. // Defragment the Drive.
  1563. uEngineState = DEFRAG_STATE_DEFRAGMENTING;
  1564. SendStatusData();
  1565. if(!DefragFat()){
  1566. // Trigger an abort.
  1567. PostMessage(hwndMain, WM_COMMAND, ID_ABORT, 0);
  1568. ExitThread(0);
  1569. return FALSE;
  1570. }
  1571. // Note the end time for that pass.
  1572. GetLocalTime(&VolData.EndTime);
  1573. // mwp - Display the stats after the defrag. Why was this left out
  1574. DisplayFatVolumeStats();
  1575. // If this engine has a visible window, write the basic statistics for this drive to the screen.
  1576. Message(TEXT("Completed defragmentation - run analyze to see the results."), -1, NULL);
  1577. // Now clean-up the extent buffer. This will purge it as well, so we'll
  1578. //have a fully up-to-date DiskView of the disk.
  1579. EF(DestroyExtentBuffer());
  1580. //Send status data to the UI.
  1581. uEngineState = DEFRAG_STATE_DEFRAGMENTED;
  1582. SendStatusData();
  1583. //Send the graphical data to the UI.
  1584. SendGraphicsData();
  1585. //Send the report text data to the UI.
  1586. SendReportData();
  1587. //Send the most fragged list to the UI.
  1588. SendMostFraggedList();
  1589. // All done, close down now.
  1590. PostMessage(hwndMain, WM_CLOSE, 0, 0);
  1591. // set the event to signaled, allowing the UI to proceed
  1592. if (hDefragCompleteEvent){
  1593. SetEvent(hDefragCompleteEvent);
  1594. }
  1595. // Kill the thread.
  1596. ExitThread(0);
  1597. return TRUE;
  1598. }
  1599. /*****************************************************************************************************************
  1600. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  1601. ROUTINE DESCRIPTION:
  1602. Routine that carries out the defragmentation of a drive.
  1603. INPUT + OUTPUT:
  1604. None.
  1605. GLOBALS:
  1606. IN OUT Multiple VolData fields.
  1607. RETURN:
  1608. TRUE - Success.
  1609. FALSE - Fatal Error.
  1610. */
  1611. BOOL
  1612. DefragFatInitializePass(
  1613. );
  1614. BOOL
  1615. DefragFatFiles(
  1616. );
  1617. BOOL
  1618. DefragFat(
  1619. )
  1620. {
  1621. Message(TEXT("DefragFat"), -1, NULL);
  1622. uPass = 0;
  1623. VolData.Pass6Rep = 0;
  1624. for(VolData.Pass = 1; VolData.Pass <= 6; VolData.Pass++) {
  1625. uPass = VolData.Pass;
  1626. switch(VolData.Pass){
  1627. case 2:
  1628. case 4:
  1629. // If there are no fragmented files then Skip pass 2 & 4.
  1630. if(VolData.NumFraggedFiles == 0) {
  1631. VolData.Pass++;
  1632. }
  1633. break;
  1634. case 6:
  1635. // We are done if this is Pass 6 and we moved zero
  1636. // files in the last pass or done Pass 5 five times.
  1637. if(VolData.FilesMovedInLastPass == 0 || VolData.Pass6Rep > 5) {
  1638. // WE ARE DONE.
  1639. return TRUE;
  1640. }
  1641. // Do pass 5 again
  1642. VolData.Pass = 5;
  1643. VolData.Pass6Rep++;
  1644. break;
  1645. default:
  1646. break;
  1647. }
  1648. // Initialize the next pass.
  1649. if(!DefragFatInitializePass()) {
  1650. return FALSE;
  1651. }
  1652. // Defragment the files for this pass.
  1653. if(!DefragFatFiles()) {
  1654. return FALSE;
  1655. }
  1656. //this does not work at all
  1657. //bug # 101865
  1658. //if the number of files moved in this pass for fragmented and contiguous
  1659. //files is zero, then exit out of the defrag loop
  1660. // if(VolData.FragmentedFileMovesSucceeded[VolData.Pass] == 0 &&
  1661. // VolData.ContiguousFileMovesSucceeded[VolData.Pass] == 0)
  1662. // {
  1663. // return FALSE;
  1664. // }
  1665. }
  1666. return TRUE;
  1667. }
  1668. /*****************************************************************************************************************
  1669. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  1670. ROUTINE DESCRIPTION:
  1671. Routine initializes the required parameters based on the pass number.
  1672. INPUT + OUTPUT:
  1673. None.
  1674. GLOBALS:
  1675. IN OUT Various VolData fields.
  1676. RETURN:
  1677. TRUE - Success.
  1678. FALSE - Fatal error.
  1679. */
  1680. BOOL
  1681. DefragFatInitializePass(
  1682. )
  1683. {
  1684. TCHAR cString[300];
  1685. FILE_LIST_ENTRY* pFileList = VolData.pMoveableFileList;
  1686. // Note which stage this is.
  1687. uPass = VolData.Pass;
  1688. _stprintf(cString, TEXT("Pass %d"), VolData.Pass);
  1689. Message(cString, -1, NULL);
  1690. // After each pass, go through the fragged file list
  1691. // and reset the high bit for each FRN. This means
  1692. // we'll be able to defrag these files again on the next pass.
  1693. for (UINT i = 0; i < VolData.MoveableFileListIndex; i ++) {
  1694. if(pFileList[i].FileRecordNumber == 0){
  1695. break;
  1696. }
  1697. pFileList[i].Flags &= ~FLE_NEXT_PASS;
  1698. }
  1699. // Initialize the appropriate variables for the pass.
  1700. switch(VolData.Pass){
  1701. case 1:
  1702. // Files can be moved from any point on the disk.
  1703. VolData.SourceStartLcn = 0;
  1704. VolData.SourceEndLcn = VolData.TotalClusters;
  1705. // Files can be moved to any point on the disk.
  1706. VolData.DestStartLcn = 0;
  1707. VolData.DestEndLcn = VolData.TotalClusters;
  1708. // Start at the end of the disk and move to the beginning.
  1709. VolData.ProcessFilesDirection = BACKWARD;
  1710. VolData.FilesMovedInLastPass = 0;
  1711. dwMoveFlags = MOVE_CONTIGUOUS;
  1712. break;
  1713. case 2:
  1714. case 4:
  1715. // Files can be moved from any point on the disk.
  1716. VolData.SourceStartLcn = 0;
  1717. VolData.SourceEndLcn = VolData.TotalClusters;
  1718. // Files can be moved to any point on the disk.
  1719. VolData.DestStartLcn = 0;
  1720. VolData.DestEndLcn = VolData.TotalClusters;
  1721. // Start at the beginning of the disk and move to the end.
  1722. VolData.ProcessFilesDirection = FORWARD;
  1723. VolData.FilesMovedInLastPass = 0;
  1724. dwMoveFlags = MOVE_FRAGMENTED;
  1725. break;
  1726. case 3:
  1727. case 5:
  1728. // Files can be moved from any point on the disk.
  1729. VolData.SourceStartLcn = 0;
  1730. VolData.SourceEndLcn = VolData.TotalClusters;
  1731. // Files can be moved to any point on the disk.
  1732. VolData.DestStartLcn = 0;
  1733. VolData.DestEndLcn = VolData.TotalClusters;
  1734. // Start at the end of the disk and move to the beginning.
  1735. VolData.ProcessFilesDirection = BACKWARD;
  1736. VolData.FilesMovedInLastPass = 0;
  1737. dwMoveFlags = MOVE_FRAGMENTED|MOVE_CONTIGUOUS;
  1738. break;
  1739. default:
  1740. EF_ASSERT(FALSE);
  1741. VolData.Status = TERMINATE_ENGINE;
  1742. return FALSE;
  1743. }
  1744. // Set which lcn to begin looking for files at depending on which direction on the disk the engine
  1745. // is selecting files from. i.e. If the engine should start looking forward on the disk, LastStartingLcn
  1746. // is just less than zero so that a file at the beginning of the disk gets moved first. i.e. If the
  1747. // engine should start looking backward on the disk, LastStartingLcn is equivalent to the end of the
  1748. // disk so that a file at the end of the disk gets moved first.
  1749. VolData.LastStartingLcn = (VolData.ProcessFilesDirection == FORWARD) ? VolData.SourceStartLcn - 1 : VolData.SourceEndLcn;
  1750. return TRUE;
  1751. }
  1752. /*****************************************************************************************************************
  1753. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  1754. ROUTINE DESCRIPTION:
  1755. Defragments files on a volume based on the pass.
  1756. INPUT + OUTPUT:
  1757. None.
  1758. GLOBALS:
  1759. IN OUT Various VolData fields.
  1760. RETURN:
  1761. TRUE - Success.
  1762. FALSE - Fatal Error or Terminate.
  1763. */
  1764. BOOL
  1765. DefragFatFiles(
  1766. )
  1767. {
  1768. double dFileRecordNumber = 0;
  1769. UINT uPercentDoneMem = 0;
  1770. LONGLONG llNumFraggedFiles = VolData.NumFraggedFiles;
  1771. LONGLONG llNumContiguousFiles = VolData.MoveableFileListEntries - VolData.NumFraggedFiles;
  1772. //acs bug #101862// Upadate Percent done & progress bar.
  1773. uPercentDone = 1;
  1774. SendStatusData();
  1775. VolData.Status = NEXT_FILE;
  1776. // Do all the files on the disk.
  1777. while(VolData.Status != NEXT_PASS && VolData.Status != TERMINATE_ENGINE) {
  1778. // Sleep if paused.
  1779. while(VolData.EngineState == PAUSED){
  1780. Sleep(1000);
  1781. }
  1782. // Terminate if told to stop by the controller - this is not an error.
  1783. if(VolData.EngineState == TERMINATE){
  1784. PostMessage(hwndMain, WM_CLOSE, 0, 0);
  1785. return FALSE;
  1786. }
  1787. // Get next file to process.
  1788. if(!GetNextFatFile(dwMoveFlags)){
  1789. VolData.Status = NEXT_PASS;
  1790. continue;
  1791. }
  1792. //acs bug #101862// Increment for the Percent done & progress bar status.
  1793. dFileRecordNumber++;
  1794. // We have already opened thte file once during GetNextFatFile - we do not have to do it again.
  1795. // Get the extent list & number of fragments in the file.
  1796. if(!GetExtentList(DEFAULT_STREAMS, NULL)) {
  1797. VolData.Status = NEXT_FILE;
  1798. LOG_ERR();
  1799. continue;
  1800. }
  1801. // Display the file data.
  1802. DisplayFatFileSpecs();
  1803. // Set the length of free space found to zero - We haven't found any yet.
  1804. VolData.FoundLen = 0;
  1805. VolData.Status = NEXT_ALGO_STEP;
  1806. switch(VolData.Pass) {
  1807. case 1:
  1808. // Try to to consolidate some free space.
  1809. //acs bug #101862// Upadate Percent done & progress bar.
  1810. if(llNumContiguousFiles != 0) {
  1811. //acs bug #101862// Calculate the Percent done.
  1812. uPercentDone = UINT((dFileRecordNumber / llNumContiguousFiles) *100);
  1813. //acs bug #101862// Only send it if there is a change - don't overload the SendStatusData
  1814. if(uPercentDone != uPercentDoneMem) {
  1815. SendStatusData();
  1816. uPercentDoneMem = uPercentDone;
  1817. // Pause if the volume has a snapshot present
  1818. PauseOnVolumeSnapshot(VolData.cVolumeName);
  1819. }
  1820. }
  1821. // Move contiguous files earlier.
  1822. if(VolData.bFragmented == FALSE){
  1823. // Put contiguous files earlier on the disk.
  1824. if(FindFreeSpace(EARLIER)) {
  1825. Message(TEXT("MoveFatFile - EARLIER"), -1, NULL);
  1826. MoveFatFile();
  1827. }
  1828. else {
  1829. EndPassIfNoSpaces();
  1830. }
  1831. }
  1832. break;
  1833. case 2:
  1834. case 4:
  1835. // Defragment files on the disk. Move them earlier
  1836. // but if necessary use the last half of the
  1837. // disk as a temporary dumping zone.
  1838. //acs bug #101862// Upadate Percent done & progress bar.
  1839. if(llNumFraggedFiles != 0) {
  1840. //acs bug #101862// Calculate the Percent done.
  1841. uPercentDone = UINT((dFileRecordNumber / llNumFraggedFiles) *100);
  1842. //acs bug #101862// Only send it if there is a change - don't overload the SendStatusData
  1843. if(uPercentDone != uPercentDoneMem) {
  1844. SendStatusData();
  1845. uPercentDoneMem = uPercentDone;
  1846. //Pause if the volume has a snapshot present
  1847. PauseOnVolumeSnapshot(VolData.cVolumeName);
  1848. }
  1849. }
  1850. // Do not move contiguous files on this pass.
  1851. if(VolData.bFragmented == FALSE){
  1852. VolData.Status = NEXT_FILE;
  1853. }
  1854. // Defrag fragmented files.
  1855. else {
  1856. // First, try to put them at the beginning of the disk.
  1857. if(VolData.Status == NEXT_ALGO_STEP) {
  1858. if(FindFreeSpace(EARLIER)) {
  1859. if(VolData.Status == NEXT_ALGO_STEP){
  1860. Message(TEXT("MoveFatFile - EARLIER"), -1, NULL);
  1861. MoveFatFile();
  1862. }
  1863. }
  1864. }
  1865. // If that fails, try the last half of the disk.
  1866. if(VolData.Status == NEXT_ALGO_STEP){
  1867. if(FindFreeSpace(FIRST_FIT)) {
  1868. if(VolData.Status == NEXT_ALGO_STEP){
  1869. Message(TEXT("MoveFatFile - LAST_FIT"), -1, NULL);
  1870. MoveFatFile();
  1871. }
  1872. }
  1873. }
  1874. // If that fails, defrag any way possible to get some change.
  1875. if(VolData.Status == NEXT_ALGO_STEP){
  1876. if(FindLastFreeSpaceChunks()) {
  1877. if(VolData.Status == NEXT_ALGO_STEP){
  1878. Message(TEXT("PartialDefragFat"), -1, NULL);
  1879. PartialDefragFat();
  1880. }
  1881. }
  1882. }
  1883. }
  1884. break;
  1885. case 3:
  1886. case 5:
  1887. // Move all files working backwards from
  1888. // the disk to the front of the disk.
  1889. //acs bug #101862// Upadate Percent done & progress bar.
  1890. if(EnumeratedFatFiles != 0) {
  1891. //acs bug #101862// Calculate the Percent done.
  1892. uPercentDone = UINT((dFileRecordNumber / EnumeratedFatFiles) *100);
  1893. //acs bug #101862// Only send it if there is a change - don't overload the SendStatusData
  1894. if(uPercentDone != uPercentDoneMem) {
  1895. SendStatusData();
  1896. uPercentDoneMem = uPercentDone;
  1897. //Pause if the volume has a snapshot present
  1898. PauseOnVolumeSnapshot(VolData.cVolumeName);
  1899. }
  1900. }
  1901. // Move contiguous files earlier.
  1902. if(VolData.bFragmented == FALSE){
  1903. // Put contiguous files earlier on the disk.
  1904. if(FindFreeSpace(EARLIER)) {
  1905. Message(TEXT("MoveFatFile - EARLIER"), -1, NULL);
  1906. MoveFatFile();
  1907. }
  1908. else {
  1909. EndPassIfNoSpaces();
  1910. }
  1911. }
  1912. // Defrag fragmented files.
  1913. else{
  1914. // First, try to put them at the beginning of the disk.
  1915. if(FindFreeSpace(EARLIER)) {
  1916. Message(TEXT("MoveFatFile - EARLIER"), -1, NULL);
  1917. MoveFatFile();
  1918. }
  1919. // else {
  1920. // EndPassIfNoSpaces();
  1921. // }
  1922. }
  1923. break;
  1924. default:
  1925. EF_ASSERT(FALSE);
  1926. VolData.Status = TERMINATE_ENGINE;
  1927. return FALSE;
  1928. }
  1929. // Clean up resources.
  1930. if(VolData.hFile != INVALID_HANDLE_VALUE) {
  1931. // Send graphics display data only
  1932. // if we moved a file. We know
  1933. // because we have a file handle.
  1934. PurgeExtentBuffer();
  1935. CloseHandle(VolData.hFile);
  1936. VolData.hFile = INVALID_HANDLE_VALUE;
  1937. }
  1938. if(VolData.hFreeExtents != NULL) {
  1939. EH_ASSERT(GlobalUnlock(VolData.hFreeExtents) == FALSE);
  1940. EH_ASSERT(GlobalFree(VolData.hFreeExtents) == NULL);
  1941. VolData.hFreeExtents = NULL;
  1942. }
  1943. }
  1944. TCHAR cString[300];
  1945. _stprintf(cString, TEXT("Pass completed - FilesMovedInLastPass = %d"), (ULONG)VolData.FilesMovedInLastPass);
  1946. Message(cString, -1, NULL);
  1947. return TRUE;
  1948. }
  1949. /*****************************************************************************************************************
  1950. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  1951. ROUTINE DESCRIPTION:
  1952. If there are no spaces found to move a file into, then set the variable to end the pass.
  1953. Otherwise, just go on normally.
  1954. INPUT + OUTPUT:
  1955. None.
  1956. GLOBALS:
  1957. IN VolData.LargestFound - The largest free space that was found.
  1958. OUT VolData.Status - Equals NEXT_PASS if there are no spaces, or NEXT_ALGO_STEP otherwise.
  1959. RETURN:
  1960. TRUE - Success.
  1961. */
  1962. BOOL
  1963. EndPassIfNoSpaces(
  1964. )
  1965. {
  1966. if(VolData.LargestFound == 0) {
  1967. Message(TEXT(""), -1, NULL);
  1968. Message(TEXT("Ending pass because no more spaces left to move files into."), -1, NULL);
  1969. VolData.Status = NEXT_PASS;
  1970. }
  1971. else {
  1972. VolData.Status = NEXT_ALGO_STEP;
  1973. }
  1974. return TRUE;
  1975. }
  1976. /*****************************************************************************************************************
  1977. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  1978. ROUTINE DESCRIPTION:
  1979. If the last bitmap routine didn't find any space, then go onto the next file.
  1980. Otherwise, go onto the next algorithm step.
  1981. INPUT + OUTPUT:
  1982. None.
  1983. GLOBALS:
  1984. IN VolData.FoundLen - The free space that was found to move this file into.
  1985. OUT VolData.Status - Equals NEXT_PASS if there are no spaces, or NEXT_ALGO_STEP otherwise.
  1986. RETURN:
  1987. TRUE - Success.
  1988. */
  1989. BOOL
  1990. NextFileIfFalse(
  1991. )
  1992. {
  1993. if(VolData.FoundLen == 0){
  1994. VolData.Status = NEXT_FILE;
  1995. }else{
  1996. VolData.Status = NEXT_ALGO_STEP;
  1997. }
  1998. return TRUE;
  1999. }
  2000. /*****************************************************************************************************************
  2001. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2002. ROUTINE DESCRIPTION:
  2003. Partially defrags a FAT file.
  2004. INPUT + OUTPUT:
  2005. None.
  2006. GLOBALS:
  2007. IN VolData.hFreeExtents - Used to determine if there is free space to move the file into.
  2008. OUT VolData.Status - Can be any of several values returned from CheckFileForExclude() or PartialDefrag().
  2009. RETURN:
  2010. TRUE - Success.
  2011. FALSE - Fatal Error.
  2012. */
  2013. BOOL
  2014. PartialDefragFat(
  2015. )
  2016. {
  2017. // Check to see if there any free space.
  2018. if(VolData.hFreeExtents == NULL) {
  2019. return TRUE;
  2020. }
  2021. // Check if file is in exclude list
  2022. if(!CheckFileForExclude()) {
  2023. return VolData.Status;
  2024. }
  2025. // Move the file
  2026. if(!PartialDefrag()) {
  2027. return FALSE;
  2028. }
  2029. //1.0E00 Note that a file was moved (update the file moved counters).
  2030. VolData.FilesMoved ++;
  2031. VolData.FilesMovedInLastPass ++;
  2032. return TRUE;
  2033. }
  2034. /*****************************************************************************************************************
  2035. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2036. ROUTINE DESCRIPTION:
  2037. After a place has been found to move this file to, this function will move it there.
  2038. INPUT + OUTPUT:
  2039. None.
  2040. GLOBALS:
  2041. OUT VolData.Status - Can be any of several values returned from CheckFileForExclude() or MoveFile().
  2042. RETURN:
  2043. TRUE - Success.
  2044. FALSE - Fatal Error.
  2045. */
  2046. BOOL
  2047. MoveFatFile(
  2048. )
  2049. {
  2050. LONGLONG RunLength = VolData.NumberOfClusters;
  2051. // Check to see if there is enough free space.
  2052. if(VolData.FoundLen < RunLength) {
  2053. VolData.Status = NEXT_ALGO_STEP;
  2054. return FALSE;
  2055. }
  2056. // Check if file is in exclude list
  2057. if(!CheckFileForExclude()) {
  2058. VolData.Status = NEXT_FILE;
  2059. return FALSE;
  2060. }
  2061. // VolData.Status already set.
  2062. return MoveFile();
  2063. }
  2064. void SendGraphicsData()
  2065. {
  2066. char * pAnalyzeLineArray = NULL;
  2067. char * pDefragLineArray = NULL;
  2068. DISPLAY_DATA * pDispData = NULL;
  2069. __try {
  2070. // Kill the timer until we're done.
  2071. KillTimer(hwndMain, DISKVIEW_TIMER_ID);
  2072. // don't send the data unless the engine is running
  2073. if (VolData.EngineState != RUNNING){
  2074. return;
  2075. }
  2076. // if DiskView didn't get memory, forget it
  2077. if (!AnalyzeView.HasMapMemory() || !DefragView.HasMapMemory()) {
  2078. SendGraphicsMemoryErr();
  2079. return;
  2080. }
  2081. DISPLAY_DATA DisplayData = {0};
  2082. DWORD dwDispDataSize = 0;
  2083. // get copies of line arrays for analyze and defrag
  2084. // (delete copy when finished)
  2085. AnalyzeView.GetLineArray(&pAnalyzeLineArray, &DisplayData.dwAnalyzeNumLines);
  2086. DefragView.GetLineArray(&pDefragLineArray, &DisplayData.dwDefragNumLines);
  2087. // Allocate enough memory to hold both analyze and defrag displays.
  2088. // If only analyze or defrag is present, then the NumLines field for the
  2089. // other one will equal zero -- hence no additional allocation.
  2090. dwDispDataSize =
  2091. DisplayData.dwAnalyzeNumLines +
  2092. DisplayData.dwDefragNumLines +
  2093. sizeof(DISPLAY_DATA);
  2094. // If neither an analyze diskview nor a defrag diskview are present, don't continue.
  2095. if (DisplayData.dwAnalyzeNumLines == 0 && DisplayData.dwDefragNumLines == 0) {
  2096. return;
  2097. }
  2098. pDispData = (DISPLAY_DATA *) new char[dwDispDataSize];
  2099. // If we can't get memory, don't continue.
  2100. if (pDispData == NULL) {
  2101. return;
  2102. }
  2103. wcscpy(pDispData->cVolumeName, VolData.cVolumeName);
  2104. // Copy over the fields for the analyze and defrag data.
  2105. // If only one or the other is present, the fields for the other will equal zero.
  2106. pDispData->dwAnalyzeNumLines = DisplayData.dwAnalyzeNumLines;
  2107. pDispData->dwDefragNumLines = DisplayData.dwDefragNumLines;
  2108. // Get the line array for the analyze view if it exists.
  2109. if (pAnalyzeLineArray) {
  2110. CopyMemory((char*) &(pDispData->LineArray),
  2111. pAnalyzeLineArray,
  2112. DisplayData.dwAnalyzeNumLines);
  2113. }
  2114. // Get the line array for the defrag view if it exists
  2115. if (pDefragLineArray) {
  2116. CopyMemory((char*) ((BYTE*)&pDispData->LineArray) + DisplayData.dwAnalyzeNumLines,
  2117. pDefragLineArray,
  2118. DisplayData.dwDefragNumLines);
  2119. }
  2120. // If the gui is connected, send gui data to it
  2121. DataIoClientSetData(ID_DISP_DATA, (TCHAR*) pDispData, dwDispDataSize, pdataDfrgCtl);
  2122. Message(TEXT("engine sending graphics to UI"), -1, NULL);
  2123. }
  2124. __finally {
  2125. // clean up
  2126. if (pAnalyzeLineArray) {
  2127. delete [] pAnalyzeLineArray;
  2128. }
  2129. if (pDefragLineArray) {
  2130. delete [] pDefragLineArray;
  2131. }
  2132. if (pDispData) {
  2133. delete [] pDispData;
  2134. }
  2135. // reset the next timer for updating the disk view
  2136. if(SetTimer(hwndMain, DISKVIEW_TIMER_ID, DiskViewInterval, NULL) != 0)
  2137. {
  2138. LOG_ERR();
  2139. }
  2140. }
  2141. }
  2142. /*****************************************************************************************************************
  2143. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2144. ROUTINE DESCRIPTION:
  2145. This is the exit routine which will clean up all the open handles, free up all unused memory etc.
  2146. INPUT + OUTPUT:
  2147. None.
  2148. GLOBALS:
  2149. Pointless to enumerate here -- all unhandled handles (pun intended) and allocated memories are closed/freed.
  2150. RETURN:
  2151. None.
  2152. */
  2153. VOID
  2154. Exit(
  2155. )
  2156. {
  2157. if (TERMINATE != VolData.EngineState) {
  2158. VolData.EngineState = TERMINATE;
  2159. Sleep(3000); // give the other thread a few seconds to realise we're going away
  2160. }
  2161. // Delete the pointer to the GUI object.
  2162. ExitDataIoClient(&pdataDfrgCtl);
  2163. //If we were logging, then close the log file.
  2164. if(bLogFile){
  2165. ExitLogFile();
  2166. }
  2167. // If the gui is still connected, force a disconnection, error message and continue. This shouldn't happen.
  2168. // Cleanup our internal memory allocations and handles.
  2169. if(hThread){
  2170. DWORD dwExitCode = 0;
  2171. //If the worker thread is still active, then terminate it.
  2172. GetExitCodeThread(hThread, &dwExitCode);
  2173. if(dwExitCode == STILL_ACTIVE){
  2174. WaitForSingleObject(hThread, 10000);
  2175. }
  2176. CloseHandle(hThread);
  2177. hThread = NULL;
  2178. }
  2179. CoUninitialize();
  2180. /*
  2181. (guhans, cenke, 01/09/01)
  2182. Process is exiting. To exit fast we don't wait for the worker thread
  2183. to exit, or free the global memory it might be using.
  2184. if(GetDfrgResHandle() != NULL)
  2185. {
  2186. FreeLibrary(GetDfrgResHandle());
  2187. }
  2188. if(VolData.hVolume){
  2189. CloseHandle(VolData.hVolume);
  2190. }
  2191. if(VolData.hFile != INVALID_HANDLE_VALUE){
  2192. CloseHandle(VolData.hFile);
  2193. VolData.hFile = INVALID_HANDLE_VALUE;
  2194. }
  2195. if(VolData.hExtentList){
  2196. EH_ASSERT(GlobalUnlock(VolData.hExtentList) == FALSE);
  2197. EH_ASSERT(GlobalFree(VolData.hExtentList) == NULL);
  2198. }
  2199. if(VolData.hVolumeBitmap){
  2200. EH_ASSERT(GlobalFree(VolData.hVolumeBitmap) == NULL);
  2201. }
  2202. if(VolData.hExcludeList){
  2203. EH_ASSERT(GlobalFree(VolData.hExcludeList) == NULL);
  2204. }
  2205. if(hPageFileNames){
  2206. EH_ASSERT(GlobalUnlock(hPageFileNames) == FALSE);
  2207. EH_ASSERT(GlobalFree(hPageFileNames) == NULL);
  2208. }
  2209. // Free up the file lists.
  2210. DeallocateFileLists();
  2211. */
  2212. // Close event logging.
  2213. CleanupLogging();
  2214. //Close the error log.
  2215. ExitErrorLog();
  2216. }
  2217. /*****************************************************************************************************************
  2218. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2219. ROUTINE DESCRIPTION:
  2220. Get the name of the pagefiles and store them in a double null-terminated list of null terminated strings.
  2221. INPUT + OUTPUT:
  2222. IN cDrive - The current drive so that this can tell which pagefile names to store. (Only the current drive.)
  2223. OUT phPageFileNames - Where to store the handle for the allocated memory.
  2224. OUT ppPageFileNames - Where to store the pointer for the pagefile names.
  2225. GLOBALS:
  2226. None.
  2227. RETURN:
  2228. TRUE - Success.
  2229. FALSE - Fatal Error.
  2230. */
  2231. BOOL
  2232. GetPagefileNames(
  2233. IN TCHAR cDrive,
  2234. OUT HANDLE * phPageFileNames,
  2235. OUT TCHAR ** ppPageFileNames
  2236. )
  2237. {
  2238. HKEY hKey = NULL;
  2239. ULONG lRegLen = 0;
  2240. int i;
  2241. int iStrLen;
  2242. int iNameStart;
  2243. TCHAR * pTemp;
  2244. TCHAR * pProcessed;
  2245. DWORD dwRet = 0;
  2246. DWORD dwType = 0;
  2247. if (cDrive == NULL){
  2248. //this is a mounted volume, and pagefiles cannot be placed on a mounted volumes
  2249. EF(AllocateMemory(2, phPageFileNames, (void**)ppPageFileNames));
  2250. ZeroMemory((PVOID) *ppPageFileNames, 2);
  2251. return TRUE;
  2252. }
  2253. // Open the registry key to the pagefile.
  2254. EF_ASSERT(ERROR_SUCCESS == RegOpenKeyEx(
  2255. HKEY_LOCAL_MACHINE,
  2256. TEXT("SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Memory Management"),
  2257. 0,
  2258. KEY_QUERY_VALUE,
  2259. &hKey));
  2260. // Find out how much memory we need to hold the value pagefile names.
  2261. EF_ASSERT(ERROR_SUCCESS == RegQueryValueEx(
  2262. hKey,
  2263. TEXT("PagingFiles"),
  2264. 0,
  2265. &dwType,
  2266. NULL,
  2267. &lRegLen));
  2268. // If there is no data then allocate enough for two bytes (a double termination).
  2269. if(lRegLen<2){
  2270. lRegLen = 2;
  2271. }
  2272. // Allocate enough memory.
  2273. EF(AllocateMemory(lRegLen, phPageFileNames, (void**)ppPageFileNames));
  2274. // Get the value.
  2275. EF_ASSERT(ERROR_SUCCESS ==RegQueryValueEx(
  2276. hKey,
  2277. TEXT("PagingFiles"),
  2278. 0,
  2279. &dwType,
  2280. (LPBYTE)*ppPageFileNames,
  2281. &lRegLen));
  2282. // Strip out the numbers and drive letters so that we have only the pagefile names.
  2283. //The REG_MULTI_SZ type has a series of null terminated strings with a double null termination at the end
  2284. //of the list.
  2285. //The format of each string is "c:\pagefile.sys 100 100". The data after the slash and before the first space
  2286. //is the page file name. The numbers specify the size of the pagefile which we don't care about.
  2287. //We extract the filename minus the drive letter of the pagefile (which must be in the root dir so we don't
  2288. //need to worry about subdirs existing). Therfore we put a null at the first space, and shift the pagefile
  2289. //name earlier so that we don't have c:\ in there. The end product should be a list of pagefile
  2290. //names with a double null termination for example: "pagefile.sys[null]pagefile2.sys[null][null]" Furthermore,
  2291. //we only take names for this drive, so the string may simply consist of a double null termination.
  2292. //We use the same memory space for output as we use for input, so we just clip the pagefile.sys and bump it up
  2293. //to the beginning of ppPageFileNames. We keep a separate pointer which points to the next byte after
  2294. //The previous outputed data.
  2295. pProcessed = pTemp = *ppPageFileNames;
  2296. // For each string...
  2297. while(*pTemp!=0){
  2298. iStrLen = lstrlen(pTemp);
  2299. // If this pagefile is on the current drive.
  2300. if((TCHAR)CharUpper((TCHAR*)pTemp[0]) == (TCHAR)CharUpper((TCHAR*)cDrive)){
  2301. // Go through each character in this string.
  2302. for(i=0; i<iStrLen; i++){
  2303. // If this is a slash, then the next character is the first of the pagefile name.
  2304. if(pTemp[i] == TEXT('\\')){
  2305. iNameStart = i+1;
  2306. continue;
  2307. }
  2308. // If this is a space then the rest of the string is numbers. Null terminate it here.
  2309. if(pTemp[i] == TEXT(' ')){
  2310. pTemp[i] = 0;
  2311. break;
  2312. }
  2313. }
  2314. // Bump the string up so all the processed names are adjacent.
  2315. MoveMemory(pProcessed, pTemp+iNameStart, (lstrlen(pTemp+iNameStart)+1)*sizeof(TCHAR));
  2316. // Note where the next string should go.
  2317. pProcessed += lstrlen(pProcessed) + 1;
  2318. }
  2319. // If this pagefile is not on this current drive then simply ignore it.
  2320. else{
  2321. }
  2322. // Note where to search for the next string.
  2323. pTemp += iStrLen + 1;
  2324. }
  2325. // Add double null termination.
  2326. *pProcessed = 0;
  2327. EF_ASSERT(RegCloseKey(hKey)==ERROR_SUCCESS);
  2328. return TRUE;
  2329. }
  2330. /*****************************************************************************************************************
  2331. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2332. ROUTINE DESCRIPTION:
  2333. Check to see if a file is a pagefile and grab it's extent list if it is.
  2334. INPUT + OUTPUT:
  2335. None.
  2336. GLOBALS:
  2337. IN pPageFileNames - Pointer to the memory that holds the list of active pagefile names for this drive.
  2338. IN VolData.cFileName - The name of the file to check.
  2339. // OUT VolData.PagefileFrags - The number of fragments in the pagefile.
  2340. OUT VolData.bPageFile - TRUE if this is a pagefile, false otherwise.
  2341. RETURN:
  2342. TRUE - Success.
  2343. FALSE - Fatal Error.
  2344. */
  2345. BOOL
  2346. CheckForPagefileFat(
  2347. )
  2348. {
  2349. // find the last backslash in the path
  2350. TCHAR *cFileName = NULL;
  2351. if (VolData.vFileName.GetLength() > 0) {
  2352. cFileName = wcsrchr(VolData.vFileName.GetBuffer(), L'\\');
  2353. }
  2354. if (cFileName == (TCHAR *) NULL){
  2355. return TRUE;
  2356. }
  2357. cFileName++; // start at first character after the last backslash
  2358. // Check it against the pagefile list.
  2359. BOOL bIsPageFile = CheckPagefileNameMatch(cFileName, pPageFileNames);
  2360. // return if not a pagefile
  2361. if(bIsPageFile == FALSE){
  2362. return TRUE; // TRUE means no error occurred
  2363. }
  2364. // Since we're getting the extent list manually, we have to offset the
  2365. // starting lcn to account for the fact that
  2366. // the first data cluster is cluster 2.
  2367. VolData.StartingLcn -= 2;
  2368. // Get the extent list for the pagefile.
  2369. EF(GetExtentListManuallyFat());
  2370. VolData.bPageFile = TRUE;
  2371. return TRUE;
  2372. }
  2373. /*****************************************************************************************************************
  2374. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2375. ROUTINE DESCRIPTION:
  2376. Check a name against all the pagefile names to see if this name matches that of a pagefile.
  2377. INPUT + OUTPUT:
  2378. IN pCompareName - The name of that we are checking to see if it is a pagefile.
  2379. IN pPageFileNames - The list of pagefile names for this drive.
  2380. GLOBALS:
  2381. None.
  2382. RETURN:
  2383. TRUE - This file name is a pagefile
  2384. FALSE - This file name is NOT a pagefile
  2385. */
  2386. BOOL
  2387. CheckPagefileNameMatch(
  2388. IN TCHAR * pCompareName,
  2389. IN TCHAR * pPageFileNames
  2390. )
  2391. {
  2392. require(pCompareName);
  2393. require(pPageFileNames);
  2394. // Loop through all the pagefile names -- the list is double null terminated.
  2395. while(*pPageFileNames!=0){
  2396. // Check if these names match.
  2397. if(!lstrcmpi(pCompareName, pPageFileNames)){
  2398. return TRUE;
  2399. }
  2400. // If not then move to the next name.
  2401. else{
  2402. pPageFileNames+=lstrlen(pPageFileNames)+1;
  2403. }
  2404. }
  2405. // No match with any of the names, so return FALSE.
  2406. return FALSE;
  2407. }
  2408. /*****************************************************************************************************************
  2409. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2410. ROUTINE DESCRIPTION:
  2411. Prints out the disk statistics on screen.
  2412. INPUT + OUTPUT:
  2413. None.
  2414. GLOBALS:
  2415. IN various VolData fields that get printed onto the screen.
  2416. RETURN:
  2417. None.
  2418. */
  2419. VOID
  2420. DisplayFatVolumeStats(
  2421. )
  2422. {
  2423. TCHAR cString[200];
  2424. ULONG iTmp;
  2425. _stprintf(cString, TEXT("Total sectors on disk = %I64d"), VolData.TotalSectors);
  2426. Message(cString, -1, NULL);
  2427. WriteStringToLogFile(cString);
  2428. _stprintf(cString, TEXT("Bytes per sector = %I64d"), VolData.BytesPerSector);
  2429. Message(cString, -1, NULL);
  2430. WriteStringToLogFile(cString);
  2431. _stprintf(cString, TEXT("Bytes per cluster = %I64d"), VolData.BytesPerCluster);
  2432. Message(cString, -1, NULL);
  2433. WriteStringToLogFile(cString);
  2434. _stprintf(cString, TEXT("Sectors per cluster = %I64d"), VolData.SectorsPerCluster);
  2435. Message(cString, -1, NULL);
  2436. WriteStringToLogFile(cString);
  2437. _stprintf(cString, TEXT("Total clusters on disk = %I64d"), VolData.TotalClusters);
  2438. Message(cString, -1, NULL);
  2439. WriteStringToLogFile(cString);
  2440. _stprintf(cString, TEXT("Volume Bitmap Size = %I64d"), VolData.BitmapSize);
  2441. Message(cString, -1, NULL);
  2442. WriteStringToLogFile(cString);
  2443. _stprintf(cString, TEXT("Disk Size = %I64d"), VolData.TotalClusters * VolData.BytesPerCluster);
  2444. Message(cString, -1, NULL);
  2445. WriteStringToLogFile(cString);
  2446. _stprintf(cString, TEXT("Cluster Size = %I64d"), VolData.BytesPerCluster);
  2447. Message(cString, -1, NULL);
  2448. WriteStringToLogFile(cString);
  2449. _stprintf(cString, TEXT("Used Space = %I64d bytes"), VolData.UsedClusters * VolData.BytesPerCluster);
  2450. Message(cString, -1, NULL);
  2451. WriteStringToLogFile(cString);
  2452. _stprintf(cString, TEXT("Free Space = %I64d bytes"), (VolData.TotalClusters - VolData.UsedClusters) * VolData.BytesPerCluster);
  2453. Message(cString, -1, NULL);
  2454. WriteStringToLogFile(cString);
  2455. _stprintf(cString, TEXT("Pagefile Size = %I64d"), VolData.PagefileSize);
  2456. Message(cString, -1, NULL);
  2457. WriteStringToLogFile(cString);
  2458. _stprintf(cString, TEXT("Pagefile Fragments = %I64d"), VolData.PagefileFrags);
  2459. Message(cString, -1, NULL);
  2460. WriteStringToLogFile(cString);
  2461. _stprintf(cString, TEXT("Total Directories = %I64d"), VolData.TotalDirs);
  2462. Message(cString, -1, NULL);
  2463. WriteStringToLogFile(cString);
  2464. _stprintf(cString, TEXT("Fragmented Dirs = %I64d"), VolData.NumFraggedDirs);
  2465. Message(cString, -1, NULL);
  2466. WriteStringToLogFile(cString);
  2467. _stprintf(cString, TEXT("Excess Dir Frags = %I64d"), VolData.NumExcessDirFrags);
  2468. Message(cString, -1, NULL);
  2469. WriteStringToLogFile(cString);
  2470. _stprintf(cString, TEXT("Total Files = %I64d"), VolData.TotalFiles);
  2471. Message(cString, -1, NULL);
  2472. WriteStringToLogFile(cString);
  2473. _stprintf(cString, TEXT("Avg. File Size = %7ld.%ld kb"), (int)VolData.AveFileSize / 1024, (10 * (VolData.AveFileSize % 1024)) / 1024);
  2474. Message(cString, -1, NULL);
  2475. WriteStringToLogFile(cString);
  2476. _stprintf(cString, TEXT("Fragmented Files = %I64d"), VolData.NumFraggedFiles);
  2477. Message(cString, -1, NULL);
  2478. WriteStringToLogFile(cString);
  2479. _stprintf(cString, TEXT("Excess Fragments = %I64d"), VolData.NumExcessFrags);
  2480. Message(cString, -1, NULL);
  2481. WriteStringToLogFile(cString);
  2482. if (VolData.TotalClusters - VolData.UsedClusters){
  2483. iTmp = (ULONG)(100 * VolData.NumFreeSpaces /
  2484. (VolData.TotalClusters - VolData.UsedClusters));
  2485. }
  2486. else {
  2487. iTmp = -1;
  2488. }
  2489. _stprintf(cString, TEXT("Free Space Fragmention Percent = %ld"), iTmp);
  2490. Message(cString, -1, NULL);
  2491. WriteStringToLogFile(cString);
  2492. _stprintf(cString, TEXT("Fragged Space = %I64d bytes"), VolData.FraggedSpace);
  2493. Message(cString, -1, NULL);
  2494. WriteStringToLogFile(cString);
  2495. _stprintf(cString, TEXT("File Fragmention Percent = %I64d"), VolData.PercentDiskFragged);
  2496. Message(cString, S_OK, NULL);
  2497. WriteStringToLogFile(cString);
  2498. ULONG ulTotalFragFileMoves = 0;
  2499. ULONG ulTotalFragFileFail = 0;
  2500. ULONG ulTotalFragFilePass = 0;
  2501. ULONG ulTotalContigFileMoves = 0;
  2502. ULONG ulTotalContigFileFail = 0;
  2503. ULONG ulTotalContigFilePass = 0;
  2504. if (uEngineState == DEFRAG_STATE_DEFRAGMENTING){ // do not display the post-analysis stats (they're all 0)
  2505. WriteStringToLogFile(TEXT("Statistics by Pass"));
  2506. Message(TEXT("Statistics by Pass"), -1, NULL);
  2507. for (UINT uPass=0; uPass<PASS_COUNT; uPass++){
  2508. ulTotalFragFileMoves += VolData.FragmentedFileMovesAttempted[uPass];
  2509. ulTotalFragFileFail += VolData.FragmentedFileMovesFailed[uPass];
  2510. ulTotalFragFilePass += VolData.FragmentedFileMovesSucceeded[uPass];
  2511. ulTotalContigFileMoves += VolData.ContiguousFileMovesAttempted[uPass];
  2512. ulTotalContigFileFail += VolData.ContiguousFileMovesFailed[uPass];
  2513. ulTotalContigFilePass += VolData.ContiguousFileMovesSucceeded[uPass];
  2514. _stprintf(cString, TEXT("Pass %d:"), uPass+1);
  2515. Message(cString, -1, NULL);
  2516. WriteStringToLogFile(cString);
  2517. _stprintf(cString, TEXT(" Total Volume Buffer Flushes = %5d"), VolData.VolumeBufferFlushes[uPass]);
  2518. Message(cString, -1, NULL);
  2519. WriteStringToLogFile(cString);
  2520. WriteStringToLogFile(TEXT(""));
  2521. _stprintf(cString, TEXT(" Fragmented File Moves Attempted = %5d"),
  2522. VolData.FragmentedFileMovesAttempted[uPass]);
  2523. Message(cString, -1, NULL);
  2524. WriteStringToLogFile(cString);
  2525. if (VolData.FragmentedFileMovesAttempted[uPass]){
  2526. _stprintf(cString, TEXT(" Fragmented File Moves Succeeded = %5d, %3d%%"),
  2527. VolData.FragmentedFileMovesSucceeded[uPass],
  2528. 100 * VolData.FragmentedFileMovesSucceeded[uPass] / VolData.FragmentedFileMovesAttempted[uPass]);
  2529. Message(cString, -1, NULL);
  2530. WriteStringToLogFile(cString);
  2531. _stprintf(cString, TEXT(" Fragmented File Moves Failed = %5d, %3d%%"),
  2532. VolData.FragmentedFileMovesFailed[uPass],
  2533. 100 * VolData.FragmentedFileMovesFailed[uPass] / VolData.FragmentedFileMovesAttempted[uPass]);
  2534. Message(cString, -1, NULL);
  2535. WriteStringToLogFile(cString);
  2536. }
  2537. WriteStringToLogFile(TEXT(""));
  2538. _stprintf(cString, TEXT(" Contiguous File Moves Attempted = %5d"),
  2539. VolData.ContiguousFileMovesAttempted[uPass]);
  2540. Message(cString, -1, NULL);
  2541. WriteStringToLogFile(cString);
  2542. if (VolData.ContiguousFileMovesAttempted[uPass]){
  2543. _stprintf(cString, TEXT(" Contiguous File Moves Succeeded = %5d, %3d%%"),
  2544. VolData.ContiguousFileMovesSucceeded[uPass],
  2545. 100 * VolData.ContiguousFileMovesSucceeded[uPass] / VolData.ContiguousFileMovesAttempted[uPass]);
  2546. Message(cString, -1, NULL);
  2547. WriteStringToLogFile(cString);
  2548. _stprintf(cString, TEXT(" Contiguous File Moves Failed = %5d, %3d%%"),
  2549. VolData.ContiguousFileMovesFailed[uPass],
  2550. 100 * VolData.ContiguousFileMovesFailed[uPass] / VolData.ContiguousFileMovesAttempted[uPass]);
  2551. Message(cString, -1, NULL);
  2552. WriteStringToLogFile(cString);
  2553. }
  2554. }
  2555. Message(TEXT("Totals:"), -1, NULL);
  2556. WriteStringToLogFile(TEXT("Totals:"));
  2557. _stprintf(cString, TEXT(" Total File Moves Attempted = %5d"), ulTotalFragFileMoves + ulTotalContigFileMoves);
  2558. Message(cString, -1, NULL);
  2559. WriteStringToLogFile(cString);
  2560. if (VolData.TotalDirs + VolData.TotalFiles > 0){
  2561. _stprintf(cString, TEXT(" File Moves Attempted/File = %3d%%"),
  2562. 100 * (ulTotalFragFileMoves + ulTotalContigFileMoves) / (VolData.TotalDirs + VolData.TotalFiles));
  2563. Message(cString, -1, NULL);
  2564. WriteStringToLogFile(cString);
  2565. }
  2566. _stprintf(cString, TEXT(" Fragmented File Moves Attempted = %5d"), ulTotalFragFileMoves);
  2567. Message(cString, -1, NULL);
  2568. WriteStringToLogFile(cString);
  2569. if (ulTotalFragFileMoves){
  2570. _stprintf(cString, TEXT(" Fragmented File Moves Succeeded = %5d, %3d%%"),
  2571. ulTotalFragFilePass,
  2572. 100 * ulTotalFragFilePass / ulTotalFragFileMoves);
  2573. Message(cString, -1, NULL);
  2574. WriteStringToLogFile(cString);
  2575. _stprintf(cString, TEXT(" Fragmented File Moves Failed = %5d, %3d%%"),
  2576. ulTotalFragFileFail,
  2577. 100 * ulTotalFragFileFail / ulTotalFragFileMoves);
  2578. Message(cString, -1, NULL);
  2579. WriteStringToLogFile(cString);
  2580. }
  2581. WriteStringToLogFile(TEXT(""));
  2582. _stprintf(cString, TEXT(" Contiguous File Moves Attempted = %5d"), ulTotalContigFileMoves);
  2583. Message(cString, -1, NULL);
  2584. WriteStringToLogFile(cString);
  2585. if (ulTotalContigFileMoves){
  2586. _stprintf(cString, TEXT(" Contiguous File Moves Succeeded = %5d, %3d%%"),
  2587. ulTotalContigFilePass,
  2588. 100 * ulTotalContigFilePass / ulTotalContigFileMoves);
  2589. Message(cString, -1, NULL);
  2590. WriteStringToLogFile(cString);
  2591. _stprintf(cString, TEXT(" Contiguous File Moves Failed = %5d, %3d%%"),
  2592. ulTotalContigFileFail,
  2593. 100 * ulTotalContigFileFail / ulTotalContigFileMoves);
  2594. Message(cString, -1, NULL);
  2595. WriteStringToLogFile(cString);
  2596. }
  2597. }
  2598. // time data
  2599. _stprintf(cString, TEXT("Start Time = %s"), GetTmpTimeString(VolData.StartTime));
  2600. Message(cString, S_OK, NULL);
  2601. WriteStringToLogFile(cString);
  2602. _stprintf(cString, TEXT("End Time = %s"), GetTmpTimeString(VolData.EndTime));
  2603. Message(cString, S_OK, NULL);
  2604. WriteStringToLogFile(cString);
  2605. DWORD dwSeconds;
  2606. if (GetDeltaTime(&VolData.StartTime, &VolData.EndTime, &dwSeconds)){
  2607. _stprintf(cString, TEXT("Delta Time = %d seconds"), dwSeconds);
  2608. Message(cString, S_OK, NULL);
  2609. WriteStringToLogFile(cString);
  2610. }
  2611. WriteStringToLogFile(L"------------- End of Log --------------");
  2612. Message(TEXT(""), -1, NULL);
  2613. }
  2614. /*****************************************************************************************************************
  2615. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2616. ROUTINE DESCRIPTION:
  2617. Displays data about the current file for the developer.
  2618. INPUT + OUTPUT:
  2619. None.
  2620. GLOBALS:
  2621. IN Various VolData fields.
  2622. RETURN:
  2623. None.
  2624. */
  2625. VOID
  2626. DisplayFatFileSpecsFunction(
  2627. )
  2628. {
  2629. TCHAR cString[200];
  2630. Message(TEXT(""), -1, NULL);
  2631. // Display File Name, number of extents and number of fragments.
  2632. Message(ESICompressFilePath(VolData.vFileName), -1, NULL);
  2633. wsprintf(cString, TEXT("Extents = 0x%lX "), ((FILE_EXTENT_HEADER*)VolData.pExtentList)->ExcessExtents);
  2634. Message(cString, -1, NULL);
  2635. wsprintf(cString,
  2636. TEXT("%s %s at Lcn 0x%lX for Cluster Count of 0x%lX"),
  2637. (VolData.bFragmented == TRUE) ? TEXT("Fragmented") : TEXT("Contiguous"),
  2638. (VolData.bDirectory) ? TEXT("Directory") : TEXT("File"),
  2639. (ULONG)VolData.StartingLcn,
  2640. (ULONG)VolData.NumberOfClusters);
  2641. Message(cString, -1, NULL);
  2642. }
  2643. /****************************************************************************************************************
  2644. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2645. ROUTINE DESCRIPTION:
  2646. Allocates memory for the file lists.
  2647. INPUT + OUTPUT:
  2648. None.
  2649. GLOBALS:
  2650. IN VolData.SysListSize - System file list.
  2651. OUT VolData.hSysList
  2652. OUT VolData.pSysList
  2653. IN VolData.DirListSize - Directory file list.
  2654. OUT VolData.hDirList
  2655. OUT VolData.pDirList
  2656. IN VolData.ContiguousListSize - Contiguous file list.
  2657. OUT VolData.hContiguousList
  2658. OUT VolData.pContiguousList
  2659. IN VolData.PagefileListSize - Page file list.
  2660. OUT VolData.hPagefileList
  2661. OUT VolData.pPagefileList
  2662. IN VolData.NameListSize - The name list is only used by the FAT engine, but this is a common routine.
  2663. OUT VolData.hNameList
  2664. OUT VolData.pNameList
  2665. RETURN:
  2666. TRUE - Success.
  2667. FALSE - Fatal Error.
  2668. */
  2669. BOOL
  2670. AllocateFileLists(
  2671. )
  2672. {
  2673. TCHAR cString[300];
  2674. if(VolData.SysListSize>0){ // this is never > 0 for FAT
  2675. wsprintf(cString, TEXT("SysList - Allocating %x bytes"), VolData.SysListSize);
  2676. Message(cString, -1, NULL);
  2677. if (!AllocateMemory(VolData.SysListSize, &VolData.hSysList,(void**)&VolData.pSysList)) {
  2678. EF(FALSE);
  2679. }
  2680. }
  2681. if(VolData.MoveableFileListSize>0){
  2682. wsprintf(cString, TEXT("MoveableFileList - Allocating %x bytes"), VolData.MoveableFileListSize);
  2683. Message(cString, -1, NULL);
  2684. if (!AllocateMemory(VolData.MoveableFileListSize, &VolData.hMoveableFileList, (void**)&VolData.pMoveableFileList)) {
  2685. EF(FALSE);
  2686. }
  2687. }
  2688. if(VolData.PagefileListSize>0){
  2689. wsprintf(cString, TEXT("PagefileList - Allocating %x bytes"), VolData.PagefileListSize);
  2690. Message(cString, -1, NULL);
  2691. if (!AllocateMemory(VolData.PagefileListSize, &VolData.hPagefileList, (void**)&VolData.pPagefileList)) {
  2692. EF(FALSE);
  2693. }
  2694. }
  2695. if(VolData.NameListSize>0){
  2696. wsprintf(cString, TEXT("NameList - Allocating %x bytes"), VolData.NameListSize);
  2697. Message(cString, -1, NULL);
  2698. if (!AllocateMemory(VolData.NameListSize, &VolData.hNameList, (void**)&VolData.pNameList)) {
  2699. EF(FALSE);
  2700. }
  2701. }
  2702. wsprintf(cString, TEXT("File list memories alloced for Drive %s"), VolData.cDisplayLabel);
  2703. Message(cString, S_OK, NULL);
  2704. Message(TEXT(""), -1, NULL);
  2705. return TRUE;
  2706. }
  2707. /****************************************************************************************************************
  2708. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2709. ROUTINE DESCRIPTION:
  2710. Deallocates the mapping files for the file lists.
  2711. INPUT + OUTPUT:
  2712. None.
  2713. GLOBALS:
  2714. Similar to AllocateFileLists above.
  2715. RETURN:
  2716. TRUE - Success.
  2717. FALSE - Fatal Error.
  2718. */
  2719. BOOL
  2720. DeallocateFileLists(
  2721. )
  2722. {
  2723. TCHAR cString[200];
  2724. if(VolData.hSysList){
  2725. EH_ASSERT(GlobalUnlock(VolData.hSysList) == FALSE);
  2726. EH_ASSERT(GlobalFree(VolData.hSysList) == NULL);
  2727. VolData.hSysList = NULL;
  2728. VolData.pSysList = NULL;
  2729. }
  2730. if(VolData.hMoveableFileList){
  2731. EH_ASSERT(GlobalUnlock(VolData.hMoveableFileList) == FALSE);
  2732. EH_ASSERT(GlobalFree(VolData.hMoveableFileList) == NULL);
  2733. VolData.hMoveableFileList = NULL;
  2734. VolData.pMoveableFileList = NULL;
  2735. }
  2736. if(VolData.hPagefileList){
  2737. EH_ASSERT(GlobalUnlock(VolData.hPagefileList) == FALSE);
  2738. EH_ASSERT(GlobalFree(VolData.hPagefileList) == NULL);
  2739. VolData.hPagefileList = NULL;
  2740. VolData.pPagefileList = NULL;
  2741. }
  2742. if(VolData.hNameList){
  2743. EH_ASSERT(GlobalUnlock(VolData.hNameList) == FALSE);
  2744. EH_ASSERT(GlobalFree(VolData.hNameList) == NULL);
  2745. VolData.hNameList = NULL;
  2746. VolData.pNameList = NULL;
  2747. }
  2748. wsprintf(cString, TEXT("Shared memory freed for Drive %s:"), VolData.cDisplayLabel);
  2749. Message(cString, -1, NULL);
  2750. return TRUE;
  2751. }
  2752. /****************************************************************************************************************
  2753. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2754. ROUTINE DESCRIPTION:
  2755. INPUT + OUTPUT:
  2756. GLOBALS:
  2757. RETURN:
  2758. TRUE - Success.
  2759. FALSE - Fatal error.
  2760. */
  2761. BOOL
  2762. SendMostFraggedList(
  2763. )
  2764. {
  2765. CFraggedFileList fraggedFileList(VolData.cVolumeName);
  2766. // Build the most fragged list.
  2767. EF(FillMostFraggedList(fraggedFileList));
  2768. // create the block of data to send to UI
  2769. EF(fraggedFileList.CreateTransferBuffer());
  2770. // Send the packet to the UI.
  2771. DataIoClientSetData(
  2772. ID_FRAGGED_DATA,
  2773. fraggedFileList.GetTransferBuffer(),
  2774. fraggedFileList.GetTransferBufferSize(),
  2775. pdataDfrgCtl);
  2776. return TRUE;
  2777. }
  2778. /*****************************************************************************************************************
  2779. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2780. ROUTINE DESCRIPTION:
  2781. INPUT + OUTPUT:
  2782. RETURN:
  2783. None.
  2784. */
  2785. VOID
  2786. SendStatusData(
  2787. )
  2788. {
  2789. STATUS_DATA statusData = {0};
  2790. //acs bug #101862//
  2791. statusData.dwPass = uPass;
  2792. _tcsncpy(statusData.cVolumeName, VolData.cVolumeName,GUID_LENGTH);
  2793. statusData.dwPercentDone = (uPercentDone > 100 ? 100 : uPercentDone);
  2794. statusData.dwEngineState = uEngineState;
  2795. if(VolData.vFileName.GetLength() > 0)
  2796. {
  2797. _tcsncpy(statusData.vsFileName, VolData.vFileName.GetBuffer(),200);
  2798. }
  2799. //If the gui is connected, send gui data to it.
  2800. DataIoClientSetData(ID_STATUS, (TCHAR*)&statusData, sizeof(STATUS_DATA), pdataDfrgCtl);
  2801. }
  2802. /*****************************************************************************************************************
  2803. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2804. ROUTINE DESCRIPTION:
  2805. INPUT + OUTPUT:
  2806. RETURN:
  2807. None.
  2808. */
  2809. VOID
  2810. SendReportData(
  2811. )
  2812. {
  2813. TEXT_DATA textData = {0};
  2814. _tcscpy(textData.cVolumeName, VolData.cVolumeName);
  2815. _tcscpy(textData.cVolumeLabel, VolData.cVolumeLabel);
  2816. if(VolData.FileSystem == FS_FAT32){
  2817. _tcscpy(textData.cFileSystem, TEXT("FAT32"));
  2818. }
  2819. else{
  2820. _tcscpy(textData.cFileSystem, TEXT("FAT"));
  2821. }
  2822. //Figure out how many free spaces there are on the drive.
  2823. CountFreeSpaces();
  2824. // get usable free space
  2825. LONGLONG llUsableFreeClusters;
  2826. if (DetermineUsableFreespace(&llUsableFreeClusters)){
  2827. VolData.UsableFreeSpace = llUsableFreeClusters * VolData.BytesPerCluster;
  2828. }
  2829. else{
  2830. VolData.UsableFreeSpace = VolData.FreeSpace;
  2831. }
  2832. //Fill in all the TEXT_DATA fields for the UI's text display.
  2833. textData.DiskSize = VolData.TotalClusters * VolData.BytesPerCluster;
  2834. textData.BytesPerCluster = VolData.BytesPerCluster;
  2835. textData.UsedSpace = VolData.UsedClusters * VolData.BytesPerCluster;
  2836. textData.FreeSpace = (VolData.TotalClusters - VolData.UsedClusters) *
  2837. VolData.BytesPerCluster;
  2838. EV_ASSERT(VolData.TotalClusters);
  2839. textData.FreeSpacePercent = 100 * (VolData.TotalClusters - VolData.UsedClusters) /
  2840. VolData.TotalClusters;
  2841. textData.UsableFreeSpace = textData.FreeSpace;
  2842. textData.UsableFreeSpacePercent = textData.FreeSpacePercent;
  2843. textData.PagefileBytes = VolData.PagefileSize;
  2844. textData.PagefileFrags = __max(VolData.PagefileFrags, 0);
  2845. textData.TotalDirectories = __max(VolData.TotalDirs, 1);
  2846. textData.FragmentedDirectories = __max(VolData.NumFraggedDirs, 1);
  2847. textData.ExcessDirFrags = __max(VolData.NumExcessDirFrags, 0);
  2848. textData.TotalFiles = VolData.TotalFiles;
  2849. textData.AvgFileSize = VolData.AveFileSize;
  2850. textData.NumFraggedFiles = __max(VolData.NumFraggedFiles, 0);
  2851. textData.NumExcessFrags = __max(VolData.NumExcessFrags, 0);
  2852. textData.PercentDiskFragged = VolData.PercentDiskFragged;
  2853. if(VolData.TotalFiles){
  2854. textData.AvgFragsPerFile = (VolData.NumExcessFrags + VolData.TotalFiles) * 100 /
  2855. (VolData.TotalFiles);
  2856. }
  2857. textData.MFTBytes = VolData.MftSize;
  2858. textData.InUseMFTRecords = VolData.InUseFileRecords;
  2859. textData.MFTExtents = VolData.MftNumberOfExtents;
  2860. if(VolData.TotalClusters - VolData.UsedClusters){
  2861. if(VolData.NumFreeSpaces){
  2862. textData.FreeSpaceFragPercent = 100 * VolData.NumFreeSpaces /
  2863. (VolData.TotalClusters - VolData.UsedClusters);
  2864. }
  2865. }
  2866. //If the gui is connected, send gui data to it.
  2867. DataIoClientSetData(ID_REPORT_TEXT_DATA, (TCHAR*)&textData, sizeof(TEXT_DATA),
  2868. pdataDfrgCtl);
  2869. }
  2870. /*****************************************************************************************************************
  2871. COPYRIGHT 2001 Microsoft Corporation and Executive Software International, Inc.
  2872. ROUTINE DESCRIPTION:
  2873. INPUT + OUTPUT:
  2874. RETURN:
  2875. None.
  2876. */
  2877. void SendGraphicsMemoryErr()
  2878. {
  2879. // don't need to send any data
  2880. NOT_DATA NotData;
  2881. _tcscpy(NotData.cVolumeName, VolData.cVolumeName);
  2882. // if the gui is connected, send gui data to it.
  2883. Message(TEXT("engine sending ID_NO_GRAPHICS_MEMORY"), -1, NULL);
  2884. DataIoClientSetData(ID_NO_GRAPHICS_MEMORY, (PTCHAR) &NotData, sizeof(NOT_DATA),
  2885. pdataDfrgCtl);
  2886. }
  2887. // send error code to client
  2888. // (for command line mode)
  2889. VOID SendErrData(PTCHAR pErrText, DWORD ErrCode)
  2890. {
  2891. static BOOL FirstTime = TRUE;
  2892. // only send the first error
  2893. if (FirstTime)
  2894. {
  2895. // prepare COM message for client
  2896. ERROR_DATA ErrData = {0};
  2897. _tcscpy(ErrData.cVolumeName, VolData.cVolumeName);
  2898. ErrData.dwErrCode = ErrCode;
  2899. if (pErrText != NULL)
  2900. {
  2901. _tcsncpy(ErrData.cErrText, pErrText, 999);
  2902. ErrData.cErrText[999] = TEXT('\0');
  2903. }
  2904. // send COM message to client
  2905. DataIoClientSetData(ID_ERROR, (TCHAR*) &ErrData, sizeof(ERROR_DATA), pdataDfrgCtl);
  2906. // write the error to the error log.
  2907. if (bLogFile && pErrText != NULL)
  2908. {
  2909. WriteErrorToErrorLog(pErrText, -1, NULL);
  2910. }
  2911. // only one error
  2912. FirstTime = FALSE;
  2913. }
  2914. }