protected override bool ResolveParameter(string param) { int equalPos = param.IndexOf('='); if (IsParam(param, "method", "m")) { if (equalPos == -1) throw new ArgumentException("--method must be specified with an Erasure " + "method GUID."); List<KeyValuePair<string, string> > subParams = GetSubParameters(param.Substring(equalPos + 1)); ErasureMethod = new Guid(subParams[0].Key); } else if (IsParam(param, "schedule", "s")) { if (equalPos == -1) throw new ArgumentException("--schedule must be specified with a Schedule " + "type."); List<KeyValuePair<string, string> > subParams = GetSubParameters(param.Substring(equalPos + 1)); switch (subParams[0].Key) { case "now": Schedule = Schedule.RunNow; break; case "manually": Schedule = Schedule.RunManually; break; case "restart": Schedule = Schedule.RunOnRestart; break; default: throw new ArgumentException("Unknown schedule type: " + subParams[0].Key); } } else if (IsParam(param, "recycled", "r")) { Targets.Add(new RecycleBinTarget()); } else if (IsParam(param, "unused", "u")) { if (equalPos == -1) throw new ArgumentException("--unused must be specified with the Volume " + "to erase."); UnusedSpaceTarget target = new UnusedSpaceTarget(); target.EraseClusterTips = false; List<KeyValuePair<string, string> > subParams = GetSubParameters(param.Substring(equalPos + 1)); foreach (KeyValuePair<string, string> kvp in subParams) if (kvp.Value == null && target.Drive == null) target.Drive = Path.GetFullPath(kvp.Key); else if (kvp.Key == "clusterTips") target.EraseClusterTips = true; else throw new ArgumentException("Unknown subparameter: " + kvp.Key); Targets.Add(target); } else if (IsParam(param, "dir", "d") || IsParam(param, "directory", null)) { if (equalPos == -1) throw new ArgumentException("--directory must be specified with the " + "directory to erase."); FolderTarget target = new FolderTarget(); List<KeyValuePair<string, string> > subParams = GetSubParameters(param.Substring(equalPos + 1)); foreach (KeyValuePair<string, string> kvp in subParams) if (kvp.Value == null && target.Path == null) target.Path = Path.GetFullPath(kvp.Key); else if (kvp.Key == "excludeMask") { if (kvp.Value == null) throw new ArgumentException("The exclude mask must be specified " + "if the excludeMask subparameter is specified"); target.ExcludeMask = kvp.Value; } else if (kvp.Key == "includeMask") { if (kvp.Value == null) throw new ArgumentException("The include mask must be specified " + "if the includeMask subparameter is specified"); target.IncludeMask = kvp.Value; } else if (kvp.Key == "delete") target.DeleteIfEmpty = true; else throw new ArgumentException("Unknown subparameter: " + kvp.Key); Targets.Add(target); } else if (IsParam(param, "file", "f")) { if (equalPos == -1) throw new ArgumentException("--file must be specified with the " + "file to erase."); FileTarget target = new FileTarget(); List<KeyValuePair<string, string> > subParams = GetSubParameters(param.Substring(equalPos + 1)); foreach (KeyValuePair<string, string> kvp in subParams) if (kvp.Value == null && target.Path == null) target.Path = Path.GetFullPath(kvp.Key); else throw new ArgumentException("Unknown subparameter: " + kvp.Key); Targets.Add(target); } else return false; return true; }
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); } ); }
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 static void CommandAddTask(ConsoleArguments arg) { AddTaskArguments arguments = (AddTaskArguments)arg; Task task = new Task(); ErasureMethod method = arguments.ErasureMethod == Guid.Empty ? ErasureMethodManager.Default : ErasureMethodManager.GetInstance(arguments.ErasureMethod); switch (arguments.Schedule.ToUpperInvariant()) { case "NOW": task.Schedule = Schedule.RunNow; break; case "MANUALLY": task.Schedule = Schedule.RunManually; break; case "RESTART": task.Schedule = Schedule.RunOnRestart; break; default: throw new ArgumentException(string.Format(CultureInfo.CurrentCulture, "Unknown schedule type: {0}", arguments.Schedule), "--schedule"); } List<string> trueValues = new List<string>(new string[] { "yes", "true" }); string[] strings = new string[] { "(?<recycleBin>recyclebin)", "unused=(?<unusedVolume>.*)(?<unusedTips>,clusterTips(=(?<unusedTipsValue>true|false))?)?", "dir=(?<directoryName>.*)(?<directoryParams>(?<directoryExcludeMask>,-[^,]+)|(?<directoryIncludeMask>,\\+[^,]+)|(?<directoryDeleteIfEmpty>,deleteIfEmpty(=(?<directoryDeleteIfEmptyValue>true|false))?))*", "file=(?<fileName>.*)" }; Regex regex = new Regex(string.Join("|", strings), RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.RightToLeft); foreach (string argument in arguments.PositionalArguments) { Match match = regex.Match(argument); if (match.Captures.Count == 0) { Console.WriteLine("Unknown argument: {0}, skipped.", argument); continue; } ErasureTarget target = null; if (match.Groups["recycleBin"].Success) { target = new RecycleBinTarget(); } else if (match.Groups["unusedVolume"].Success) { UnusedSpaceTarget unusedSpaceTarget = new UnusedSpaceTarget(); target = unusedSpaceTarget; unusedSpaceTarget.Drive = match.Groups["unusedVolume"].Value; if (!match.Groups["unusedTips"].Success) unusedSpaceTarget.EraseClusterTips = false; else if (!match.Groups["unusedTipsValue"].Success) unusedSpaceTarget.EraseClusterTips = true; else unusedSpaceTarget.EraseClusterTips = trueValues.IndexOf(match.Groups["unusedTipsValue"].Value) != -1; } else if (match.Groups["directoryName"].Success) { FolderTarget folderTarget = new FolderTarget(); target = folderTarget; folderTarget.Path = match.Groups["directoryName"].Value; if (!match.Groups["directoryDeleteIfEmpty"].Success) folderTarget.DeleteIfEmpty = false; else if (!match.Groups["directoryDeleteIfEmptyValue"].Success) folderTarget.DeleteIfEmpty = true; else folderTarget.DeleteIfEmpty = trueValues.IndexOf(match.Groups["directoryDeleteIfEmptyValue"].Value) != -1; if (match.Groups["directoryExcludeMask"].Success) folderTarget.ExcludeMask += match.Groups["directoryExcludeMask"].Value.Remove(0, 2) + ' '; if (match.Groups["directoryIncludeMask"].Success) folderTarget.IncludeMask += match.Groups["directoryIncludeMask"].Value.Remove(0, 2) + ' '; } else if (match.Groups["fileName"].Success) { FileTarget fileTarget = new FileTarget(); target = fileTarget; fileTarget.Path = match.Groups["fileName"].Value; } if (target == null) continue; target.Method = method; task.Targets.Add(target); } if (task.Targets.Count == 0) throw new ArgumentException("Tasks must contain at least one erasure target."); try { using (RemoteExecutorClient client = new RemoteExecutorClient()) { client.Run(); if (!client.IsConnected) { Process eraserInstance = Process.Start( Assembly.GetExecutingAssembly().Location, "--quiet"); eraserInstance.WaitForInputIdle(); client.Run(); if (!client.IsConnected) throw new IOException("Eraser cannot connect to the running " + "instance for erasures."); } client.Tasks.Add(task); } } catch (UnauthorizedAccessException e) { throw new UnauthorizedAccessException("Another instance of Eraser " + "is already running but it is running with higher privileges than " + "this instance of Eraser. Tasks cannot be added in this manner.\n\n" + "Close the running instance of Eraser and start it again without " + "administrator privileges, or run the command again as an " + "administrator.", e); } }