ReactOS  0.4.13-dev-66-gc714b7f
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 
14 bool QuietMode = false;
15 bool VerboseMode = false;
16 
17 
18 // Makes sure we're in Windows 2000
19 bool 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 
48 wchar_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 
85 void 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 
95 void 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
146 extern "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;
222  HANDLE Screen;
223 
225  while (Continue)
226  {
227  Sleep (25);
228 
229  // Get current screen coords
230  CONSOLE_SCREEN_BUFFER_INFO ScreenInfo;
231 
232  GetConsoleScreenBufferInfo (Screen, &ScreenInfo);
233 
234  // Now set back to the beginning
235  ScreenInfo.dwCursorPosition.X = 0;
236  ScreenInfo.dwCursorPosition.Y -= 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;
316  FileInfo Info;
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  {
387  FileInfo Info;
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
unsigned long long uint64
Definition: platform.h:18
void PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco)
Definition: spec2def.c:488
static int argc
Definition: ServiceArgs.c:12
ULONG dwMajorVersion
Definition: rtltypes.h:234
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:736
Defragment * StartDefragThread(wstring Drive, DefragType Method, HANDLE &Handle)
Definition: Unfrag.cpp:132
_CRTIMP void __cdecl _endthread(void)
Definition: thread.c:95
int wmain(int argc, WCHAR **argv)
Definition: at.c:753
#define __cdecl
Definition: accygwin.h:79
bool VerboseMode
Definition: Unfrag.cpp:15
int FitName(wchar_t *destination, const wchar_t *path, const wchar_t *filename, uint32 totalWidth)
Definition: Defragment.cpp:9
unsigned int uint32
Definition: types.h:32
void __cdecl DefragThread(LPVOID parm)
Definition: Unfrag.cpp:120
#define ZeroMemory
Definition: winbase.h:1635
HANDLE WINAPI GetStdHandle(IN DWORD nStdHandle)
Definition: console.c:152
#define wprintf(...)
Definition: whoami.c:18
#define argv
Definition: mplay32.c:18
Defragment * Defrag
Definition: Fraginator.cpp:20
struct TraceInfo Info
#define APPCOPYRIGHT
Definition: Unfrag.h:43
wchar_t * AddCommas(wchar_t *Result, uint64 Number)
Definition: Unfrag.cpp:48
#define VER_PLATFORM_WIN32s
Definition: rtltypes.h:234
void Start(void)
Definition: Defragment.cpp:157
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
PWCHAR Drive
Definition: chkdsk.c:73
smooth NULL
Definition: ftsmooth.c:416
BOOL WINAPI SetConsoleCursorPosition(IN HANDLE hConsoleOutput, IN COORD dwCursorPosition)
Definition: console.c:590
_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:426
_CRTIMP wchar_t *__cdecl _wcsupr(_Inout_z_ wchar_t *_String)
ULONG dwOSVersionInfoSize
Definition: rtltypes.h:233
BOOL WINAPI GetConsoleScreenBufferInfo(IN HANDLE hConsoleOutput, OUT PCONSOLE_SCREEN_BUFFER_INFO lpConsoleScreenBufferInfo)
Definition: console.c:544
ULONG X
Definition: bl.h:1340
_In_ HANDLE Handle
Definition: extypes.h:390
#define d
Definition: ke_i.h:81
void push_back(const _Tp &__x=_STLP_DEFAULT_CONSTRUCTED(_Tp))
Definition: _vector.h:376
#define swprintf(buf, format,...)
Definition: sprintf.c:56
const GLubyte * c
Definition: glext.h:8905
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
volatile int Continue
Definition: gdblib.c:102
static const WCHAR L[]
Definition: oid.c:1250
#define STD_OUTPUT_HANDLE
Definition: winbase.h:265
_In_opt_ PENTER_STATE_SYSTEM_HANDLER _In_opt_ PVOID _In_ LONG _In_opt_ LONG volatile * Number
Definition: ntpoapi.h:204
bool CheckWinVer(void)
Definition: Unfrag.cpp:19
bool QuietMode
Definition: Unfrag.cpp:14
ULONG dwPlatformId
Definition: rtltypes.h:237
#define GetVersionEx
Definition: winbase.h:3666
void PrintBanner(void)
Definition: Unfrag.cpp:85
#define VER_PLATFORM_WIN32_WINDOWS
Definition: rtltypes.h:235
void FraggerHelp(void)
Definition: Unfrag.cpp:95
DefragType
Definition: Unfrag.h:66
_CRTIMP uintptr_t __cdecl _beginthread(_In_ void(__cdecl *_StartAddress)(void *), _In_ unsigned _StackSize, _In_opt_ void *_ArgList)
size_type size() const
Definition: _vector.h:192
Definition: console.h:34
#define APPNAME_CLI
Definition: Unfrag.h:38
ULONG Y
Definition: bl.h:1341
int tolower(int c)
Definition: utclib.c:902
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
_Must_inspect_result_ _In_ PHYSICAL_ADDRESS _In_ PHYSICAL_ADDRESS _In_ SIZE_T TotalBytes
Definition: mmfuncs.h:226
#define APPVER_STR
Definition: Unfrag.h:40