public void Start() { string PrintName = string.Empty; int Width = 70; try { if (Error) { Close(); return; } // First thing: build a file list. StatusString = "Getting volume bitmap"; if (!Volume.GetBitmap()) { StatusString = "Could not get volume " + DriveName + " bitmap"; Error = true; Close(); return; } UpdateDrawing = true; _lastBMPUpdate = DateTime.Now; if (PleaseStop) { Close(); return; } StatusString = "Obtaining volume geometry"; if (!Volume.PartInfo.GetPartitionInfo()) { StatusString = "Could not obtain volume " + DriveName + " geometry"; Error = true; Close(); return; } if (PleaseStop) { Close(); return; } StatusString = "Obtaining partition information"; if (!Volume.PartInfo.GetPartitionDetails()) { StatusString = "Could not obtain partition " + DriveName + " information"; Error = true; Close(); return; } if (PleaseStop) { Close(); return; } StatusString = "Building file database for volume " + DriveName; if (!Volume.BuildFileList(this)) { StatusString = "Could not build file database for volume " + DriveName; Error = true; Close(); return; } if (PleaseStop) { Close(); return; } StatusString = "Analyzing database for " + DriveName; UInt64 TotalClusters = 0; uint i; for (i = 0; i < Volume.DBFileCount; i++) { TotalClusters += Volume.GetDBFile(i).Clusters; } // Defragment! UInt64 ClustersProgress = 0; // Find first free LCN for speedier searches ... UInt64 FirstFreeLCN; Volume.FindFreeRange(0, 1, out FirstFreeLCN); if (PleaseStop) { Close(); return; } // Analyze? if (DefragType == DefragMethod.ANALYZE) { uint j; Report.RootPath = Volume.RootPath; Report.Label = Volume.PartInfo.Name; Report.Serial = Volume.PartInfo.Serial; Report.FileSystem = Volume.PartInfo.FileSystem; Report.FreeBytes = Volume.PartInfo.FreeBytes; Report.ClusterCount = Volume.PartInfo.ClusterCount; Report.ClusterSize = Volume.PartInfo.ClusterSize; Report.FraggedFiles.Clear(); Report.UnfraggedFiles.Clear(); Report.UnmovableFiles.Clear(); Report.FilesCount = (ulong)Volume.DBFileCount - (ulong)Volume.DBDirCount; Report.DirsCount = (ulong)Volume.DBDirCount; Report.DiskSizeBytes = Volume.PartInfo.TotalBytes; Report.FilesSizeClusters = 0; Report.FilesSlackBytes = 0; Report.FilesSizeBytes = 0; Report.FilesFragments = 0; for (j = 0; j < Volume.DBFileCount; j++) { var Info = Volume.GetDBFile(j); Report.FilesFragments += (uint)Utils.Max(1UL, (ulong)Info.Fragments.Count); // add 1 fragment even for 0 bytes/0 cluster files if (!Info.Attributes.Process) { continue; } StatusString = Volume.GetDBDir(Info.DirIndice) + Info.Name; Report.FilesSizeClusters += Info.Clusters; Report.FilesSizeBytes += Info.Size; if (Info.Attributes.Unmovable) { Report.UnmovableFiles.Add(j); } if (Info.Fragments.Count > 1) { Report.FraggedFiles.Add(j); } else { Report.UnfraggedFiles.Add(j); } StatusPercent = (j / (double)Report.FilesCount) * 100.0f; } Report.FilesSizeOnDisk = Report.FilesSizeClusters * Volume.PartInfo.ClusterSize; Report.FilesSlackBytes = Report.FilesSizeOnDisk - Report.FilesSizeBytes; Report.PercentFragged = 100.0f * (Report.FraggedFiles.Count / (double)Report.FilesCount); var Percent = (10000 * Report.FilesSlackBytes) / Report.FilesSizeOnDisk; Report.PercentSlack = (double)Percent / 100.0f; } else { // Go through all the files and ... defragment them! for (i = 0; i < Volume.DBFileCount; i++) { // What? They want us to pause? Oh ok. if (PleasePause) { StatusString = "Paused"; PleasePause = false; while (PleasePause == false) { Thread.Sleep(50); } PleasePause = false; } if (PleaseStop) { StatusString = "Stopping"; break; } // var Info = Volume.GetDBFile(i); var PreviousClusters = ClustersProgress; ClustersProgress += Info.Clusters; if (!Info.Attributes.Process) { continue; } if (!DoLimitLength) { StatusString = Volume.GetDBDir(Info.DirIndice) + Info.Name; } else { PrintName = Utils.FitName(Volume.GetDBDir(Info.DirIndice), Info.Name, Width); StatusString = PrintName; } // Calculate percentage complete StatusPercent = 100.0f * (PreviousClusters / (double)TotalClusters); // Can't defrag directories yet if (Info.Attributes.Directory) { continue; } // Can't defrag 0 byte files :) if (Info.Fragments.Count == 0) { 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.Count == 1 && DefragType == DefragMethod.FASTDEFRAG) { continue; } // Otherwise, defrag0rize it! int Retry = 3; // retry a few times while (Retry > 0) { // Find a place that can fit the file UInt64 TargetLCN; var Result = Volume.FindFreeRange(FirstFreeLCN, Info.Clusters, out 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 (DefragType == DefragMethod.NORMDEFRAG && Info.Fragments.Count == 1 && TargetLCN > Info.Fragments[0].StartLCN) { Retry = 1; } else { if (Volume.MoveFileDumb((int)i, TargetLCN)) { Retry = 1; // yay, all done with this file. Volume.FindFreeRange(0, 1, out FirstFreeLCN); } } } // Only update bitmap if it's older than 15 seconds if (DateTime.Now.Subtract(_lastBMPUpdate).TotalSeconds < 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) { StatusString += " ."; } if (Volume.GetBitmap()) { _lastBMPUpdate = DateTime.Now; if (!DoLimitLength) { StatusString = Volume.GetDBDir(Info.DirIndice) + Info.Name; } else { StatusString = PrintName; } Volume.FindFreeRange(0, 1, out FirstFreeLCN); } else { StatusString = "Could not re-obtain volume " + DriveName + " bitmap"; Error = true; } } Retry--; } if (Error) { break; } } } } catch (ThreadAbortException) { } finally { Close(); } }