ReactOS 0.4.15-dev-7705-g2320c37
Unfrag.cpp
Go to the documentation of this file.
1/*****************************************************************************
2
3 Unfrag
4
5*****************************************************************************/
6
7
8#include "Unfrag.h"
9#include "DriveVolume.h"
10#include "Defragment.h"
11#include <process.h>
12
13
14bool QuietMode = false;
15bool VerboseMode = false;
16
17
18// Makes sure we're in Windows 2000
19bool CheckWinVer (void)
20{
21 OSVERSIONINFO OSVersion;
22
23 ZeroMemory (&OSVersion, sizeof (OSVersion));
24 OSVersion.dwOSVersionInfoSize = sizeof (OSVersion);
25 GetVersionEx (&OSVersion);
26
27 // Need Windows 2000!
28
29 // Check for NT first
30 // Actually what we do is check that weLL're not on Win31+Win32s and that we're
31 // not in Windows 9x. It's possible that there could be more Windows "platforms"
32 // in the future and there's no sense in claiming incompatibility.
33 if (OSVersion.dwPlatformId == VER_PLATFORM_WIN32s ||
35 {
36 return (false);
37 }
38
39 // Ok weLL're in Windows NT, now make sure we're in 2000
40 if (OSVersion.dwMajorVersion < 5)
41 return (false);
42
43 // Kew, we're in at least Windows 2000 ("NT 5.0")
44 return (true);
45}
46
47
48wchar_t *AddCommas (wchar_t *Result, uint64 Number)
49{
50 wchar_t Temp[128];
51 int TempLen;
52 //wchar_t *p = NULL;
53 int AddCommas = 0;
54 wchar_t *StrPosResult = NULL;
55 wchar_t *StrPosOrig = NULL;
56
57 // we get the string form of the number, then we count down w/ AddCommas
58 // while copying the string from Temp1 to Result. when AddCommas % 3 == 1,
59 // slap in a commas as well, before the #.
60 swprintf (Temp, L"%I64u", Number);
61 AddCommas = TempLen = wcslen (Temp);
62 StrPosOrig = Temp;
63 StrPosResult = Result;
64 while (AddCommas)
65 {
66 if ((AddCommas % 3) == 0 && AddCommas != TempLen) // avoid stuff like ",345"
67 {
68 *StrPosResult = L',';
69 StrPosResult++;
70 }
71
72 *StrPosResult = *StrPosOrig;
73 StrPosResult++;
74 StrPosOrig++;
75
76 *StrPosResult = 0;
77
78 AddCommas--;
79 }
80
81 return (Result);
82}
83
84
85void PrintBanner (void)
86{
87 wprintf (L"%s v%s\n", APPNAME_CLI, APPVER_STR);
88 wprintf (L"%s\n", APPCOPYRIGHT);
89 wprintf (L"\n");
90
91 return;
92}
93
94
95void FraggerHelp (void)
96{
97 wprintf (L"Usage: unfrag drive: [...] <-f | -e>\n");
98 wprintf (L"\n");
99 wprintf (L"drive: : The drive to defrag. Should be two characters long, ie 'c:' or 'd:'.\n");
100 wprintf (L" Multiple drives may be given, and all will be simultaneously\n");
101 wprintf (L" defragmented using the same options.\n");
102 wprintf (L"-f : Do a fast defragmentation. Files that are not fragmented will not be\n");
103 wprintf (L" moved. Only one pass is made over the file list. Using this option\n");
104 wprintf (L" may result in not all files being defragmented, depending on\n");
105 wprintf (L" available disk space.\n");
106 wprintf (L"-e : Do an extensive defragmention. Files will be moved in an attempt to\n");
107 wprintf (L" defragment both files and free space.\n");
108
109 if (!CheckWinVer())
110 {
111 wprintf (L"\n");
112 wprintf (L"NOTE: This program requires Windows 2000, which is not presently running on\n");
113 wprintf (L"this system.\n");
114 }
115
116 return;
117}
118
119
121{
123
124 Defrag = (Defragment *) parm;
125 Defrag->Start ();
126
127 _endthread ();
128 return;
129}
130
131
133{
134 Defragment *Defragger;
135 unsigned long Thread;
136
137 Defragger = new Defragment (Drive, Method);
138 //Thread = /*CreateThread*/ _beginthreadex (NULL, 0, DefragThread, Defragger, 0, &ThreadID);
139 Thread = _beginthread (DefragThread, 0, Defragger);
140 Handle = *((HANDLE *)&Thread);
141 return (Defragger);
142}
143
144#ifdef _CUI_
145// Main Initialization
146extern "C" int wmain (int argc, wchar_t **argv)
147{
148 vector<wstring> Drives;
149 vector<Defragment *> Defrags;
150 DefragType DefragMode = DefragInvalid;
151
152 PrintBanner ();
153
154 // Parse command line arguments
155 bool ValidCmdLine = false;
156 for (int c = 0; c < argc; c++)
157 {
158 if (wcslen(argv[c]) == 2 && argv[c][1] == L':')
159 {
160 Drives.push_back (_wcsupr(argv[c]));
161 }
162 else
163 if ((argv[c][0] == L'-' || argv[c][0] == L'/') && wcslen(argv[c]) == 2)
164 {
165 switch (tolower(argv[c][1]))
166 {
167 case L'?' :
168 case L'h' :
169 FraggerHelp ();
170 return (0);
171
172 case L'f' :
173 if (DefragMode != DefragInvalid)
174 {
175 ValidCmdLine = false;
176 break;
177 }
178 DefragMode = DefragFast;
179 ValidCmdLine = true;
180 break;
181
182 case L'e' :
183 if (DefragMode != DefragInvalid)
184 {
185 ValidCmdLine = false;
186 break;
187 }
188 DefragMode = DefragExtensive;
189 ValidCmdLine = true;
190 break;
191
192 }
193 }
194 }
195
196 if (DefragMode == DefragInvalid)
197 ValidCmdLine = false;
198
199 if (!ValidCmdLine)
200 {
201 wprintf (L"Invalid command-line options. Use '%s -?' for help.\n", argv[0]);
202 return (0);
203 }
204
205 // Check OS requirements
206 if (!CheckWinVer())
207 {
208 wprintf (L"Fatal Error: This program requires Windows 2000.\n");
209 return (0);
210 }
211
212 for (size_t d = 0; d < Drives.size (); d++)
213 {
214 HANDLE TossMe;
215 Defrags.push_back (StartDefragThread (Drives[d], DefragMode, TossMe));
216 }
217
218 for (size_t d = 0; d < Drives.size () - 1; d++)
219 wprintf (L"\n ");
220
221 bool Continue = true;
223
225 while (Continue)
226 {
227 Sleep (25);
228
229 // Get current screen coords
231
232 GetConsoleScreenBufferInfo (Screen, &ScreenInfo);
233
234 // Now set back to the beginning
235 ScreenInfo.dwCursorPosition.X = 0;
236 ScreenInfo.dwCursorPosition.Y -= (USHORT)Drives.size();
238
239 for (size_t d = 0; d < Drives.size (); d++)
240 {
241 wprintf (L"\n%6.2f%% %-70s", Defrags[d]->GetStatusPercent(), Defrags[d]->GetStatusString().c_str());
242 }
243
244 // Determine if we should keep going
245 Continue = false;
246 for (size_t d = 0; d < Drives.size (); d++)
247 {
248 if (!Defrags[d]->IsDoneYet() && !Defrags[d]->HasError())
249 Continue = true;
250 }
251 }
252
253#if 0
254 // Loop through the drives list
255 for (int d = 0; d < Drives.size(); d++)
256 {
258
259 Drive = new DriveVolume;
260
261 // First thing: build a file list.
262 wprintf (L"Opening volume %s ...", Drives[d].c_str());
263 if (!Drive->Open (Drives[d]))
264 {
265 wprintf (L"FAILED\n\n");
266 delete Drive;
267 continue;
268 }
269 wprintf (L"\n");
270
271 wprintf (L" Getting drive bitmap ...");
272 if (!Drive->GetBitmap ())
273 {
274 wprintf (L"FAILED\n\n");
275 delete Drive;
276 continue;
277 }
278 wprintf (L"\n");
279
280 wprintf (L" Obtaining drive geometry ...");
281 if (!Drive->ObtainInfo ())
282 {
283 wprintf (L"FAILED\n\n");
284 delete Drive;
285 continue;
286 }
287 wprintf (L"\n");
288
289 wprintf (L" Building file database for drive %s ...", Drives[d].c_str());
290 if (!Drive->BuildFileList ())
291 {
292 wprintf (L"FAILED\n\n");
293 delete Drive;
294 continue;
295 }
296 wprintf (L"\n");
297
298 wprintf (L" %u files\n", Drive->GetDBFileCount ());
299
300 // Analyze only?
301 if (DefragMode == DefragAnalyze)
302 {
303 uint64 UsedBytes = 0; // total bytes used, with cluster size considerations
304 uint64 TotalBytes = 0; // total bytes used
305 uint64 SlackBytes = 0; // wasted space due to slack
306 uint32 Fragged = 0; // fragmented files
307
308 wprintf (L" Analyzing ...");
309 if (VerboseMode)
310 wprintf (L"\n");
311
312 for (int i = 0; i < Drive->GetDBFileCount(); i++)
313 {
314 uint64 Used;
315 uint64 Slack;
317
318 Info = Drive->GetDBFile (i);
319
320 // Compute total used disk space
321 Used = ((Info.Size + Drive->GetClusterSize() - 1) / Drive->GetClusterSize()) * Drive->GetClusterSize();
322 Slack = Used - Info.Size;
323
324 UsedBytes += Used;
325 SlackBytes += Slack;
326 TotalBytes += Info.Size;
327
328 if (VerboseMode)
329 {
330 wprintf (L" %s%s, ", Drive->GetDBDir (Info.DirIndice).c_str(), Info.Name.c_str());
331
332 if (Info.Attributes.AccessDenied)
333 wprintf (L"access was denied\n");
334 else
335 {
336 if (Info.Attributes.Unmovable == 1)
337 wprintf (L"unmovable, ");
338
339 wprintf (L"%I64u bytes, %I64u bytes on disk, %I64u bytes slack, %u fragments\n",
340 Info.Size, Used, Slack, Info.Fragments.size());
341 }
342 }
343
344 if (Info.Fragments.size() > 1)
345 Fragged++;
346 }
347
348 if (!VerboseMode)
349 wprintf (L"\n");
350
351 // TODO: Make it not look like ass
352 wprintf (L"\n");
353 wprintf (L" Overall Analysis\n");
354 wprintf (L" ----------------\n");
355 wprintf (L" %u clusters\n", Drive->GetClusterCount ());
356 wprintf (L" %u bytes per cluster\n", Drive->GetClusterSize());
357 wprintf (L" %I64u total bytes on drive\n", (uint64)Drive->GetClusterCount() * (uint64)Drive->GetClusterSize());
358 wprintf (L"\n");
359 wprintf (L" %u files\n", Drive->GetDBFileCount ());
360 wprintf (L" %u contiguous files\n", Drive->GetDBFileCount () - Fragged);
361 wprintf (L" %u fragmented files\n", Fragged);
362 wprintf (L"\n");
363 wprintf (L" %I64u bytes\n", TotalBytes);
364 wprintf (L" %I64u bytes on disk\n", UsedBytes);
365 wprintf (L" %I64u bytes slack\n", SlackBytes);
366 }
367
368 // Fast defragment!
369 if (DefragMode == DefragFast || DefragMode == DefragExtensive)
370 {
371 uint32 i;
372 uint64 FirstFreeLCN;
373 wchar_t PrintName[80];
374 int Width = 66;
375
376 if (DefragMode == DefragFast)
377 wprintf (L" Performing fast file defragmentation ...\n");
378 else
379 if (DefragMode == DefragExtensive)
380 wprintf (L" Performing extensive file defragmentation\n");
381
382 // Find first free LCN for speedier searches ...
383 Drive->FindFreeRange (0, 1, FirstFreeLCN);
384
385 for (i = 0; i < Drive->GetDBFileCount(); i++)
386 {
388 bool Result;
389 uint64 TargetLCN;
390
391 wprintf (L"\r");
392
393 Info = Drive->GetDBFile (i);
394
395 FitName (PrintName, Drive->GetDBDir (Info.DirIndice).c_str(), Info.Name.c_str(), Width);
396 wprintf (L" %6.2f%% %-66s", (float)i / (float)Drive->GetDBFileCount() * 100.0f, PrintName);
397
398 // Can't defrag 0 byte files :)
399 if (Info.Fragments.size() == 0)
400 continue;
401
402 // If doing fast defrag, skip non-fragmented files
403 if (Info.Fragments.size() == 1 && DefragMode == DefragFast)
404 continue;
405
406 // Find a place that can fit the file
407 Result = Drive->FindFreeRange (FirstFreeLCN, Info.Clusters, TargetLCN);
408
409 // If we're doing an extensive defrag and the file is already defragmented
410 // and if its new location would be after its current location, don't
411 // move it.
412 if (DefragMode == DefragExtensive && Info.Fragments.size() == 1)
413 {
414 if (TargetLCN > Info.Fragments[0].StartLCN)
415 continue;
416 }
417
418 // Otherwise, defrag0rize it!
419 if (Result)
420 {
421 bool Success = false;
422
423 if (Drive->MoveFileDumb (i, TargetLCN))
424 Success = true;
425 else
426 { // hmm, look for another area to move it to
427 Result = Drive->FindFreeRange (TargetLCN + 1, Info.Clusters, TargetLCN);
428 if (Result)
429 {
430 if (Drive->MoveFileDumb (i, TargetLCN))
431 Success = true;
432 else
433 { // Try updating the drive bitmap
434 if (Drive->GetBitmap ())
435 {
436 Result = Drive->FindFreeRange (0, Info.Clusters, TargetLCN);
437 if (Result)
438 {
439 if (Drive->MoveFileDumb (i, TargetLCN))
440 Success = true;
441 }
442 }
443 }
444 }
445 }
446
447 if (!Success)
448 wprintf (L"\n -> failed\n");
449
450 Drive->FindFreeRange (0, 1, FirstFreeLCN);
451 }
452 }
453
454 wprintf (L"\n");
455 }
456 wprintf (L"Closing volume %s ...", Drives[d].c_str());
457 delete Drive;
458 wprintf (L"\n");
459 }
460#endif
461
462 return (0);
463}
464#endif
int FitName(wchar_t *destination, const wchar_t *path, const wchar_t *filename, uint32 totalWidth)
Definition: Defragment.cpp:9
Defragment * Defrag
Definition: Fraginator.cpp:20
static int argc
Definition: ServiceArgs.c:12
bool VerboseMode
Definition: Unfrag.cpp:15
void FraggerHelp(void)
Definition: Unfrag.cpp:95
wchar_t * AddCommas(wchar_t *Result, uint64 Number)
Definition: Unfrag.cpp:48
void PrintBanner(void)
Definition: Unfrag.cpp:85
bool CheckWinVer(void)
Definition: Unfrag.cpp:19
bool QuietMode
Definition: Unfrag.cpp:14
Defragment * StartDefragThread(wstring Drive, DefragType Method, HANDLE &Handle)
Definition: Unfrag.cpp:132
void __cdecl DefragThread(LPVOID parm)
Definition: Unfrag.cpp:120
DefragType
Definition: Unfrag.h:67
@ DefragExtensive
Definition: Unfrag.h:70
@ DefragAnalyze
Definition: Unfrag.h:71
@ DefragInvalid
Definition: Unfrag.h:68
@ DefragFast
Definition: Unfrag.h:69
#define APPVER_STR
Definition: Unfrag.h:40
#define APPCOPYRIGHT
Definition: Unfrag.h:43
#define APPNAME_CLI
Definition: Unfrag.h:38
int tolower(int c)
Definition: utclib.c:902
#define __cdecl
Definition: accygwin.h:79
unsigned int uint32
Definition: types.h:32
BOOL WINAPI SetConsoleCursorPosition(IN HANDLE hConsoleOutput, IN COORD dwCursorPosition)
Definition: console.c:641
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:203
BOOL WINAPI GetConsoleScreenBufferInfo(IN HANDLE hConsoleOutput, OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo)
Definition: console.c:595
PWCHAR Drive
Definition: chkdsk.c:73
void Start(void)
Definition: Defragment.cpp:157
#define NULL
Definition: types.h:112
@ Screen
Definition: console.h:34
#define swprintf
Definition: precomp.h:40
unsigned long long uint64
Definition: platform.h:18
@ Success
Definition: eventcreate.c:712
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
ULONG Handle
Definition: gdb_input.c:15
const GLubyte * c
Definition: glext.h:8905
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
#define d
Definition: ke_i.h:81
#define argv
Definition: mplay32.c:18
#define VER_PLATFORM_WIN32_WINDOWS
Definition: rtltypes.h:237
#define VER_PLATFORM_WIN32s
Definition: rtltypes.h:236
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:207
#define L(x)
Definition: ntvdm.h:50
unsigned short USHORT
Definition: pedump.c:61
int wmain()
_CRTIMP uintptr_t __cdecl _beginthread(_In_ void(__cdecl *_StartAddress)(void *), _In_ unsigned _StackSize, _In_opt_ void *_ArgList)
_CRTIMP void __cdecl _endthread(void)
Definition: thread.c:95
_CRTIMP wchar_t *__cdecl _wcsupr(_Inout_z_ wchar_t *_String)
void PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco)
Definition: spec2def.c:540
ULONG dwPlatformId
Definition: rtltypes.h:241
ULONG dwOSVersionInfoSize
Definition: rtltypes.h:237
ULONG dwMajorVersion
Definition: rtltypes.h:238
SHORT Y
Definition: blue.h:27
SHORT X
Definition: blue.h:26
void push_back(const _Tp &__x=_STLP_DEFAULT_CONSTRUCTED(_Tp))
Definition: _vector.h:379
size_type size() const
Definition: _vector.h:192
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
_In_ HFONT _Out_ PUINT _Out_ PUINT Width
Definition: font.h:89
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
#define wprintf(...)
Definition: whoami.c:18
#define ZeroMemory
Definition: winbase.h:1712
#define STD_OUTPUT_HANDLE
Definition: winbase.h:268
#define GetVersionEx
Definition: winbase.h:3787
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
_Must_inspect_result_ _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS _In_ SIZE_T TotalBytes
Definition: mmfuncs.h:228