├── JkDefrag
├── JkDefrag2005.vcproj
├── JkDefrag2008.vcproj
├── Manifest
│ └── JkDefrag.manifest
├── Resource
│ ├── JkDefrag.aps
│ ├── JkDefrag.ico
│ ├── JkDefrag.rc
│ └── resource.h
└── Source
│ ├── JKDefrag.h
│ ├── JKDefragLog.cpp
│ ├── JKDefragLog.h
│ ├── JKDefragStruct.cpp
│ ├── JKDefragStruct.h
│ ├── JkDefrag.cpp
│ ├── JkDefragGui.cpp
│ ├── JkDefragGui.h
│ ├── JkDefragLib.cpp
│ ├── JkDefragLib.h
│ ├── ScanFat.cpp
│ ├── ScanFat.h
│ ├── ScanNtfs.cpp
│ ├── ScanNtfs.h
│ ├── StdAfx.cpp
│ └── StdAfx.h
├── JkDefrag2005.sln
├── JkDefrag2008.sln
├── LICENSE
└── README.md
/JkDefrag/JkDefrag2005.vcproj:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
26 |
29 |
32 |
35 |
38 |
41 |
54 |
57 |
60 |
63 |
73 |
76 |
79 |
82 |
85 |
88 |
91 |
94 |
95 |
103 |
106 |
109 |
112 |
115 |
118 |
127 |
130 |
133 |
136 |
148 |
151 |
154 |
157 |
160 |
163 |
166 |
169 |
170 |
171 |
172 |
173 |
174 |
179 |
182 |
183 |
186 |
187 |
190 |
191 |
194 |
195 |
198 |
199 |
202 |
203 |
206 |
207 |
210 |
213 |
217 |
218 |
221 |
225 |
226 |
227 |
228 |
233 |
236 |
237 |
240 |
241 |
244 |
245 |
248 |
249 |
252 |
253 |
256 |
257 |
260 |
261 |
264 |
265 |
266 |
269 |
272 |
273 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
--------------------------------------------------------------------------------
/JkDefrag/JkDefrag2008.vcproj:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
15 |
16 |
17 |
18 |
19 |
26 |
29 |
32 |
35 |
38 |
41 |
54 |
57 |
60 |
63 |
73 |
76 |
79 |
82 |
85 |
88 |
91 |
94 |
95 |
103 |
106 |
109 |
112 |
115 |
118 |
127 |
130 |
133 |
136 |
148 |
151 |
154 |
157 |
160 |
163 |
166 |
169 |
170 |
171 |
172 |
173 |
174 |
179 |
182 |
183 |
186 |
187 |
190 |
191 |
194 |
195 |
198 |
199 |
202 |
203 |
206 |
207 |
210 |
213 |
217 |
218 |
221 |
225 |
226 |
227 |
228 |
233 |
236 |
237 |
240 |
241 |
244 |
245 |
248 |
249 |
252 |
253 |
256 |
257 |
260 |
261 |
264 |
265 |
266 |
269 |
272 |
273 |
276 |
277 |
278 |
279 |
280 |
281 |
282 |
--------------------------------------------------------------------------------
/JkDefrag/Manifest/JkDefrag.manifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/JkDefrag/Resource/JkDefrag.aps:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dasmurphy/JKDefrag-Original/4e8e60e9eb0108a740b46e7e775776547642b0cd/JkDefrag/Resource/JkDefrag.aps
--------------------------------------------------------------------------------
/JkDefrag/Resource/JkDefrag.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/dasmurphy/JKDefrag-Original/4e8e60e9eb0108a740b46e7e775776547642b0cd/JkDefrag/Resource/JkDefrag.ico
--------------------------------------------------------------------------------
/JkDefrag/Resource/JkDefrag.rc:
--------------------------------------------------------------------------------
1 | // Microsoft Visual C++ generated resource script.
2 | //
3 | #include "resource.h"
4 |
5 | #define APSTUDIO_READONLY_SYMBOLS
6 | /////////////////////////////////////////////////////////////////////////////
7 | //
8 | // Generated from the TEXTINCLUDE 2 resource.
9 | //
10 | #include "afxres.h"
11 |
12 | /////////////////////////////////////////////////////////////////////////////
13 | #undef APSTUDIO_READONLY_SYMBOLS
14 |
15 | /////////////////////////////////////////////////////////////////////////////
16 | // Neutral resources
17 |
18 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
19 | #ifdef _WIN32
20 | LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
21 | #pragma code_page(1252)
22 | #endif //_WIN32
23 |
24 | /////////////////////////////////////////////////////////////////////////////
25 | //
26 | // Dialog
27 | //
28 |
29 | DLG_SCRNSAVECONFIGURE DIALOG 6, 18, 200, 147
30 | STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU
31 | CAPTION "JkDefrag screensaver setup"
32 | FONT 8, "MS Shell Dlg"
33 | BEGIN
34 | CTEXT "JkDefrag screensaver v3.36",1001,0,2,200,8
35 | LTEXT "Commandline options (optional):",1002,6,20,170,8
36 | EDITTEXT 1003,5,30,189,13,ES_AUTOHSCROLL
37 | LTEXT "Screensaver to run after JkDefrag has finished:",1004,5,51,180,8
38 | COMBOBOX 1005,5,60,135,200,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
39 | PUSHBUTTON "Settings...",1006,144,60,51,13
40 | LTEXT "Do not defrag if last run was less than",1007,5,85,180,8
41 | COMBOBOX 1008,127,83,30,200,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
42 | LTEXT "hours ago.",1009,160,85,50,8
43 | LTEXT "Status bar:",1010,5,107,50,8
44 | COMBOBOX 1011,45,105,150,200,CBS_DROPDOWNLIST | CBS_SORT | WS_VSCROLL | WS_TABSTOP
45 | PUSHBUTTON "OK",1012,80,128,40,13
46 | END
47 |
48 |
49 | /////////////////////////////////////////////////////////////////////////////
50 | //
51 | // String Table
52 | //
53 |
54 | STRINGTABLE
55 | BEGIN
56 | 1 "JkDefrag screensaver"
57 | IDS_STRING2 "Version 2.2"
58 | END
59 |
60 | #endif // Neutral resources
61 | /////////////////////////////////////////////////////////////////////////////
62 |
63 |
64 | /////////////////////////////////////////////////////////////////////////////
65 | // English (U.S.) resources
66 |
67 | #if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
68 | #ifdef _WIN32
69 | LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
70 | #pragma code_page(1252)
71 | #endif //_WIN32
72 |
73 | /////////////////////////////////////////////////////////////////////////////
74 | //
75 | // Icon
76 | //
77 |
78 | // Icon with lowest ID value placed first to ensure application icon
79 | // remains consistent on all systems.
80 | 1 ICON "jkdefrag.ico"
81 |
82 | /////////////////////////////////////////////////////////////////////////////
83 | //
84 | // Version
85 | //
86 |
87 | 1 VERSIONINFO
88 | FILEVERSION 3,36,0,2
89 | PRODUCTVERSION 3,36,0,2
90 | FILEFLAGSMASK 0x0L
91 | #ifdef _DEBUG
92 | FILEFLAGS 0x1L
93 | #else
94 | FILEFLAGS 0x0L
95 | #endif
96 | FILEOS 0x0L
97 | FILETYPE 0x0L
98 | FILESUBTYPE 0x0L
99 | BEGIN
100 | BLOCK "StringFileInfo"
101 | BEGIN
102 | BLOCK "040904e4"
103 | BEGIN
104 | VALUE "ProductName", "JkDefrag"
105 | VALUE "ProductVersion", "3.36"
106 | VALUE "LegalCopyright", "GNU General Public License"
107 | VALUE "CompanyName", "J.C. Kessels"
108 | VALUE "FileDescription", "JkDefrag - disk defragmentation and optimization tool"
109 | VALUE "FileVersion", "3.36"
110 | VALUE "InternalName", "JkDefrag"
111 | VALUE "OriginalFilename", "JkDefrag.exe"
112 | END
113 | END
114 | BLOCK "VarFileInfo"
115 | BEGIN
116 | VALUE "Translation", 0x409, 1252
117 | END
118 | END
119 |
120 |
121 | #ifdef APSTUDIO_INVOKED
122 | /////////////////////////////////////////////////////////////////////////////
123 | //
124 | // TEXTINCLUDE
125 | //
126 |
127 | 1 TEXTINCLUDE
128 | BEGIN
129 | "resource.\0"
130 | END
131 |
132 |
133 | 3 TEXTINCLUDE
134 | BEGIN
135 | "\r\0"
136 | END
137 |
138 | #endif // APSTUDIO_INVOKED
139 |
140 | #endif // English (U.S.) resources
141 | /////////////////////////////////////////////////////////////////////////////
142 |
143 |
144 |
145 | #ifndef APSTUDIO_INVOKED
146 | /////////////////////////////////////////////////////////////////////////////
147 | //
148 | // Generated from the TEXTINCLUDE 3 resource.
149 | //
150 |
151 |
152 | /////////////////////////////////////////////////////////////////////////////
153 | #endif // not APSTUDIO_INVOKED
154 |
155 |
--------------------------------------------------------------------------------
/JkDefrag/Source/JKDefrag.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef JKDEFRAG
3 | #define JKDEFRAG
4 |
5 | class JKDefrag
6 | {
7 | public:
8 | JKDefrag();
9 | ~JKDefrag();
10 |
11 | // Get instance of the class
12 | static JKDefrag *getInstance();
13 | static void releaseInstance();
14 |
15 | WPARAM startProgram(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow);
16 |
17 | static DWORD WINAPI DefragThread(LPVOID);
18 |
19 | #ifdef _DEBUG
20 |
21 | static LONG __stdcall CrashReport(EXCEPTION_POINTERS *ExceptionInfo);
22 |
23 | #endif
24 |
25 | int AlreadyRunning(void);
26 |
27 | protected:
28 | private:
29 | int Running; /* If not RUNNING then stop defragging. */
30 | int IamRunning;
31 |
32 | /* Debug level.
33 | 0: Fatal errors.
34 | 1: Warning messages.
35 | 2: General progress messages.
36 | 3: Detailed progress messages.
37 | 4: Detailed file information.
38 | 5: Detailed gap-filling messages.
39 | 6: Detailed gap-finding messages.
40 | */
41 | int Debug;
42 |
43 | JKDefragGui *m_jkGui;
44 | JKDefragLib *m_jkLib;
45 | JKDefragLog *m_jkLog;
46 | JKDefragStruct *m_jkStruct;
47 |
48 | // static member that is an instance of itself
49 | static JKDefrag *m_jkDefrag;
50 | };
51 |
52 | #endif
--------------------------------------------------------------------------------
/JkDefrag/Source/JKDefragLog.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 |
3 | JKDefragLog::JKDefragLog()
4 | {
5 | WCHAR *p1;
6 |
7 | m_jkLib = JKDefragLib::getInstance();
8 |
9 | GetModuleFileNameW(NULL,MyName,MAX_PATH);
10 | GetShortPathNameW(MyName,MyShortName,MAX_PATH);
11 | GetLongPathNameW(MyShortName,MyName,MAX_PATH);
12 |
13 | /* Determine default path to logfile. */
14 | swprintf_s(LogFile,MAX_PATH,L"%s",MyName);
15 |
16 | p1 = m_jkLib->stristrW(LogFile,L".exe");
17 |
18 | if (p1 == NULL) p1 = m_jkLib->stristrW(LogFile,L".scr");
19 |
20 | if (p1 != NULL)
21 | {
22 | *p1 = '\0';
23 |
24 | wcscat_s(LogFile,MAX_PATH,L".log");
25 | _wunlink(LogFile);
26 |
27 | }
28 | else
29 | {
30 | *LogFile = '\0';
31 | }
32 | }
33 |
34 | void JKDefragLog::SetLogFilename(WCHAR *fileName)
35 | {
36 | /* Determine default path to logfile. */
37 | swprintf_s(LogFile,MAX_PATH,L"%s",fileName);
38 | _wunlink(LogFile);
39 | }
40 |
41 | WCHAR *JKDefragLog::GetLogFilename()
42 | {
43 | return LogFile;
44 | }
45 |
46 | /* Write a text to the logfile. The parameters are the same as for the "printf"
47 | functions, a Format string and a series of parameters. */
48 | void JKDefragLog::LogMessage(WCHAR *Format, ...)
49 | {
50 | va_list VarArgs;
51 | FILE *Fout;
52 | int Result;
53 | time_t Now;
54 | struct tm NowTm;
55 |
56 | /* If there is no message then return. */
57 | if (Format == NULL) return;
58 |
59 | /* If there is no logfile then return. */
60 | if (*LogFile == '\0') return;
61 |
62 | /* Open the logfile. */
63 | Result = _wfopen_s(&Fout,LogFile,L"a, ccs=UTF-8");
64 | if ((Result != 0) || (Fout == NULL)) return;
65 |
66 | /* Write the string to the logfile. */
67 | time(&Now);
68 | Result = localtime_s(&NowTm,&Now);
69 | fwprintf_s(Fout,L"%02lu:%02lu:%02lu ",NowTm.tm_hour,NowTm.tm_min,NowTm.tm_sec);
70 | va_start(VarArgs,Format);
71 | vfwprintf_s(Fout,Format,VarArgs);
72 | va_end(VarArgs);
73 | fwprintf_s(Fout,L"\n");
74 |
75 | /* Close the logfile. */
76 | fflush(Fout);
77 | fclose(Fout);
78 | }
79 |
80 |
--------------------------------------------------------------------------------
/JkDefrag/Source/JKDefragLog.h:
--------------------------------------------------------------------------------
1 | #ifndef __JKDEFRAGLOG_H__
2 | #define __JKDEFRAGLOG_H__
3 |
4 | class JKDefragLog
5 | {
6 | public:
7 | JKDefragLog();
8 | void LogMessage(WCHAR *Format, ...);
9 | void SetLogFilename(WCHAR *fileName);
10 |
11 | WCHAR MyName[MAX_PATH];
12 | WCHAR MyShortName[MAX_PATH];
13 |
14 | WCHAR *GetLogFilename();
15 |
16 | protected:
17 | private:
18 | WCHAR LogFile[MAX_PATH];
19 |
20 | JKDefragLib *m_jkLib;
21 | };
22 |
23 | #endif
--------------------------------------------------------------------------------
/JkDefrag/Source/JKDefragStruct.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 |
3 | #include "JKDefragStruct.h"
4 |
5 | JKDefragStruct::JKDefragStruct()
6 | {
7 | wcsncpy_s(VERSIONTEXT, L"JkDefrag 3.36", 100);
8 | }
9 |
10 | JKDefragStruct::~JKDefragStruct()
11 | {
12 | }
--------------------------------------------------------------------------------
/JkDefrag/Source/JKDefragStruct.h:
--------------------------------------------------------------------------------
1 | #ifndef __JKDEFRAGSTRUCT_H__
2 | #define __JKDEFRAGSTRUCT_H__
3 |
4 | /* The colors used by the defragger. */
5 | //#define COLOREMPTY 0 /* Empty diskspace. */
6 | //#define COLORALLOCATED 1 /* Used diskspace / system files. */
7 | //#define COLORUNFRAGMENTED 2 /* Unfragmented files. */
8 | //#define COLORUNMOVABLE 3 /* Unmovable files. */
9 | //#define COLORFRAGMENTED 4 /* Fragmented files. */
10 | //#define COLORBUSY 5 /* Busy color. */
11 | //#define COLORMFT 6 /* MFT reserved zones. */
12 | //#define COLORSPACEHOG 7 /* Spacehogs. */
13 | //#define COLORBACK 8 /* Background color. */
14 |
15 | class JKDefragStruct
16 | {
17 | public:
18 | JKDefragStruct();
19 | ~JKDefragStruct();
20 |
21 | WCHAR VERSIONTEXT[100];
22 |
23 | enum colors {
24 | COLOREMPTY,
25 | COLORALLOCATED,
26 | COLORUNFRAGMENTED,
27 | COLORUNMOVABLE,
28 | COLORFRAGMENTED,
29 | COLORBUSY,
30 | COLORMFT,
31 | COLORSPACEHOG,
32 | COLORBACK
33 | };
34 |
35 | protected:
36 |
37 | private:
38 | };
39 |
40 | #endif
41 |
--------------------------------------------------------------------------------
/JkDefrag/Source/JkDefrag.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | JkDefrag -- Defragment and optimize all harddisks.
3 |
4 | This program is free software; you can redistribute it and/or modify
5 | it under the terms of the GNU General Public License as published by
6 | the Free Software Foundation; either version 2 of the License, or
7 | (at your option) any later version.
8 |
9 | This program is distributed in the hope that it will be useful,
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 | GNU General Public License for more details.
13 |
14 | For the full text of the license see the "License gpl.txt" file.
15 |
16 | Jeroen C. Kessels
17 | Internet Engineer
18 | http://www.kessels.com/
19 | */
20 |
21 | #include "StdAfx.h"
22 |
23 | #include "JKDefrag.h"
24 |
25 | JKDefrag *JKDefrag::m_jkDefrag = 0;
26 |
27 | JKDefrag::JKDefrag()
28 | {
29 | Running = STOPPED;
30 |
31 | Debug = 1;
32 |
33 | m_jkGui = JKDefragGui::getInstance();
34 | m_jkLib = JKDefragLib::getInstance();
35 |
36 | m_jkLog = new JKDefragLog();
37 | m_jkStruct = new JKDefragStruct();
38 | }
39 |
40 | JKDefrag::~JKDefrag()
41 | {
42 | delete m_jkLog;
43 | delete m_jkStruct;
44 |
45 | delete m_jkDefrag;
46 | }
47 |
48 | JKDefrag *JKDefrag::getInstance()
49 | {
50 | if (m_jkDefrag == NULL)
51 | {
52 | m_jkDefrag = new JKDefrag();
53 | }
54 |
55 | return m_jkDefrag;
56 | }
57 |
58 | void JKDefrag::releaseInstance()
59 | {
60 | if (m_jkDefrag != NULL)
61 | {
62 | delete m_jkDefrag;
63 | }
64 | }
65 |
66 | WPARAM JKDefrag::startProgram(HINSTANCE hInstance,
67 | HINSTANCE hPrevInstance,
68 | LPSTR lpCmdLine,
69 | int nCmdShow)
70 | {
71 | IamRunning = RUNNING;
72 |
73 | /* Test if another instance is already running. */
74 | if (AlreadyRunning() == YES) return(0);
75 |
76 | #ifdef _DEBUG
77 | /* Setup crash report handler. */
78 | SetUnhandledExceptionFilter(&JKDefrag::CrashReport);
79 | #endif
80 |
81 | m_jkGui->Initialize(hInstance,nCmdShow, m_jkLog, Debug);
82 |
83 | /* Start up the defragmentation and timer threads. */
84 | if (CreateThread(NULL, 0, &JKDefrag::DefragThread, NULL, 0, NULL) == NULL) return(0);
85 |
86 | WPARAM wParam = m_jkGui->DoModal();
87 |
88 | /* If the defragger is still running then ask & wait for it to stop. */
89 | IamRunning = STOPPED;
90 |
91 | m_jkLib->StopJkDefrag(&Running,0);
92 |
93 | return wParam;
94 | }
95 |
96 |
97 | #ifdef _DEBUG
98 |
99 | /*
100 |
101 | Write a crash report to the log.
102 | To test the crash handler add something like this:
103 | char *p1;
104 | p1 = 0;
105 | *p1 = 0;
106 |
107 | */
108 |
109 | LONG __stdcall JKDefrag::CrashReport(EXCEPTION_POINTERS *ExceptionInfo)
110 | {
111 | IMAGEHLP_LINE64 SourceLine;
112 | DWORD LineDisplacement;
113 | STACKFRAME64 StackFrame;
114 | DWORD ImageType;
115 | BOOL Result;
116 | int FrameNumber;
117 | char s1[BUFSIZ];
118 | WCHAR s2[BUFSIZ];
119 |
120 | JKDefragLog *jkLog = m_jkDefrag->m_jkLog;
121 | JKDefragLib *jkLib = m_jkDefrag->m_jkLib;
122 |
123 | /* Exit if we're running inside a debugger. */
124 | // if (IsDebuggerPresent() == TRUE) return(EXCEPTION_EXECUTE_HANDLER);
125 |
126 | jkLog->LogMessage(L"I have crashed!");
127 | jkLog->LogMessage(L" Command line: %s",GetCommandLineW());
128 |
129 | /* Show the type of exception. */
130 | switch(ExceptionInfo->ExceptionRecord->ExceptionCode) {
131 | case EXCEPTION_ACCESS_VIOLATION : strcpy_s(s1,BUFSIZ,"ACCESS_VIOLATION (the memory could not be read or written)"); break;
132 | case EXCEPTION_DATATYPE_MISALIGNMENT : strcpy_s(s1,BUFSIZ,"DATATYPE_MISALIGNMENT (a datatype misalignment error was detected in a load or store instruction)"); break;
133 | case EXCEPTION_BREAKPOINT : strcpy_s(s1,BUFSIZ,"BREAKPOINT"); break;
134 | case EXCEPTION_SINGLE_STEP : strcpy_s(s1,BUFSIZ,"SINGLE_STEP"); break;
135 | case EXCEPTION_ARRAY_BOUNDS_EXCEEDED : strcpy_s(s1,BUFSIZ,"ARRAY_BOUNDS_EXCEEDED"); break;
136 | case EXCEPTION_FLT_DENORMAL_OPERAND : strcpy_s(s1,BUFSIZ,"FLT_DENORMAL_OPERAND"); break;
137 | case EXCEPTION_FLT_DIVIDE_BY_ZERO : strcpy_s(s1,BUFSIZ,"FLT_DIVIDE_BY_ZERO"); break;
138 | case EXCEPTION_FLT_INEXACT_RESULT : strcpy_s(s1,BUFSIZ,"FLT_INEXACT_RESULT"); break;
139 | case EXCEPTION_FLT_INVALID_OPERATION : strcpy_s(s1,BUFSIZ,"FLT_INVALID_OPERATION"); break;
140 | case EXCEPTION_FLT_OVERFLOW : strcpy_s(s1,BUFSIZ,"FLT_OVERFLOW"); break;
141 | case EXCEPTION_FLT_STACK_CHECK : strcpy_s(s1,BUFSIZ,"FLT_STACK_CHECK"); break;
142 | case EXCEPTION_FLT_UNDERFLOW : strcpy_s(s1,BUFSIZ,"FLT_UNDERFLOW"); break;
143 | case EXCEPTION_INT_DIVIDE_BY_ZERO : strcpy_s(s1,BUFSIZ,"INT_DIVIDE_BY_ZERO"); break;
144 | case EXCEPTION_INT_OVERFLOW : strcpy_s(s1,BUFSIZ,"INT_OVERFLOW"); break;
145 | case EXCEPTION_PRIV_INSTRUCTION : strcpy_s(s1,BUFSIZ,"PRIV_INSTRUCTION"); break;
146 | case EXCEPTION_IN_PAGE_ERROR : strcpy_s(s1,BUFSIZ,"IN_PAGE_ERROR"); break;
147 | case EXCEPTION_ILLEGAL_INSTRUCTION : strcpy_s(s1,BUFSIZ,"ILLEGAL_INSTRUCTION"); break;
148 | case EXCEPTION_NONCONTINUABLE_EXCEPTION : strcpy_s(s1,BUFSIZ,"NONCONTINUABLE_EXCEPTION"); break;
149 | case EXCEPTION_STACK_OVERFLOW : strcpy_s(s1,BUFSIZ,"STACK_OVERFLOW"); break;
150 | case EXCEPTION_INVALID_DISPOSITION : strcpy_s(s1,BUFSIZ,"INVALID_DISPOSITION"); break;
151 | case EXCEPTION_GUARD_PAGE : strcpy_s(s1,BUFSIZ,"GUARD_PAGE"); break;
152 | case EXCEPTION_INVALID_HANDLE : strcpy_s(s1,BUFSIZ,"INVALID_HANDLE"); break;
153 | case CONTROL_C_EXIT : strcpy_s(s1,BUFSIZ,"STATUS_CONTROL_C_EXIT"); break;
154 | case DBG_TERMINATE_THREAD : strcpy_s(s1,BUFSIZ,"DBG_TERMINATE_THREAD (Debugger terminated thread)"); break;
155 | case DBG_TERMINATE_PROCESS : strcpy_s(s1,BUFSIZ,"DBG_TERMINATE_PROCESS (Debugger terminated process)"); break;
156 | case DBG_CONTROL_C : strcpy_s(s1,BUFSIZ,"DBG_CONTROL_C (Debugger got control C)"); break;
157 | case DBG_CONTROL_BREAK : strcpy_s(s1,BUFSIZ,"DBG_CONTROL_BREAK (Debugger received control break)"); break;
158 | case DBG_COMMAND_EXCEPTION : strcpy_s(s1,BUFSIZ,"DBG_COMMAND_EXCEPTION (Debugger command communication exception)"); break;
159 | default : strcpy_s(s1,BUFSIZ,"(unknown exception)");
160 | }
161 |
162 | jkLog->LogMessage(L" Exception: %S",s1);
163 |
164 | /* Try to show the linenumber of the sourcefile. */
165 | SymSetOptions(SymGetOptions() || SYMOPT_LOAD_LINES);
166 | Result = SymInitialize(GetCurrentProcess(),NULL,TRUE);
167 |
168 | if (Result == FALSE)
169 | {
170 | jkLib->SystemErrorStr(GetLastError(),s2,BUFSIZ);
171 |
172 | jkLog->LogMessage(L" Failed to initialize SymInitialize(): %s",s2);
173 |
174 | return(EXCEPTION_EXECUTE_HANDLER);
175 | }
176 |
177 | ZeroMemory(&StackFrame,sizeof(StackFrame));
178 |
179 | #ifdef _M_IX86
180 | ImageType = IMAGE_FILE_MACHINE_I386;
181 | StackFrame.AddrPC.Offset = ExceptionInfo->ContextRecord->Eip;
182 | StackFrame.AddrPC.Mode = AddrModeFlat;
183 | StackFrame.AddrFrame.Offset = ExceptionInfo->ContextRecord->Ebp;
184 | StackFrame.AddrFrame.Mode = AddrModeFlat;
185 | StackFrame.AddrStack.Offset = ExceptionInfo->ContextRecord->Esp;
186 | StackFrame.AddrStack.Mode = AddrModeFlat;
187 | #elif _M_X64
188 | ImageType = IMAGE_FILE_MACHINE_AMD64;
189 | StackFrame.AddrPC.Offset = ExceptionInfo->ContextRecord->Rip;
190 | StackFrame.AddrPC.Mode = AddrModeFlat;
191 | StackFrame.AddrFrame.Offset = ExceptionInfo->ContextRecord->Rsp;
192 | StackFrame.AddrFrame.Mode = AddrModeFlat;
193 | StackFrame.AddrStack.Offset = ExceptionInfo->ContextRecord->Rsp;
194 | StackFrame.AddrStack.Mode = AddrModeFlat;
195 | #elif _M_IA64
196 | ImageType = IMAGE_FILE_MACHINE_IA64;
197 | StackFrame.AddrPC.Offset = ExceptionInfo->ContextRecord->StIIP;
198 | StackFrame.AddrPC.Mode = AddrModeFlat;
199 | StackFrame.AddrFrame.Offset = ExceptionInfo->ContextRecord->IntSp;
200 | StackFrame.AddrFrame.Mode = AddrModeFlat;
201 | StackFrame.AddrBStore.Offset = ExceptionInfo->ContextRecord->RsBSP;
202 | StackFrame.AddrBStore.Mode = AddrModeFlat;
203 | StackFrame.AddrStack.Offset = ExceptionInfo->ContextRecord->IntSp;
204 | StackFrame.AddrStack.Mode = AddrModeFlat;
205 | #endif
206 | for (FrameNumber = 1; ; FrameNumber++) {
207 | Result = StackWalk64(ImageType,GetCurrentProcess(),GetCurrentThread(),&StackFrame,
208 | ExceptionInfo->ContextRecord,NULL,SymFunctionTableAccess64,SymGetModuleBase64,NULL);
209 | if (Result == FALSE) break;
210 | if (StackFrame.AddrPC.Offset == StackFrame.AddrReturn.Offset) break;
211 | if (StackFrame.AddrPC.Offset != 0) {
212 | LineDisplacement = 0;
213 | ZeroMemory(&SourceLine,sizeof(SourceLine));
214 | SourceLine.SizeOfStruct = sizeof(SourceLine);
215 | Result = SymGetLineFromAddr64(GetCurrentProcess(),StackFrame.AddrPC.Offset,
216 | &LineDisplacement,&SourceLine);
217 | if (Result == TRUE) {
218 | jkLog->LogMessage(L" %i. At line %d in '%S'",FrameNumber,SourceLine.LineNumber,SourceLine.FileName);
219 | } else {
220 | jkLog->LogMessage(L" %i. At line (unknown) in (unknown)",FrameNumber);
221 | /*
222 | SystemErrorStr(GetLastError(),s2,BUFSIZ);
223 | LogMessage(L" Error executing SymGetLineFromAddr64(): %s",s2);
224 | */
225 | }
226 | }
227 | }
228 |
229 | /* Possible return values:
230 | EXCEPTION_CONTINUE_SEARCH = popup a window about the error, user has to click.
231 | EXCEPTION_CONTINUE_EXECUTION = infinite loop
232 | EXCEPTION_EXECUTE_HANDLER = stop program, do not run debugger
233 | */
234 | return(EXCEPTION_EXECUTE_HANDLER);
235 | }
236 | #endif
237 |
238 | /*
239 |
240 | The main thread that performs all the work. Interpret the commandline
241 | parameters and call the defragger library.
242 |
243 | */
244 | DWORD WINAPI JKDefrag::DefragThread(LPVOID)
245 | {
246 | int QuitOnFinish;
247 | int OptimizeMode; /* 1...11 */
248 | int Speed; /* 0...100 */
249 | double FreeSpace; /* 0...100 */
250 | WCHAR **Excludes;
251 | WCHAR **SpaceHogs;
252 | int DoAllVolumes;
253 | LPWSTR *argv;
254 | int argc;
255 | time_t Now;
256 | struct tm NowTm;
257 | OSVERSIONINFO OsVersion;
258 | int i;
259 |
260 | JKDefragLog *jkLog = m_jkDefrag->m_jkLog;
261 | JKDefragStruct *jkStruct = m_jkDefrag->m_jkStruct;
262 | JKDefragGui *jkGui = m_jkDefrag->m_jkGui;
263 | JKDefragLib *jkLib = m_jkDefrag->m_jkLib;
264 |
265 | /* Setup the defaults. */
266 | OptimizeMode = 2;
267 | Speed = 100;
268 | FreeSpace = 1;
269 | Excludes = NULL;
270 | SpaceHogs = NULL;
271 | QuitOnFinish = NO;
272 |
273 | /* Fetch the commandline. */
274 | argv = CommandLineToArgvW(GetCommandLineW(),&argc);
275 |
276 | /* Scan the commandline arguments for "-l" and setup the logfile. */
277 | if (argc > 1)
278 | {
279 | for (i = 1; i < argc; i++)
280 | {
281 | if (wcscmp(argv[i],L"-l") == 0)
282 | {
283 | i++;
284 | if (i >= argc) continue;
285 |
286 | jkLog->SetLogFilename(argv[i]);
287 |
288 | continue;
289 | }
290 | if ((wcsncmp(argv[i],L"-l",2) == 0) && (wcslen(argv[i]) >= 3))
291 | {
292 | jkLog->SetLogFilename(&argv[i][2]);
293 |
294 | continue;
295 | }
296 | }
297 | }
298 |
299 | /* Show some standard information in the logfile. */
300 | jkLog->LogMessage(jkStruct->VERSIONTEXT);
301 | time(&Now);
302 |
303 | localtime_s(&NowTm,&Now);
304 | jkLog->LogMessage(L"Date: %04lu/%02lu/%02lu",1900 + NowTm.tm_year,1 + NowTm.tm_mon,NowTm.tm_mday);
305 |
306 | ZeroMemory(&OsVersion,sizeof(OSVERSIONINFO));
307 | OsVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
308 |
309 | if (GetVersionEx(&OsVersion) != 0)
310 | {
311 | jkLog->LogMessage(L"Windows version: v%lu.%lu build %lu %S",OsVersion.dwMajorVersion,
312 | OsVersion.dwMinorVersion,OsVersion.dwBuildNumber,OsVersion.szCSDVersion);
313 | }
314 |
315 | /* Scan the commandline again for all the other arguments. */
316 | if (argc > 1)
317 | {
318 | for (i = 1; i < argc; i++)
319 | {
320 | if (wcscmp(argv[i],L"-a") == 0)
321 | {
322 | i++;
323 |
324 | if (i >= argc)
325 | {
326 | jkGui->ShowDebug(0,NULL,L"Error: you have not specified a number after the \"-a\" commandline argument.");
327 |
328 | continue;
329 | }
330 |
331 | OptimizeMode = _wtol(argv[i]);
332 |
333 | if ((OptimizeMode < 1) || (OptimizeMode > 11))
334 | {
335 | jkGui->ShowDebug(0,NULL,L"Error: the number after the \"-a\" commandline argument is invalid.");
336 |
337 | OptimizeMode = 3;
338 | }
339 |
340 | OptimizeMode = OptimizeMode - 1;
341 |
342 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-a' accepted, optimizemode = %u",OptimizeMode+1);
343 |
344 | continue;
345 | }
346 |
347 | if (wcsncmp(argv[i],L"-a",2) == 0)
348 | {
349 | OptimizeMode = _wtol(&argv[i][2]);
350 |
351 | if ((OptimizeMode < 1) || (OptimizeMode > 11))
352 | {
353 | jkGui->ShowDebug(0,NULL,L"Error: the number after the \"-a\" commandline argument is invalid.");
354 |
355 | OptimizeMode = 3;
356 | }
357 |
358 | OptimizeMode = OptimizeMode - 1;
359 |
360 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-a' accepted, optimizemode = %u",OptimizeMode+1);
361 |
362 | continue;
363 | }
364 |
365 | if (wcscmp(argv[i],L"-s") == 0)
366 | {
367 | i++;
368 |
369 | if (i >= argc)
370 | {
371 | jkGui->ShowDebug(0,NULL,L"Error: you have not specified a number after the \"-s\" commandline argument.");
372 |
373 | continue;
374 | }
375 |
376 | Speed = _wtol(argv[i]);
377 |
378 | if ((Speed < 1) || (Speed > 100))
379 | {
380 | jkGui->ShowDebug(0,NULL,L"Error: the number after the \"-s\" commandline argument is invalid.");
381 |
382 | Speed = 100;
383 | }
384 |
385 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-s' accepted, speed = %u%%",Speed);
386 |
387 | continue;
388 | }
389 |
390 | if ((wcsncmp(argv[i],L"-s",2) == 0) && (wcslen(argv[i]) >= 3))
391 | {
392 | Speed = _wtol(&argv[i][2]);
393 |
394 | if ((Speed < 1) || (Speed > 100))
395 | {
396 | jkGui->ShowDebug(0,NULL,L"Error: the number after the \"-s\" commandline argument is invalid.");
397 |
398 | Speed = 100;
399 | }
400 |
401 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-s' accepted, speed = %u%%",Speed);
402 |
403 | continue;
404 | }
405 |
406 | if (wcscmp(argv[i],L"-f") == 0)
407 | {
408 | i++;
409 |
410 | if (i >= argc)
411 | {
412 | jkGui->ShowDebug(0,NULL,L"Error: you have not specified a number after the \"-f\" commandline argument.");
413 |
414 | continue;
415 | }
416 |
417 | FreeSpace = _wtof(argv[i]);
418 |
419 | if ((FreeSpace < 0) || (FreeSpace > 100))
420 | {
421 | jkGui->ShowDebug(0,NULL,L"Error: the number after the \"-f\" commandline argument is invalid.");
422 |
423 | FreeSpace = 1;
424 | }
425 |
426 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-f' accepted, freespace = %0.1f%%",FreeSpace);
427 |
428 | continue;
429 | }
430 |
431 | if ((wcsncmp(argv[i],L"-f",2) == 0) && (wcslen(argv[i]) >= 3))
432 | {
433 | FreeSpace = _wtof(&argv[i][2]);
434 |
435 | if ((FreeSpace < 0) || (FreeSpace > 100))
436 | {
437 | jkGui->ShowDebug(0,NULL,L"Error: the number after the \"-f\" command line argument is invalid.");
438 |
439 | FreeSpace = 1;
440 | }
441 |
442 | jkGui->ShowDebug(0,NULL,L"Command line argument '-f' accepted, free space = %0.1f%%",FreeSpace);
443 |
444 | continue;
445 | }
446 |
447 | if (wcscmp(argv[i],L"-d") == 0)
448 | {
449 | i++;
450 |
451 | if (i >= argc)
452 | {
453 | jkGui->ShowDebug(0,NULL,L"Error: you have not specified a number after the \"-d\" commandline argument.");
454 |
455 | continue;
456 | }
457 |
458 | m_jkDefrag->Debug = _wtol(argv[i]);
459 |
460 | if ((m_jkDefrag->Debug < 0) || (m_jkDefrag->Debug > 6))
461 | {
462 | jkGui->ShowDebug(0,NULL,L"Error: the number after the \"-d\" commandline argument is invalid.");
463 |
464 | m_jkDefrag->Debug = 1;
465 | }
466 |
467 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-d' accepted, debug = %u",m_jkDefrag->Debug);
468 |
469 | continue;
470 | }
471 |
472 | if ((wcsncmp(argv[i],L"-d",2) == 0) && (wcslen(argv[i]) == 3) &&
473 | (argv[i][2] >= '0') && (argv[i][2] <= '6'))
474 | {
475 | m_jkDefrag->Debug = _wtol(&argv[i][2]);
476 |
477 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-d' accepted, debug = %u",m_jkDefrag->Debug);
478 |
479 | continue;
480 | }
481 |
482 | if (wcscmp(argv[i],L"-l") == 0)
483 | {
484 | i++;
485 |
486 | if (i >= argc)
487 | {
488 | jkGui->ShowDebug(0,NULL,L"Error: you have not specified a filename after the \"-l\" commandline argument.");
489 |
490 | continue;
491 | }
492 |
493 | WCHAR *LogFile = jkLog->GetLogFilename();
494 |
495 | if (*LogFile != '\0')
496 | {
497 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-l' accepted, logfile = %s",LogFile);
498 | }
499 | else
500 | {
501 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-l' accepted, logfile turned off");
502 | }
503 |
504 | continue;
505 | }
506 |
507 | if ((wcsncmp(argv[i],L"-l",2) == 0) && (wcslen(argv[i]) >= 3))
508 | {
509 | WCHAR *LogFile = jkLog->GetLogFilename();
510 |
511 | if (*LogFile != '\0')
512 | {
513 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-l' accepted, logfile = %s",LogFile);
514 | }
515 | else
516 | {
517 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-l' accepted, logfile turned off");
518 | }
519 |
520 | continue;
521 | }
522 |
523 | if (wcscmp(argv[i],L"-e") == 0)
524 | {
525 | i++;
526 |
527 | if (i >= argc)
528 | {
529 | jkGui->ShowDebug(0,NULL,L"Error: you have not specified a mask after the \"-e\" commandline argument.");
530 |
531 | continue;
532 | }
533 |
534 | Excludes = jkLib->AddArrayString(Excludes,argv[i]);
535 |
536 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-e' accepted, added '%s' to the excludes",argv[i]);
537 |
538 | continue;
539 | }
540 |
541 | if ((wcsncmp(argv[i],L"-e",2) == 0) && (wcslen(argv[i]) >= 3))
542 | {
543 | Excludes = jkLib->AddArrayString(Excludes,&argv[i][2]);
544 |
545 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-e' accepted, added '%s' to the excludes",&argv[i][2]);
546 |
547 | continue;
548 | }
549 |
550 | if (wcscmp(argv[i],L"-u") == 0)
551 | {
552 | i++;
553 |
554 | if (i >= argc)
555 | {
556 | jkGui->ShowDebug(0,NULL,L"Error: you have not specified a mask after the \"-u\" commandline argument.");
557 |
558 | continue;
559 | }
560 |
561 | SpaceHogs = jkLib->AddArrayString(SpaceHogs,argv[i]);
562 |
563 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-u' accepted, added '%s' to the spacehogs",argv[i]);
564 |
565 | continue;
566 | }
567 |
568 | if ((wcsncmp(argv[i],L"-u",2) == 0) && (wcslen(argv[i]) >= 3))
569 | {
570 | SpaceHogs = jkLib->AddArrayString(SpaceHogs,&argv[i][2]);
571 |
572 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-u' accepted, added '%s' to the spacehogs",&argv[i][2]);
573 |
574 | continue;
575 | }
576 |
577 | if (wcscmp(argv[i],L"-q") == 0)
578 | {
579 | QuitOnFinish = YES;
580 |
581 | jkGui->ShowDebug(0,NULL,L"Commandline argument '-q' accepted, quitonfinish = yes");
582 |
583 | continue;
584 | }
585 |
586 | if (argv[i][0] == '-')
587 | {
588 | jkGui->ShowDebug(0,NULL,L"Error: commandline argument not recognised: %s",argv[i]);
589 | }
590 | }
591 | }
592 |
593 | /* Defragment all the paths that are specified on the commandline one by one. */
594 | DoAllVolumes = YES;
595 |
596 | if (argc > 1)
597 | {
598 | for (i = 1; i < argc; i++)
599 | {
600 | if (m_jkDefrag->IamRunning != RUNNING) break;
601 |
602 | if ((wcscmp(argv[i],L"-a") == 0) ||
603 | (wcscmp(argv[i],L"-e") == 0) ||
604 | (wcscmp(argv[i],L"-u") == 0) ||
605 | (wcscmp(argv[i],L"-s") == 0) ||
606 | (wcscmp(argv[i],L"-f") == 0) ||
607 | (wcscmp(argv[i],L"-d") == 0) ||
608 | (wcscmp(argv[i],L"-l") == 0))
609 | {
610 | i++;
611 | continue;
612 | }
613 |
614 | if (*argv[i] == '-') continue;
615 | if (*argv[i] == '\0') continue;
616 |
617 | jkLib->RunJkDefrag(argv[i],OptimizeMode,Speed,FreeSpace,Excludes,SpaceHogs,&m_jkDefrag->Running,
618 | /*&JKDefragGui::getInstance()->RedrawScreen,*/NULL);
619 |
620 | DoAllVolumes = NO;
621 | }
622 | }
623 |
624 | /* If no paths are specified on the commandline then defrag all fixed harddisks. */
625 | if ((DoAllVolumes == YES) && (m_jkDefrag->IamRunning == RUNNING))
626 | {
627 | jkLib->RunJkDefrag(NULL,OptimizeMode,Speed,FreeSpace,Excludes,SpaceHogs,&m_jkDefrag->Running,
628 | /*&JKDefragGui::getInstance()->RedrawScreen,*/NULL);
629 | }
630 |
631 | /* If the "-q" command line argument was specified then exit the program. */
632 | if (QuitOnFinish == YES) exit(EXIT_SUCCESS);
633 |
634 | /* End of this thread. */
635 | return(0);
636 | }
637 |
638 | /*
639 |
640 | If the defragger is not yet running then return NO. If it's already
641 | running or if there was an error getting the processlist then return
642 | YES.
643 |
644 | */
645 | int JKDefrag::AlreadyRunning(void)
646 | {
647 | HANDLE Snapshot;
648 | PROCESSENTRY32 pe32;
649 | DWORD MyPid;
650 | char MyName[MAX_PATH];
651 | WCHAR s1[BUFSIZ];
652 | WCHAR s2[BUFSIZ];
653 |
654 | /* Get a process-snapshot from the kernel. */
655 | Snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);
656 |
657 | if (Snapshot == INVALID_HANDLE_VALUE)
658 | {
659 | m_jkLib->SystemErrorStr(GetLastError(),s1,BUFSIZ);
660 |
661 | swprintf_s(s2,BUFSIZ,L"Cannot get process snapshot: %s",s1);
662 |
663 | m_jkGui->ShowDebug(0,NULL,s2);
664 |
665 | return(YES);
666 | }
667 |
668 | pe32.dwSize = sizeof(PROCESSENTRY32);
669 |
670 | /* Get my own executable name. */
671 | MyPid = GetCurrentProcessId();
672 | *MyName = '\0';
673 |
674 | if (Process32First(Snapshot,&pe32) != FALSE)
675 | {
676 | do
677 | {
678 | if (MyPid == pe32.th32ProcessID)
679 | {
680 | strcpy_s(MyName,MAX_PATH,pe32.szExeFile);
681 | break;
682 | }
683 | } while (Process32Next(Snapshot,&pe32));
684 | }
685 |
686 | if (*MyName == '\0')
687 | {
688 | /* "Cannot find my own name in the process list: %s" */
689 | swprintf_s(s1,BUFSIZ,L"Cannot find my own name in the process list: %s",MyName);
690 |
691 | m_jkGui->ShowDebug(0,NULL,s1);
692 |
693 | return(YES);
694 | }
695 |
696 | /* Search for any other process with the same executable name as
697 | myself. If found then return YES. */
698 | Process32First(Snapshot,&pe32);
699 |
700 | do
701 | {
702 | if (MyPid == pe32.th32ProcessID) continue; /* Ignore myself. */
703 |
704 | if ((_stricmp(pe32.szExeFile,MyName) == 0) ||
705 | (_stricmp(pe32.szExeFile,"jkdefrag.exe") == 0) ||
706 | (_stricmp(pe32.szExeFile,"jkdefragscreensaver.exe") == 0) ||
707 | (_stricmp(pe32.szExeFile,"jkdefragcmd.exe") == 0))
708 | {
709 | CloseHandle(Snapshot);
710 |
711 | swprintf_s(s1,BUFSIZ,L"I am already running: %S",pe32.szExeFile);
712 |
713 | m_jkGui->ShowDebug(0,NULL,s1);
714 |
715 | return(YES);
716 | }
717 | } while (Process32Next(Snapshot,&pe32));
718 |
719 | /* Return NO, not yet running. */
720 | CloseHandle(Snapshot);
721 | return(NO);
722 | }
723 |
724 |
725 | int __stdcall WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
726 | {
727 | JKDefrag *jkDefrag = JKDefrag::getInstance();
728 |
729 | WPARAM retValue = 0;
730 |
731 | if (jkDefrag != NULL)
732 | {
733 | retValue = jkDefrag->startProgram(hInstance,hPrevInstance,lpCmdLine,nCmdShow);
734 |
735 | JKDefrag::releaseInstance();
736 | }
737 |
738 | return((int)retValue);
739 | }
740 |
--------------------------------------------------------------------------------
/JkDefrag/Source/JkDefragGui.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 |
3 | /*
4 | #include "JKDefragStruct.h"
5 | #include "JKDefragLog.h"
6 | #include "JkDefragLib.h"
7 | #include "JkDefragGui.h"
8 | */
9 |
10 | JKDefragGui *JKDefragGui::m_jkDefragGui = 0;
11 |
12 | JKDefragGui::JKDefragGui()
13 | {
14 | m_jkLib = JKDefragLib::getInstance();
15 |
16 | m_bmp = NULL;
17 |
18 | jkStruct = new JKDefragStruct();
19 |
20 | m_squareSize = 12;
21 | // m_clusterSquares = NULL;
22 | m_numDiskSquares = 0;
23 |
24 | m_offsetX = 26;
25 | m_offsetY = 16;
26 |
27 | clusterInfo = NULL;
28 | m_numClusters = 1;
29 |
30 | ProgressStartTime = 0;
31 | ProgressTime = 0;
32 | ProgressDone = 0;
33 |
34 | int i = 0;
35 |
36 | for (i = 0; i < 6; i++) *Messages[i] = '\0';
37 |
38 | // RedrawScreen = 0;
39 | }
40 |
41 | JKDefragGui::~JKDefragGui()
42 | {
43 | delete jkStruct;
44 | delete m_jkDefragGui;
45 |
46 | /*
47 | if (m_jkDefragGui->m_clusterSquares != NULL)
48 | {
49 | delete[] m_jkDefragGui->m_clusterSquares;
50 | }
51 | */
52 |
53 | if (m_bmp != NULL)
54 | {
55 | delete m_bmp;
56 | }
57 | }
58 |
59 | JKDefragGui *JKDefragGui::getInstance()
60 | {
61 | if (m_jkDefragGui == NULL)
62 | {
63 | m_jkDefragGui = new JKDefragGui();
64 | }
65 |
66 | return m_jkDefragGui;
67 | }
68 |
69 | int JKDefragGui::Initialize(HINSTANCE hInstance, int nCmdShow, JKDefragLog *jkLog, int debugLevel)
70 | {
71 | ULONG_PTR gdiplusToken;
72 |
73 | GdiplusStartupInput gdiplusStartupInput;
74 |
75 | GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
76 |
77 | m_jkLog = jkLog;
78 | m_debugLevel = debugLevel;
79 |
80 | m_displayMutex = CreateMutex(NULL,FALSE,"JKDefrag");
81 |
82 | m_wndClass.cbClsExtra = 0;
83 | m_wndClass.cbWndExtra = 0;
84 | m_wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
85 | m_wndClass.hCursor = LoadCursor(NULL,IDC_ARROW);
86 | m_wndClass.hIcon = LoadIcon(NULL,MAKEINTRESOURCE(1));
87 | m_wndClass.hInstance = hInstance;
88 | m_wndClass.lpfnWndProc = (WNDPROC)JKDefragGui::ProcessMessagefn;
89 | m_wndClass.lpszClassName = "MyClass";
90 | m_wndClass.lpszMenuName = NULL;
91 | m_wndClass.style = CS_HREDRAW | CS_VREDRAW;
92 | m_wndClass.cbSize = sizeof(WNDCLASSEX);
93 | m_wndClass.hIconSm = LoadIcon(hInstance,MAKEINTRESOURCE(1));
94 |
95 | CHAR koko[100];
96 |
97 | LoadString(hInstance,2,koko, 99);
98 |
99 | if (RegisterClassEx(&m_wndClass) == 0)
100 | {
101 | MessageBoxW(NULL,L"Cannot register class",jkStruct->VERSIONTEXT,MB_ICONEXCLAMATION | MB_OK);
102 | return(0);
103 | }
104 |
105 | m_hWnd = CreateWindowW(L"MyClass",jkStruct->VERSIONTEXT,WS_TILEDWINDOW,
106 | CW_USEDEFAULT,0,1024,768,NULL,NULL,hInstance,NULL);
107 |
108 | if (m_hWnd == NULL)
109 | {
110 | MessageBoxW(NULL,L"Cannot create window",jkStruct->VERSIONTEXT,MB_ICONEXCLAMATION | MB_OK);
111 | return(0);
112 | }
113 |
114 | /* Show the window in the state that Windows has specified, minimized or maximized. */
115 | ShowWindow(m_hWnd,nCmdShow);
116 | UpdateWindow(m_hWnd);
117 |
118 | SetTimer(m_hWnd,1,300,NULL);
119 |
120 | // InvalidateRect(m_hWnd,NULL,FALSE);
121 |
122 | return 1;
123 | }
124 |
125 | WPARAM JKDefragGui::DoModal()
126 | {
127 | int GetMessageResult;
128 |
129 | /* The main message thread. */
130 | while (TRUE)
131 | {
132 | GetMessageResult = GetMessage(&Message,NULL,0,0);
133 |
134 | if (GetMessageResult == 0) break;
135 | if (GetMessageResult == -1) break;
136 | if (Message.message == WM_QUIT) break;
137 |
138 | TranslateMessage(&Message);
139 | DispatchMessage(&Message);
140 | }
141 |
142 | return Message.wParam;;
143 | }
144 |
145 | void JKDefragGui::setDisplayData(HDC hdc)
146 | {
147 | Graphics graphics(hdc);
148 |
149 | Rect clientWindowSize;
150 |
151 | Status status = graphics.GetVisibleClipBounds(&clientWindowSize);
152 |
153 | m_clientWindowSize = clientWindowSize;
154 |
155 | /*
156 | if (m_clusterSquares != NULL)
157 | {
158 | delete[] m_clusterSquares;
159 | }
160 | */
161 |
162 | m_topHeight = 33;
163 |
164 | if (m_debugLevel > 1)
165 | {
166 | m_topHeight = 49;
167 | }
168 |
169 | m_diskAreaSize.Width = clientWindowSize.Width - m_offsetX * 2;
170 | m_diskAreaSize.Height = clientWindowSize.Height - m_topHeight - m_offsetY * 2;
171 |
172 | m_numDiskSquaresX = (int)(m_diskAreaSize.Width / m_squareSize);
173 | m_numDiskSquaresY = (int)(m_diskAreaSize.Height / m_squareSize);
174 |
175 | m_numDiskSquares = m_numDiskSquaresX * m_numDiskSquaresY;
176 |
177 | // m_clusterSquares = new clusterSquareStruct[m_numDiskSquares];
178 |
179 | for (int ii = 0; ii < m_numDiskSquares; ii++)
180 | {
181 | m_clusterSquares[ii].color = 0;
182 | m_clusterSquares[ii].dirty = true;
183 | }
184 |
185 | m_realOffsetX = (int)((m_clientWindowSize.Width - m_numDiskSquaresX * m_squareSize) * 0.5);
186 | m_realOffsetY = (int)((m_clientWindowSize.Height - m_topHeight - m_numDiskSquaresY * m_squareSize) * 0.5);
187 |
188 | if (m_bmp != NULL)
189 | {
190 | delete m_bmp;
191 |
192 | m_bmp = NULL;
193 | }
194 |
195 | m_bmp = new Bitmap(m_clientWindowSize.Width, m_clientWindowSize.Height);
196 |
197 | // Color bottomPartColor;
198 | // bottomPartColor.SetFromCOLORREF(RGB(255,255,255));
199 |
200 | // SolidBrush bottomPartBrush(bottomPartColor);
201 |
202 | // Rect drawArea(0, 0, m_clientWindowSize.Width, m_clientWindowSize.Height);
203 | // graphics.FillRectangle(&bottomPartBrush, drawArea);
204 |
205 | /* Ask defragger to completely redraw the screen. */
206 | // RedrawScreen = 0;
207 | }
208 |
209 | /* Callback: clear the screen. */
210 | void JKDefragGui::ClearScreen(WCHAR *Format, ...)
211 | {
212 | va_list VarArgs;
213 |
214 | int i;
215 |
216 | /* If there is no message then return. */
217 | if (Format == NULL) return;
218 |
219 | /* Clear all the messages. */
220 | for (i = 0; i < 6; i++) *Messages[i] = '\0';
221 |
222 | /* Save the message in Messages 0. */
223 | va_start(VarArgs,Format);
224 | vswprintf_s(Messages[0],50000,Format,VarArgs);
225 |
226 | /* If there is no logfile then return. */
227 | if (m_jkLog != NULL)
228 | {
229 | m_jkLog->LogMessage(Format, VarArgs);
230 | }
231 |
232 | va_end(VarArgs);
233 |
234 | PaintImage(m_hDC);
235 | // InvalidateRect(m_hWnd,NULL,FALSE);
236 | }
237 |
238 | /* Callback: whenever an item (file, directory) is moved on disk. */
239 | void JKDefragGui::ShowMove(struct ItemStruct *Item,
240 | ULONG64 Clusters,
241 | ULONG64 FromLcn,
242 | ULONG64 ToLcn,
243 | ULONG64 FromVcn)
244 | {
245 | /* Save the message in Messages 3. */
246 | if (Clusters == 1)
247 | {
248 | swprintf_s(Messages[3],50000,L"Moving 1 cluster from %I64d to %I64d.",FromLcn,ToLcn);
249 | }
250 | else
251 | {
252 | swprintf_s(Messages[3],50000,L"Moving %I64d clusters from %I64d to %I64d.",
253 | Clusters,FromLcn,ToLcn);
254 | }
255 |
256 | /* Save the name of the file in Messages 4. */
257 | if ((Item != NULL) && (Item->LongPath != NULL))
258 | {
259 | swprintf_s(Messages[4],50000,L"%s",Item->LongPath);
260 | }
261 | else
262 | {
263 | *(Messages[4]) = '\0';
264 | }
265 |
266 | /* If debug mode then write a message to the logfile. */
267 | if (m_debugLevel < 3) return;
268 |
269 | if (FromVcn > 0)
270 | {
271 | if (Clusters == 1)
272 | {
273 | m_jkLog->LogMessage(L"%s\n Moving 1 cluster from %I64d to %I64d, VCN=%I64d.",
274 | Item->LongPath,FromLcn,ToLcn,FromVcn);
275 | }
276 | else
277 | {
278 | m_jkLog->LogMessage(L"%s\n Moving %I64d clusters from %I64d to %I64d, VCN=%I64d.",
279 | Item->LongPath,Clusters,FromLcn,ToLcn,FromVcn);
280 | }
281 | }
282 | else
283 | {
284 | if (Clusters == 1)
285 | {
286 | m_jkLog->LogMessage(L"%s\n Moving 1 cluster from %I64d to %I64d.",
287 | Item->LongPath,FromLcn,ToLcn);
288 | }
289 | else
290 | {
291 | m_jkLog->LogMessage(L"%s\n Moving %I64d clusters from %I64d to %I64d.",
292 | Item->LongPath,Clusters,FromLcn,ToLcn);
293 | }
294 | }
295 | PaintImage(m_hDC);
296 |
297 | // InvalidateRect(m_hWnd,NULL,FALSE);
298 | }
299 |
300 |
301 | /* Callback: for every file during analysis.
302 | This subroutine is called one last time with Item=NULL when analysis has
303 | finished. */
304 | void JKDefragGui::ShowAnalyze(struct DefragDataStruct *Data, struct ItemStruct *Item)
305 | {
306 | if ((Data != NULL) && (Data->CountAllFiles != 0))
307 | {
308 | swprintf_s(Messages[3],50000,L"Files %I64d, Directories %I64d, Clusters %I64d",
309 | Data->CountAllFiles,Data->CountDirectories,Data->CountAllClusters);
310 | }
311 | else
312 | {
313 | swprintf_s(Messages[3],50000,L"Applying Exclude and SpaceHogs masks....");
314 | }
315 |
316 | /* Save the name of the file in Messages 4. */
317 | if ((Item != NULL) && (Item->LongPath != NULL))
318 | {
319 | swprintf_s(Messages[4],50000,L"%s",Item->LongPath);
320 | }
321 | else
322 | {
323 | *(Messages[4]) = '\0';
324 | }
325 | PaintImage(m_hDC);
326 |
327 | // InvalidateRect(m_hWnd,NULL,FALSE);
328 | }
329 |
330 | /* Callback: show a debug message. */
331 |
332 | void JKDefragGui::ShowDebug(int Level, struct ItemStruct *Item, WCHAR *Format, ...)
333 | {
334 | va_list VarArgs;
335 |
336 | if (m_debugLevel < Level) return;
337 |
338 | /* Save the name of the file in Messages 4. */
339 | if ((Item != NULL) && (Item->LongPath != NULL))
340 | {
341 | swprintf_s(Messages[4],50000,L"%s",Item->LongPath);
342 | }
343 |
344 | /* If there is no message then return. */
345 | if (Format == NULL) return;
346 |
347 | /* Save the debug message in Messages 5. */
348 | va_start(VarArgs,Format);
349 | vswprintf_s(Messages[5],50000,Format,VarArgs);
350 | m_jkLog->LogMessage(Format, VarArgs);
351 | va_end(VarArgs);
352 | PaintImage(m_hDC);
353 |
354 | // InvalidateRect(m_hWnd,NULL,FALSE);
355 | }
356 |
357 | /* Callback: paint a cluster on the screen in a color. */
358 | void JKDefragGui::DrawCluster(struct DefragDataStruct *Data,
359 | ULONG64 ClusterStart,
360 | ULONG64 ClusterEnd,
361 | int Color)
362 | {
363 | struct __timeb64 Now;
364 |
365 | Rect windowSize = m_clientWindowSize;
366 |
367 | /* Save the PhaseTodo and PhaseDone counters for later use by the progress counter. */
368 | if (Data->PhaseTodo != 0)
369 | {
370 | _ftime64_s(&Now);
371 |
372 | ProgressTime = Now.time * 1000 + Now.millitm;
373 | ProgressDone = Data->PhaseDone;
374 | ProgressTodo = Data->PhaseTodo;
375 | }
376 |
377 | /* Sanity check. */
378 | if (Data->TotalClusters == 0) return;
379 | if (m_hDC == NULL) return;
380 | if (ClusterStart == ClusterEnd) return;
381 | // if (ClusterStart > Data->TotalClusters) ClusterStart = 0;
382 |
383 | WaitForSingleObject(m_displayMutex,100);
384 |
385 | m_displayMutex = CreateMutex(NULL,FALSE,"JKDefrag");
386 |
387 | if (m_numClusters != Data->TotalClusters || clusterInfo == NULL)
388 | {
389 | if (clusterInfo != NULL)
390 | {
391 | free(clusterInfo);
392 |
393 | clusterInfo = NULL;
394 | }
395 |
396 | m_numClusters = Data->TotalClusters;
397 |
398 | clusterInfo = (byte *)malloc((size_t)m_numClusters);
399 |
400 | for(int ii = 0; ii <= m_numClusters; ii++)
401 | {
402 | clusterInfo[ii] = JKDefragStruct::COLOREMPTY;
403 | }
404 |
405 | // RedrawScreen = 0;
406 |
407 | return;
408 | }
409 |
410 |
411 | for(ULONG64 ii = ClusterStart; ii <= ClusterEnd; ii++)
412 | {
413 | clusterInfo[ii] = Color;
414 | }
415 |
416 | float clusterPerSquare = (float)(m_numClusters / m_numDiskSquares);
417 | int clusterStartSquareNum = (int)((ULONG64)ClusterStart / (ULONG64)clusterPerSquare);
418 | int clusterEndSquareNum = (int)((ULONG64)ClusterEnd / (ULONG64)clusterPerSquare);
419 |
420 | FillSquares(clusterStartSquareNum, clusterEndSquareNum);
421 |
422 | ReleaseMutex(m_displayMutex);
423 | PaintImage(m_hDC);
424 |
425 | // InvalidateRect(m_hWnd,NULL,FALSE);
426 | }
427 |
428 | /* Callback: just before the defragger starts a new Phase, and when it finishes. */
429 | void JKDefragGui::ShowStatus(struct DefragDataStruct *Data)
430 | {
431 | struct ItemStruct *Item;
432 |
433 | int Fragments;
434 |
435 | ULONG64 TotalFragments;
436 | ULONG64 TotalBytes;
437 | ULONG64 TotalClusters;
438 |
439 | struct ItemStruct *LargestItems[25];
440 |
441 | int LastLargest;
442 |
443 | struct __timeb64 Now;
444 |
445 | int i;
446 | int j;
447 |
448 | /* Reset the progress counter. */
449 | _ftime64_s(&Now);
450 |
451 | ProgressStartTime = Now.time * 1000 + Now.millitm;
452 | ProgressTime = ProgressStartTime;
453 | ProgressDone = 0;
454 | ProgressTodo = 0;
455 |
456 | /* Reset all the messages. */
457 | for (i = 0; i < 6; i++) *(Messages[i]) = '\0';
458 |
459 | /* Update Message 0 and 1. */
460 | if (Data != NULL)
461 | {
462 | swprintf_s(Messages[0],50000,L"%s",Data->Disk.MountPoint);
463 |
464 | switch(Data->Phase)
465 | {
466 | case 1: wcscpy_s(Messages[1],50000,L"Phase 1: Analyze"); break;
467 | case 2: wcscpy_s(Messages[1],50000,L"Phase 2: Defragment"); break;
468 | case 3: wcscpy_s(Messages[1],50000,L"Phase 3: ForcedFill"); break;
469 | case 4: swprintf_s(Messages[1],50000,L"Zone %u: Sort",Data->Zone + 1); break;
470 | case 5: swprintf_s(Messages[1],50000,L"Zone %u: Fast Optimize",Data->Zone + 1); break;
471 | case 6: wcscpy_s(Messages[1],50000,L"Phase 3: Move Up"); break;
472 | case 7:
473 | wcscpy_s(Messages[1],50000,L"Finished.");
474 | swprintf_s(Messages[4],50000,L"Logfile: %s",m_jkLog->GetLogFilename());
475 | break;
476 | case 8: wcscpy_s(Messages[1],50000,L"Phase 3: Fixup"); break;
477 | }
478 |
479 | m_jkLog->LogMessage(Messages[1]);
480 | }
481 |
482 | /* Write some statistics to the logfile. */
483 | if ((Data != NULL) && (Data->Phase == 7))
484 | {
485 | m_jkLog->LogMessage(L"- Total disk space: %I64d bytes (%.04f gigabytes), %I64d clusters",
486 | Data->BytesPerCluster * Data->TotalClusters,
487 | (double)(Data->BytesPerCluster * Data->TotalClusters) / (1024 * 1024 * 1024),
488 | Data->TotalClusters);
489 |
490 | m_jkLog->LogMessage(L"- Bytes per cluster: %I64d bytes",Data->BytesPerCluster);
491 |
492 | m_jkLog->LogMessage(L"- Number of files: %I64d",Data->CountAllFiles);
493 | m_jkLog->LogMessage(L"- Number of directories: %I64d",Data->CountDirectories);
494 | m_jkLog->LogMessage(L"- Total size of analyzed items: %I64d bytes (%.04f gigabytes), %I64d clusters",
495 | Data->CountAllClusters * Data->BytesPerCluster,
496 | (double)(Data->CountAllClusters * Data->BytesPerCluster) / (1024 * 1024 * 1024),
497 | Data->CountAllClusters);
498 |
499 | if (Data->CountAllFiles + Data->CountDirectories > 0)
500 | {
501 | m_jkLog->LogMessage(L"- Number of fragmented items: %I64d (%.04f%% of all items)",
502 | Data->CountFragmentedItems,
503 | (double)(Data->CountFragmentedItems * 100) / (Data->CountAllFiles + Data->CountDirectories));
504 | }
505 | else
506 | {
507 | m_jkLog->LogMessage(L"- Number of fragmented items: %I64d",Data->CountFragmentedItems);
508 | }
509 |
510 | if ((Data->CountAllClusters > 0) && (Data->TotalClusters > 0))
511 | {
512 | m_jkLog->LogMessage(L"- Total size of fragmented items: %I64d bytes, %I64d clusters, %.04f%% of all items, %.04f%% of disk",
513 | Data->CountFragmentedClusters * Data->BytesPerCluster,
514 | Data->CountFragmentedClusters,
515 | (double)(Data->CountFragmentedClusters * 100) / Data->CountAllClusters,
516 | (double)(Data->CountFragmentedClusters * 100) / Data->TotalClusters);
517 | }
518 | else
519 | {
520 | m_jkLog->LogMessage(L"- Total size of fragmented items: %I64d bytes, %I64d clusters",
521 | Data->CountFragmentedClusters * Data->BytesPerCluster,
522 | Data->CountFragmentedClusters);
523 | }
524 |
525 | if (Data->TotalClusters > 0)
526 | {
527 | m_jkLog->LogMessage(L"- Free disk space: %I64d bytes, %I64d clusters, %.04f%% of disk",
528 | Data->CountFreeClusters * Data->BytesPerCluster,
529 | Data->CountFreeClusters,
530 | (double)(Data->CountFreeClusters * 100) / Data->TotalClusters);
531 | }
532 | else
533 | {
534 | m_jkLog->LogMessage(L"- Free disk space: %I64d bytes, %I64d clusters",
535 | Data->CountFreeClusters * Data->BytesPerCluster,
536 | Data->CountFreeClusters);
537 | }
538 |
539 | m_jkLog->LogMessage(L"- Number of gaps: %I64d",Data->CountGaps);
540 |
541 | if (Data->CountGaps > 0)
542 | {
543 | m_jkLog->LogMessage(L"- Number of small gaps: %I64d (%.04f%% of all gaps)",
544 | Data->CountGapsLess16,
545 | (double)(Data->CountGapsLess16 * 100) / Data->CountGaps);
546 | }
547 | else
548 | {
549 | m_jkLog->LogMessage(L"- Number of small gaps: %I64d",
550 | Data->CountGapsLess16);
551 | }
552 |
553 | if (Data->CountFreeClusters > 0)
554 | {
555 | m_jkLog->LogMessage(L"- Size of small gaps: %I64d bytes, %I64d clusters, %.04f%% of free disk space",
556 | Data->CountClustersLess16 * Data->BytesPerCluster,
557 | Data->CountClustersLess16,
558 | (double)(Data->CountClustersLess16 * 100) / Data->CountFreeClusters);
559 | }
560 | else
561 | {
562 | m_jkLog->LogMessage(L"- Size of small gaps: %I64d bytes, %I64d clusters",
563 | Data->CountClustersLess16 * Data->BytesPerCluster,
564 | Data->CountClustersLess16);
565 | }
566 |
567 | if (Data->CountGaps > 0)
568 | {
569 | m_jkLog->LogMessage(L"- Number of big gaps: %I64d (%.04f%% of all gaps)",
570 | Data->CountGaps - Data->CountGapsLess16,
571 | (double)((Data->CountGaps - Data->CountGapsLess16) * 100) / Data->CountGaps);
572 | }
573 | else
574 | {
575 | m_jkLog->LogMessage(L"- Number of big gaps: %I64d",
576 | Data->CountGaps - Data->CountGapsLess16);
577 | }
578 |
579 | if (Data->CountFreeClusters > 0)
580 | {
581 | m_jkLog->LogMessage(L"- Size of big gaps: %I64d bytes, %I64d clusters, %.04f%% of free disk space",
582 | (Data->CountFreeClusters - Data->CountClustersLess16) * Data->BytesPerCluster,
583 | Data->CountFreeClusters - Data->CountClustersLess16,
584 | (double)((Data->CountFreeClusters - Data->CountClustersLess16) * 100) / Data->CountFreeClusters);
585 | }
586 | else
587 | {
588 | m_jkLog->LogMessage(L"- Size of big gaps: %I64d bytes, %I64d clusters",
589 | (Data->CountFreeClusters - Data->CountClustersLess16) * Data->BytesPerCluster,
590 | Data->CountFreeClusters - Data->CountClustersLess16);
591 | }
592 |
593 | if (Data->CountGaps > 0)
594 | {
595 | m_jkLog->LogMessage(L"- Average gap size: %.04f clusters",
596 | (double)(Data->CountFreeClusters) / Data->CountGaps);
597 | }
598 |
599 | if (Data->CountFreeClusters > 0)
600 | {
601 | m_jkLog->LogMessage(L"- Biggest gap: %I64d bytes, %I64d clusters, %.04f%% of free disk space",
602 | Data->BiggestGap * Data->BytesPerCluster,
603 | Data->BiggestGap,
604 | (double)(Data->BiggestGap * 100) / Data->CountFreeClusters);
605 | }
606 | else
607 | {
608 | m_jkLog->LogMessage(L"- Biggest gap: %I64d bytes, %I64d clusters",
609 | Data->BiggestGap * Data->BytesPerCluster,
610 | Data->BiggestGap);
611 | }
612 |
613 | if (Data->TotalClusters > 0)
614 | {
615 | m_jkLog->LogMessage(L"- Average end-begin distance: %.0f clusters, %.4f%% of volume size",
616 | Data->AverageDistance,100.0 * Data->AverageDistance / Data->TotalClusters);
617 | }
618 | else
619 | {
620 | m_jkLog->LogMessage(L"- Average end-begin distance: %.0f clusters",Data->AverageDistance);
621 | }
622 |
623 | for (Item = m_jkLib->TreeSmallest(Data->ItemTree); Item != NULL; Item = m_jkLib->TreeNext(Item))
624 | {
625 | if (Item->Unmovable != YES) continue;
626 | if (Item->Exclude == YES) continue;
627 | if ((Item->Directory == YES) && (Data->CannotMoveDirs > 20)) continue;
628 | break;
629 | }
630 |
631 | if (Item != NULL)
632 | {
633 | m_jkLog->LogMessage(L"These items could not be moved:");
634 | m_jkLog->LogMessage(L" Fragments Bytes Clusters Name");
635 |
636 | TotalFragments = 0;
637 | TotalBytes = 0;
638 | TotalClusters = 0;
639 |
640 | for (Item = m_jkLib->TreeSmallest(Data->ItemTree); Item != NULL; Item = m_jkLib->TreeNext(Item))
641 | {
642 | if (Item->Unmovable != YES) continue;
643 | if (Item->Exclude == YES) continue;
644 | if ((Item->Directory == YES) && (Data->CannotMoveDirs > 20)) continue;
645 | if ((Item->LongFilename != NULL) &&
646 | ((_wcsicmp(Item->LongFilename,L"$BadClus") == 0) ||
647 | (_wcsicmp(Item->LongFilename,L"$BadClus:$Bad:$DATA") == 0))) continue;
648 |
649 | Fragments = m_jkLib->FragmentCount(Item);
650 |
651 | if (Item->LongPath == NULL)
652 | {
653 | m_jkLog->LogMessage(L" %9lu %11I64u %9I64u [at cluster %I64u]",Fragments,Item->Bytes,Item->Clusters,
654 | m_jkLib->GetItemLcn(Item));
655 | }
656 | else
657 | {
658 | m_jkLog->LogMessage(L" %9lu %11I64u %9I64u %s",Fragments,Item->Bytes,Item->Clusters,Item->LongPath);
659 | }
660 |
661 | TotalFragments = TotalFragments + Fragments;
662 | TotalBytes = TotalBytes + Item->Bytes;
663 | TotalClusters = TotalClusters + Item->Clusters;
664 | }
665 |
666 | m_jkLog->LogMessage(L" --------- ----------- --------- -----");
667 | m_jkLog->LogMessage(L" %9I64u %11I64u %9I64u Total",TotalFragments,TotalBytes,TotalClusters);
668 | }
669 |
670 | for (Item = m_jkLib->TreeSmallest(Data->ItemTree); Item != NULL; Item = m_jkLib->TreeNext(Item))
671 | {
672 | if (Item->Exclude == YES) continue;
673 | if ((Item->Directory == YES) && (Data->CannotMoveDirs > 20)) continue;
674 |
675 | Fragments = m_jkLib->FragmentCount(Item);
676 |
677 | if (Fragments <= 1) continue;
678 |
679 | break;
680 | }
681 |
682 | if (Item != NULL)
683 | {
684 | m_jkLog->LogMessage(L"These items are still fragmented:");
685 | m_jkLog->LogMessage(L" Fragments Bytes Clusters Name");
686 |
687 | TotalFragments = 0;
688 | TotalBytes = 0;
689 | TotalClusters = 0;
690 |
691 | for (Item = m_jkLib->TreeSmallest(Data->ItemTree); Item != NULL; Item = m_jkLib->TreeNext(Item))
692 | {
693 | if (Item->Exclude == YES) continue;
694 | if ((Item->Directory == YES) && (Data->CannotMoveDirs > 20)) continue;
695 |
696 | Fragments = m_jkLib->FragmentCount(Item);
697 |
698 | if (Fragments <= 1) continue;
699 |
700 | if (Item->LongPath == NULL)
701 | {
702 | m_jkLog->LogMessage(L" %9lu %11I64u %9I64u [at cluster %I64u]",Fragments,Item->Bytes,Item->Clusters,
703 | m_jkLib->GetItemLcn(Item));
704 | }
705 | else
706 | {
707 | m_jkLog->LogMessage(L" %9lu %11I64u %9I64u %s",Fragments,Item->Bytes,Item->Clusters,Item->LongPath);
708 | }
709 |
710 | TotalFragments = TotalFragments + Fragments;
711 | TotalBytes = TotalBytes + Item->Bytes;
712 | TotalClusters = TotalClusters + Item->Clusters;
713 | }
714 |
715 | m_jkLog->LogMessage(L" --------- ----------- --------- -----");
716 | m_jkLog->LogMessage(L" %9I64u %11I64u %9I64u Total",TotalFragments,TotalBytes,TotalClusters);
717 | }
718 |
719 | LastLargest = 0;
720 |
721 | for (Item = m_jkLib->TreeSmallest(Data->ItemTree); Item != NULL; Item = m_jkLib->TreeNext(Item))
722 | {
723 | if ((Item->LongFilename != NULL) &&
724 | ((_wcsicmp(Item->LongFilename,L"$BadClus") == 0) ||
725 | (_wcsicmp(Item->LongFilename,L"$BadClus:$Bad:$DATA") == 0)))
726 | {
727 | continue;
728 | }
729 |
730 | for (i = LastLargest - 1; i >= 0; i--)
731 | {
732 | if (Item->Clusters < LargestItems[i]->Clusters) break;
733 |
734 | if ((Item->Clusters == LargestItems[i]->Clusters) &&
735 | (Item->Bytes < LargestItems[i]->Bytes)) break;
736 |
737 | if ((Item->Clusters == LargestItems[i]->Clusters) &&
738 | (Item->Bytes == LargestItems[i]->Bytes) &&
739 | (Item->LongPath != NULL) &&
740 | (LargestItems[i]->LongPath != NULL) &&
741 | (_wcsicmp(Item->LongPath,LargestItems[i]->LongPath) > 0)) break;
742 | }
743 |
744 | if (i < 24)
745 | {
746 | if (LastLargest < 25) LastLargest++;
747 |
748 | for (j = LastLargest - 1; j > i + 1; j--)
749 | {
750 | LargestItems[j] = LargestItems[j-1];
751 | }
752 |
753 | LargestItems[i + 1] = Item;
754 | }
755 | }
756 |
757 | if (LastLargest > 0)
758 | {
759 | m_jkLog->LogMessage(L"The 25 largest items on disk:");
760 | m_jkLog->LogMessage(L" Fragments Bytes Clusters Name");
761 |
762 | for (i = 0; i < LastLargest; i++)
763 | {
764 | if (LargestItems[i]->LongPath == NULL)
765 | {
766 | m_jkLog->LogMessage(L" %9u %11I64u %9I64u [at cluster %I64u]",m_jkLib->FragmentCount(LargestItems[i]),
767 | LargestItems[i]->Bytes,LargestItems[i]->Clusters,m_jkLib->GetItemLcn(LargestItems[i]));
768 | }
769 | else
770 | {
771 | m_jkLog->LogMessage(L" %9u %11I64u %9I64u %s",m_jkLib->FragmentCount(LargestItems[i]),
772 | LargestItems[i]->Bytes,LargestItems[i]->Clusters,LargestItems[i]->LongPath);
773 | }
774 | }
775 | }
776 | }
777 | }
778 |
779 |
780 | void JKDefragGui::PaintImage(HDC hdc)
781 | {
782 | Graphics *graphics = Graphics::FromImage(m_bmp);
783 |
784 | double Done;
785 |
786 | Rect windowSize = m_clientWindowSize;
787 | Rect drawArea;
788 |
789 | float squareSizeUnit = (float)(1 / (float)m_squareSize);
790 |
791 | /* Reset the display idle timer (screen saver) and system idle timer (power saver). */
792 | SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED);
793 |
794 | if (ProgressTodo > 0)
795 | {
796 | Done = (double)((double)ProgressDone / (double)ProgressTodo);
797 |
798 | if (Done > 1) Done = 1;
799 |
800 | swprintf_s(Messages[2],50000,L"%.4f%%",100 * Done);
801 | }
802 |
803 | Color backColor1;
804 | backColor1.SetFromCOLORREF(RGB(0, 0, 255));
805 |
806 | Color backColor2;
807 | backColor2.SetFromCOLORREF(RGB(255, 0, 0));
808 |
809 | LinearGradientBrush bgBrush(windowSize,Color::DarkBlue,Color::LightBlue,LinearGradientModeForwardDiagonal);
810 |
811 | drawArea = windowSize;
812 |
813 | drawArea.Height = m_topHeight + 1;
814 |
815 | Color busyColor;
816 | busyColor.SetFromCOLORREF(Colors[JKDefragStruct::COLORBUSY]);
817 |
818 | SolidBrush busyBrush(busyColor);
819 |
820 | /*
821 | graphics->FillRectangle(&busyBrush, drawArea);
822 | */
823 | graphics->FillRectangle(&bgBrush, drawArea);
824 |
825 | SolidBrush brush(Color::White);
826 |
827 | FontFamily fontFamily(L"Tahoma");
828 | Font font(&fontFamily,12,FontStyleRegular, UnitPixel);
829 | WCHAR *text;
830 | PointF pointF(2.0f, 0.0f);
831 |
832 | text = Messages[0];
833 | graphics->DrawString(text, -1, &font, pointF, &brush);
834 |
835 | pointF = PointF(40.0f, 0.0f);
836 | text = Messages[1];
837 | graphics->DrawString(text, -1, &font, pointF, &brush);
838 |
839 | pointF = PointF(200.0f, 0.0f);
840 | text = Messages[2];
841 | graphics->DrawString(text, -1, &font, pointF, &brush);
842 |
843 | pointF = PointF(280.0f, 0.0f);
844 | text = Messages[3];
845 | graphics->DrawString(text, -1, &font, pointF, &brush);
846 |
847 | pointF = PointF(2.0f, 17.0f);
848 | text = Messages[4];
849 | graphics->DrawString(text, -1, &font, pointF, &brush);
850 |
851 | if (m_debugLevel > 1)
852 | {
853 | pointF = PointF(2.0f, 33.0f);
854 | text = Messages[5];
855 | graphics->DrawString(text, -1, &font, pointF, &brush);
856 | }
857 |
858 |
859 | int xx1 = m_realOffsetX - 1;
860 | int yy1 = m_realOffsetY + m_topHeight - 1;
861 |
862 | int xx2 = xx1 + m_numDiskSquaresX * m_squareSize + 1;
863 | int yy2 = yy1 + m_numDiskSquaresY * m_squareSize + 1;
864 |
865 | /*
866 | Color bottomPartColor;
867 | bottomPartColor.SetFromCOLORREF(Colors[JKDefragStruct::COLORBUSY]);
868 |
869 | SolidBrush bottomPartBrush(bottomPartColor);
870 | */
871 |
872 | drawArea = Rect(0, m_topHeight + 1, m_clientWindowSize.Width, yy1 - m_topHeight - 2);
873 | /*
874 | graphics->FillRectangle(&bottomPartBrush, drawArea);
875 | */
876 | graphics->FillRectangle(&bgBrush, drawArea);
877 |
878 | drawArea = Rect(0, yy2 + 2, m_clientWindowSize.Width, m_clientWindowSize.Height - yy2 - 2);
879 | /*
880 | graphics->FillRectangle(&bottomPartBrush, drawArea);
881 | */
882 | graphics->FillRectangle(&bgBrush, drawArea);
883 |
884 | drawArea = Rect(0, yy1 - 1, xx1 - 1, yy2 - yy1 + 3);
885 | /*
886 | graphics->FillRectangle(&bottomPartBrush, drawArea);
887 | */
888 | graphics->FillRectangle(&bgBrush, drawArea);
889 |
890 | drawArea = Rect(xx2, yy1 - 1, m_clientWindowSize.Width - xx2, yy2 - yy1 + 3);
891 | /*
892 | graphics->FillRectangle(&bottomPartBrush, drawArea);
893 | */
894 | graphics->FillRectangle(&bgBrush, drawArea);
895 |
896 | Pen pen1(Color(0,0,0));
897 | Pen pen2(Color(255,255,255));
898 |
899 | graphics->DrawLine(&pen1, xx1, yy2, xx1, yy1);
900 | graphics->DrawLine(&pen1, xx1, yy1, xx2, yy1);
901 | graphics->DrawLine(&pen1, xx2, yy1, xx2, yy2);
902 | graphics->DrawLine(&pen1, xx2, yy2, xx1, yy2);
903 |
904 | graphics->DrawLine(&pen2, xx1 - 1, yy2 + 1, xx1 - 1, yy1 - 1);
905 | graphics->DrawLine(&pen2, xx1 - 1, yy1 - 1, xx2 + 1, yy1 - 1);
906 | graphics->DrawLine(&pen2, xx2 + 1, yy1 - 1, xx2 + 1, yy2 + 1);
907 | graphics->DrawLine(&pen2, xx2 + 1, yy2 + 1, xx1 - 1, yy2 + 1);
908 |
909 | COLORREF colEmpty = Colors[JKDefragStruct::COLOREMPTY];
910 | Color colorEmpty;
911 | colorEmpty.SetFromCOLORREF(colEmpty);
912 |
913 | Pen pen(Color(210,210,210));
914 | Pen penEmpty(colorEmpty);
915 |
916 | for (int jj = 0; jj < m_numDiskSquares; jj++)
917 | {
918 | if (m_clusterSquares[jj].dirty == false)
919 | {
920 | continue;
921 | }
922 |
923 | m_clusterSquares[jj].dirty = false;
924 |
925 | int x1 = jj % m_numDiskSquaresX;
926 | int y1 = jj / m_numDiskSquaresX;
927 |
928 | int xx1 = m_realOffsetX + x1 * m_squareSize;
929 | int yy1 = m_realOffsetY + y1 * m_squareSize + m_topHeight;
930 |
931 | byte clusterEmpty = (m_clusterSquares[jj].color & (1 << 7)) >> 7;
932 | byte clusterAllocated = (m_clusterSquares[jj].color & (1 << 6)) >> 6;
933 | byte clusterUnfragmented = (m_clusterSquares[jj].color & (1 << 5)) >> 5;
934 | byte clusterUnmovable = (m_clusterSquares[jj].color & (1 << 4)) >> 4;
935 | byte clusterFragmented = (m_clusterSquares[jj].color & (1 << 3)) >> 3;
936 | byte clusterBusy = (m_clusterSquares[jj].color & (1 << 2)) >> 2;
937 | byte clusterMft = (m_clusterSquares[jj].color & (1 << 1)) >> 1;
938 | byte clusterSpacehog = (m_clusterSquares[jj].color & 1);
939 |
940 | COLORREF col = Colors[JKDefragStruct::COLOREMPTY];
941 |
942 | int emptyCluster = true;
943 |
944 | if (clusterBusy == 1)
945 | {
946 | col = Colors[JKDefragStruct::COLORBUSY];
947 | emptyCluster = false;
948 | }
949 | else if (clusterUnmovable == 1)
950 | {
951 | col = Colors[JKDefragStruct::COLORUNMOVABLE];
952 | emptyCluster = false;
953 | }
954 | else if (clusterFragmented == 1)
955 | {
956 | col = Colors[JKDefragStruct::COLORFRAGMENTED];
957 | emptyCluster = false;
958 | }
959 | else if (clusterMft == 1)
960 | {
961 | col = Colors[JKDefragStruct::COLORMFT];
962 | emptyCluster = false;
963 | }
964 | else if (clusterUnfragmented == 1)
965 | {
966 | col = Colors[JKDefragStruct::COLORUNFRAGMENTED];
967 | emptyCluster = false;
968 | }
969 | else if (clusterSpacehog == 1)
970 | {
971 | col = Colors[JKDefragStruct::COLORSPACEHOG];
972 | emptyCluster = false;
973 | }
974 |
975 | Color C1;
976 | Color C2;
977 |
978 | C1.SetFromCOLORREF(col);
979 |
980 | int RR = GetRValue(col) + 200;
981 | RR = (RR > 255) ? 255 : RR;
982 |
983 | int GG = GetGValue(col) + 200;
984 | GG = (GG > 255) ? 255 : GG;
985 |
986 | int BB = GetBValue(col) + 100;
987 | BB = (BB > 255) ? 255 : BB;
988 |
989 | C2.SetFromCOLORREF(RGB((byte)RR, (byte)GG, (byte)BB));
990 |
991 | if (emptyCluster)
992 | {
993 | Rect drawArea2(xx1, yy1, m_squareSize - 0, m_squareSize - 0);
994 |
995 | LinearGradientBrush BB2(drawArea2,C1,C2,LinearGradientModeVertical);
996 | graphics->FillRectangle(&BB2, drawArea2);
997 |
998 | int lineX1 = drawArea2.X;
999 | int lineY1 = drawArea2.Y;
1000 | int lineX2 = drawArea2.X + m_squareSize - 1;
1001 | int lineY2 = drawArea2.Y;
1002 | int lineX3 = drawArea2.X;
1003 | int lineY3 = drawArea2.Y + m_squareSize - 1;
1004 | int lineX4 = drawArea2.X + m_squareSize - 1;
1005 | int lineY4 = drawArea2.Y + m_squareSize - 1;
1006 |
1007 | graphics->DrawLine(&penEmpty, lineX1, lineY1, lineX2, lineY2);
1008 | graphics->DrawLine(&pen, lineX3, lineY3, lineX4, lineY4);
1009 | }
1010 | else
1011 | {
1012 | Rect drawArea2(xx1, yy1, m_squareSize - 0, m_squareSize - 0);
1013 |
1014 | LinearGradientBrush BB1(drawArea2,C2,C1,LinearGradientModeForwardDiagonal);
1015 |
1016 | graphics->FillRectangle(&BB1, drawArea2);
1017 |
1018 | int lineX1 = drawArea2.X;
1019 | int lineY1 = drawArea2.Y + m_squareSize - 1;
1020 | int lineX2 = drawArea2.X + m_squareSize - 1;
1021 | int lineY2 = drawArea2.Y;
1022 | int lineX3 = drawArea2.X + m_squareSize - 1;
1023 | int lineY3 = drawArea2.Y + m_squareSize - 1;
1024 |
1025 | graphics->DrawLine(&pen, lineX1, lineY1, lineX3, lineY3);
1026 | graphics->DrawLine(&pen, lineX2, lineY2, lineX3, lineY3);
1027 | }
1028 |
1029 | }
1030 |
1031 | delete graphics;
1032 |
1033 | }
1034 |
1035 | void JKDefragGui::OnPaint(HDC hdc)
1036 | {
1037 | /*
1038 | Bitmap bmp(m_clientWindowSize.Width, m_clientWindowSize.Height);
1039 |
1040 | Graphics *graphics2 = Graphics::FromImage(&bmp);
1041 | */
1042 |
1043 | Graphics graphics(hdc);
1044 |
1045 | /*
1046 | graphics2->DrawImage(m_bmp,0,0);
1047 | */
1048 |
1049 | /*
1050 | Color busyColor(128,128,128,128);
1051 |
1052 | SolidBrush busyBrush(busyColor);
1053 |
1054 | Rect rr = Rect(100, 100, 400, 100);
1055 |
1056 | graphics2->FillRectangle(&busyBrush, rr);
1057 |
1058 | SolidBrush brush(Color::White);
1059 |
1060 | FontFamily fontFamily(L"Tahoma");
1061 | Font font(&fontFamily,12,FontStyleRegular, UnitPixel);
1062 | PointF pointF(132.0f, 120.0f);
1063 |
1064 | WCHAR *text;
1065 |
1066 | text = Messages[2];
1067 |
1068 | graphics2->DrawString(text, -1, &font, pointF, &brush);
1069 | */
1070 |
1071 | graphics.DrawImage(m_bmp,0,0);
1072 |
1073 | /*
1074 | delete graphics2;
1075 | */
1076 |
1077 | return;
1078 | }
1079 |
1080 | /* Message handler. */
1081 | LRESULT CALLBACK JKDefragGui::ProcessMessagefn(HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam)
1082 | {
1083 | switch(Message)
1084 | {
1085 | case WM_DESTROY:
1086 | PostQuitMessage(0);
1087 | return 0;
1088 |
1089 | case WM_TIMER:
1090 |
1091 | /*
1092 | if (wParam == 333)
1093 | {
1094 | PAINTSTRUCT ps;
1095 |
1096 | WaitForSingleObject(m_jkDefragGui->m_displayMutex,100);
1097 |
1098 | m_jkDefragGui->m_displayMutex = CreateMutex(NULL,FALSE,"JKDefrag");
1099 |
1100 | m_jkDefragGui->m_hDC = BeginPaint(hWnd, &ps);
1101 |
1102 | m_jkDefragGui->setDisplayData(m_jkDefragGui->m_hDC);
1103 |
1104 | m_jkDefragGui->FillSquares( 0, m_jkDefragGui->m_numDiskSquares);
1105 |
1106 | m_jkDefragGui->PaintImage(m_jkDefragGui->m_hDC);
1107 |
1108 | EndPaint(hWnd, &ps);
1109 |
1110 | ReleaseMutex(m_jkDefragGui->m_displayMutex);
1111 |
1112 | KillTimer(m_jkDefragGui->m_hWnd, m_jkDefragGui->m_sizeTimer);
1113 | }
1114 | */
1115 |
1116 |
1117 | InvalidateRect(hWnd,NULL,FALSE);
1118 |
1119 | return 0;
1120 |
1121 | case WM_PAINT:
1122 | {
1123 | /* Grab the display mutex, to make sure that we are the only thread changing the window. */
1124 | WaitForSingleObject(m_jkDefragGui->m_displayMutex,100);
1125 |
1126 | m_jkDefragGui->m_displayMutex = CreateMutex(NULL,FALSE,"JKDefrag");
1127 |
1128 | PAINTSTRUCT ps;
1129 |
1130 | m_jkDefragGui->m_hDC = BeginPaint(hWnd, &ps);
1131 |
1132 | m_jkDefragGui->OnPaint(m_jkDefragGui->m_hDC);
1133 |
1134 | EndPaint(hWnd, &ps);
1135 |
1136 | ReleaseMutex(m_jkDefragGui->m_displayMutex);
1137 | }
1138 |
1139 | return 0;
1140 |
1141 |
1142 | case WM_ERASEBKGND:
1143 | {
1144 | // m_jkDefragGui->RedrawScreen = 0;
1145 | InvalidateRect(m_jkDefragGui->m_hWnd,NULL,FALSE);
1146 | }
1147 |
1148 | return 0;
1149 | /*
1150 | case WM_WINDOWPOSCHANGED:
1151 | {
1152 | m_jkDefragGui->RedrawScreen = 0;
1153 | InvalidateRect(m_jkDefragGui->m_hWnd,NULL,FALSE);
1154 | }
1155 |
1156 | return 0;
1157 | */
1158 |
1159 | case WM_SIZE:
1160 | {
1161 |
1162 | /*
1163 | m_jkDefragGui->m_sizeTimer = SetTimer(m_jkDefragGui->m_hWnd,333,500,NULL);
1164 | */
1165 |
1166 |
1167 |
1168 | PAINTSTRUCT ps;
1169 |
1170 | WaitForSingleObject(m_jkDefragGui->m_displayMutex,100);
1171 |
1172 | m_jkDefragGui->m_displayMutex = CreateMutex(NULL,FALSE,"JKDefrag");
1173 |
1174 | m_jkDefragGui->m_hDC = BeginPaint(hWnd, &ps);
1175 |
1176 | m_jkDefragGui->setDisplayData(m_jkDefragGui->m_hDC);
1177 |
1178 | m_jkDefragGui->FillSquares( 0, m_jkDefragGui->m_numDiskSquares);
1179 |
1180 | m_jkDefragGui->PaintImage(m_jkDefragGui->m_hDC);
1181 |
1182 | EndPaint(hWnd, &ps);
1183 |
1184 | ReleaseMutex(m_jkDefragGui->m_displayMutex);
1185 |
1186 | }
1187 |
1188 | return 0;
1189 | }
1190 |
1191 | return(DefWindowProc(hWnd,Message,wParam,lParam));
1192 | }
1193 |
1194 | void JKDefragGui::FillSquares( int clusterStartSquareNum, int clusterEndSquareNum )
1195 | {
1196 | float clusterPerSquare = (float)(m_numClusters / m_numDiskSquares);
1197 |
1198 | for(int ii = clusterStartSquareNum; ii <= clusterEndSquareNum; ii++)
1199 | {
1200 | byte currentColor = JKDefragStruct::COLOREMPTY;
1201 |
1202 | byte clusterEmpty = 0;
1203 | byte clusterAllocated = 0;
1204 | byte clusterUnfragmented = 0;
1205 | byte clusterUnmovable= 0;
1206 | byte clusterFragmented = 0;
1207 | byte clusterBusy = 0;
1208 | byte clusterMft = 0;
1209 | byte clusterSpacehog = 0;
1210 |
1211 | for(int kk = (int)(ii * clusterPerSquare); kk < m_numClusters && kk < (int)((ii + 1) * clusterPerSquare); kk++)
1212 | {
1213 | switch (clusterInfo[kk])
1214 | {
1215 | case JKDefragStruct::COLOREMPTY:
1216 | clusterEmpty = 1;
1217 | break;
1218 | case JKDefragStruct::COLORALLOCATED:
1219 | clusterAllocated = 1;
1220 | break;
1221 | case JKDefragStruct::COLORUNFRAGMENTED:
1222 | clusterUnfragmented = 1;
1223 | break;
1224 | case JKDefragStruct::COLORUNMOVABLE:
1225 | clusterUnmovable = 1;
1226 | break;
1227 | case JKDefragStruct::COLORFRAGMENTED:
1228 | clusterFragmented = 1;
1229 | break;
1230 | case JKDefragStruct::COLORBUSY:
1231 | clusterBusy = 1;
1232 | break;
1233 | case JKDefragStruct::COLORMFT:
1234 | clusterMft = 1;
1235 | break;
1236 | case JKDefragStruct::COLORSPACEHOG:
1237 | clusterSpacehog = 1;
1238 | break;
1239 | }
1240 | }
1241 |
1242 | if (ii < m_numDiskSquares)
1243 | {
1244 | m_clusterSquares[ii].dirty = true;
1245 | m_clusterSquares[ii].color = //maxColor;
1246 | clusterEmpty << 7 |
1247 | clusterAllocated << 6 |
1248 | clusterUnfragmented << 5 |
1249 | clusterUnmovable << 4 |
1250 | clusterFragmented << 3 |
1251 | clusterBusy << 2 |
1252 | clusterMft << 1 |
1253 | clusterSpacehog;
1254 | }
1255 | }
1256 | }
1257 |
1258 | /*
1259 |
1260 | Show a map on the screen of all the clusters on disk. The map shows
1261 | which clusters are free and which are in use.
1262 | The Data->RedrawScreen flag controls redrawing of the screen. It is set
1263 | to "2" (busy) when the subroutine starts. If another thread changes it to
1264 | "1" (request) while the subroutine is busy then it will immediately exit
1265 | without completing the redraw. When redrawing is completely finished the
1266 | flag is set to "0" (no).
1267 |
1268 | */
1269 | void JKDefragGui::ShowDiskmap(struct DefragDataStruct *Data)
1270 | {
1271 | struct ItemStruct *Item;
1272 |
1273 | STARTING_LCN_INPUT_BUFFER BitmapParam;
1274 |
1275 | struct
1276 | {
1277 | ULONG64 StartingLcn;
1278 | ULONG64 BitmapSize;
1279 |
1280 | BYTE Buffer[65536]; /* Most efficient if binary multiple. */
1281 | } BitmapData;
1282 |
1283 | ULONG64 Lcn;
1284 | ULONG64 ClusterStart;
1285 |
1286 | DWORD ErrorCode;
1287 |
1288 | int Index;
1289 | int IndexMax;
1290 |
1291 | BYTE Mask;
1292 |
1293 | int InUse;
1294 | int PrevInUse;
1295 |
1296 | DWORD w;
1297 |
1298 | int i;
1299 |
1300 | // *Data->RedrawScreen = 2; /* Set the flag to "busy". */
1301 |
1302 | /* Exit if the library is not processing a disk yet. */
1303 | if (Data->Disk.VolumeHandle == NULL)
1304 | {
1305 | // *Data->RedrawScreen = 0; /* Set the flag to "no". */
1306 | return;
1307 | }
1308 |
1309 | /* Clear screen. */
1310 | ClearScreen(NULL);
1311 |
1312 | /* Show the map of all the clusters in use. */
1313 | Lcn = 0;
1314 | ClusterStart = 0;
1315 | PrevInUse = 1;
1316 |
1317 | do
1318 | {
1319 | if (*Data->Running != RUNNING) break;
1320 | // if (*Data->RedrawScreen != 2) break;
1321 | if (Data->Disk.VolumeHandle == INVALID_HANDLE_VALUE) break;
1322 |
1323 | /* Fetch a block of cluster data. */
1324 | BitmapParam.StartingLcn.QuadPart = Lcn;
1325 |
1326 | ErrorCode = DeviceIoControl(Data->Disk.VolumeHandle,FSCTL_GET_VOLUME_BITMAP,
1327 | &BitmapParam,sizeof(BitmapParam),&BitmapData,sizeof(BitmapData),&w,NULL);
1328 |
1329 | if (ErrorCode != 0)
1330 | {
1331 | ErrorCode = NO_ERROR;
1332 | }
1333 | else
1334 | {
1335 | ErrorCode = GetLastError();
1336 | }
1337 |
1338 | if ((ErrorCode != NO_ERROR) && (ErrorCode != ERROR_MORE_DATA)) break;
1339 |
1340 | /* Sanity check. */
1341 | if (Lcn >= BitmapData.StartingLcn + BitmapData.BitmapSize) break;
1342 |
1343 | /* Analyze the clusterdata. We resume where the previous block left off. */
1344 | Lcn = BitmapData.StartingLcn;
1345 | Index = 0;
1346 | Mask = 1;
1347 |
1348 | IndexMax = sizeof(BitmapData.Buffer);
1349 |
1350 | if (BitmapData.BitmapSize / 8 < IndexMax) IndexMax = (int)(BitmapData.BitmapSize / 8);
1351 |
1352 | while ((Index < IndexMax) && (*Data->Running == RUNNING))
1353 | {
1354 | InUse = (BitmapData.Buffer[Index] & Mask);
1355 |
1356 | /* If at the beginning of the disk then copy the InUse value as our
1357 | starting value. */
1358 | if (Lcn == 0) PrevInUse = InUse;
1359 |
1360 | /* At the beginning and end of an Exclude draw the cluster. */
1361 | if ((Lcn == Data->MftExcludes[0].Start) || (Lcn == Data->MftExcludes[0].End) ||
1362 | (Lcn == Data->MftExcludes[1].Start) || (Lcn == Data->MftExcludes[1].End) ||
1363 | (Lcn == Data->MftExcludes[2].Start) || (Lcn == Data->MftExcludes[2].End))
1364 | {
1365 | if ((Lcn == Data->MftExcludes[0].End) ||
1366 | (Lcn == Data->MftExcludes[1].End) ||
1367 | (Lcn == Data->MftExcludes[2].End))
1368 | {
1369 | DrawCluster(Data,ClusterStart,Lcn,JKDefragStruct::COLORUNMOVABLE);
1370 | }
1371 | else
1372 | if (PrevInUse == 0)
1373 | {
1374 | DrawCluster(Data,ClusterStart,Lcn,JKDefragStruct::COLOREMPTY);
1375 | }
1376 | else
1377 | {
1378 | DrawCluster(Data,ClusterStart,Lcn,JKDefragStruct::COLORALLOCATED);
1379 | }
1380 |
1381 | InUse = 1;
1382 | PrevInUse = 1;
1383 | ClusterStart = Lcn;
1384 | }
1385 |
1386 | if ((PrevInUse == 0) && (InUse != 0)) /* Free */
1387 | {
1388 | DrawCluster(Data,ClusterStart,Lcn,JKDefragStruct::COLOREMPTY);
1389 |
1390 | ClusterStart = Lcn;
1391 | }
1392 |
1393 | if ((PrevInUse != 0) && (InUse == 0)) /* In use */
1394 | {
1395 | DrawCluster(Data,ClusterStart,Lcn,JKDefragStruct::COLORALLOCATED);
1396 |
1397 | ClusterStart = Lcn;
1398 | }
1399 |
1400 | PrevInUse = InUse;
1401 |
1402 | if (Mask == 128)
1403 | {
1404 | Mask = 1;
1405 | Index = Index + 1;
1406 | }
1407 | else
1408 | {
1409 | Mask = Mask << 1;
1410 | }
1411 |
1412 | Lcn = Lcn + 1;
1413 | }
1414 | } while ((ErrorCode == ERROR_MORE_DATA) && (Lcn < BitmapData.StartingLcn + BitmapData.BitmapSize));
1415 |
1416 | if ((Lcn > 0)/* && (*Data->RedrawScreen == 2)*/)
1417 | {
1418 | if (PrevInUse == 0) /* Free */
1419 | {
1420 | DrawCluster(Data,ClusterStart,Lcn,JKDefragStruct::COLOREMPTY);
1421 | }
1422 |
1423 | if (PrevInUse != 0) /* In use */
1424 | {
1425 | DrawCluster(Data,ClusterStart,Lcn,JKDefragStruct::COLORALLOCATED);
1426 | }
1427 | }
1428 |
1429 | /* Show the MFT zones. */
1430 | for (i = 0; i < 3; i++)
1431 | {
1432 | // if (*Data->RedrawScreen != 2) break;
1433 | if (Data->MftExcludes[i].Start <= 0) continue;
1434 |
1435 | DrawCluster(Data,Data->MftExcludes[i].Start, Data->MftExcludes[i].End, JKDefragStruct::COLORMFT);
1436 | }
1437 |
1438 | /* Colorize all the files on the screen.
1439 | Note: the "$BadClus" file on NTFS disks maps the entire disk, so we have to
1440 | ignore it. */
1441 | for (Item = m_jkLib->TreeSmallest(Data->ItemTree); Item != NULL; Item = m_jkLib->TreeNext(Item))
1442 | {
1443 | if (*Data->Running != RUNNING) break;
1444 | // if (*Data->RedrawScreen != 2) break;
1445 |
1446 | if ((Item->LongFilename != NULL) &&
1447 | ((_wcsicmp(Item->LongFilename,L"$BadClus") == 0) ||
1448 | (_wcsicmp(Item->LongFilename,L"$BadClus:$Bad:$DATA") == 0))) continue;
1449 |
1450 | m_jkLib->ColorizeItem(Data,Item,0,0,NO);
1451 | }
1452 |
1453 | /* Set the flag to "no". */
1454 | // if (*Data->RedrawScreen == 2) *Data->RedrawScreen = 0;
1455 | }
1456 |
--------------------------------------------------------------------------------
/JkDefrag/Source/JkDefragGui.h:
--------------------------------------------------------------------------------
1 | #ifndef __JKDEFRAGGUI_H__
2 | #define __JKDEFRAGGUI_H__
3 |
4 | const COLORREF Colors[9] = {
5 | RGB(150,150,150), /* 0 COLOREMPTY Empty diskspace. */
6 | RGB(200,200,200), /* 1 COLORALLOCATED Used diskspace / system files. */
7 | RGB(0,150,0), /* 2 COLORUNFRAGMENTED Unfragmented files. */
8 | RGB(128,0,0), /* 3 COLORUNMOVABLE Unmovable files. */
9 | RGB(200,100,60), /* 4 COLORFRAGMENTED Fragmented files. */
10 | RGB(0,0,255), /* 5 COLORBUSY Busy color. */
11 | RGB(255,0,255), /* 6 COLORMFT MFT reserved zones. */
12 | RGB(0,150,150), /* 7 COLORSPACEHOG Spacehogs. */
13 | RGB(255,255,255) /* 8 background */
14 | };
15 |
16 | struct clusterSquareStruct {
17 | bool dirty;
18 | byte color;
19 | } ;
20 |
21 | class JKDefragGui
22 | {
23 | public:
24 |
25 | // Constructor and destructor
26 | JKDefragGui();
27 | ~JKDefragGui();
28 |
29 | // Get instance of the class
30 | static JKDefragGui *getInstance();
31 |
32 | void ClearScreen(WCHAR *Format, ...);
33 | void DrawCluster(struct DefragDataStruct *Data, ULONG64 ClusterStart, ULONG64 ClusterEnd, int Color);
34 |
35 | void FillSquares( int clusterStartSquareNum, int clusterEndSquareNum );
36 | void ShowDebug(int Level, struct ItemStruct *Item, WCHAR *Format, ...);
37 | void ShowStatus(struct DefragDataStruct *Data);
38 | void ShowAnalyze(struct DefragDataStruct *Data, struct ItemStruct *Item);
39 | void ShowMove(struct ItemStruct *Item, ULONG64 Clusters, ULONG64 FromLcn, ULONG64 ToLcn, ULONG64 FromVcn);
40 | void ShowDiskmap(struct DefragDataStruct *Data);
41 |
42 | int Initialize(HINSTANCE hInstance, int nCmdShow, JKDefragLog *jkLog, int debugLevel);
43 | void setDisplayData(HDC hdc);
44 |
45 | WPARAM DoModal();
46 |
47 | void OnPaint(HDC hdc);
48 | void PaintImage(HDC hdc);
49 |
50 | static LRESULT CALLBACK ProcessMessagefn(HWND WindowHandle, UINT Message, WPARAM wParam, LPARAM lParam);
51 |
52 | private:
53 |
54 | HWND m_hWnd;
55 | WNDCLASSEX m_wndClass;
56 | MSG Message;
57 | UINT_PTR m_sizeTimer;
58 |
59 | WCHAR Messages[6][50000]; /* The texts displayed on the screen. */
60 | int m_debugLevel;
61 |
62 | ULONG64 ProgressStartTime; /* The time at percentage zero. */
63 | ULONG64 ProgressTime; /* When ProgressDone/ProgressTodo were last updated. */
64 | ULONG64 ProgressTodo; /* Number of clusters to do. */
65 | ULONG64 ProgressDone; /* Number of clusters already done. */
66 |
67 | JKDefragStruct *jkStruct;
68 |
69 | /* graphics data */
70 |
71 | int m_topHeight;
72 | int m_squareSize;
73 |
74 | // Offsets of drawing area of disk
75 | int m_offsetX;
76 | int m_offsetY;
77 |
78 | // Calculated offset of drawing area of disk
79 | int m_realOffsetX;
80 | int m_realOffsetY;
81 |
82 | // Size of drawing area of disk
83 | Rect m_diskAreaSize;
84 |
85 | // Number of squares in horizontal direction of disk area
86 | int m_numDiskSquaresX;
87 |
88 | // Number of squares in horizontal direction of disk area
89 | int m_numDiskSquaresY;
90 |
91 | // Total number of squares in disk area
92 | int m_numDiskSquares;
93 |
94 | // Color of each square in disk area and status if it is "dirty"
95 | struct clusterSquareStruct m_clusterSquares[1000000];
96 |
97 | // Color of each disk cluster
98 | byte *clusterInfo;
99 |
100 | // Number of disk clusters
101 | UINT64 m_numClusters;
102 |
103 | /* 0:no, 1:request, 2: busy. */
104 | // int RedrawScreen;
105 |
106 | // Current window size
107 | Rect m_clientWindowSize;
108 |
109 | // Mutex to make the display single-threaded.
110 | HANDLE m_displayMutex;
111 |
112 | // Handle to graphics device context
113 | HDC m_hDC;
114 |
115 | // Bitmap used for double buffering
116 | Bitmap *m_bmp;
117 |
118 | // pointer to logger
119 | JKDefragLog *m_jkLog;
120 |
121 | // pointer to library
122 | JKDefragLib *m_jkLib;
123 |
124 | // static member that is an instance of itself
125 | static JKDefragGui *m_jkDefragGui;
126 | };
127 |
128 |
129 | #endif
--------------------------------------------------------------------------------
/JkDefrag/Source/JkDefragLib.h:
--------------------------------------------------------------------------------
1 | /*
2 |
3 | The JkDefragDll library.
4 |
5 | This program is free software; you can redistribute it and/or modify
6 | it under the terms of the GNU General Public License as published by
7 | the Free Software Foundation; either version 2 of the License, or
8 | (at your option) any later version.
9 |
10 | This program is distributed in the hope that it will be useful,
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | GNU Lesser General Public License for more details.
14 |
15 | For the full text of the license see the "License lgpl.txt" file.
16 |
17 | Jeroen C. Kessels
18 | Internet Engineer
19 | http://www.kessels.com/
20 |
21 | */
22 |
23 |
24 | /* Include guard */
25 |
26 | #ifndef JKDEFRAGLIB
27 | #define JKDEFRAGLIB
28 |
29 | #define NO 0
30 | #define YES 1
31 |
32 | #define VIRTUALFRAGMENT 18446744073709551615 /* _UI64_MAX - 1 */
33 |
34 | /* The three running states. */
35 | #define RUNNING 0
36 | #define STOPPING 1
37 | #define STOPPED 2
38 |
39 | /* List in memory of the fragments of a file. */
40 |
41 | struct FragmentListStruct
42 | {
43 | ULONG64 Lcn; /* Logical cluster number, location on disk. */
44 | ULONG64 NextVcn; /* Virtual cluster number of next fragment. */
45 | struct FragmentListStruct *Next;
46 | };
47 |
48 | /* List in memory of all the files on disk, sorted by LCN (Logical Cluster Number). */
49 |
50 | struct ItemStruct
51 | {
52 | struct ItemStruct *Parent; /* Parent item. */
53 | struct ItemStruct *Smaller; /* Next smaller item. */
54 | struct ItemStruct *Bigger; /* Next bigger item. */
55 |
56 | WCHAR *LongFilename; /* Long filename. */
57 | WCHAR *LongPath; /* Full path on disk, long filenames. */
58 | WCHAR *ShortFilename; /* Short filename (8.3 DOS). */
59 | WCHAR *ShortPath; /* Full path on disk, short filenames. */
60 |
61 | ULONG64 Bytes; /* Total number of bytes. */
62 | ULONG64 Clusters; /* Total number of clusters. */
63 | ULONG64 CreationTime; /* 1 second = 10000000 */
64 | ULONG64 MftChangeTime;
65 | ULONG64 LastAccessTime;
66 |
67 | struct FragmentListStruct *Fragments; /* List of fragments. */
68 |
69 | ULONG64 ParentInode; /* The Inode number of the parent directory. */
70 |
71 | struct ItemStruct *ParentDirectory;
72 |
73 | BOOL Directory; /* YES: it's a directory. */
74 | BOOL Unmovable; /* YES: file can't/couldn't be moved. */
75 | BOOL Exclude; /* YES: file is not to be defragged/optimized. */
76 | BOOL SpaceHog; /* YES: file to be moved to end of disk. */
77 | };
78 |
79 | enum DiskType
80 | {
81 | UnknownType = 0,
82 | NTFS = 1,
83 | FAT12 = 12,
84 | FAT16 = 16,
85 | FAT32 = 32
86 | };
87 |
88 | /* Information about a disk volume. */
89 |
90 | struct DiskStruct
91 | {
92 | HANDLE VolumeHandle;
93 |
94 | WCHAR *MountPoint; /* Example: "c:" */
95 | WCHAR *MountPointSlash; /* Example: "c:\" */
96 | WCHAR VolumeName[52]; /* Example: "\\?\Volume{08439462-3004-11da-bbca-806d6172696f}" */
97 | WCHAR VolumeNameSlash[52]; /* Example: "\\?\Volume{08439462-3004-11da-bbca-806d6172696f}\" */
98 |
99 | DiskType Type;
100 |
101 | ULONG64 MftLockedClusters; /* Number of clusters at begin of MFT that cannot be moved. */
102 | };
103 |
104 | /* List of clusters used by the MFT. */
105 |
106 | struct ExcludesStruct
107 | {
108 | ULONG64 Start;
109 | ULONG64 End;
110 | };
111 |
112 | /* The big data struct that holds all the defragger's variables for a single thread. */
113 |
114 | struct DefragDataStruct
115 | {
116 | int Phase; /* The current Phase (1...3). */
117 | int Zone; /* The current Zone (0..2) for Phase 3. */
118 | int *Running; /* If not RUNNING then stop defragging. */
119 | // int *RedrawScreen; /* 0:no, 1:request, 2: busy. */
120 | BOOL UseLastAccessTime; /* If TRUE then use LastAccessTime for SpaceHogs. */
121 | int CannotMoveDirs; /* If bigger than 20 then do not move dirs. */
122 |
123 | WCHAR *IncludeMask; /* Example: "c:\t1\*" */
124 | struct DiskStruct Disk;
125 |
126 | double FreeSpace; /* Percentage of total disk size 0..100. */
127 |
128 | /* Tree in memory with information about all the files. */
129 |
130 | struct ItemStruct *ItemTree;
131 | int BalanceCount;
132 | WCHAR **Excludes; /* Array with exclude masks. */
133 | BOOL UseDefaultSpaceHogs; /* TRUE: use the built-in SpaceHogs. */
134 | WCHAR **SpaceHogs; /* Array with SpaceHog masks. */
135 | ULONG64 Zones[4]; /* Begin (LCN) of the zones. */
136 |
137 | struct ExcludesStruct MftExcludes[3]; /* List of clusters reserved for the MFT. */
138 |
139 | /* Counters filled before Phase 1. */
140 |
141 | ULONG64 TotalClusters; /* Size of the volume, in clusters. */
142 | ULONG64 BytesPerCluster; /* Number of bytes per cluster. */
143 |
144 | /* Counters updated before/after every Phase. */
145 |
146 | ULONG64 CountFreeClusters; /* Number of free clusters. */
147 | ULONG64 CountGaps; /* Number of gaps. */
148 | ULONG64 BiggestGap; /* Size of biggest gap, in clusters. */
149 | ULONG64 CountGapsLess16; /* Number of gaps smaller than 16 clusters. */
150 | ULONG64 CountClustersLess16; /* Number of clusters in gaps that are smaller than 16 clusters. */
151 |
152 | /* Counters updated after every Phase, but not before Phase 1 (analyze). */
153 |
154 | ULONG64 CountDirectories; /* Number of analysed subdirectories. */
155 | ULONG64 CountAllFiles; /* Number of analysed files. */
156 | ULONG64 CountFragmentedItems; /* Number of fragmented files. */
157 | ULONG64 CountAllBytes; /* Bytes in analysed files. */
158 | ULONG64 CountFragmentedBytes; /* Bytes in fragmented files. */
159 | ULONG64 CountAllClusters; /* Clusters in analysed files. */
160 | ULONG64 CountFragmentedClusters; /* Clusters in fragmented files. */
161 | double AverageDistance; /* Between end and begin of files. */
162 |
163 | /* Counters used to calculate the percentage of work done. */
164 |
165 | ULONG64 PhaseTodo; /* Number of items to do in this Phase. */
166 | ULONG64 PhaseDone; /* Number of items already done in this Phase. */
167 |
168 | /* Variables used to throttle the speed. */
169 |
170 | int Speed; /* Speed as a percentage 1..100. */
171 | LONG64 StartTime;
172 | LONG64 RunningTime;
173 | LONG64 LastCheckpoint;
174 |
175 | /* The array with error messages. */
176 | WCHAR **DebugMsg;
177 | };
178 |
179 |
180 | class JKDefragLib
181 | {
182 | public:
183 | JKDefragLib();
184 | ~JKDefragLib();
185 |
186 | static JKDefragLib *getInstance();
187 |
188 | /* Run the defragger/optimizer.
189 |
190 | The parameters:
191 |
192 | Path:
193 | The name of a disk, mountpoint, directory, or file. It may contain
194 | wildcards '*' and '?'. If Path is empty or NULL then defrag all the
195 | mounted, writable, fixed disks on the computer. Some examples:
196 |
197 | c:
198 | c:\xyz
199 | c:\xyz\*.txt
200 | \\?\Volume{08439462-3004-11da-bbca-806d6172696f}
201 |
202 | Mode:
203 | 0 = Analyze only, do not defragment and do not optimize.
204 | 1 = Analyze and fixup, do not optimize.
205 | 2 = Analyze, fixup, and fast optimization (default).
206 | 3 = Deprecated. Analyze, fixup, and full optimization.
207 | 4 = Analyze and force together.
208 | 5 = Analyze and move to end of disk.
209 | 6 = Analyze and sort files by name.
210 | 7 = Analyze and sort files by size (smallest first).
211 | 8 = Analyze and sort files by last access (newest first).
212 | 9 = Analyze and sort files by last change (oldest first).
213 | 10 = Analyze and sort files by creation time (oldest first).
214 |
215 | Speed:
216 | Percentage 0...100 of the normal speed. The defragger will slow down
217 | by inserting sleep periods so that the wall time is 100% and the
218 | actual processing time is this percentage. Specify 100 (or zero) to
219 | run at maximum speed.
220 |
221 | FreeSpace:
222 | Percentage 0...100 of the total volume space that must be kept
223 | free after the MFT and directories.
224 |
225 | Excludes:
226 | Array of strings. Each string contains a mask, last string must be
227 | NULL. If an item (disk, file, directory) matches one of the strings
228 | in this array then it will be ignored (skipped). Specify NULL to
229 | disable this feature.
230 |
231 | SpaceHogs:
232 | Array of strings. Each string contains a mask, last string must be
233 | NULL. If an item (file, directory) matches one of the strings in
234 | this array then it will be marked as a space hog and moved to the end
235 | of the disk. A build-in list of spacehogs will be added to this list,
236 | except if one of the strings in the array is "DisableDefaults".
237 |
238 | Running:
239 | Pointer to an integer. It is used by the StopJkDefrag() subroutine
240 | to stop the defragger. If the pointer is NULL then this feature is
241 | disabled.
242 |
243 | RedrawScreen:
244 | Pointer to an integer. It can be used by other threads to signal the
245 | defragger that it must redraw the screen, for example when the window
246 | is resized. If the pointer is NULL then this feature is disabled.
247 |
248 | ShowStatus:
249 | Callback subroutine. Is called just before the defragger starts a
250 | new Phase, and when it finishes a volume. Specify NULL if the callback
251 | is not needed.
252 |
253 | ShowMove:
254 | Callback subroutine. Is called whenever an item (file, directory) is
255 | moved on disk. Specify NULL if the callback is not needed.
256 |
257 | ShowAnalyze:
258 | Callback subroutine. Is called for every file during analysis.
259 | This subroutine is called one last time with Item=NULL when analysis
260 | has finished. Specify NULL if the callback is not needed.
261 |
262 | ShowDebug:
263 | Callback subroutine. Is called for every message to show. Specify NULL
264 | if the callback is not needed.
265 |
266 | DrawCluster:
267 | Callback subroutine. Is called to paint a fragment on the screen in
268 | a color. There are 7 colors, see the .h file. Specify NULL if the
269 | callback is not needed.
270 |
271 | ClearScreen:
272 | Callback subroutine. Is called when the defragger wants to clear the
273 | diskmap on the screen. Specify NULL if the callback is not needed.
274 |
275 | DebugMsg:
276 | Array of textmessages, used when the defragger wants to show a debug
277 | message. Specify NULL to use the internal default array of english text
278 | messages.
279 | */
280 |
281 | __declspec(dllexport) void RunJkDefrag(WCHAR *Path, int Mode, int Speed, double FreeSpace, WCHAR **Excludes, WCHAR **SpaceHogs, int *Running,
282 | /*int *RedrawScreen, */WCHAR **DebugMsg);
283 |
284 | /*
285 |
286 | Stop the defragger. Wait for a maximum of TimeOut milliseconds for the
287 | defragger to stop. If TimeOut is zero then wait indefinitely. If TimeOut is
288 | negative then immediately return without waiting.
289 | Note: The "Running" variable must be the same as what was given to the
290 | RunJkDefrag() subroutine.
291 |
292 | */
293 | __declspec(dllexport) void StopJkDefrag(int *Running, int TimeOut);
294 |
295 | /* Other exported functions that might be useful in programs that use JkDefrag. */
296 |
297 | __declspec(dllexport) char *stristr(char *Haystack, char *Needle);
298 | __declspec(dllexport) WCHAR *stristrW(WCHAR *Haystack, WCHAR *Needle);
299 |
300 | __declspec(dllexport) void SystemErrorStr(DWORD ErrorCode, WCHAR *Out, size_t Width);
301 | __declspec(dllexport) void ShowHex(struct DefragDataStruct *Data, BYTE *Buffer, ULONG64 Count);
302 |
303 | __declspec(dllexport) int MatchMask(WCHAR *String, WCHAR *Mask);
304 |
305 | __declspec(dllexport) WCHAR **AddArrayString(WCHAR **Array, WCHAR *NewString);
306 | __declspec(dllexport) WCHAR *GetShortPath(struct DefragDataStruct *Data, struct ItemStruct *Item);
307 | __declspec(dllexport) WCHAR *GetLongPath(struct DefragDataStruct *Data, struct ItemStruct *Item);
308 |
309 | __declspec(dllexport) void SlowDown(struct DefragDataStruct *Data);
310 |
311 | __declspec(dllexport) ULONG64 GetItemLcn(struct ItemStruct *Item);
312 |
313 | __declspec(dllexport) struct ItemStruct *TreeSmallest(struct ItemStruct *Top);
314 | __declspec(dllexport) struct ItemStruct *TreeBiggest(struct ItemStruct *Top);
315 | __declspec(dllexport) struct ItemStruct *TreeFirst(struct ItemStruct *Top, int Direction);
316 | __declspec(dllexport) struct ItemStruct *TreePrev(struct ItemStruct *Here);
317 | __declspec(dllexport) struct ItemStruct *TreeNext(struct ItemStruct *Here);
318 | __declspec(dllexport) struct ItemStruct *TreeNextPrev(struct ItemStruct *Here, int Direction);
319 |
320 | __declspec(dllexport) void TreeInsert(struct DefragDataStruct *Data, struct ItemStruct *New);
321 | __declspec(dllexport) void TreeDetach(struct DefragDataStruct *Data, struct ItemStruct *Item);
322 | __declspec(dllexport) void DeleteItemTree(struct ItemStruct *Top);
323 | __declspec(dllexport) int FragmentCount(struct ItemStruct *Item);
324 | __declspec(dllexport) int IsFragmented(struct ItemStruct *Item, ULONG64 Offset, ULONG64 Size);
325 | __declspec(dllexport) void ColorizeItem(struct DefragDataStruct *Data,struct ItemStruct *Item, ULONG64 BusyOffset, ULONG64 BusySize, int UnDraw);
326 | /*
327 | __declspec(dllexport) void ShowDiskmap(struct DefragDataStruct *Data);
328 | */
329 | __declspec(dllexport) void CallShowStatus(struct DefragDataStruct *Data, int Phase, int Zone);
330 |
331 | private:
332 | WCHAR LowerCase(WCHAR c);
333 |
334 | void AppendToShortPath(struct ItemStruct *Item, WCHAR *Path, size_t Length);
335 | void AppendToLongPath(struct ItemStruct *Item, WCHAR *Path, size_t Length);
336 | ULONG64 FindFragmentBegin(struct ItemStruct *Item, ULONG64 Lcn);
337 |
338 | struct ItemStruct *FindItemAtLcn(struct DefragDataStruct *Data, ULONG64 Lcn);
339 | HANDLE OpenItemHandle(struct DefragDataStruct *Data, struct ItemStruct *Item);
340 | int GetFragments(struct DefragDataStruct *Data, struct ItemStruct *Item, HANDLE FileHandle);
341 |
342 | int FindGap(struct DefragDataStruct *Data,
343 | ULONG64 MinimumLcn, /* Gap must be at or above this LCN. */
344 | ULONG64 MaximumLcn, /* Gap must be below this LCN. */
345 | ULONG64 MinimumSize, /* Gap must be at least this big. */
346 | int MustFit, /* YES: gap must be at least MinimumSize. */
347 | int FindHighestGap, /* YES: return the last gap that fits. */
348 | ULONG64 *BeginLcn, /* Result, LCN of begin of cluster. */
349 | ULONG64 *EndLcn, /* Result, LCN of end of cluster. */
350 | BOOL IgnoreMftExcludes);
351 |
352 | void CalculateZones(struct DefragDataStruct *Data);
353 |
354 | DWORD MoveItem1(struct DefragDataStruct *Data,
355 | HANDLE FileHandle,
356 | struct ItemStruct *Item,
357 | ULONG64 NewLcn, /* Where to move to. */
358 | ULONG64 Offset, /* Number of first cluster to be moved. */
359 | ULONG64 Size); /* Number of clusters to be moved. */
360 |
361 | DWORD MoveItem2(struct DefragDataStruct *Data,
362 | HANDLE FileHandle,
363 | struct ItemStruct *Item,
364 | ULONG64 NewLcn, /* Where to move to. */
365 | ULONG64 Offset, /* Number of first cluster to be moved. */
366 | ULONG64 Size); /* Number of clusters to be moved. */
367 |
368 | int MoveItem3(struct DefragDataStruct *Data,
369 | struct ItemStruct *Item,
370 | HANDLE FileHandle,
371 | ULONG64 NewLcn, /* Where to move to. */
372 | ULONG64 Offset, /* Number of first cluster to be moved. */
373 | ULONG64 Size, /* Number of clusters to be moved. */
374 | int Strategy); /* 0: move in one part, 1: move individual fragments. */
375 |
376 | int MoveItem4(struct DefragDataStruct *Data,
377 | struct ItemStruct *Item,
378 | HANDLE FileHandle,
379 | ULONG64 NewLcn, /* Where to move to. */
380 | ULONG64 Offset, /* Number of first cluster to be moved. */
381 | ULONG64 Size, /* Number of clusters to be moved. */
382 | int Direction); /* 0: move up, 1: move down. */
383 |
384 | int MoveItem(struct DefragDataStruct *Data,
385 | struct ItemStruct *Item,
386 | ULONG64 NewLcn, /* Where to move to. */
387 | ULONG64 Offset, /* Number of first cluster to be moved. */
388 | ULONG64 Size, /* Number of clusters to be moved. */
389 | int Direction); /* 0: move up, 1: move down. */
390 |
391 | struct ItemStruct *FindHighestItem(struct DefragDataStruct *Data,
392 | ULONG64 ClusterStart,
393 | ULONG64 ClusterEnd,
394 | int Direction,
395 | int Zone);
396 |
397 | struct ItemStruct *FindBestItem(struct DefragDataStruct *Data,
398 | ULONG64 ClusterStart,
399 | ULONG64 ClusterEnd,
400 | int Direction,
401 | int Zone);
402 |
403 | void CompareItems(struct DefragDataStruct *Data, struct ItemStruct *Item);
404 |
405 | int CompareItems(struct ItemStruct *Item1, struct ItemStruct *Item2, int SortField);
406 |
407 | void ScanDir(struct DefragDataStruct *Data, WCHAR *Mask, struct ItemStruct *ParentDirectory);
408 |
409 | void AnalyzeVolume(struct DefragDataStruct *Data);
410 |
411 | void Fixup(struct DefragDataStruct *Data);
412 |
413 | void Defragment(struct DefragDataStruct *Data);
414 |
415 | void ForcedFill(struct DefragDataStruct *Data);
416 |
417 | void Vacate(struct DefragDataStruct *Data, ULONG64 Lcn, ULONG64 Clusters, BOOL IgnoreMftExcludes);
418 |
419 | void MoveMftToBeginOfDisk(struct DefragDataStruct *Data);
420 |
421 | void OptimizeVolume(struct DefragDataStruct *Data);
422 |
423 | void OptimizeSort(struct DefragDataStruct *Data, int SortField);
424 |
425 | void OptimizeUp(struct DefragDataStruct *Data);
426 |
427 | void DefragOnePath(struct DefragDataStruct *Data, WCHAR *Path, int Mode);
428 |
429 | void DefragMountpoints(struct DefragDataStruct *Data, WCHAR *MountPoint, int Mode);
430 | /*
431 | JKScanFat *m_jkScanFat;
432 | JKScanNtfs *m_jkScanNtfs;
433 | */
434 |
435 | // static member that is an instance of itself
436 | static JKDefragLib *m_jkDefragLib;
437 | };
438 |
439 | #endif /* Include guard */
--------------------------------------------------------------------------------
/JkDefrag/Source/ScanFat.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 |
3 | /*
4 | #include "JkDefragLib.h"
5 | #include "JKDefragStruct.h"
6 | #include "JKDefragLog.h"
7 | #include "JkDefragGui.h"
8 | #include "ScanFat.h"
9 | */
10 |
11 | JKScanFat *JKScanFat::m_jkScanFat = 0;
12 |
13 | JKScanFat::JKScanFat()
14 | {
15 | m_jkLib = JKDefragLib::getInstance();
16 | }
17 |
18 | JKScanFat::~JKScanFat()
19 | {
20 | delete m_jkScanFat;
21 | }
22 |
23 | JKScanFat *JKScanFat::getInstance()
24 | {
25 | if (m_jkScanFat == NULL)
26 | {
27 | m_jkScanFat = new JKScanFat();
28 | }
29 |
30 | return m_jkScanFat;
31 | }
32 |
33 | /* Calculate the checksum of 8.3 filename. */
34 | UCHAR JKScanFat::CalculateShortNameCheckSum(UCHAR *Name)
35 | {
36 | short Index;
37 | UCHAR CheckSum;
38 |
39 | CheckSum = 0;
40 |
41 | for (Index = 11; Index != 0; Index--)
42 | {
43 | CheckSum = ((CheckSum & 1) ? 0x80 : 0) + (CheckSum >> 1) + *Name++;
44 | }
45 |
46 | return(CheckSum);
47 | }
48 |
49 | /*
50 |
51 | Convert the FAT time fields into a ULONG64 time.
52 | Note: the FAT stores times in local time, not in GMT time. This subroutine converts
53 | that into GMT time, to be compatible with the NTFS date/times.
54 |
55 | */
56 | ULONG64 JKScanFat::ConvertTime(USHORT Date, USHORT Time, USHORT Time10)
57 | {
58 | FILETIME Time1;
59 | FILETIME Time2;
60 |
61 | ULARGE_INTEGER Time3;
62 |
63 | if (DosDateTimeToFileTime(Date,Time,&Time1) == 0) return(0);
64 | if (LocalFileTimeToFileTime(&Time1,&Time2) == 0) return(0);
65 |
66 | Time3.LowPart = Time2.dwLowDateTime;
67 | Time3.HighPart = Time2.dwHighDateTime;
68 | Time3.QuadPart = Time3.QuadPart + Time10 * 100000;
69 |
70 | return(Time3.QuadPart);
71 | }
72 |
73 | /*
74 |
75 | Determine the number of clusters in an item and translate the FAT clusterlist
76 | into a FragmentList.
77 | - The first cluster number of an item is recorded in it's directory entry. The second
78 | and next cluster numbers are recorded in the FAT, which is simply an array of "next"
79 | cluster numbers.
80 | - A zero-length file has a first cluster number of 0.
81 | - The FAT contains either an EOC mark (End Of Clusterchain) or the cluster number of
82 | the next cluster of the file.
83 |
84 | */
85 | void JKScanFat::MakeFragmentList(struct DefragDataStruct *Data, struct FatDiskInfoStruct *DiskInfo, struct ItemStruct *Item, ULONG64 Cluster)
86 | {
87 | struct FragmentListStruct *NewFragment;
88 | struct FragmentListStruct *LastFragment;
89 |
90 | ULONG64 FirstCluster;
91 | ULONG64 LastCluster;
92 | ULONG64 Vcn;
93 |
94 | int MaxIterate;
95 |
96 | JKDefragGui *jkGui = JKDefragGui::getInstance();
97 |
98 | Item->Clusters = 0;
99 | Item->Fragments = NULL;
100 |
101 | /* If cluster is zero then return zero. */
102 | if (Cluster == 0) return;
103 |
104 | /* Loop through the FAT cluster list, counting the clusters and creating items in the fragment list. */
105 | FirstCluster = Cluster;
106 | LastCluster = 0;
107 | Vcn = 0;
108 |
109 | for (MaxIterate = 0; MaxIterate < DiskInfo->CountofClusters + 1; MaxIterate++)
110 | {
111 | /* Exit the loop when we have reached the end of the cluster list. */
112 | if ((Data->Disk.Type == FAT12) && (Cluster >= 0xFF8)) break;
113 | if ((Data->Disk.Type == FAT16) && (Cluster >= 0xFFF8)) break;
114 | if ((Data->Disk.Type == FAT32) && (Cluster >= 0xFFFFFF8)) break;
115 |
116 | /* Sanity check, test if the cluster is within the range of valid cluster numbers. */
117 | if (Cluster < 2) break;
118 | if (Cluster > DiskInfo->CountofClusters + 1) break;
119 |
120 | /* Increment the cluster counter. */
121 | Item->Clusters = Item->Clusters + 1;
122 |
123 | /* If this is a new fragment then create a record for the previous fragment. If not then
124 | add the cluster to the counters and continue. */
125 | if ((Cluster != LastCluster + 1) && (LastCluster != 0))
126 | {
127 | NewFragment = (struct FragmentListStruct *)malloc(sizeof(struct FragmentListStruct));
128 |
129 | if (NewFragment == NULL)
130 | {
131 | jkGui->ShowDebug(2,NULL,L"Error: malloc() returned NULL.");
132 | return;
133 | }
134 |
135 | NewFragment->Lcn = FirstCluster - 2;
136 | Vcn = Vcn + LastCluster - FirstCluster + 1;
137 | NewFragment->NextVcn = Vcn;
138 | NewFragment->Next = NULL;
139 |
140 | if (Item->Fragments == NULL)
141 | {
142 | Item->Fragments = NewFragment;
143 | }
144 | else
145 | {
146 | if (LastFragment != NULL) LastFragment->Next = NewFragment;
147 | }
148 |
149 | LastFragment = NewFragment;
150 | FirstCluster = Cluster;
151 | }
152 |
153 | LastCluster = Cluster;
154 |
155 | /* Get next cluster from FAT. */
156 | switch (Data->Disk.Type)
157 | {
158 | case FAT12:
159 | if ((Cluster & 1) == 1)
160 | {
161 | Cluster = *((WORD *)&DiskInfo->FatData.FAT12[Cluster + Cluster / 2]) >> 4;
162 | }
163 | else
164 | {
165 | Cluster = *((WORD *)&DiskInfo->FatData.FAT12[Cluster + Cluster / 2]) & 0xFFF;
166 | }
167 |
168 | break;
169 |
170 | case FAT16: Cluster = DiskInfo->FatData.FAT16[Cluster]; break;
171 | case FAT32: Cluster = DiskInfo->FatData.FAT32[Cluster] & 0xFFFFFFF; break;
172 | }
173 | }
174 |
175 | /* If too many iterations (infinite loop in FAT) then exit. */
176 | if (MaxIterate >= DiskInfo->CountofClusters + 1)
177 | {
178 | jkGui->ShowDebug(2,NULL,L"Infinite loop in FAT detected, perhaps the disk is corrupted.");
179 |
180 | return;
181 | }
182 |
183 | /* Create the last fragment. */
184 | if (LastCluster != 0)
185 | {
186 | NewFragment = (struct FragmentListStruct *)malloc(sizeof(struct FragmentListStruct));
187 |
188 | if (NewFragment == NULL)
189 | {
190 | jkGui->ShowDebug(2,NULL,L"Error: malloc() returned NULL.");
191 |
192 | return;
193 | }
194 |
195 | NewFragment->Lcn = FirstCluster - 2;
196 | Vcn = Vcn + LastCluster - FirstCluster + 1;
197 | NewFragment->NextVcn = Vcn;
198 | NewFragment->Next = NULL;
199 |
200 | if (Item->Fragments == NULL)
201 | {
202 | Item->Fragments = NewFragment;
203 | }
204 | else
205 | {
206 | if (LastFragment != NULL) LastFragment->Next = NewFragment;
207 | }
208 | }
209 | }
210 |
211 | /* Load a directory from disk into a new memory buffer. Return NULL if error.
212 | Note: the caller is responsible for free'ing the buffer. */
213 | BYTE *JKScanFat::LoadDirectory(struct DefragDataStruct *Data, struct FatDiskInfoStruct *DiskInfo, ULONG64 StartCluster, ULONG64 *OutLength)
214 | {
215 | BYTE *Buffer;
216 |
217 | ULONG64 BufferLength;
218 | ULONG64 BufferOffset;
219 | ULONG64 Cluster;
220 | ULONG64 FirstCluster;
221 | ULONG64 LastCluster;
222 | ULONG64 FragmentLength;
223 |
224 | OVERLAPPED gOverlapped;
225 |
226 | ULARGE_INTEGER Trans;
227 |
228 | DWORD BytesRead;
229 |
230 | int Result;
231 | int MaxIterate;
232 |
233 | WCHAR s1[BUFSIZ];
234 |
235 | JKDefragGui *jkGui = JKDefragGui::getInstance();
236 |
237 | /* Reset the OutLength to zero, in case we exit for an error. */
238 | if (OutLength != NULL) *OutLength = 0;
239 |
240 | /* If cluster is zero then return NULL. */
241 | if (StartCluster == 0) return(NULL);
242 |
243 | /* Count the size of the directory. */
244 | BufferLength = 0;
245 | Cluster = StartCluster;
246 |
247 | for (MaxIterate = 0; MaxIterate < DiskInfo->CountofClusters + 1; MaxIterate++)
248 | {
249 | /* Exit the loop when we have reached the end of the cluster list. */
250 | if ((Data->Disk.Type == FAT12) && (Cluster >= 0xFF8)) break;
251 | if ((Data->Disk.Type == FAT16) && (Cluster >= 0xFFF8)) break;
252 | if ((Data->Disk.Type == FAT32) && (Cluster >= 0xFFFFFF8)) break;
253 |
254 | /* Sanity check, test if the cluster is within the range of valid cluster numbers. */
255 | if (Cluster < 2) return(NULL);
256 | if (Cluster > DiskInfo->CountofClusters + 1) return(NULL);
257 |
258 | /* Increment the BufferLength counter. */
259 | BufferLength = BufferLength + DiskInfo->SectorsPerCluster * DiskInfo->BytesPerSector;
260 |
261 | /* Get next cluster from FAT. */
262 | switch (Data->Disk.Type)
263 | {
264 | case FAT12:
265 | if ((Cluster & 1) == 1)
266 | {
267 | Cluster = *((WORD *)&DiskInfo->FatData.FAT12[Cluster + Cluster / 2]) >> 4;
268 | }
269 | else
270 | {
271 | Cluster = *((WORD *)&DiskInfo->FatData.FAT12[Cluster + Cluster / 2]) & 0xFFF;
272 | }
273 | break;
274 |
275 | case FAT16: Cluster = DiskInfo->FatData.FAT16[Cluster]; break;
276 | case FAT32: Cluster = DiskInfo->FatData.FAT32[Cluster] & 0xFFFFFFF; break;
277 | }
278 | }
279 |
280 | /* If too many iterations (infinite loop in FAT) then return NULL. */
281 | if (MaxIterate >= DiskInfo->CountofClusters + 1)
282 | {
283 | jkGui->ShowDebug(2,NULL,L"Infinite loop in FAT detected, perhaps the disk is corrupted.");
284 |
285 | return(NULL);
286 | }
287 |
288 | /* Allocate buffer. */
289 | if (BufferLength > UINT_MAX)
290 | {
291 | jkGui->ShowDebug(2,NULL,L"Directory is too big, %I64u bytes",BufferLength);
292 |
293 | return(NULL);
294 | }
295 |
296 | Buffer = (BYTE *)malloc((size_t)BufferLength);
297 |
298 | if (Buffer == NULL)
299 | {
300 | jkGui->ShowDebug(2,NULL,L"Error: malloc() returned NULL.");
301 |
302 | return(NULL);
303 | }
304 |
305 | /* Loop through the FAT cluster list and load all fragments from disk into the buffer. */
306 | BufferOffset = 0;
307 | Cluster = StartCluster;
308 | FirstCluster = Cluster;
309 | LastCluster = 0;
310 |
311 | for (MaxIterate = 0; MaxIterate < DiskInfo->CountofClusters + 1; MaxIterate++)
312 | {
313 | /* Exit the loop when we have reached the end of the cluster list. */
314 | if ((Data->Disk.Type == FAT12) && (Cluster >= 0xFF8)) break;
315 | if ((Data->Disk.Type == FAT16) && (Cluster >= 0xFFF8)) break;
316 | if ((Data->Disk.Type == FAT32) && (Cluster >= 0xFFFFFF8)) break;
317 |
318 | /* Sanity check, test if the cluster is within the range of valid cluster numbers. */
319 | if (Cluster < 2) break;
320 | if (Cluster > DiskInfo->CountofClusters + 1) break;
321 |
322 | /* If this is a new fragment then load the previous fragment from disk. If not then
323 | add to the counters and continue. */
324 | if ((Cluster != LastCluster + 1) && (LastCluster != 0))
325 | {
326 | FragmentLength = (LastCluster - FirstCluster + 1) * DiskInfo->SectorsPerCluster * DiskInfo->BytesPerSector;
327 | Trans.QuadPart = (DiskInfo->FirstDataSector + (FirstCluster - 2) * DiskInfo->SectorsPerCluster) * DiskInfo->BytesPerSector;
328 |
329 | gOverlapped.Offset = Trans.LowPart;
330 | gOverlapped.OffsetHigh = Trans.HighPart;
331 | gOverlapped.hEvent = NULL;
332 |
333 | jkGui->ShowDebug(6,NULL,L"Reading directory fragment, %I64u bytes at offset=%I64u.", FragmentLength,Trans.QuadPart);
334 |
335 | Result = ReadFile(Data->Disk.VolumeHandle,&Buffer[BufferOffset],(DWORD)FragmentLength,&BytesRead,&gOverlapped);
336 |
337 | if (Result == 0)
338 | {
339 | m_jkLib->SystemErrorStr(GetLastError(),s1,BUFSIZ);
340 |
341 | jkGui->ShowDebug(2,NULL,L"Error: %s",s1);
342 |
343 | free(Buffer);
344 |
345 | return(NULL);
346 | }
347 |
348 | //ShowHex(Data,Buffer,256);
349 | BufferOffset = BufferOffset + FragmentLength;
350 | FirstCluster = Cluster;
351 | }
352 |
353 | LastCluster = Cluster;
354 |
355 | /* Get next cluster from FAT. */
356 | switch (Data->Disk.Type)
357 | {
358 | case FAT12:
359 | if ((Cluster & 1) == 1)
360 | {
361 | Cluster = *((WORD *)&DiskInfo->FatData.FAT12[Cluster + Cluster / 2]) >> 4;
362 | } else {
363 | Cluster = *((WORD *)&DiskInfo->FatData.FAT12[Cluster + Cluster / 2]) & 0xFFF;
364 | }
365 |
366 | break;
367 | case FAT16: Cluster = DiskInfo->FatData.FAT16[Cluster]; break;
368 | case FAT32: Cluster = DiskInfo->FatData.FAT32[Cluster] & 0xFFFFFFF; break;
369 | }
370 | }
371 |
372 | /* Load the last fragment. */
373 | if (LastCluster != 0)
374 | {
375 | FragmentLength = (LastCluster - FirstCluster + 1) * DiskInfo->SectorsPerCluster * DiskInfo->BytesPerSector;
376 | Trans.QuadPart = (DiskInfo->FirstDataSector + (FirstCluster - 2) * DiskInfo->SectorsPerCluster) * DiskInfo->BytesPerSector;
377 |
378 | gOverlapped.Offset = Trans.LowPart;
379 | gOverlapped.OffsetHigh = Trans.HighPart;
380 | gOverlapped.hEvent = NULL;
381 |
382 | jkGui->ShowDebug(6,NULL,L"Reading directory fragment, %I64u bytes at offset=%I64u.", FragmentLength,Trans.QuadPart);
383 |
384 | Result = ReadFile(Data->Disk.VolumeHandle,&Buffer[BufferOffset],(DWORD)FragmentLength, &BytesRead,&gOverlapped);
385 |
386 | if (Result == 0)
387 | {
388 | m_jkLib->SystemErrorStr(GetLastError(),s1,BUFSIZ);
389 |
390 | jkGui->ShowDebug(2,NULL,L"Error: %s",s1);
391 |
392 | free(Buffer);
393 |
394 | return(NULL);
395 | }
396 | }
397 |
398 | if (OutLength != NULL) *OutLength = BufferLength;
399 |
400 | return(Buffer);
401 | }
402 |
403 | /* Analyze a directory and add all the items to the item tree. */
404 | void JKScanFat::AnalyzeFatDirectory(struct DefragDataStruct *Data, struct FatDiskInfoStruct *DiskInfo, BYTE *Buffer, ULONG64 Length, struct ItemStruct *ParentDirectory)
405 | {
406 | struct FatDirStruct *Dir;
407 | struct FatLongNameDirStruct *LDir;
408 | struct ItemStruct *Item;
409 |
410 | DWORD Index;
411 |
412 | WCHAR ShortName[13];
413 | WCHAR LongName[820];
414 |
415 | int LastLongNameSection;
416 |
417 | UCHAR LongNameChecksum;
418 |
419 | BYTE *SubDirBuf;
420 |
421 | ULONG64 SubDirLength;
422 | ULONG64 StartCluster;
423 |
424 | WCHAR *p1;
425 |
426 | int i;
427 |
428 | JKDefragGui *jkGui = JKDefragGui::getInstance();
429 |
430 | /* Sanity check. */
431 | if ((Buffer == NULL) || (Length == 0)) return;
432 |
433 | /* Slow the program down to the percentage that was specified on the
434 | command line. */
435 | m_jkLib->SlowDown(Data);
436 |
437 | //ShowHex(Data,Buffer,256);
438 |
439 | /* Walk through all the directory entries, extract the info, and store in memory
440 | in the ItemTree. */
441 | LastLongNameSection = 0;
442 |
443 | for (Index = 0; Index + 31 < Length; Index = Index + 32)
444 | {
445 | if (*Data->Running != RUNNING) break;
446 |
447 | Dir = (struct FatDirStruct *)&Buffer[Index];
448 |
449 | /* Ignore free (not used) entries. */
450 | if (Dir->DIR_Name[0] == 0xE5)
451 | {
452 | jkGui->ShowDebug(6,NULL,L"%u.\tFree (not used)",Index/32);
453 |
454 | continue;
455 | }
456 |
457 | /* Exit at the end of the directory. */
458 | if (Dir->DIR_Name[0] == 0)
459 | {
460 | jkGui->ShowDebug(6,NULL,L"%u.\tFree (not used), end of directory.",Index/32);
461 |
462 | break;
463 | }
464 |
465 | /* If this is a long filename component then save the string and loop. */
466 | if ((Dir->DIR_Attr & ATTR_LONG_NAME_MASK) == ATTR_LONG_NAME)
467 | {
468 | LDir = (struct FatLongNameDirStruct *)&Buffer[Index];
469 |
470 | jkGui->ShowDebug(6,NULL,L"%u.\tLong filename part.",Index/32);
471 |
472 | i = (LDir->LDIR_Ord & 0x3F);
473 |
474 | if (i == 0)
475 | {
476 | LastLongNameSection = 0;
477 |
478 | continue;
479 | }
480 |
481 | if ((LDir->LDIR_Ord & 0x40) == 0x40)
482 | {
483 | wmemset(LongName,L'\0',820);
484 |
485 | LastLongNameSection = i;
486 | LongNameChecksum = LDir->LDIR_Chksum;
487 | }
488 | else
489 | {
490 | if ((i + 1 != LastLongNameSection) || (LongNameChecksum != LDir->LDIR_Chksum))
491 | {
492 | LastLongNameSection = 0;
493 |
494 | continue;
495 | }
496 |
497 | LastLongNameSection = i;
498 | }
499 |
500 | i = (i - 1) * 13;
501 |
502 | LongName[i++] = LDir->LDIR_Name1[0];
503 | LongName[i++] = LDir->LDIR_Name1[1];
504 | LongName[i++] = LDir->LDIR_Name1[2];
505 | LongName[i++] = LDir->LDIR_Name1[3];
506 | LongName[i++] = LDir->LDIR_Name1[4];
507 | LongName[i++] = LDir->LDIR_Name2[0];
508 | LongName[i++] = LDir->LDIR_Name2[1];
509 | LongName[i++] = LDir->LDIR_Name2[2];
510 | LongName[i++] = LDir->LDIR_Name2[3];
511 | LongName[i++] = LDir->LDIR_Name2[4];
512 | LongName[i++] = LDir->LDIR_Name2[5];
513 | LongName[i++] = LDir->LDIR_Name3[0];
514 | LongName[i++] = LDir->LDIR_Name3[1];
515 |
516 | continue;
517 | }
518 |
519 | /* If we are here and the long filename counter is not 1 then something is wrong
520 | with the long filename. Ignore the long filename. */
521 | if (LastLongNameSection != 1)
522 | {
523 | LongName[0] = '\0';
524 | }
525 | else
526 | if (CalculateShortNameCheckSum(Dir->DIR_Name) != LongNameChecksum)
527 | {
528 | jkGui->ShowDebug(0,NULL,L"%u.\tError: long filename is out of sync");
529 | LongName[0] = '\0';
530 | }
531 |
532 | LastLongNameSection = 0;
533 |
534 | /* Extract the short name. */
535 | for (i = 0; i < 8; i++) ShortName[i] = Dir->DIR_Name[i];
536 |
537 | for (i = 7; i > 0; i--) if (ShortName[i] != ' ') break;
538 |
539 | if (ShortName[i] != ' ') i++;
540 |
541 | ShortName[i] = '.';
542 | ShortName[i+1] = Dir->DIR_Name[8];
543 | ShortName[i+2] = Dir->DIR_Name[9];
544 | ShortName[i+3] = Dir->DIR_Name[10];
545 |
546 | if (ShortName[i+3] != ' ')
547 | {
548 | ShortName[i+4] = '\0';
549 | }
550 | else
551 | if (ShortName[i+2] != ' ')
552 | {
553 | ShortName[i+3] = '\0';
554 | }
555 | else
556 | if (ShortName[i+1] != ' ')
557 | {
558 | ShortName[i+2] = '\0';
559 | }
560 | else
561 | {
562 | ShortName[i] = '\0';
563 | }
564 | if (ShortName[0] == 0x05) ShortName[0] = 0xE5;
565 |
566 | /* If this is a VolumeID then loop. We have no use for it. */
567 | if ((Dir->DIR_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == ATTR_VOLUME_ID)
568 | {
569 | p1 = wcschr(ShortName,L'.');
570 |
571 | if (p1 != NULL) wcscpy_s(p1,wcslen(p1),p1+1);
572 |
573 | jkGui->ShowDebug(6,NULL,L"%u.\t'%s' (volume ID)",Index/32,ShortName);
574 |
575 | continue;
576 | }
577 |
578 | if ((Dir->DIR_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == (ATTR_DIRECTORY | ATTR_VOLUME_ID))
579 | {
580 | jkGui->ShowDebug(6,NULL,L"%u.\tInvalid directory entry");
581 |
582 | continue;
583 | }
584 |
585 | /* Ignore "." and "..". */
586 | if (wcscmp(ShortName,L".") == 0)
587 | {
588 | jkGui->ShowDebug(6,NULL,L"%u.\t'.'",Index/32);
589 |
590 | continue;
591 | }
592 |
593 | if (wcscmp(ShortName,L"..") == 0)
594 | {
595 | jkGui->ShowDebug(6,NULL,L"%u.\t'..'",Index/32);
596 |
597 | continue;
598 | }
599 |
600 | /* Create and fill a new item record in memory. */
601 | Item = (struct ItemStruct *)malloc(sizeof(struct ItemStruct));
602 |
603 | if (Item == NULL)
604 | {
605 | jkGui->ShowDebug(2,NULL,L"Error: malloc() returned NULL.");
606 | break;
607 | }
608 |
609 | if (wcscmp(ShortName,L".") == 0)
610 | {
611 | Item->ShortFilename = NULL;
612 | }
613 | else
614 | {
615 | Item->ShortFilename = _wcsdup(ShortName);
616 | jkGui->ShowDebug(6,NULL,L"%u.\t'%s'",Index/32,ShortName);
617 | }
618 |
619 | if (LongName[0] == '\0')
620 | {
621 | Item->LongFilename = NULL;
622 | }
623 | else
624 | {
625 | Item->LongFilename = _wcsdup(LongName);
626 | jkGui->ShowDebug(6,NULL,L"\tLong filename = '%s'",LongName);
627 | }
628 |
629 | if ((Item->LongFilename != NULL) &&
630 | (Item->ShortFilename != NULL) &&
631 | (_wcsicmp(Item->LongFilename,Item->ShortFilename) == 0))
632 | {
633 | free(Item->ShortFilename);
634 |
635 | Item->ShortFilename = Item->LongFilename;
636 | }
637 |
638 | if ((Item->LongFilename == NULL) && (Item->ShortFilename != NULL)) Item->LongFilename = Item->ShortFilename;
639 | if ((Item->LongFilename != NULL) && (Item->ShortFilename == NULL)) Item->ShortFilename = Item->LongFilename;
640 |
641 | Item->ShortPath = NULL;
642 | Item->LongPath = NULL;
643 | Item->Bytes = Dir->DIR_FileSize;
644 |
645 | if (Data->Disk.Type == FAT32)
646 | {
647 | StartCluster = MAKELONG(Dir->DIR_FstClusLO,Dir->DIR_FstClusHI);
648 | }
649 | else
650 | {
651 | StartCluster = Dir->DIR_FstClusLO;
652 | }
653 |
654 | MakeFragmentList(Data,DiskInfo,Item,StartCluster);
655 |
656 | Item->CreationTime = ConvertTime(Dir->DIR_CrtDate,Dir->DIR_CrtTime,Dir->DIR_CrtTimeTenth);
657 | Item->MftChangeTime = ConvertTime(Dir->DIR_WrtDate,Dir->DIR_WrtTime,0);
658 | Item->LastAccessTime = ConvertTime(Dir->DIR_LstAccDate,0,0);
659 | Item->ParentInode = 0;
660 | Item->ParentDirectory = ParentDirectory;
661 | Item->Directory = NO;
662 |
663 | if ((Dir->DIR_Attr & (ATTR_DIRECTORY | ATTR_VOLUME_ID)) == ATTR_DIRECTORY) Item->Directory = YES;
664 |
665 | Item->Unmovable = NO;
666 | Item->Exclude = NO;
667 | Item->SpaceHog = NO;
668 |
669 | jkGui->ShowDebug(6,NULL,L"\tSize = %I64u clusters, %I64u bytes",Item->Clusters,Item->Bytes);
670 |
671 | /* Add the item record to the sorted item tree in memory. */
672 | m_jkLib->TreeInsert(Data,Item);
673 |
674 | /* Draw the item on the screen. */
675 | jkGui->ShowAnalyze(Data,Item);
676 | // if (*Data->RedrawScreen == NO) {
677 | m_jkLib->ColorizeItem(Data,Item,0,0,NO);
678 | // } else {
679 | // ShowDiskmap(Data);
680 | // }
681 |
682 | /* Increment counters. */
683 | if (Item->Directory == YES)
684 | {
685 | Data->CountDirectories = Data->CountDirectories + 1;
686 | }
687 |
688 | Data->CountAllFiles = Data->CountAllFiles + 1;
689 | Data->CountAllBytes = Data->CountAllBytes + Item->Bytes;
690 | Data->CountAllClusters = Data->CountAllClusters + Item->Clusters;
691 |
692 | if (m_jkLib->FragmentCount(Item) > 1)
693 | {
694 | Data->CountFragmentedItems = Data->CountFragmentedItems + 1;
695 | Data->CountFragmentedBytes = Data->CountFragmentedBytes + Item->Bytes;
696 | Data->CountFragmentedClusters = Data->CountFragmentedClusters + Item->Clusters;
697 | }
698 |
699 | /* If this is a directory then iterate. */
700 | if (Item->Directory == YES)
701 | {
702 | SubDirBuf = LoadDirectory(Data,DiskInfo,StartCluster,&SubDirLength);
703 |
704 | AnalyzeFatDirectory(Data,DiskInfo,SubDirBuf,SubDirLength,Item);
705 |
706 | free(SubDirBuf);
707 |
708 | jkGui->ShowDebug(6,NULL,L"Finished with subdirectory.");
709 | }
710 | }
711 | }
712 |
713 | /* Analyze a FAT disk and load into the ItemTree in memory. Return FALSE if the disk is
714 | not a FAT disk, or could not be analyzed.
715 |
716 | - The maximum valid cluster number for the volume is CountofClusters + 1
717 | - The FAT runs from cluster 0 to CountofClusters + 1.
718 | - The size of the FAT is:
719 | FAT12: (CountofClusters + 1) * 1.5
720 | FAT16: (CountofClusters + 1) * 2
721 | FAT32: (CountofClusters + 1) * 4
722 | - Compute the sector number for data cluster number N:
723 | FirstSectorOfCluster = ((N - 2) * BootSector.BPB_SecPerClus) + DiskInfo.FirstDataSector;
724 | - Calculate location in the FAT for a given cluster number N:
725 | switch (FATType) {
726 | case FAT12: FATOffset = N + (N / 2); break; // 12 bit is 1.5 bytes.
727 | case FAT16: FATOffset = N * 2; break; // 16 bit is 2 bytes.
728 | case FAT32: FATOffset = N * 4; break; // 32 bit is 4 bytes.
729 | }
730 | ThisFATSecNum = BPB_ResvdSecCnt + (FATOffset / BPB_BytsPerSec);
731 | ThisFATEntOffset = FATOffset % BPB_BytsPerSec;
732 | - Determine End Of Clusterchain:
733 | IsEOC = FALSE;
734 | switch (FATType) {
735 | case FAT12: if (FATContent >= 0x0FF8) IsEOC = TRUE; break;
736 | case FAT16: if (FATContent >= 0xFFF8) IsEOC = TRUE; break;
737 | case FAT32: if (FATContent >= 0x0FFFFFF8) IsEOC = TRUE; break;
738 | }
739 | - Determine Bad Cluster:
740 | IsBadCluster = FALSE;
741 | switch (FATType) {
742 | case FAT12: if (FATContent == 0x0FF7) IsBadCluster = TRUE; break;
743 | case FAT16: if (FATContent == 0xFFF7) IsBadCluster = TRUE; break;
744 | case FAT32: if (FATContent == 0x0FFFFFF7) IsBadCluster = TRUE; break;
745 | }
746 | */
747 | BOOL JKScanFat::AnalyzeFatVolume(struct DefragDataStruct *Data)
748 | {
749 | struct FatBootSectorStruct BootSector;
750 | struct FatDiskInfoStruct DiskInfo;
751 |
752 | ULARGE_INTEGER Trans;
753 |
754 | OVERLAPPED gOverlapped;
755 |
756 | DWORD BytesRead;
757 |
758 | size_t FatSize;
759 |
760 | BYTE *RootDirectory;
761 |
762 | ULONG64 RootStart;
763 | ULONG64 RootLength;
764 |
765 | int Result;
766 |
767 | WCHAR s1[BUFSIZ];
768 |
769 | char s2[BUFSIZ];
770 |
771 | JKDefragGui *jkGui = JKDefragGui::getInstance();
772 |
773 | /* Read the boot block from the disk. */
774 | gOverlapped.Offset = 0;
775 | gOverlapped.OffsetHigh = 0;
776 | gOverlapped.hEvent = NULL;
777 |
778 | Result = ReadFile(Data->Disk.VolumeHandle,&BootSector,sizeof(struct FatBootSectorStruct),&BytesRead,&gOverlapped);
779 |
780 | if ((Result == 0) || (BytesRead != 512))
781 | {
782 | m_jkLib->SystemErrorStr(GetLastError(),s1,BUFSIZ);
783 |
784 | jkGui->ShowDebug(2,NULL,L"Error while reading bootblock: %s",s1);
785 |
786 | return(FALSE);
787 | }
788 |
789 | /* Test if the boot block is a FAT boot block. */
790 | if ((BootSector.Signature != 0xAA55) ||
791 | (((BootSector.BS_jmpBoot[0] != 0xEB) || (BootSector.BS_jmpBoot[2] != 0x90)) &&
792 | (BootSector.BS_jmpBoot[0] != 0xE9)))
793 | {
794 | jkGui->ShowDebug(2,NULL,L"This is not a FAT disk (different cookie).");
795 |
796 | return(FALSE);
797 | }
798 |
799 | /* Fetch values from the bootblock and determine what FAT this is, FAT12, FAT16, or FAT32. */
800 | DiskInfo.BytesPerSector = BootSector.BPB_BytsPerSec;
801 |
802 | if (DiskInfo.BytesPerSector == 0)
803 | {
804 | jkGui->ShowDebug(2,NULL,L"This is not a FAT disk (BytesPerSector is zero).");
805 |
806 | return(FALSE);
807 | }
808 |
809 | DiskInfo.SectorsPerCluster = BootSector.BPB_SecPerClus;
810 |
811 | if (DiskInfo.SectorsPerCluster == 0)
812 | {
813 | jkGui->ShowDebug(2,NULL,L"This is not a FAT disk (SectorsPerCluster is zero).");
814 |
815 | return(FALSE);
816 | }
817 |
818 | DiskInfo.TotalSectors = BootSector.BPB_TotSec16;
819 |
820 | if (DiskInfo.TotalSectors == 0) DiskInfo.TotalSectors = BootSector.BPB_TotSec32;
821 |
822 | DiskInfo.RootDirSectors = ((BootSector.BPB_RootEntCnt * 32) + (BootSector.BPB_BytsPerSec - 1)) / BootSector.BPB_BytsPerSec;
823 |
824 | DiskInfo.FATSz = BootSector.BPB_FATSz16;
825 |
826 | if (DiskInfo.FATSz == 0) DiskInfo.FATSz = BootSector.Fat32.BPB_FATSz32;
827 |
828 | DiskInfo.FirstDataSector = BootSector.BPB_RsvdSecCnt + (BootSector.BPB_NumFATs * DiskInfo.FATSz) + DiskInfo.RootDirSectors;
829 |
830 | DiskInfo.DataSec = DiskInfo.TotalSectors - (BootSector.BPB_RsvdSecCnt + (BootSector.BPB_NumFATs * DiskInfo.FATSz) + DiskInfo.RootDirSectors);
831 |
832 | DiskInfo.CountofClusters = DiskInfo.DataSec / BootSector.BPB_SecPerClus;
833 |
834 | if (DiskInfo.CountofClusters < 4085)
835 | {
836 | Data->Disk.Type = FAT12;
837 |
838 | jkGui->ShowDebug(0,NULL,L"This is a FAT12 disk.");
839 | }
840 | else
841 | if (DiskInfo.CountofClusters < 65525)
842 | {
843 | Data->Disk.Type = FAT16;
844 |
845 | jkGui->ShowDebug(0,NULL,L"This is a FAT16 disk.");
846 | }
847 | else
848 | {
849 | Data->Disk.Type = FAT32;
850 |
851 | jkGui->ShowDebug(0,NULL,L"This is a FAT32 disk.");
852 | }
853 |
854 | Data->BytesPerCluster = DiskInfo.BytesPerSector * DiskInfo.SectorsPerCluster;
855 | Data->TotalClusters = DiskInfo.CountofClusters;
856 |
857 | /* Output debug information. */
858 | strncpy_s(s2,BUFSIZ,(char *)&BootSector.BS_OEMName[0],8);
859 |
860 | s2[8] = '\0';
861 |
862 | jkGui->ShowDebug(2,NULL,L" OEMName: %S",s2);
863 | jkGui->ShowDebug(2,NULL,L" BytesPerSector: %I64u",DiskInfo.BytesPerSector);
864 | jkGui->ShowDebug(2,NULL,L" TotalSectors: %I64u",DiskInfo.TotalSectors);
865 | jkGui->ShowDebug(2,NULL,L" SectorsPerCluster: %I64u",DiskInfo.SectorsPerCluster);
866 | jkGui->ShowDebug(2,NULL,L" RootDirSectors: %I64u",DiskInfo.RootDirSectors);
867 | jkGui->ShowDebug(2,NULL,L" FATSz: %I64u",DiskInfo.FATSz);
868 | jkGui->ShowDebug(2,NULL,L" FirstDataSector: %I64u",DiskInfo.FirstDataSector);
869 | jkGui->ShowDebug(2,NULL,L" DataSec: %I64u",DiskInfo.DataSec);
870 | jkGui->ShowDebug(2,NULL,L" CountofClusters: %I64u",DiskInfo.CountofClusters);
871 | jkGui->ShowDebug(2,NULL,L" ReservedSectors: %lu",BootSector.BPB_RsvdSecCnt);
872 | jkGui->ShowDebug(2,NULL,L" NumberFATs: %lu",BootSector.BPB_NumFATs);
873 | jkGui->ShowDebug(2,NULL,L" RootEntriesCount: %lu",BootSector.BPB_RootEntCnt);
874 | jkGui->ShowDebug(2,NULL,L" MediaType: %X",BootSector.BPB_Media);
875 | jkGui->ShowDebug(2,NULL,L" SectorsPerTrack: %lu",BootSector.BPB_SecPerTrk);
876 | jkGui->ShowDebug(2,NULL,L" NumberOfHeads: %lu",BootSector.BPB_NumHeads);
877 | jkGui->ShowDebug(2,NULL,L" HiddenSectors: %lu",BootSector.BPB_HiddSec);
878 |
879 | if (Data->Disk.Type != FAT32)
880 | {
881 | jkGui->ShowDebug(2,NULL,L" BS_DrvNum: %u",BootSector.Fat16.BS_DrvNum);
882 | jkGui->ShowDebug(2,NULL,L" BS_BootSig: %u",BootSector.Fat16.BS_BootSig);
883 | jkGui->ShowDebug(2,NULL,L" BS_VolID: %u",BootSector.Fat16.BS_VolID);
884 |
885 | strncpy_s(s2,BUFSIZ,(char *)&BootSector.Fat16.BS_VolLab[0],11);
886 |
887 | s2[11] = '\0';
888 |
889 | jkGui->ShowDebug(2,NULL,L" VolLab: %S",s2);
890 |
891 | strncpy_s(s2,BUFSIZ,(char *)&BootSector.Fat16.BS_FilSysType[0],8);
892 |
893 | s2[8] = '\0';
894 |
895 | jkGui->ShowDebug(2,NULL,L" FilSysType: %S",s2);
896 | }
897 | else
898 | {
899 | jkGui->ShowDebug(2,NULL,L" FATSz32: %lu",BootSector.Fat32.BPB_FATSz32);
900 | jkGui->ShowDebug(2,NULL,L" ExtFlags: %lu",BootSector.Fat32.BPB_ExtFlags);
901 | jkGui->ShowDebug(2,NULL,L" FSVer: %lu",BootSector.Fat32.BPB_FSVer);
902 | jkGui->ShowDebug(2,NULL,L" RootClus: %lu",BootSector.Fat32.BPB_RootClus);
903 | jkGui->ShowDebug(2,NULL,L" FSInfo: %lu",BootSector.Fat32.BPB_FSInfo);
904 | jkGui->ShowDebug(2,NULL,L" BkBootSec: %lu",BootSector.Fat32.BPB_BkBootSec);
905 | jkGui->ShowDebug(2,NULL,L" DrvNum: %lu",BootSector.Fat32.BS_DrvNum);
906 | jkGui->ShowDebug(2,NULL,L" BootSig: %lu",BootSector.Fat32.BS_BootSig);
907 | jkGui->ShowDebug(2,NULL,L" VolID: %lu",BootSector.Fat32.BS_VolID);
908 |
909 | strncpy_s(s2,BUFSIZ,(char *)&BootSector.Fat32.BS_VolLab[0],11);
910 |
911 | s2[11] = '\0';
912 |
913 | jkGui->ShowDebug(2,NULL,L" VolLab: %S",s2);
914 |
915 | strncpy_s(s2,BUFSIZ,(char *)&BootSector.Fat32.BS_FilSysType[0],8);
916 |
917 | s2[8] = '\0';
918 |
919 | jkGui->ShowDebug(2,NULL,L" FilSysType: %S",s2);
920 | }
921 |
922 | /* Read the FAT from disk into memory. */
923 | switch (Data->Disk.Type)
924 | {
925 | case FAT12: FatSize = (size_t)((DiskInfo.CountofClusters + 1) + (DiskInfo.CountofClusters + 1) / 2); break;
926 | case FAT16: FatSize = (size_t)((DiskInfo.CountofClusters + 1) * 2); break;
927 | case FAT32: FatSize = (size_t)((DiskInfo.CountofClusters + 1) * 4); break;
928 | }
929 |
930 | if (FatSize % DiskInfo.BytesPerSector > 0)
931 | {
932 | FatSize = (size_t)(FatSize + DiskInfo.BytesPerSector - FatSize % DiskInfo.BytesPerSector);
933 | }
934 |
935 | DiskInfo.FatData.FAT12 = (BYTE *)malloc(FatSize);
936 |
937 | if (DiskInfo.FatData.FAT12 == NULL)
938 | {
939 | jkGui->ShowDebug(2,NULL,L"Error: malloc() returned NULL.");
940 |
941 | return(FALSE);
942 | }
943 |
944 | Trans.QuadPart = BootSector.BPB_RsvdSecCnt * DiskInfo.BytesPerSector;
945 | gOverlapped.Offset = Trans.LowPart;
946 | gOverlapped.OffsetHigh = Trans.HighPart;
947 | gOverlapped.hEvent = NULL;
948 |
949 | jkGui->ShowDebug(2,NULL,L"Reading FAT, %lu bytes at offset=%I64u",FatSize,Trans.QuadPart);
950 |
951 | Result = ReadFile(Data->Disk.VolumeHandle,DiskInfo.FatData.FAT12,(DWORD)FatSize,&BytesRead,&gOverlapped);
952 |
953 | if (Result == 0)
954 | {
955 | m_jkLib->SystemErrorStr(GetLastError(),s1,BUFSIZ);
956 |
957 | jkGui->ShowDebug(2,NULL,L"Error: %s",s1);
958 |
959 | return(FALSE);
960 | }
961 |
962 | //ShowHex(Data,DiskInfo.FatData.FAT12,32);
963 |
964 | /* Read the root directory from disk into memory. */
965 | if (Data->Disk.Type == FAT32)
966 | {
967 | RootDirectory = LoadDirectory(Data,&DiskInfo,BootSector.Fat32.BPB_RootClus,&RootLength);
968 | }
969 | else
970 | {
971 | RootStart = (BootSector.BPB_RsvdSecCnt + BootSector.BPB_NumFATs * DiskInfo.FATSz) * DiskInfo.BytesPerSector;
972 | RootLength = BootSector.BPB_RootEntCnt * 32;
973 |
974 | /* Sanity check. */
975 | if (RootLength > UINT_MAX)
976 | {
977 | jkGui->ShowDebug(2,NULL,L"Root directory is too big, %I64u bytes",RootLength);
978 |
979 | free(DiskInfo.FatData.FAT12);
980 |
981 | return(FALSE);
982 | }
983 |
984 | if (RootStart > (DiskInfo.CountofClusters + 1) * DiskInfo.SectorsPerCluster * DiskInfo.BytesPerSector)
985 | {
986 | jkGui->ShowDebug(2,NULL,L"Trying to access %I64u, but the last sector is at %I64u",
987 | RootStart,(DiskInfo.CountofClusters + 1) * DiskInfo.SectorsPerCluster * DiskInfo.BytesPerSector);
988 |
989 | free(DiskInfo.FatData.FAT12);
990 |
991 | return(FALSE);
992 | }
993 |
994 | /* We have to round up the Length to the nearest sector. For some reason or other
995 | Microsoft has decided that raw reading from disk can only be done by whole sector,
996 | even though ReadFile() accepts it's parameters in bytes. */
997 | BytesRead = (DWORD)RootLength;
998 |
999 | if (RootLength % DiskInfo.BytesPerSector > 0)
1000 | {
1001 | BytesRead = (DWORD)(RootLength + DiskInfo.BytesPerSector - RootLength % DiskInfo.BytesPerSector);
1002 | }
1003 |
1004 | /* Allocate buffer. */
1005 | RootDirectory = (BYTE *)malloc(BytesRead);
1006 | if (RootDirectory == NULL) {
1007 | jkGui->ShowDebug(2,NULL,L"Error: malloc() returned NULL.");
1008 | free(DiskInfo.FatData.FAT12);
1009 | return(FALSE);
1010 | }
1011 |
1012 | /* Read data from disk. */
1013 | Trans.QuadPart = RootStart;
1014 |
1015 | gOverlapped.Offset = Trans.LowPart;
1016 | gOverlapped.OffsetHigh = Trans.HighPart;
1017 | gOverlapped.hEvent = NULL;
1018 |
1019 | jkGui->ShowDebug(6,NULL,L"Reading root directory, %lu bytes at offset=%I64u.", BytesRead,Trans.QuadPart);
1020 |
1021 | Result = ReadFile(Data->Disk.VolumeHandle,RootDirectory,BytesRead,&BytesRead,&gOverlapped);
1022 |
1023 | if (Result == 0)
1024 | {
1025 | m_jkLib->SystemErrorStr(GetLastError(),s1,BUFSIZ);
1026 |
1027 | jkGui->ShowDebug(2,NULL,L"Error: %s",s1);
1028 |
1029 | free(DiskInfo.FatData.FAT12);
1030 | free(RootDirectory);
1031 |
1032 | return(FALSE);
1033 | }
1034 | }
1035 |
1036 | /* Analyze all the items in the root directory and add to the item tree. */
1037 | AnalyzeFatDirectory(Data,&DiskInfo,RootDirectory,RootLength,NULL);
1038 |
1039 | /* Cleanup. */
1040 | free(RootDirectory);
1041 | free(DiskInfo.FatData.FAT12);
1042 |
1043 | return(TRUE);
1044 | }
1045 |
--------------------------------------------------------------------------------
/JkDefrag/Source/ScanFat.h:
--------------------------------------------------------------------------------
1 | #ifndef __SCANFAT_H__
2 | #define __SCANFAT_H__
3 |
4 | #pragma pack(push,1) /* Align to bytes. */
5 |
6 | struct FatBootSectorStruct
7 | {
8 | UCHAR BS_jmpBoot[3]; // 0
9 | UCHAR BS_OEMName[8]; // 3
10 | USHORT BPB_BytsPerSec; // 11
11 | UCHAR BPB_SecPerClus; // 13
12 | USHORT BPB_RsvdSecCnt; // 14
13 | UCHAR BPB_NumFATs; // 16
14 | USHORT BPB_RootEntCnt; // 17
15 | USHORT BPB_TotSec16; // 19
16 | UCHAR BPB_Media; // 21
17 | USHORT BPB_FATSz16; // 22
18 | USHORT BPB_SecPerTrk; // 24
19 | USHORT BPB_NumHeads; // 26
20 | ULONG BPB_HiddSec; // 28
21 | ULONG BPB_TotSec32; // 32
22 |
23 | union
24 | {
25 | struct
26 | {
27 | UCHAR BS_DrvNum; // 36
28 | UCHAR BS_Reserved1; // 37
29 | UCHAR BS_BootSig; // 38
30 | ULONG BS_VolID; // 39
31 | UCHAR BS_VolLab[11]; // 43
32 | UCHAR BS_FilSysType[8]; // 54
33 | UCHAR BS_Reserved2[448]; // 62
34 | } Fat16;
35 |
36 | struct
37 | {
38 | ULONG BPB_FATSz32; // 36
39 | USHORT BPB_ExtFlags; // 40
40 | USHORT BPB_FSVer; // 42
41 | ULONG BPB_RootClus; // 44
42 | USHORT BPB_FSInfo; // 48
43 | USHORT BPB_BkBootSec; // 50
44 | UCHAR BPB_Reserved[12]; // 52
45 | UCHAR BS_DrvNum; // 64
46 | UCHAR BS_Reserved1; // 65
47 | UCHAR BS_BootSig; // 66
48 | ULONG BS_VolID; // 67
49 | UCHAR BS_VolLab[11]; // 71
50 | UCHAR BS_FilSysType[8]; // 82
51 | UCHAR BPB_Reserved2[420]; // 90
52 | } Fat32;
53 | };
54 |
55 | USHORT Signature; // 510
56 | };
57 |
58 | struct FatDirStruct
59 | {
60 | UCHAR DIR_Name[11]; // 0 File name, 8 + 3.
61 | UCHAR DIR_Attr; // 11 File attributes.
62 | UCHAR DIR_NTRes; // 12 Reserved.
63 | UCHAR DIR_CrtTimeTenth; // 13 Creation time, tenths of a second, 0...199.
64 | USHORT DIR_CrtTime; // 14 Creation time.
65 | USHORT DIR_CrtDate; // 16 Creation date.
66 | USHORT DIR_LstAccDate; // 18 Last access date.
67 | USHORT DIR_FstClusHI; // 20 First cluster number, high word.
68 | USHORT DIR_WrtTime; // 22 Last write time.
69 | USHORT DIR_WrtDate; // 24 Last write date.
70 | USHORT DIR_FstClusLO; // 26 First cluster number, low word.
71 | ULONG DIR_FileSize; // 28 File size in bytes.
72 | };
73 |
74 | struct FatLongNameDirStruct
75 | {
76 | UCHAR LDIR_Ord; // 0 Sequence number
77 | WCHAR LDIR_Name1[5]; // 1 Characters 1-5 in name
78 | UCHAR LDIR_Attr; // 11 Attribute, must be ATTR_LONG_NAME
79 | UCHAR LDIR_Type; // 12 Always zero
80 | UCHAR LDIR_Chksum; // 13 Checksum
81 | WCHAR LDIR_Name2[6]; // 14 Characters 6-11
82 | UCHAR LDIR_FstClusLO[2]; // 26 Always zero
83 | WCHAR LDIR_Name3[2]; // 28 Characters 12-13
84 | };
85 |
86 | #pragma pack(pop) /* Reset byte alignment. */
87 |
88 | /* The attribute flags. */
89 | #define ATTR_READ_ONLY 0x01
90 | #define ATTR_HIDDEN 0x02
91 | #define ATTR_SYSTEM 0x04
92 | #define ATTR_VOLUME_ID 0x08
93 | #define ATTR_DIRECTORY 0x10
94 | #define ATTR_ARCHIVE 0x20
95 |
96 | #define ATTR_LONG_NAME (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID)
97 | #define ATTR_LONG_NAME_MASK (ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID | ATTR_DIRECTORY | ATTR_ARCHIVE)
98 |
99 | /* Struct used by the scanner to store disk information from the bootblock. */
100 | struct FatDiskInfoStruct
101 | {
102 | ULONG64 BytesPerSector;
103 | ULONG64 SectorsPerCluster;
104 | ULONG64 TotalSectors;
105 | ULONG64 RootDirSectors;
106 | ULONG64 FirstDataSector;
107 | ULONG64 FATSz;
108 | ULONG64 DataSec;
109 | ULONG64 CountofClusters;
110 |
111 | union
112 | {
113 | BYTE *FAT12;
114 | USHORT *FAT16;
115 | ULONG *FAT32;
116 | } FatData;
117 | };
118 |
119 | class JKScanFat
120 | {
121 | public:
122 | JKScanFat();
123 | ~JKScanFat();
124 |
125 | // Get instance of the class
126 | static JKScanFat *getInstance();
127 |
128 | BOOL AnalyzeFatVolume(struct DefragDataStruct *Data);
129 |
130 | private:
131 |
132 | UCHAR CalculateShortNameCheckSum(UCHAR *Name);
133 | ULONG64 ConvertTime(USHORT Date, USHORT Time, USHORT Time10);
134 | void MakeFragmentList(struct DefragDataStruct *Data, struct FatDiskInfoStruct *DiskInfo, struct ItemStruct *Item, ULONG64 Cluster);
135 | BYTE *LoadDirectory(struct DefragDataStruct *Data, struct FatDiskInfoStruct *DiskInfo, ULONG64 StartCluster, ULONG64 *OutLength);
136 | void AnalyzeFatDirectory(struct DefragDataStruct *Data, struct FatDiskInfoStruct *DiskInfo, BYTE *Buffer, ULONG64 Length, struct ItemStruct *ParentDirectory);
137 |
138 | // static member that is an instance of itself
139 | static JKScanFat *m_jkScanFat;
140 |
141 | JKDefragLib *m_jkLib;
142 | };
143 |
144 | #endif
--------------------------------------------------------------------------------
/JkDefrag/Source/ScanNtfs.h:
--------------------------------------------------------------------------------
1 | #ifndef __SCANNTFS_H__
2 | #define __SCANNTFS_H__
3 |
4 | #define MFTBUFFERSIZE 256 * 1024 /* 256 KB seems to be the optimum. */
5 |
6 | struct INODE_REFERENCE
7 | {
8 | ULONG InodeNumberLowPart;
9 |
10 | USHORT InodeNumberHighPart;
11 | USHORT SequenceNumber;
12 | };
13 |
14 | struct NTFS_RECORD_HEADER
15 | {
16 | ULONG Type; /* File type, for example 'FILE' */
17 |
18 | USHORT UsaOffset; /* Offset to the Update Sequence Array */
19 | USHORT UsaCount; /* Size in words of Update Sequence Array */
20 |
21 | USN Lsn; /* $LogFile Sequence Number (LSN) */
22 | };
23 |
24 | struct FILE_RECORD_HEADER
25 | {
26 | struct NTFS_RECORD_HEADER RecHdr;
27 |
28 | USHORT SequenceNumber; /* Sequence number */
29 | USHORT LinkCount; /* Hard link count */
30 | USHORT AttributeOffset; /* Offset to the first Attribute */
31 | USHORT Flags; /* Flags. bit 1 = in use, bit 2 = directory, bit 4 & 8 = unknown. */
32 |
33 | ULONG BytesInUse; /* Real size of the FILE record */
34 | ULONG BytesAllocated; /* Allocated size of the FILE record */
35 |
36 | INODE_REFERENCE BaseFileRecord; /* File reference to the base FILE record */
37 |
38 | USHORT NextAttributeNumber; /* Next Attribute Id */
39 | USHORT Padding; /* Align to 4 UCHAR boundary (XP) */
40 |
41 | ULONG MFTRecordNumber; /* Number of this MFT Record (XP) */
42 |
43 | USHORT UpdateSeqNum; /* */
44 | };
45 |
46 | enum ATTRIBUTE_TYPE
47 | {
48 | AttributeInvalid = 0x00, /* Not defined by Windows */
49 | AttributeStandardInformation = 0x10,
50 | AttributeAttributeList = 0x20,
51 | AttributeFileName = 0x30,
52 | AttributeObjectId = 0x40,
53 | AttributeSecurityDescriptor = 0x50,
54 | AttributeVolumeName = 0x60,
55 | AttributeVolumeInformation = 0x70,
56 | AttributeData = 0x80,
57 | AttributeIndexRoot = 0x90,
58 | AttributeIndexAllocation = 0xA0,
59 | AttributeBitmap = 0xB0,
60 | AttributeReparsePoint = 0xC0, /* Reparse Point = Symbolic link */
61 | AttributeEAInformation = 0xD0,
62 | AttributeEA = 0xE0,
63 | AttributePropertySet = 0xF0,
64 | AttributeLoggedUtilityStream = 0x100
65 | };
66 |
67 | struct ATTRIBUTE
68 | {
69 | enum ATTRIBUTE_TYPE AttributeType;
70 |
71 | ULONG Length;
72 |
73 | BOOLEAN Nonresident;
74 |
75 | UCHAR NameLength;
76 |
77 | USHORT NameOffset;
78 | USHORT Flags; /* 0x0001 = Compressed, 0x4000 = Encrypted, 0x8000 = Sparse */
79 | USHORT AttributeNumber;
80 | };
81 |
82 | struct RESIDENT_ATTRIBUTE
83 | {
84 | struct ATTRIBUTE Attribute;
85 |
86 | ULONG ValueLength;
87 |
88 | USHORT ValueOffset;
89 | USHORT Flags; // 0x0001 = Indexed
90 | };
91 |
92 | struct NONRESIDENT_ATTRIBUTE
93 | {
94 | struct ATTRIBUTE Attribute;
95 |
96 | ULONGLONG StartingVcn;
97 | ULONGLONG LastVcn;
98 |
99 | USHORT RunArrayOffset;
100 |
101 | UCHAR CompressionUnit;
102 | UCHAR AlignmentOrReserved[5];
103 |
104 | ULONGLONG AllocatedSize;
105 | ULONGLONG DataSize;
106 | ULONGLONG InitializedSize;
107 | ULONGLONG CompressedSize; // Only when compressed
108 | };
109 |
110 | struct STANDARD_INFORMATION
111 | {
112 | ULONG64 CreationTime;
113 | ULONG64 FileChangeTime;
114 | ULONG64 MftChangeTime;
115 | ULONG64 LastAccessTime;
116 |
117 | ULONG FileAttributes; /* READ_ONLY=0x01, HIDDEN=0x02, SYSTEM=0x04, VOLUME_ID=0x08, ARCHIVE=0x20, DEVICE=0x40 */
118 | ULONG MaximumVersions;
119 | ULONG VersionNumber;
120 | ULONG ClassId;
121 | ULONG OwnerId; // NTFS 3.0 only
122 | ULONG SecurityId; // NTFS 3.0 only
123 |
124 | ULONGLONG QuotaCharge; // NTFS 3.0 only
125 |
126 | USN Usn; // NTFS 3.0 only
127 | };
128 |
129 | struct ATTRIBUTE_LIST
130 | {
131 | enum ATTRIBUTE_TYPE AttributeType;
132 |
133 | USHORT Length;
134 |
135 | UCHAR NameLength;
136 | UCHAR NameOffset;
137 |
138 | ULONGLONG LowestVcn;
139 |
140 | INODE_REFERENCE FileReferenceNumber;
141 |
142 | USHORT Instance;
143 | USHORT AlignmentOrReserved[3];
144 | };
145 |
146 | struct FILENAME_ATTRIBUTE
147 | {
148 | struct INODE_REFERENCE ParentDirectory;
149 |
150 | ULONG64 CreationTime;
151 | ULONG64 ChangeTime;
152 | ULONG64 LastWriteTime;
153 | ULONG64 LastAccessTime;
154 |
155 | ULONGLONG AllocatedSize;
156 | ULONGLONG DataSize;
157 |
158 | ULONG FileAttributes;
159 | ULONG AlignmentOrReserved;
160 |
161 | UCHAR NameLength;
162 | UCHAR NameType; /* NTFS=0x01, DOS=0x02 */
163 |
164 | WCHAR Name[1];
165 | };
166 |
167 | struct OBJECTID_ATTRIBUTE
168 | {
169 | GUID ObjectId;
170 |
171 | union
172 | {
173 | struct
174 | {
175 | GUID BirthVolumeId;
176 | GUID BirthObjectId;
177 | GUID DomainId;
178 | };
179 |
180 | UCHAR ExtendedInfo[48];
181 | };
182 | };
183 |
184 | struct VOLUME_INFORMATION
185 | {
186 | LONGLONG Reserved;
187 |
188 | UCHAR MajorVersion;
189 | UCHAR MinorVersion;
190 |
191 | USHORT Flags; /* DIRTY=0x01, RESIZE_LOG_FILE=0x02 */
192 | };
193 |
194 | struct DIRECTORY_INDEX
195 | {
196 | ULONG EntriesOffset;
197 | ULONG IndexBlockLength;
198 | ULONG AllocatedSize;
199 | ULONG Flags; /* SMALL=0x00, LARGE=0x01 */
200 | };
201 |
202 | struct DIRECTORY_ENTRY
203 | {
204 | ULONGLONG FileReferenceNumber;
205 |
206 | USHORT Length;
207 | USHORT AttributeLength;
208 |
209 | ULONG Flags; // 0x01 = Has trailing VCN, 0x02 = Last entry
210 |
211 | // FILENAME_ATTRIBUTE Name;
212 | // ULONGLONG Vcn; // VCN in IndexAllocation of earlier entries
213 | };
214 |
215 | struct INDEX_ROOT
216 | {
217 | enum ATTRIBUTE_TYPE Type;
218 |
219 | ULONG CollationRule;
220 | ULONG BytesPerIndexBlock;
221 | ULONG ClustersPerIndexBlock;
222 |
223 | struct DIRECTORY_INDEX DirectoryIndex;
224 | };
225 |
226 | struct INDEX_BLOCK_HEADER
227 | {
228 | struct NTFS_RECORD_HEADER Ntfs;
229 |
230 | ULONGLONG IndexBlockVcn;
231 |
232 | struct DIRECTORY_INDEX DirectoryIndex;
233 | };
234 |
235 | struct REPARSE_POINT
236 | {
237 | ULONG ReparseTag;
238 |
239 | USHORT ReparseDataLength;
240 | USHORT Reserved;
241 |
242 | UCHAR ReparseData[1];
243 | };
244 |
245 | struct EA_INFORMATION
246 | {
247 | ULONG EaLength;
248 | ULONG EaQueryLength;
249 | };
250 |
251 | struct EA_ATTRIBUTE
252 | {
253 | ULONG NextEntryOffset;
254 |
255 | UCHAR Flags;
256 | UCHAR EaNameLength;
257 |
258 | USHORT EaValueLength;
259 |
260 | CHAR EaName[1];
261 | // UCHAR EaData[];
262 | };
263 |
264 | struct ATTRIBUTE_DEFINITION
265 | {
266 | WCHAR AttributeName[64];
267 |
268 | ULONG AttributeNumber;
269 | ULONG Unknown[2];
270 | ULONG Flags;
271 |
272 | ULONGLONG MinimumSize;
273 | ULONGLONG MaximumSize;
274 | };
275 |
276 | /*
277 | The NTFS scanner will construct an ItemStruct list in memory, but needs some
278 | extra information while constructing it. The following structs wrap the ItemStruct
279 | into a new struct with some extra info, discarded when the ItemStruct list is
280 | ready.
281 |
282 | A single Inode can contain multiple streams of data. Every stream has it's own
283 | list of fragments. The name of a stream is the same as the filename plus two
284 | extensions separated by colons:
285 | filename:"stream name":"stream type"
286 |
287 | For example:
288 | myfile.dat:stream1:$DATA
289 |
290 | The "stream name" is an empty string for the default stream, which is the data
291 | of regular files. The "stream type" is one of the following strings:
292 | 0x10 $STANDARD_INFORMATION
293 | 0x20 $ATTRIBUTE_LIST
294 | 0x30 $FILE_NAME
295 | 0x40 NT $VOLUME_VERSION
296 | 0x40 2K $OBJECT_ID
297 | 0x50 $SECURITY_DESCRIPTOR
298 | 0x60 $VOLUME_NAME
299 | 0x70 $VOLUME_INFORMATION
300 | 0x80 $DATA
301 | 0x90 $INDEX_ROOT
302 | 0xA0 $INDEX_ALLOCATION
303 | 0xB0 $BITMAP
304 | 0xC0 NT $SYMBOLIC_LINK
305 | 0xC0 2K $REPARSE_POINT
306 | 0xD0 $EA_INFORMATION
307 | 0xE0 $EA
308 | 0xF0 NT $PROPERTY_SET
309 | 0x100 2K $LOGGED_UTILITY_STREAM
310 | */
311 |
312 | struct StreamStruct
313 | {
314 | struct StreamStruct *Next;
315 |
316 | WCHAR *StreamName; /* "stream name" */
317 |
318 | ATTRIBUTE_TYPE StreamType; /* "stream type" */
319 |
320 | struct FragmentListStruct *Fragments; /* The fragments of the stream. */
321 |
322 | ULONG64 Clusters; /* Total number of clusters. */
323 | ULONG64 Bytes; /* Total number of bytes. */
324 | };
325 |
326 | struct InodeDataStruct
327 | {
328 | ULONG64 Inode; /* The Inode number. */
329 | ULONG64 ParentInode; /* The Inode number of the parent directory. */
330 |
331 | BOOL Directory; /* YES: it's a directory. */
332 |
333 | WCHAR *LongFilename; /* Long filename. */
334 | WCHAR *ShortFilename; /* Short filename (8.3 DOS). */
335 |
336 | ULONG64 Bytes; /* Total number of bytes. */
337 | ULONG64 CreationTime; /* 1 second = 10000000 */
338 | ULONG64 MftChangeTime;
339 | ULONG64 LastAccessTime;
340 |
341 | struct StreamStruct *Streams; /* List of StreamStruct. */
342 | struct FragmentListStruct *MftDataFragments; /* The Fragments of the $MFT::$DATA stream. */
343 |
344 | ULONG64 MftDataBytes; /* Length of the $MFT::$DATA. */
345 |
346 | struct FragmentListStruct *MftBitmapFragments; /* The Fragments of the $MFT::$BITMAP stream. */
347 |
348 | ULONG64 MftBitmapBytes; /* Length of the $MFT::$BITMAP. */
349 | };
350 |
351 | struct NtfsDiskInfoStruct
352 | {
353 | ULONG64 BytesPerSector;
354 | ULONG64 SectorsPerCluster;
355 | ULONG64 TotalSectors;
356 | ULONG64 MftStartLcn;
357 | ULONG64 Mft2StartLcn;
358 | ULONG64 BytesPerMftRecord;
359 | ULONG64 ClustersPerIndexRecord;
360 |
361 | struct
362 | {
363 | BYTE Buffer[MFTBUFFERSIZE];
364 |
365 | ULONG64 Offset;
366 |
367 | int Age;
368 | } Buffers[3];
369 | };
370 |
371 | class JKScanNtfs
372 | {
373 | public:
374 | JKScanNtfs();
375 | ~JKScanNtfs();
376 |
377 | // Get instance of the class
378 | static JKScanNtfs *getInstance();
379 |
380 | BOOL AnalyzeNtfsVolume(struct DefragDataStruct *Data);
381 |
382 | private:
383 | WCHAR *StreamTypeNames(ATTRIBUTE_TYPE StreamType);
384 |
385 | BOOL FixupRawMftdata(struct DefragDataStruct *Data,struct NtfsDiskInfoStruct *DiskInfo, BYTE *Buffer, ULONG64 BufLength);
386 |
387 | BYTE *ReadNonResidentData(struct DefragDataStruct *Data, struct NtfsDiskInfoStruct *DiskInfo, BYTE *RunData, DWORD RunDataLength,
388 | ULONG64 Offset, ULONG64 WantedLength);
389 |
390 | BOOL TranslateRundataToFragmentlist(
391 | struct DefragDataStruct *Data,
392 | struct InodeDataStruct *InodeData,
393 | WCHAR *StreamName,
394 | ATTRIBUTE_TYPE StreamType,
395 | BYTE *RunData,
396 | DWORD RunDataLength,
397 | ULONG64 StartingVcn,
398 | ULONG64 Bytes);
399 |
400 | void CleanupStreams(struct InodeDataStruct *InodeData, BOOL CleanupFragments);
401 |
402 | WCHAR *ConstructStreamName(WCHAR *FileName1, WCHAR *FileName2, struct StreamStruct *Stream);
403 |
404 | BOOL ProcessAttributes(
405 | struct DefragDataStruct *Data,
406 | struct NtfsDiskInfoStruct *DiskInfo,
407 | struct InodeDataStruct *InodeData,
408 | BYTE *Buffer,
409 | ULONG64 BufLength,
410 | USHORT Instance,
411 | int Depth);
412 |
413 | void ProcessAttributeList(
414 | struct DefragDataStruct *Data,
415 | struct NtfsDiskInfoStruct *DiskInfo,
416 | struct InodeDataStruct *InodeData,
417 | BYTE *Buffer,
418 | ULONG64 BufLength,
419 | int Depth);
420 |
421 | BOOL InterpretMftRecord(
422 | struct DefragDataStruct *Data,
423 | struct NtfsDiskInfoStruct *DiskInfo,
424 | struct ItemStruct **InodeArray,
425 | ULONG64 InodeNumber,
426 | ULONG64 MaxInode,
427 | struct FragmentListStruct **MftDataFragments,
428 | ULONG64 *MftDataBytes,
429 | struct FragmentListStruct **MftBitmapFragments,
430 | ULONG64 *MftBitmapBytes,
431 | BYTE *Buffer,
432 | ULONG64 BufLength);
433 |
434 | // static member that is an instance of itself
435 | static JKScanNtfs *m_jkScanNtfs;
436 |
437 | // JKDefragGui *m_jkGui;
438 | JKDefragLib *m_jkLib;
439 | };
440 |
441 | #endif
442 |
--------------------------------------------------------------------------------
/JkDefrag/Source/StdAfx.cpp:
--------------------------------------------------------------------------------
1 | #include "StdAfx.h"
2 |
--------------------------------------------------------------------------------
/JkDefrag/Source/StdAfx.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef __STDAFX_H__
3 | #define __STDAFX_H__
4 |
5 | #define _WIN32_WINNT 0x0500
6 |
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | using namespace Gdiplus;
15 |
16 | #include /* CreateToolhelp32Snapshot() */
17 |
18 | #ifdef _DEBUG
19 | #include /* SetUnhandledExceptionFilter() */
20 | #endif
21 |
22 | #include "JKDefragStruct.h"
23 | #include "JkDefragLib.h"
24 | #include "JKDefragLog.h"
25 | #include "ScanFat.h"
26 | #include "ScanNtfs.h"
27 | #include "JkDefragGui.h"
28 |
29 | #endif // __STDAFX_H__
30 |
--------------------------------------------------------------------------------
/JkDefrag2005.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 9.00
3 | # Visual Studio 2005
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JkDefrag", "JkDefrag\JkDefrag2005.vcproj", "{205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Win32 = Debug|Win32
9 | Release|Win32 = Release|Win32
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}.Debug|Win32.ActiveCfg = Debug|Win32
13 | {205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}.Debug|Win32.Build.0 = Debug|Win32
14 | {205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}.Release|Win32.ActiveCfg = Release|Win32
15 | {205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}.Release|Win32.Build.0 = Release|Win32
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/JkDefrag2008.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 10.00
3 | # Visual Studio 2008
4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JkDefrag", "JkDefrag\JkDefrag2008.vcproj", "{205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Win32 = Debug|Win32
9 | Release|Win32 = Release|Win32
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}.Debug|Win32.ActiveCfg = Debug|Win32
13 | {205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}.Debug|Win32.Build.0 = Debug|Win32
14 | {205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}.Release|Win32.ActiveCfg = Release|Win32
15 | {205701F0-3E91-4DD7-AC0F-5A3E273BD3A6}.Release|Win32.Build.0 = Release|Win32
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "{}"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright {yyyy} {name of copyright owner}
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # JKDefrag-Original
2 | [C++] Latest Visual-Studio 2005/2008 Project Of JKDefrag Source-Code. Fixed (Will Compile 100%)
3 |
4 |
5 |
6 |
7 | ```
8 | JKDefrag is a disk defragmenter and optimizer for Windows 2000/2003/XP/Vista/2008 compatible with x86/x64 platforms architecture. Completely automatic and very easy to use, fast, low overhead, with several optimization strategies, and can handle floppies, USB disks, memory sticks, and anything else that looks like a disk to Windows.
9 |
10 | Included are a Windows version, a commandline version (for scheduling by the task scheduler or for use from administrator scripts), a screensaver version, a DLL library (for use from programming languages), versions for Windows X64, and the complete sources.
11 |
12 | Why use this defragger instead of the standard Windows defragger?
13 | - Much faster.
14 | - Totally automatic, extremely easy to use.
15 | - Optimized for daily use.
16 | - Disk optimization, several strategies.
17 | - Directories are moved to the beginning of the disk.
18 | - Reclaims MFT reserved space after disk-full.
19 | - Maintains free spaces for temporary files.
20 | - Can defragment very full harddisks.
21 | - Can defragment very large files.
22 | - Can defragment individual directories and files.
23 | - Can be run automatically with the Windows Scheduler.
24 | - Can be used from the commandline.
25 | - Can be used as a screen saver.
26 | - Can be run from cdrom or memory stick.
27 | - Sources available, can be customized.
28 | - Supports x86/x64 architecture.
29 |
30 | JKDefrag is an open source software by Jeroen Kessels,
31 | this is the "3.36" version, since from version 4,
32 | it was changed to "MyDefrag", which is a closed source freeware.
33 | ```
34 |
35 | latest pre-build can be found here: hxxp://icompile.eladkarako.com/jkdefrag/ [web.archive.org](https://web.archive.org/web/20161216015541/icompile.eladkarako.com/jkdefrag)
36 |
--------------------------------------------------------------------------------