ReactOS  0.4.14-dev-114-gc8cbd56
Defragment.cpp
Go to the documentation of this file.
1 #include "Defragment.h"
2 
3 
4 // Ahh yes I ripped this from my old Findupes project :)
5 // Fits a path name, composed of a path (i.e. "c:\blah\blah\cha\cha") and a filename ("stuff.txt")
6 // and fits it to a given length. If it has to truncate it will first truncate from the path,
7 // substituting in periods. So you might end up with something like:
8 // C:\Program Files\Micro...\Register.exe
9 int FitName (wchar_t *destination, const wchar_t *path, const wchar_t *filename, uint32 totalWidth)
10 {
11  uint32 pathLen=0;
12  uint32 fnLen=0;
13  uint32 halfTotLen=0;
14  uint32 len4fn=0; /* number of chars remaining for filename after path is applied */
15  uint32 len4path=0; /* number of chars for path before filename is applied */
16  wchar_t fmtStrPath[20]=L"";
17  wchar_t fmtStrFile[20]=L"";
18  wchar_t fmtString[40]=L"";
19 
20  /*
21  assert (destination != NULL);
22  assert (path != NULL);
23  assert (filename != NULL);
24  assert (totalWidth != 0);
25  */
26 
27  pathLen = wcslen(path);
28  fnLen = wcslen(filename);
29  if (!(totalWidth % 2))
30  halfTotLen=totalWidth / 2;
31  else
32  halfTotLen=(totalWidth-1) / 2; /* -1 because otherwise (halfTotLen*2) ==
33 (totalWidth+1) which wouldn't be good */
34 
35  /* determine how much width the path and filename each get */
36  if ( (pathLen >= halfTotLen) && (fnLen < halfTotLen) )
37  {
38  len4fn = fnLen;
39  len4path = (totalWidth - len4fn);
40  }
41 
42  if ( (pathLen < halfTotLen) && (fnLen < halfTotLen) )
43  {
44  len4fn = fnLen;
45  len4path = pathLen;
46  }
47 
48  if ( (pathLen >= halfTotLen) && (fnLen >= halfTotLen) )
49  {
50  len4fn = halfTotLen;
51  len4path = halfTotLen;
52  }
53 
54  if ( (pathLen < halfTotLen) && (fnLen >= halfTotLen) )
55  {
56  len4path = pathLen;
57  len4fn = (totalWidth - len4path);
58  }
59  /*
60  if halfTotLen was adjusted above to avoid a rounding error, give the
61  extra wchar_t to the filename
62  */
63  if (halfTotLen < (totalWidth/2)) len4path++;
64 
65  if (pathLen > len4path) swprintf (fmtStrPath, L"%%.%ds...\\", len4path-4);
66  else
67  swprintf (fmtStrPath, L"%%s");
68 
69  if (fnLen > len4fn) swprintf (fmtStrFile, L"%%.%ds...", len4fn-3);
70  else
71  swprintf (fmtStrFile, L"%%s");
72 
73  wcscpy (fmtString, fmtStrPath);
74  wcscat (fmtString, fmtStrFile);
75  /*swprintf (fmtString, L"%s%s", fmtStrPath, fmtStrFile);*/
76  swprintf (destination, fmtString, path,filename);
77 
78  return (1);
79 }
80 
81 Defragment::Defragment (wstring Name, DefragType DefragMethod)
82 {
84  DoLimitLength = true;
85  Error = false;
86  Done = false;
87  PleaseStop = false;
88  PleasePause = false;
89  DriveName = Name;
90  StatusPercent = 0.0f;
92 
93  SetStatusString (L"Opening volume " + Name);
94  if (!Volume.Open (Name))
95  {
96  SetStatusString (L"Error opening volume " + Name);
97  Error = true;
98  Done = true;
99  StatusPercent = 100.0f;
100  }
101 
102  return;
103 }
104 
105 
107 {
108  if (!IsDoneYet ())
109  {
110  Stop ();
111  while (!IsDoneYet() && !HasError())
112  {
113  SetStatusString (L"Waiting for thread to stop ...");
114  Sleep (150);
115  }
116  }
117 
118  Volume.Close ();
119  return;
120 }
121 
122 
123 void Defragment::SetStatusString (wstring NewStatus)
124 {
125  Lock ();
126  StatusString = NewStatus;
127  Unlock ();
128 
129  return;
130 }
131 
132 
134 {
135  wstring ReturnVal;
136 
137  Lock ();
138  ReturnVal = StatusString;
139  Unlock ();
140 
141  return (ReturnVal);
142 }
143 
144 
146 {
147  return (StatusPercent);
148 }
149 
150 
152 {
153  return (Done);
154 }
155 
156 
157 void Defragment::Start (void)
158 {
159  uint32 i;
160  uint64 FirstFreeLCN;
161  uint64 TotalClusters;
162  uint64 ClustersProgress;
163  wchar_t PrintName[80];
164  int Width = 70;
165 
166  if (Error)
167  goto DoneDefrag;
168 
169  // First thing: build a file list.
170  SetStatusString (L"Getting volume bitmap");
171  if (!Volume.GetBitmap())
172  {
173  SetStatusString (L"Could not get volume " + DriveName + L" bitmap");
174  Error = true;
175  goto DoneDefrag;
176  }
177 
179 
180  if (PleaseStop)
181  goto DoneDefrag;
182 
183  SetStatusString (L"Obtaining volume geometry");
184  if (!Volume.ObtainInfo ())
185  {
186  SetStatusString (L"Could not obtain volume " + DriveName + L" geometry");
187  Error = true;
188  goto DoneDefrag;
189  }
190 
191  if (PleaseStop)
192  goto DoneDefrag;
193 
194  SetStatusString (L"Building file database for volume " + DriveName);
196  {
197  SetStatusString (L"Could not build file database for volume " + DriveName);
198  Error = true;
199  goto DoneDefrag;
200  }
201 
202  if (PleaseStop)
203  goto DoneDefrag;
204 
205  SetStatusString (L"Analyzing database for " + DriveName);
206  TotalClusters = 0;
207  for (i = 0; i < Volume.GetDBFileCount(); i++)
208  {
209  TotalClusters += Volume.GetDBFile(i).Clusters;
210  }
211 
212  // Defragment!
213  ClustersProgress = 0;
214 
215  // Find first free LCN for speedier searches ...
216  Volume.FindFreeRange (0, 1, FirstFreeLCN);
217 
218  if (PleaseStop)
219  goto DoneDefrag;
220 
221  // Analyze?
222  if (Method == DefragAnalyze)
223  {
224  uint32 j;
225 
227 
228  Report.FraggedFiles.clear ();
229  Report.UnfraggedFiles.clear ();
230  Report.UnmovableFiles.clear ();
231 
235 
240 
241  for (j = 0; j < Volume.GetDBFileCount(); j++)
242  {
243  FileInfo Info;
244 
245  Info = Volume.GetDBFile (j);
246 
247  Report.FilesFragments += max ((size_t)1, Info.Fragments.size()); // add 1 fragment even for 0 bytes/0 cluster files
248 
249  if (Info.Attributes.Process == 0)
250  continue;
251 
252  SetStatusString (Volume.GetDBDir (Info.DirIndice) + Info.Name);
253 
254  Report.FilesSizeClusters += Info.Clusters;
255  Report.FilesSizeBytes += Info.Size;
256 
257  if (Info.Attributes.Unmovable == 1)
258  Report.UnmovableFiles.push_back (j);
259 
260  if (Info.Fragments.size() > 1)
261  Report.FraggedFiles.push_back (j);
262  else
263  Report.UnfraggedFiles.push_back (j);
264 
265  StatusPercent = ((double)j / (double)Report.FilesCount) * 100.0f;
266  }
267 
271  Report.PercentFragged = 100.0f * ((double)(signed)Report.FraggedFiles.size() / (double)(signed)Report.FilesCount);
272 
273  uint64 Percent;
274  Percent = (10000 * Report.FilesSlackBytes) / Report.FilesSizeOnDisk;
275  Report.PercentSlack = (double)(signed)Percent / 100.0f;
276  }
277  else
278  // Go through all the files and ... defragment them!
279  for (i = 0; i < Volume.GetDBFileCount(); i++)
280  {
281  FileInfo Info;
282  bool Result;
283  uint64 TargetLCN;
284  uint64 PreviousClusters;
285 
286  // What? They want us to pause? Oh ok.
287  if (PleasePause)
288  {
289  SetStatusString (L"Paused");
290  PleasePause = false;
291 
292  while (PleasePause == false)
293  {
294  Sleep (50);
295  }
296 
297  PleasePause = false;
298  }
299 
300  if (PleaseStop)
301  {
302  SetStatusString (L"Stopping");
303  break;
304  }
305 
306  //
307  Info = Volume.GetDBFile (i);
308 
309  PreviousClusters = ClustersProgress;
310  ClustersProgress += Info.Clusters;
311 
312  if (Info.Attributes.Process == 0)
313  continue;
314 
315  if (!DoLimitLength)
316  SetStatusString (Volume.GetDBDir (Info.DirIndice) + Info.Name);
317  else
318  {
319  FitName (PrintName, Volume.GetDBDir (Info.DirIndice).c_str(), Info.Name.c_str(), Width);
321  }
322 
323  // Calculate percentage complete
324  StatusPercent = 100.0f * double((double)PreviousClusters / (double)TotalClusters);
325 
326  // Can't defrag directories yet
327  if (Info.Attributes.Directory == 1)
328  continue;
329 
330  // Can't defrag 0 byte files :)
331  if (Info.Fragments.empty())
332  continue;
333 
334  // If doing fast defrag, skip non-fragmented files
335  // Note: This assumes that the extents stored in Info.Fragments
336  // are consolidated. I.e. we assume it is NOT the case that
337  // two extents account for a sequential range of (non-
338  // fragmented) clusters.
339  if (Info.Fragments.size() == 1 && Method == DefragFast)
340  continue;
341 
342  // Otherwise, defrag0rize it!
343  int Retry = 3; // retry a few times
344  while (Retry > 0)
345  {
346  // Find a place that can fit the file
347  Result = Volume.FindFreeRange (FirstFreeLCN, Info.Clusters, TargetLCN);
348 
349  // If yes, try moving it
350  if (Result)
351  {
352  // If we're doing an extensive defrag and the file is already defragmented
353  // and if its new location would be after its current location, don't
354  // move it.
355  if (Method == DefragExtensive && Info.Fragments.size() == 1 &&
356  TargetLCN > Info.Fragments[0].StartLCN)
357  {
358  Retry = 1;
359  }
360  else
361  {
362  if (Volume.MoveFileDumb (i, TargetLCN))
363  {
364  Retry = 1; // yay, all done with this file.
365  Volume.FindFreeRange (0, 1, FirstFreeLCN);
366  }
367  }
368  }
369 
370  // New: Only update bitmap if it's older than 15 seconds
371  if ((GetTickCount() - LastBMPUpdate) < 15000)
372  Retry = 1;
373  else
374  if (!Result || Retry != 1)
375  { // hmm. Wait for a moment, then update the drive bitmap
376  //SetStatusString (L"(Reobtaining volume " + DriveName + L" bitmap)");
377 
378  if (!DoLimitLength)
379  {
380  SetStatusString (GetStatusString() + wstring (L" ."));
381  }
382 
383  if (Volume.GetBitmap ())
384  {
386 
387  if (!DoLimitLength)
388  SetStatusString (Volume.GetDBDir (Info.DirIndice) + Info.Name);
389  else
391 
392  Volume.FindFreeRange (0, 1, FirstFreeLCN);
393  }
394  else
395  {
396  SetStatusString (L"Could not re-obtain volume " + DriveName + L" bitmap");
397  Error = true;
398  }
399  }
400 
401  Retry--;
402  }
403 
404  if (Error == true)
405  break;
406  }
407 
408 DoneDefrag:
409  wstring OldStatus;
410 
411  OldStatus = GetStatusString ();
412  StatusPercent = 99.999999f;
413  SetStatusString (L"Closing volume " + DriveName);
414  Volume.Close ();
415  StatusPercent = 100.0f;
416 
417  // If there was an error then the wstring has already been set
418  if (Error)
419  SetStatusString (OldStatus);
420  else
421  if (PleaseStop)
422  SetStatusString (L"Volume " + DriveName + L" defragmentation was stopped");
423  else
424  SetStatusString (L"Finished defragmenting " + DriveName);
425 
426  Done = true;
427 
428  return;
429 }
430 
431 
433 {
434  Lock ();
435  SetStatusString (L"Pausing ...");
436  PleasePause = true;
437  Unlock ();
438 
439  return;
440 }
441 
442 
443 void Defragment::Stop (void)
444 {
445  Lock ();
446  SetStatusString (L"Stopping ...");
447  PleaseStop = true;
448  Unlock ();
449 
450  return;
451 }
452 
453 
455 {
456  return (Error);
457 }
458 
unsigned long long uint64
Definition: platform.h:18
vector< uint32 > UnfraggedFiles
Definition: Defragment.h:36
bool MoveFileDumb(uint32 FileIndice, uint64 NewLCN)
uint64 FilesSizeClusters
Definition: Defragment.h:28
void PrintName(FILE *fileDest, EXPORT *pexp, PSTRING pstr, int fDeco)
Definition: spec2def.c:528
double PercentSlack
Definition: Defragment.h:33
#define max(a, b)
Definition: svc.c:63
vector< uint32 > UnmovableFiles
Definition: Defragment.h:37
void Close(void)
Definition: DriveVolume.cpp:21
VOID WINAPI DECLSPEC_HOTPATCH Sleep(IN DWORD dwMilliseconds)
Definition: synch.c:790
void Stop(void)
Definition: Defragment.cpp:443
uint64 DirsCount
Definition: Defragment.h:24
DWORD LastBMPUpdate
Definition: Defragment.h:74
bool GetBitmap(void)
bool IsDoneYet(void)
Definition: Defragment.cpp:151
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
DWORD WINAPI GetTickCount(VOID)
Definition: time.c:445
const char * filename
Definition: ioapi.h:135
FileInfo & GetDBFile(uint32 Indice)
double PercentFragged
Definition: Defragment.h:32
struct TraceInfo Info
void Start(void)
Definition: Defragment.cpp:157
#define signed
Definition: prototyp.h:114
VolumeInfo GetVolumeInfo(void)
Definition: DriveVolume.h:109
wstring GetRootPath(void)
Definition: DriveVolume.h:111
uint64 Clusters
Definition: DriveVolume.h:57
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
double GetStatusPercent(void)
Definition: Defragment.cpp:145
uint64 FilesSlackBytes
Definition: Defragment.h:29
struct NameRec_ * Name
Definition: cdprocs.h:464
static const char mbstate_t *static wchar_t const char mbstate_t *static const wchar_t int *static double
Definition: string.c:80
wstring RootPath
Definition: Defragment.h:22
uint64 FilesCount
Definition: Defragment.h:25
_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
IN PSCSI_REQUEST_BLOCK IN OUT NTSTATUS IN OUT BOOLEAN * Retry
Definition: class2.h:49
double AverageFragments
Definition: Defragment.h:31
double StatusPercent
Definition: Defragment.h:82
uint32 GetDBFileCount(void)
wstring StatusString
Definition: Defragment.h:80
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 GLint GLint j
Definition: glfuncs.h:250
GLfloat f
Definition: glext.h:7540
DefragType Method
Definition: Defragment.h:77
vector< uint32 > FraggedFiles
Definition: Defragment.h:35
DefragType DefragMethod
Definition: Defragment.h:88
bool PleasePause
Definition: Defragment.h:87
bool Open(wstring Name)
Definition: DriveVolume.cpp:42
#define swprintf(buf, format,...)
Definition: sprintf.c:56
void Lock(void)
Definition: Defragment.h:62
uint64 FilesSizeOnDisk
Definition: Defragment.h:27
Defragment(wstring Name, DefragType DefragMethod)
Definition: Defragment.cpp:81
bool FindFreeRange(uint64 StartLCN, uint64 ReqLength, uint64 &LCNResult)
wstring DriveName
Definition: Defragment.h:78
bool HasError(void)
Definition: Defragment.cpp:454
_CRTIMP wchar_t *__cdecl wcscpy(_Out_writes_z_(_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
static const WCHAR L[]
Definition: oid.c:1250
DefragReport Report
Definition: Defragment.h:75
uint64 TotalBytes
Definition: DriveVolume.h:74
uint32 GetDBDirCount(void)
uint64 DiskSizeBytes
Definition: Defragment.h:23
bool ObtainInfo(void)
DriveVolume Volume
Definition: Defragment.h:79
void SetStatusString(wstring NewStatus)
Definition: Defragment.cpp:123
Definition: services.c:325
_CRTIMP wchar_t *__cdecl wcscat(_Inout_updates_z_(_String_length_(_Dest)+_String_length_(_Source)+1) wchar_t *_Dest, _In_z_ const wchar_t *_Source)
uint32 ClusterSize
Definition: DriveVolume.h:73
bool DoLimitLength
Definition: Defragment.h:76
void Unlock(void)
Definition: Defragment.h:63
DefragType
Definition: Unfrag.h:66
bool BuildFileList(bool &QuitMonitor, double &Progress)
uint64 FilesSizeBytes
Definition: Defragment.h:26
uint32 FilesFragments
Definition: Defragment.h:30
bool Error
Definition: Defragment.h:84
wstring & GetDBDir(uint32 Indice)
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
wstring GetStatusString(void)
Definition: Defragment.cpp:133
void TogglePause(void)
Definition: Defragment.cpp:432
bool PleaseStop
Definition: Defragment.h:86
bool Done
Definition: Defragment.h:85