private void EraseFilesystemObject(Task task, FileSystemObjectTarget target) { long dataTotal = 0; List<string> paths = target.GetPaths(out dataTotal); ErasureMethod method = target.Method; TaskEventArgs eventArgs = new TaskEventArgs(task); SteppedProgressManager progress = new SteppedProgressManager(); target.Progress = progress; task.Progress.Steps.Add(new SteppedProgressManager.Step(progress, 1.0f / task.Targets.Count)); for (int i = 0; i < paths.Count; ++i) { ProgressManager step = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(step, 1.0f / paths.Count, S._("Erasing files..."))); task.OnProgressChanged(target, new ProgressChangedEventArgs(step, new TaskProgressChangedEventArgs(paths[i], 0, method.Passes))); StreamInfo info = new StreamInfo(paths[i]); FileSystem fsManager = FileSystemManager.Get( VolumeInfo.FromMountpoint(info.DirectoryName)); if (!info.Exists) { task.Log.LastSessionEntries.Add(new LogEntry(S._("The file {0} was not erased " + "as the file does not exist.", paths[i]), LogLevel.Notice)); continue; } bool isReadOnly = false; try { if (isReadOnly = info.IsReadOnly) info.IsReadOnly = false; if ((info.Attributes & FileAttributes.Compressed) != 0 || (info.Attributes & FileAttributes.Encrypted) != 0 || (info.Attributes & FileAttributes.SparseFile) != 0) { task.Log.LastSessionEntries.Add(new LogEntry(S._("The file {0} could " + "not be erased because the file was either compressed, encrypted or " + "a sparse file.", info.FullName), LogLevel.Error)); } fsManager.EraseFileSystemObject(info, method, delegate(long lastWritten, long totalData, int currentPass) { if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); step.Completed += lastWritten; step.Total = totalData; task.OnProgressChanged(target, new ProgressChangedEventArgs(step, new TaskProgressChangedEventArgs(info.FullName, currentPass, method.Passes))); }); FileInfo fileInfo = info.File; if (fileInfo != null) fsManager.DeleteFile(fileInfo); step.Completed = step.Total = 1; } catch (UnauthorizedAccessException) { task.Log.LastSessionEntries.Add(new LogEntry(S._("The file {0} could not " + "be erased because the file's permissions prevent access to the file.", info.FullName), LogLevel.Error)); } catch (FileLoadException) { if (!ManagerLibrary.Settings.ForceUnlockLockedFiles) throw; List<System.Diagnostics.Process> processes = new List<System.Diagnostics.Process>(); foreach (OpenHandle handle in OpenHandle.Items) if (handle.Path == paths[i]) processes.Add(System.Diagnostics.Process.GetProcessById(handle.ProcessId)); StringBuilder processStr = new StringBuilder(); foreach (System.Diagnostics.Process process in processes) processStr.AppendFormat(System.Globalization.CultureInfo.InvariantCulture, "{0}, ", process.MainModule.FileName); task.Log.LastSessionEntries.Add(new LogEntry(S._( "Could not force closure of file \"{0}\" (locked by {1})", paths[i], processStr.ToString().Remove(processStr.Length - 2)), LogLevel.Error)); } finally { if (isReadOnly && info.Exists && !info.IsReadOnly) info.IsReadOnly = isReadOnly; } } if (target is FolderTarget) { ProgressManager step = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(step, 0.0f, S._("Removing folders..."))); FolderTarget fldr = (FolderTarget)target; FileSystem fsManager = FileSystemManager.Get(VolumeInfo.FromMountpoint(fldr.Path)); Action<DirectoryInfo> eraseEmptySubFolders = null; eraseEmptySubFolders = delegate(DirectoryInfo info) { foreach (DirectoryInfo subDir in info.GetDirectories()) eraseEmptySubFolders(subDir); task.OnProgressChanged(target, new ProgressChangedEventArgs(step, new TaskProgressChangedEventArgs(info.FullName, 0, 0))); FileSystemInfo[] files = info.GetFileSystemInfos(); if (files.Length == 0) fsManager.DeleteFolder(info); }; eraseEmptySubFolders(new DirectoryInfo(fldr.Path)); if (fldr.DeleteIfEmpty) { DirectoryInfo info = new DirectoryInfo(fldr.Path); task.OnProgressChanged(target, new ProgressChangedEventArgs(step, new TaskProgressChangedEventArgs(info.FullName, 0, 0))); bool isVolumeRoot = info.Parent == null; foreach (VolumeInfo volume in VolumeInfo.Volumes) foreach (string mountPoint in volume.MountPoints) if (info.FullName == mountPoint) isVolumeRoot = true; if (!isVolumeRoot && info.Exists && info.GetFiles("*", SearchOption.AllDirectories).Length == 0) fsManager.DeleteFolder(info); } } if (target is RecycleBinTarget) { ProgressManager step = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(step, 0.0f, S._("Emptying recycle bin..."))); task.OnProgressChanged(target, new ProgressChangedEventArgs(step, new TaskProgressChangedEventArgs(string.Empty, 0, 0))); ShellApi.EmptyRecycleBin(EmptyRecycleBinOptions.NoConfirmation | EmptyRecycleBinOptions.NoProgressUI | EmptyRecycleBinOptions.NoSound); } target.Progress = null; }
private void EraseUnusedSpace(Task task, UnusedSpaceTarget target) { if (!AdvApi.IsAdministrator()) { if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version >= new Version(6, 0)) { throw new UnauthorizedAccessException(S._("The program does not have the " + "required permissions to erase the unused space on disk. Run the program " + "as an administrator and retry the operation.")); } else throw new UnauthorizedAccessException(S._("The program does not have the " + "required permissions to erase the unused space on disk.")); } if (SystemRestore.GetInstances().Count != 0) { task.Log.LastSessionEntries.Add(new LogEntry(S._("The drive {0} has System " + "Restore or Volume Shadow Copies enabled. This may allow copies of files " + "stored on the disk to be recovered and pose a security concern.", target.Drive), LogLevel.Warning)); } if (VolumeInfo.FromMountpoint(target.Drive).HasQuota) task.Log.LastSessionEntries.Add(new LogEntry(S._("The drive {0} has disk quotas " + "active. This will prevent the complete erasure of unused space and may pose " + "a security concern.", target.Drive), LogLevel.Warning)); ErasureMethod method = target.Method; DirectoryInfo info = new DirectoryInfo(target.Drive); VolumeInfo volInfo = VolumeInfo.FromMountpoint(target.Drive); FileSystem fsManager = FileSystemManager.Get(volInfo); SteppedProgressManager progress = new SteppedProgressManager(); target.Progress = progress; task.Progress.Steps.Add(new SteppedProgressManager.Step( progress, 1.0f / task.Targets.Count)); if (target.EraseClusterTips) { ProgressManager tipSearch = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(tipSearch, 0.0f, S._("Searching for files' cluster tips..."))); tipSearch.Total = 1; ClusterTipsSearchProgress searchProgress = delegate(string path) { if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); task.OnProgressChanged(target, new ProgressChangedEventArgs(tipSearch, new TaskProgressChangedEventArgs(path, 0, 0))); }; ProgressManager tipProgress = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(tipProgress, 0.1f, S._("Erasing cluster tips..."))); ClusterTipsEraseProgress eraseProgress = delegate(int currentFile, int totalFiles, string currentFilePath) { tipSearch.Completed = tipSearch.Total; tipProgress.Total = totalFiles; tipProgress.Completed = currentFile; task.OnProgressChanged(target, new ProgressChangedEventArgs(tipProgress, new TaskProgressChangedEventArgs(currentFilePath, 0, 0))); if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); }; fsManager.EraseClusterTips(VolumeInfo.FromMountpoint(target.Drive), method, task.Log, searchProgress, eraseProgress); } info = info.CreateSubdirectory(Path.GetFileName( FileSystem.GenerateRandomFileName(info, 18))); try { if (Eraser.Util.File.IsCompressed(info.FullName)) Eraser.Util.File.SetCompression(info.FullName, false); ProgressManager mainProgress = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(mainProgress, target.EraseClusterTips ? 0.8f : 0.9f, S._("Erasing unused space..."))); while (volInfo.AvailableFreeSpace > 0) { string currFile = FileSystem.GenerateRandomFileName(info, 18); using (FileStream stream = new FileStream(currFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, 8, FileOptions.WriteThrough)) { mainProgress.Total = mainProgress.Completed + volInfo.AvailableFreeSpace; long streamLength = Math.Min(ErasureMethod.FreeSpaceFileUnit, mainProgress.Total); while (true) try { stream.SetLength(streamLength); break; } catch (IOException) { if (streamLength > volInfo.ClusterSize) streamLength -= volInfo.ClusterSize; else throw; } method.Erase(stream, long.MaxValue, PrngManager.GetInstance(ManagerLibrary.Settings.ActivePrng), delegate(long lastWritten, long totalData, int currentPass) { mainProgress.Completed += lastWritten; task.OnProgressChanged(target, new ProgressChangedEventArgs(mainProgress, new TaskProgressChangedEventArgs(target.Drive, currentPass, method.Passes))); if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); } ); } } mainProgress.Completed = mainProgress.Total; ProgressManager residentProgress = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(residentProgress, 0.05f, S._("Old resident file system table files"))); fsManager.EraseOldFileSystemResidentFiles(volInfo, info, method, delegate(int currentFile, int totalFiles) { residentProgress.Completed = currentFile; residentProgress.Total = totalFiles; task.OnProgressChanged(target, new ProgressChangedEventArgs(residentProgress, new TaskProgressChangedEventArgs(string.Empty, 0, 0))); if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); } ); residentProgress.Completed = residentProgress.Total = 1; } finally { ProgressManager tempFiles = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(tempFiles, 0.0f, S._("Removing temporary files..."))); task.OnProgressChanged(target, new ProgressChangedEventArgs(tempFiles, new TaskProgressChangedEventArgs(string.Empty, 0, 0))); fsManager.DeleteFolder(info); tempFiles.Completed = tempFiles.Total = 1; } ProgressManager structureProgress = new ProgressManager(); progress.Steps.Add(new SteppedProgressManager.Step(structureProgress, 0.05f, S._("Erasing unused directory structures..."))); fsManager.EraseDirectoryStructures(volInfo, delegate(int currentFile, int totalFiles) { if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); structureProgress.Total = totalFiles; structureProgress.Completed = currentFile; task.OnProgressChanged(target, new ProgressChangedEventArgs(structureProgress, new TaskProgressChangedEventArgs(string.Empty, 0, 0))); } ); structureProgress.Completed = structureProgress.Total; target.Progress = null; }
private void EraseUnusedSpace(Task task, UnusedSpaceTarget target, TaskProgressManager progress) { if (!AdvApi.IsAdministrator()) { if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version >= new Version(6, 0)) { throw new UnauthorizedAccessException(S._("The program does not have the " + "required permissions to erase the unused space on disk. Run the program " + "as an administrator and retry the operation.")); } else throw new UnauthorizedAccessException(S._("The program does not have the " + "required permissions to erase the unused space on disk")); } if (VolumeInfo.FromMountpoint(target.Drive).HasQuota) task.Log.LastSessionEntries.Add(new LogEntry(S._("The drive which is having its " + "unused space erased has disk quotas active. This will prevent the complete " + "erasure of unused space and will pose a security concern"), LogLevel.Warning)); ErasureMethod method = target.Method; DirectoryInfo info = new DirectoryInfo(target.Drive); VolumeInfo volInfo = VolumeInfo.FromMountpoint(target.Drive); FileSystem fsManager = FileSystemManager.Get(volInfo); if (target.EraseClusterTips) { progress.Event.CurrentTargetStatus = S._("Searching for files' cluster tips..."); progress.Event.CurrentTargetTotalPasses = method.Passes; progress.Event.CurrentItemProgress = -1.0f; progress.Event.TimeLeft = new TimeSpan(0, 0, -1); ProgressManager tipProgress = new ProgressManager(); tipProgress.Start(); ClusterTipsSearchProgress searchProgress = delegate(string path) { progress.Event.CurrentItemName = path; task.OnProgressChanged(progress.Event); if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); }; ClusterTipsEraseProgress eraseProgress = delegate(int currentFile, int totalFiles, string currentFilePath) { tipProgress.Total = totalFiles; tipProgress.Completed = currentFile; progress.Event.CurrentTargetStatus = S._("Erasing cluster tips..."); progress.Event.CurrentItemName = currentFilePath; progress.Event.CurrentItemProgress = tipProgress.Progress; progress.Event.CurrentTargetProgress = progress.Event.CurrentItemProgress / 10; progress.Event.TimeLeft = tipProgress.TimeLeft; task.OnProgressChanged(progress.Event); if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); }; fsManager.EraseClusterTips(VolumeInfo.FromMountpoint(target.Drive), method, task.Log, searchProgress, eraseProgress); } info = info.CreateSubdirectory(Path.GetFileName( FileSystem.GenerateRandomFileName(info, 18))); try { if (Eraser.Util.File.IsCompressed(info.FullName)) Eraser.Util.File.SetCompression(info.FullName, false); progress.Event.CurrentTargetStatus = S._("Erasing unused space..."); progress.Event.CurrentItemName = target.Drive; task.OnProgressChanged(progress.Event); while (volInfo.AvailableFreeSpace > 0) { string currFile = FileSystem.GenerateRandomFileName(info, 18); using (FileStream stream = new FileStream(currFile, FileMode.CreateNew, FileAccess.Write, FileShare.None, 8, FileOptions.WriteThrough)) { long streamLength = Math.Min(ErasureMethod.FreeSpaceFileUnit, volInfo.AvailableFreeSpace); while (true) try { stream.SetLength(streamLength); break; } catch (IOException) { if (streamLength > volInfo.ClusterSize) streamLength -= volInfo.ClusterSize; else throw; } method.Erase(stream, long.MaxValue, PrngManager.GetInstance(ManagerLibrary.Settings.ActivePrng), delegate(long lastWritten, long totalData, int currentPass) { progress.Completed = Math.Min(progress.Total, progress.Completed + lastWritten); progress.Event.CurrentItemPass = currentPass; progress.Event.CurrentItemProgress = progress.Progress; if (target.EraseClusterTips) progress.Event.CurrentTargetProgress = (float) (0.1f + progress.Event.CurrentItemProgress * 0.8f); else progress.Event.CurrentTargetProgress = (float) (progress.Event.CurrentItemProgress * 0.9f); progress.Event.TimeLeft = progress.TimeLeft; task.OnProgressChanged(progress.Event); if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); } ); } } progress.Event.CurrentItemName = S._("Old resident file system table files"); task.OnProgressChanged(progress.Event); fsManager.EraseOldFileSystemResidentFiles(volInfo, info, method, null); } finally { progress.Event.CurrentTargetStatus = S._("Removing temporary files..."); task.OnProgressChanged(progress.Event); fsManager.DeleteFolder(info); } progress.Event.CurrentTargetStatus = S._("Erasing unused directory structures..."); ProgressManager fsEntriesProgress = new ProgressManager(); fsEntriesProgress.Start(); fsManager.EraseDirectoryStructures(volInfo, delegate(int currentFile, int totalFiles) { if (currentTask.Canceled) throw new OperationCanceledException(S._("The task was cancelled.")); fsEntriesProgress.Total = totalFiles; fsEntriesProgress.Completed = currentFile; progress.Event.TimeLeft = fsEntriesProgress.TimeLeft; progress.Event.CurrentItemProgress = fsEntriesProgress.Progress; progress.Event.CurrentTargetProgress = (float)( 0.9 + progress.Event.CurrentItemProgress / 10); task.OnProgressChanged(progress.Event); } ); }