示例#1
0
// Main Initialization
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 -= 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);
}
示例#2
0
void Defragment::Start (void)
{
    uint32 i;
    uint64 FirstFreeLCN;
    uint64 TotalClusters;
    uint64 ClustersProgress;
    wchar_t PrintName[80];
    int Width = 70;

    if (Error)
        goto DoneDefrag;

    // First thing: build a file list.
    SetStatusString (L"Getting volume bitmap");
    if (!Volume.GetBitmap())
    {
        SetStatusString (L"Could not get volume " + DriveName + L" bitmap");
        Error = true;
        goto DoneDefrag;
    }

    LastBMPUpdate = GetTickCount ();

    if (PleaseStop)
        goto DoneDefrag;

    SetStatusString (L"Obtaining volume geometry");
    if (!Volume.ObtainInfo ())
    {
        SetStatusString (L"Could not obtain volume " + DriveName + L" geometry");
        Error = true;
        goto DoneDefrag;
    }

    if (PleaseStop)
        goto DoneDefrag;

    SetStatusString (L"Building file database for volume " + DriveName);
    if (!Volume.BuildFileList (PleaseStop, StatusPercent))
    {
        SetStatusString (L"Could not build file database for volume " + DriveName);
        Error = true;
        goto DoneDefrag;
    }

    if (PleaseStop)
        goto DoneDefrag;

    SetStatusString (L"Analyzing database for " + DriveName);
    TotalClusters = 0;
    for (i = 0; i < Volume.GetDBFileCount(); i++)
    {
        TotalClusters += Volume.GetDBFile(i).Clusters;
    }

    // Defragment!
    ClustersProgress = 0;

    // Find first free LCN for speedier searches ...
    Volume.FindFreeRange (0, 1, FirstFreeLCN);

    if (PleaseStop)
        goto DoneDefrag;

    // Analyze?
    if (Method == DefragAnalyze)
    {
        uint32 j;

        Report.RootPath = Volume.GetRootPath ();

        Report.FraggedFiles.clear ();
        Report.UnfraggedFiles.clear ();
        Report.UnmovableFiles.clear ();

        Report.FilesCount = Volume.GetDBFileCount () - Volume.GetDBDirCount ();
        Report.DirsCount = Volume.GetDBDirCount ();
        Report.DiskSizeBytes = Volume.GetVolumeInfo().TotalBytes;

        Report.FilesSizeClusters = 0;
        Report.FilesSlackBytes = 0;
        Report.FilesSizeBytes = 0;
        Report.FilesFragments = 0;

        for (j = 0; j < Volume.GetDBFileCount(); j++)
        {
            FileInfo Info;

            Info = Volume.GetDBFile (j);

            Report.FilesFragments += max ((size_t)1, Info.Fragments.size()); // add 1 fragment even for 0 bytes/0 cluster files

            if (Info.Attributes.Process == 0)
                continue;

            SetStatusString (Volume.GetDBDir (Info.DirIndice) + Info.Name);

            Report.FilesSizeClusters += Info.Clusters;
            Report.FilesSizeBytes += Info.Size;

            if (Info.Attributes.Unmovable == 1)
                Report.UnmovableFiles.push_back (j);

            if (Info.Fragments.size() > 1)
                Report.FraggedFiles.push_back (j);
            else
                Report.UnfraggedFiles.push_back (j);

            StatusPercent = ((double)j / (double)Report.FilesCount) * 100.0f;
        }

        Report.FilesSizeOnDisk = Report.FilesSizeClusters * (uint64)Volume.GetVolumeInfo().ClusterSize;
        Report.FilesSlackBytes = Report.FilesSizeOnDisk - Report.FilesSizeBytes;
        Report.AverageFragments = (double)Report.FilesFragments / (double)Report.FilesCount;
        Report.PercentFragged = 100.0f * ((double)(signed)Report.FraggedFiles.size() / (double)(signed)Report.FilesCount);

        uint64 Percent;
        Percent = (10000 * Report.FilesSlackBytes) / Report.FilesSizeOnDisk;
        Report.PercentSlack = (double)(signed)Percent / 100.0f;
    }
    else
        // Go through all the files and ... defragment them!
        for (i = 0; i < Volume.GetDBFileCount(); i++)
        {
            FileInfo Info;
            bool Result;
            uint64 TargetLCN;
            uint64 PreviousClusters;

            // What? They want us to pause? Oh ok.
            if (PleasePause)
            {
                SetStatusString (L"Paused");
                PleasePause = false;

                while (PleasePause == false)
                {
                    Sleep (50);
                }

                PleasePause = false;
            }

            if (PleaseStop)
            {
                SetStatusString (L"Stopping");
                break;
            }

            //
            Info = Volume.GetDBFile (i);

            PreviousClusters = ClustersProgress;
            ClustersProgress += Info.Clusters;

            if (Info.Attributes.Process == 0)
                continue;

            if (!DoLimitLength)
                SetStatusString (Volume.GetDBDir (Info.DirIndice) + Info.Name);
            else
            {
                FitName (PrintName, Volume.GetDBDir (Info.DirIndice).c_str(), Info.Name.c_str(), Width);
                SetStatusString (PrintName);
            }

            // Calculate percentage complete
            StatusPercent = 100.0f * double((double)PreviousClusters / (double)TotalClusters);

            // Can't defrag directories yet
            if (Info.Attributes.Directory == 1)
                continue;

            // Can't defrag 0 byte files :)
            if (Info.Fragments.empty())
                continue;

            // If doing fast defrag, skip non-fragmented files
            // Note: This assumes that the extents stored in Info.Fragments
            //       are consolidated. I.e. we assume it is NOT the case that
            //       two extents account for a sequential range of (non-
            //       fragmented) clusters.
            if (Info.Fragments.size() == 1  &&  Method == DefragFast)
                continue;

            // Otherwise, defrag0rize it!
            int Retry = 3;  // retry a few times
            while (Retry > 0)
            {
                // Find a place that can fit the file
                Result = Volume.FindFreeRange (FirstFreeLCN, Info.Clusters, TargetLCN);

                // If yes, try moving it
                if (Result)
                {
                    // 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 (Method == DefragExtensive  &&  Info.Fragments.size() == 1  &&
                            TargetLCN > Info.Fragments[0].StartLCN)
                    {
                        Retry = 1;
                    }
                    else
                    {
                        if (Volume.MoveFileDumb (i, TargetLCN))
                        {
                            Retry = 1; // yay, all done with this file.
                            Volume.FindFreeRange (0, 1, FirstFreeLCN);
                        }
                    }
                }

                // New: Only update bitmap if it's older than 15 seconds
                if ((GetTickCount() - LastBMPUpdate) < 15000)
                    Retry = 1;
                else if (!Result  ||  Retry != 1)
                {   // hmm. Wait for a moment, then update the drive bitmap
                    //SetStatusString (L"(Reobtaining volume " + DriveName + L" bitmap)");

                    if (!DoLimitLength)
                    {
                        SetStatusString (GetStatusString() + wstring (L" ."));
                    }

                    if (Volume.GetBitmap ())
                    {
                        LastBMPUpdate = GetTickCount ();

                        if (!DoLimitLength)
                            SetStatusString (Volume.GetDBDir (Info.DirIndice) + Info.Name);
                        else
                            SetStatusString (PrintName);

                        Volume.FindFreeRange (0, 1, FirstFreeLCN);
                    }
                    else
                    {
                        SetStatusString (L"Could not re-obtain volume " + DriveName + L" bitmap");
                        Error = true;
                    }
                }

                Retry--;
            }

            if (Error == true)
                break;
        }

DoneDefrag:
    wstring OldStatus;

    OldStatus = GetStatusString ();
    StatusPercent = 99.999999f;
    SetStatusString (L"Closing volume " + DriveName);
    Volume.Close ();
    StatusPercent = 100.0f;

    // If there was an error then the wstring has already been set
    if (Error)
        SetStatusString (OldStatus);
    else if (PleaseStop)
        SetStatusString (L"Volume " + DriveName + L" defragmentation was stopped");
    else
        SetStatusString (L"Finished defragmenting " + DriveName);

    Done = true;

    return;
}