Something went wrong. Try again.
Reactos
Something went wrong. Try again.
14 kB · 464 lines
C++
at master
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465/*****************************************************************************
Unfrag
*****************************************************************************/
#include "Unfrag.h"#include "DriveVolume.h"#include "Defragment.h"#include <process.h>
bool QuietMode = false;bool VerboseMode = false;
// Makes sure we're in Windows 2000bool CheckWinVer (void){ OSVERSIONINFO OSVersion;
ZeroMemory (&OSVersion, sizeof (OSVersion)); OSVersion.dwOSVersionInfoSize = sizeof (OSVersion); GetVersionEx (&OSVersion);
// Need Windows 2000!
// Check for NT first // Actually what we do is check that weLL're not on Win31+Win32s and that we're // not in Windows 9x. It's possible that there could be more Windows "platforms" // in the future and there's no sense in claiming incompatibility. if (OSVersion.dwPlatformId == VER_PLATFORM_WIN32s || OSVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) { return (false); }
// Ok weLL're in Windows NT, now make sure we're in 2000 if (OSVersion.dwMajorVersion < 5) return (false);
// Kew, we're in at least Windows 2000 ("NT 5.0") return (true);}
wchar_t *AddCommas (wchar_t *Result, uint64 Number){ wchar_t Temp[128]; int TempLen; //wchar_t *p = NULL; int AddCommas = 0; wchar_t *StrPosResult = NULL; wchar_t *StrPosOrig = NULL;
// we get the string form of the number, then we count down w/ AddCommas // while copying the string from Temp1 to Result. when AddCommas % 3 == 1, // slap in a commas as well, before the #. swprintf (Temp, L"%I64u", Number); AddCommas = TempLen = wcslen (Temp); StrPosOrig = Temp; StrPosResult = Result; while (AddCommas) { if ((AddCommas % 3) == 0 && AddCommas != TempLen) // avoid stuff like ",345" { *StrPosResult = L','; StrPosResult++; }
*StrPosResult = *StrPosOrig; StrPosResult++; StrPosOrig++;
*StrPosResult = 0;
AddCommas--; }
return (Result);}
void PrintBanner (void){ wprintf (L"%s v%s\n", APPNAME_CLI, APPVER_STR); wprintf (L"%s\n", APPCOPYRIGHT); wprintf (L"\n");
return;}
void FraggerHelp (void){ wprintf (L"Usage: unfrag drive: [...] <-f | -e>\n"); wprintf (L"\n"); wprintf (L"drive: : The drive to defrag. Should be two characters long, ie 'c:' or 'd:'.\n"); wprintf (L" Multiple drives may be given, and all will be simultaneously\n"); wprintf (L" defragmented using the same options.\n"); wprintf (L"-f : Do a fast defragmentation. Files that are not fragmented will not be\n"); wprintf (L" moved. Only one pass is made over the file list. Using this option\n"); wprintf (L" may result in not all files being defragmented, depending on\n"); wprintf (L" available disk space.\n"); wprintf (L"-e : Do an extensive defragmention. Files will be moved in an attempt to\n"); wprintf (L" defragment both files and free space.\n");
if (!CheckWinVer()) { wprintf (L"\n"); wprintf (L"NOTE: This program requires Windows 2000, which is not presently running on\n"); wprintf (L"this system.\n"); }
return;}
void __cdecl DefragThread (LPVOID parm){ Defragment *Defrag;
Defrag = (Defragment *) parm; Defrag->Start ();
_endthread (); return;}
Defragment *StartDefragThread (wstring Drive, DefragType Method, HANDLE &Handle){ Defragment *Defragger; unsigned long Thread;
Defragger = new Defragment (Drive, Method); //Thread = /*CreateThread*/ _beginthreadex (NULL, 0, DefragThread, Defragger, 0, &ThreadID); Thread = _beginthread (DefragThread, 0, Defragger); Handle = *((HANDLE *)&Thread); return (Defragger);}
#ifdef _CUI_// Main Initializationextern "C" int wmain (int argc, wchar_t **argv){ vector<wstring> Drives; vector<Defragment *> Defrags; DefragType DefragMode = DefragInvalid;
PrintBanner ();
// Parse command line arguments bool ValidCmdLine = false; for (int c = 0; c < argc; c++) { if (wcslen(argv[c]) == 2 && argv[c][1] == L':') { Drives.push_back (_wcsupr(argv[c])); } else if ((argv[c][0] == L'-' || argv[c][0] == L'/') && wcslen(argv[c]) == 2) { switch (tolower(argv[c][1])) { case L'?' : case L'h' : FraggerHelp (); return (0);
case L'f' : if (DefragMode != DefragInvalid) { ValidCmdLine = false; break; } DefragMode = DefragFast; ValidCmdLine = true; break;
case L'e' : if (DefragMode != DefragInvalid) { ValidCmdLine = false; break; } DefragMode = DefragExtensive; ValidCmdLine = true; break;
} } }
if (DefragMode == DefragInvalid) ValidCmdLine = false;
if (!ValidCmdLine) { wprintf (L"Invalid command-line options. Use '%s -?' for help.\n", argv[0]); return (0); }
// Check OS requirements if (!CheckWinVer()) { wprintf (L"Fatal Error: This program requires Windows 2000.\n"); return (0); }
for (size_t d = 0; d < Drives.size (); d++) { HANDLE TossMe; Defrags.push_back (StartDefragThread (Drives[d], DefragMode, TossMe)); }
for (size_t d = 0; d < Drives.size () - 1; d++) wprintf (L"\n ");
bool Continue = true; HANDLE Screen;
Screen = GetStdHandle (STD_OUTPUT_HANDLE); while (Continue) { Sleep (25);
// Get current screen coords CONSOLE_SCREEN_BUFFER_INFO ScreenInfo;
GetConsoleScreenBufferInfo (Screen, &ScreenInfo);
// Now set back to the beginning ScreenInfo.dwCursorPosition.X = 0; ScreenInfo.dwCursorPosition.Y -= (USHORT)Drives.size(); SetConsoleCursorPosition (Screen, ScreenInfo.dwCursorPosition);
for (size_t d = 0; d < Drives.size (); d++) { wprintf (L"\n%6.2f%% %-70s", Defrags[d]->GetStatusPercent(), Defrags[d]->GetStatusString().c_str()); }
// Determine if we should keep going Continue = false; for (size_t d = 0; d < Drives.size (); d++) { if (!Defrags[d]->IsDoneYet() && !Defrags[d]->HasError()) Continue = true; } }
#if 0 // Loop through the drives list for (int d = 0; d < Drives.size(); d++) { DriveVolume *Drive;
Drive = new DriveVolume;
// First thing: build a file list. wprintf (L"Opening volume %s ...", Drives[d].c_str()); if (!Drive->Open (Drives[d])) { wprintf (L"FAILED\n\n"); delete Drive; continue; } wprintf (L"\n");
wprintf (L" Getting drive bitmap ..."); if (!Drive->GetBitmap ()) { wprintf (L"FAILED\n\n"); delete Drive; continue; } wprintf (L"\n");
wprintf (L" Obtaining drive geometry ..."); if (!Drive->ObtainInfo ()) { wprintf (L"FAILED\n\n"); delete Drive; continue; } wprintf (L"\n");
wprintf (L" Building file database for drive %s ...", Drives[d].c_str()); if (!Drive->BuildFileList ()) { wprintf (L"FAILED\n\n"); delete Drive; continue; } wprintf (L"\n");
wprintf (L" %u files\n", Drive->GetDBFileCount ());
// Analyze only? if (DefragMode == DefragAnalyze) { uint64 UsedBytes = 0; // total bytes used, with cluster size considerations uint64 TotalBytes = 0; // total bytes used uint64 SlackBytes = 0; // wasted space due to slack uint32 Fragged = 0; // fragmented files
wprintf (L" Analyzing ..."); if (VerboseMode) wprintf (L"\n");
for (int i = 0; i < Drive->GetDBFileCount(); i++) { uint64 Used; uint64 Slack; FileInfo Info;
Info = Drive->GetDBFile (i);
// Compute total used disk space Used = ((Info.Size + Drive->GetClusterSize() - 1) / Drive->GetClusterSize()) * Drive->GetClusterSize(); Slack = Used - Info.Size;
UsedBytes += Used; SlackBytes += Slack; TotalBytes += Info.Size;
if (VerboseMode) { wprintf (L" %s%s, ", Drive->GetDBDir (Info.DirIndice).c_str(), Info.Name.c_str());
if (Info.Attributes.AccessDenied) wprintf (L"access was denied\n"); else { if (Info.Attributes.Unmovable == 1) wprintf (L"unmovable, ");
wprintf (L"%I64u bytes, %I64u bytes on disk, %I64u bytes slack, %u fragments\n", Info.Size, Used, Slack, Info.Fragments.size()); } }
if (Info.Fragments.size() > 1) Fragged++; }
if (!VerboseMode) wprintf (L"\n");
// TODO: Make it not look like ass wprintf (L"\n"); wprintf (L" Overall Analysis\n"); wprintf (L" ----------------\n"); wprintf (L" %u clusters\n", Drive->GetClusterCount ()); wprintf (L" %u bytes per cluster\n", Drive->GetClusterSize()); wprintf (L" %I64u total bytes on drive\n", (uint64)Drive->GetClusterCount() * (uint64)Drive->GetClusterSize()); wprintf (L"\n"); wprintf (L" %u files\n", Drive->GetDBFileCount ()); wprintf (L" %u contiguous files\n", Drive->GetDBFileCount () - Fragged); wprintf (L" %u fragmented files\n", Fragged); wprintf (L"\n"); wprintf (L" %I64u bytes\n", TotalBytes); wprintf (L" %I64u bytes on disk\n", UsedBytes); wprintf (L" %I64u bytes slack\n", SlackBytes); }
// Fast defragment! if (DefragMode == DefragFast || DefragMode == DefragExtensive) { uint32 i; uint64 FirstFreeLCN; wchar_t PrintName[80]; int Width = 66;
if (DefragMode == DefragFast) wprintf (L" Performing fast file defragmentation ...\n"); else if (DefragMode == DefragExtensive) wprintf (L" Performing extensive file defragmentation\n");
// Find first free LCN for speedier searches ... Drive->FindFreeRange (0, 1, FirstFreeLCN);
for (i = 0; i < Drive->GetDBFileCount(); i++) { FileInfo Info; bool Result; uint64 TargetLCN;
wprintf (L"\r");
Info = Drive->GetDBFile (i);
FitName (PrintName, Drive->GetDBDir (Info.DirIndice).c_str(), Info.Name.c_str(), Width); wprintf (L" %6.2f%% %-66s", (float)i / (float)Drive->GetDBFileCount() * 100.0f, PrintName);
// Can't defrag 0 byte files :) if (Info.Fragments.size() == 0) continue;
// If doing fast defrag, skip non-fragmented files if (Info.Fragments.size() == 1 && DefragMode == DefragFast) continue;
// Find a place that can fit the file Result = Drive->FindFreeRange (FirstFreeLCN, Info.Clusters, TargetLCN);
// If we're doing an extensive defrag and the file is already defragmented // and if its new location would be after its current location, don't // move it. if (DefragMode == DefragExtensive && Info.Fragments.size() == 1) { if (TargetLCN > Info.Fragments[0].StartLCN) continue; }
// Otherwise, defrag0rize it! if (Result) { bool Success = false;
if (Drive->MoveFileDumb (i, TargetLCN)) Success = true; else { // hmm, look for another area to move it to Result = Drive->FindFreeRange (TargetLCN + 1, Info.Clusters, TargetLCN); if (Result) { if (Drive->MoveFileDumb (i, TargetLCN)) Success = true; else { // Try updating the drive bitmap if (Drive->GetBitmap ()) { Result = Drive->FindFreeRange (0, Info.Clusters, TargetLCN); if (Result) { if (Drive->MoveFileDumb (i, TargetLCN)) Success = true; } } } } }
if (!Success) wprintf (L"\n -> failed\n");
Drive->FindFreeRange (0, 1, FirstFreeLCN); } }
wprintf (L"\n"); } wprintf (L"Closing volume %s ...", Drives[d].c_str()); delete Drive; wprintf (L"\n"); }#endif
return (0);}#endif