public override long GetFileArea(StreamInfo info) { VolumeInfo volume = VolumeInfo.FromMountPoint(info.Directory.FullName); long clusterSize = volume.ClusterSize; return((info.Length + (clusterSize - 1)) & ~(clusterSize - 1)); }
/// <summary> /// Erases the folder after all files have been deleted. This folder does not /// delete folders which have files within it. /// </summary> private void EraseFolder() { //Update the progress to show that folders are being removed. ProgressManager step = new ProgressManager(); Progress.Steps.Add(new SteppedProgressManagerStep(step, 0.0f, S._("Removing folders..."))); //Erase all subdirectories which are not reparse points. DirectoryInfo directory = new DirectoryInfo(Path); if ((directory.Attributes & FileAttributes.ReparsePoint) == 0) { foreach (DirectoryInfo subDir in directory.GetDirectories()) { EraseFolder(subDir, step); } } //Does the user want this directory to be erased if there are no more //entries within it? if (DeleteIfEmpty) { //See if this is the root of a volume. bool isVolumeRoot = directory.Parent == null; foreach (VolumeInfo volume in VolumeInfo.Volumes) { if (volume.IsReady) { foreach (DirectoryInfo mountPoint in volume.MountPoints) { if (directory.FullName == mountPoint.FullName) { isVolumeRoot = true; } } } } //If the folder is a mount point, then don't delete it. If it isn't, //search for files under the folder to see if it is empty. if (!isVolumeRoot && directory.Exists) { IFileSystem fsManager = Host.Instance.FileSystems[ VolumeInfo.FromMountPoint(Path)]; if ((directory.Attributes & FileAttributes.ReparsePoint) == 0) { if (directory.GetFiles("*", SearchOption.AllDirectories).Length == 0) { fsManager.DeleteFolder(directory, true); } } else { fsManager.DeleteFolder(directory, false); } } } }
public override void EraseFileSystemObject(StreamInfo info, IErasureMethod method, ErasureMethodProgressFunction callback) { //Check if the file fits in one cluster - if it does it may be MFT resident //TODO: any more deterministic way of finding out? VolumeInfo volume = VolumeInfo.FromMountPoint(info.DirectoryName); if (info.Length < NtfsApi.GetMftRecordSegmentSize(volume)) { //Yes it does, erase exactly to the file length using (FileStream strm = info.Open(FileMode.Open, FileAccess.Write, FileShare.None)) { method.Erase(strm, long.MaxValue, Host.Instance.Prngs.ActivePrng, null); } } //Create the file stream, and call the erasure method to write to //the stream. long fileArea = GetFileArea(info); //If the stream is empty, there's nothing to overwrite. Continue //to the next entry if (fileArea == 0) { return; } using (FileStream strm = info.Open(FileMode.Open, FileAccess.Write, FileShare.None, FileOptions.WriteThrough)) { //Set the end of the stream after the wrap-round the cluster size strm.SetLength(fileArea); //Then erase the file. method.Erase(strm, long.MaxValue, Host.Instance.Prngs.ActivePrng, callback); //Set the length of the file to 0. strm.Seek(0, SeekOrigin.Begin); strm.SetLength(0); } }
private void EraseFolder(DirectoryInfo info, ProgressManager progress) { //Skip all symbolic links and junctions as we want to retain the //contents of those directories. if ((info.Attributes & FileAttributes.ReparsePoint) != 0) { return; } //Iterate over each directory and erase the subdirectories. foreach (DirectoryInfo subDir in info.GetDirectories()) { EraseFolder(subDir, progress); } //Public progress updates. progress.Tag = info.FullName; //Ensure that the current directory is empty before deleting. FileSystemInfo[] files = info.GetFileSystemInfos(); if (files.Length == 0) { try { Host.Instance.FileSystems[VolumeInfo.FromMountPoint(Path)]. DeleteFolder(info, true); } catch (DirectoryNotFoundException) { Logger.Log(new LogEntry(S._("The folder {0} was not erased because " + "the containing directory was deleted before it could be erased.", info.FullName), LogLevel.Information)); } catch (UnauthorizedAccessException) { Logger.Log(new LogEntry(S._("The folder {0} could not be deleted because " + "the folder's permissions prevents the deletion of the folder.", info.FullName), LogLevel.Error)); } } }
public override void Execute() { //Check for sufficient privileges to run the unused space erasure. if (!Security.IsAdministrator()) { if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version >= new Version(6, 0)) { Logger.Log(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."), LogLevel.Error); } else { Logger.Log(S._("The program does not have the required permissions to erase " + "the unused space on disk."), LogLevel.Error); } return; } //Check whether System Restore has any available checkpoints. if (SystemRestore.GetInstances().Count != 0) { Logger.Log(S._("This computer has had 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.", Drive), LogLevel.Warning); } //If the user is under disk quotas, log a warning message if (VolumeInfo.FromMountPoint(Drive).HasQuota) { Logger.Log(S._("The drive {0} has disk quotas active. This will prevent the " + "complete erasure of unused space and may pose a security concern.", Drive), LogLevel.Warning); } //Get the erasure method if the user specified he wants the default. IErasureMethod method = EffectiveMethod; //Make a folder to dump our temporary files in DirectoryInfo info = new DirectoryInfo(Drive); VolumeInfo volInfo = VolumeInfo.FromMountPoint(Drive); IFileSystem fsManager = Host.Instance.FileSystems[volInfo]; //Start sampling the speed of the task. Progress = new SteppedProgressManager(); //Erase the cluster tips of every file on the drive. if (EraseClusterTips) { //Define the callback handlers ProgressManager tipSearch = new ProgressManager(); tipSearch.MarkIndeterminate(); Progress.Steps.Add(new SteppedProgressManagerStep(tipSearch, 0.0f, S._("Searching for files' cluster tips..."))); ClusterTipsSearchProgress searchProgress = delegate(string path) { if (Task.Canceled) { throw new OperationCanceledException(S._("The task was cancelled.")); } tipSearch.Tag = path; }; ProgressManager tipProgress = new ProgressManager(); Progress.Steps.Add(new SteppedProgressManagerStep(tipProgress, 0.1f, S._("Erasing cluster tips..."))); ClusterTipsEraseProgress eraseProgress = delegate(int currentFile, int totalFiles, string currentFilePath) { tipSearch.MarkComplete(); tipProgress.Total = totalFiles; tipProgress.Completed = currentFile; tipProgress.Tag = currentFilePath; if (Task.Canceled) { throw new OperationCanceledException(S._("The task was cancelled.")); } }; //Start counting statistics fsManager.EraseClusterTips(VolumeInfo.FromMountPoint(Drive), method, searchProgress, eraseProgress); tipProgress.MarkComplete(); } bool lowDiskSpaceNotifications = Shell.LowDiskSpaceNotificationsEnabled; info = info.CreateSubdirectory(Path.GetFileName( FileSystemBase.GenerateRandomFileName(info, 18))); try { //Set the folder's compression flag off since we want to use as much //space as possible if (info.IsCompressed()) { info.Uncompress(); } //Disable the low disk space notifications Shell.LowDiskSpaceNotificationsEnabled = false; //Fill the disk EraseUnusedSpace(volInfo, info, fsManager, method); //Erase old resident file system table files ProgressManager residentProgress = new ProgressManager(); Progress.Steps.Add(new SteppedProgressManagerStep(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; if (Task.Canceled) { throw new OperationCanceledException(S._("The task was cancelled.")); } } ); residentProgress.MarkComplete(); } finally { //Remove the folder holding all our temporary files. ProgressManager tempFiles = new ProgressManager(); Progress.Steps.Add(new SteppedProgressManagerStep(tempFiles, 0.0f, S._("Removing temporary files..."))); fsManager.DeleteFolder(info, true); tempFiles.MarkComplete(); //Reset the low disk space notifications Shell.LowDiskSpaceNotificationsEnabled = lowDiskSpaceNotifications; } //Then clean the old file system entries ProgressManager structureProgress = new ProgressManager(); Progress.Steps.Add(new SteppedProgressManagerStep(structureProgress, 0.05f, S._("Erasing unused directory structures..."))); fsManager.EraseDirectoryStructures(volInfo, delegate(int currentFile, int totalFiles) { if (Task.Canceled) { throw new OperationCanceledException(S._("The task was cancelled.")); } //Compute the progress structureProgress.Total = totalFiles; structureProgress.Completed = currentFile; } ); structureProgress.MarkComplete(); Progress = null; }
/// <summary> /// Erases the provided stream, and updates progress using the provided /// progress manager. /// </summary> /// <param name="info">The information regarding the stream that needs erasure.</param> /// <param name="progress">The progress manager for the erasure of the current /// stream.</param> protected void EraseStream(StreamInfo info, ProgressManager progress) { //Check that the file exists - we do not want to bother erasing nonexistant files if (!info.Exists) { Logger.Log(S._("The file {0} was not erased as the file does not exist.", info.FileName), LogLevel.Notice); return; } //Get the filesystem provider to handle the secure file erasures IFileSystem fsManager = Host.Instance.FileSystems[ VolumeInfo.FromMountPoint(info.DirectoryName)]; bool isReadOnly = false; try { //Update the task progress IErasureMethod method = EffectiveMethod; //Remove the read-only flag, if it is set. if (isReadOnly = info.IsReadOnly) { info.IsReadOnly = false; } //Define the callback function for progress reporting. ErasureMethodProgressFunction callback = delegate(long lastWritten, long totalData, int currentPass) { if (Task.Canceled) { throw new OperationCanceledException(S._("The task was cancelled.")); } progress.Tag = new int[] { currentPass, method.Passes }; progress.Total = totalData; progress.Completed += lastWritten; }; TryEraseStream(fsManager, method, info, callback); //Remove the file. FileInfo fileInfo = info.File; if (fileInfo != null) { fsManager.DeleteFile(fileInfo); } progress.MarkComplete(); } catch (UnauthorizedAccessException) { Logger.Log(S._("The file {0} could not be erased because the file's " + "permissions prevent access to the file.", info.FullName), LogLevel.Error); } catch (SharingViolationException e) { Logger.Log(S._("The file {0} could not be erased because the file is " + "currently in used by another application.", info.FullName), LogLevel.Error); } finally { //Re-set the read-only flag if the file exists (i.e. there was an error) if (isReadOnly && info.Exists && !info.IsReadOnly) { info.IsReadOnly = isReadOnly; } } }
private void CopyDirectory(DirectoryInfo info) { //Check the the destination is not a subfolder of the source. if (PathUtil.IsRootedAt(info, Destination)) { Logger.Log(S._("The destination directory cannot be within the source directory."), LogLevel.Error); return; } //We need to get the files from the list of streams List <StreamInfo> streams = GetPaths(); List <FileInfo> files = new List <FileInfo>( streams.Distinct(new StreamInfoFileEqualityComparer()). Select(x => x.File)); long totalSize = streams.Sum(x => x.Length); foreach (FileInfo file in files) { //Compute the total size of the file on the disk (including ADSes) List <StreamInfo> fileStreams = new List <StreamInfo>(file.GetADSes()); fileStreams.Add(new StreamInfo(file.FullName)); long fileSize = fileStreams.Sum(x => x.Length); SteppedProgressManager fileProgress = new SteppedProgressManager(); Progress.Steps.Add(new SteppedProgressManagerStep(fileProgress, fileSize / (float)totalSize, S._("Securely moving files and folders..."))); //Add the copying step to the file progress. ProgressManager copyProgress = new ProgressManager(); int totalPasses = 1 + EffectiveMethod.Passes; fileProgress.Steps.Add(new SteppedProgressManagerStep(copyProgress, 1f / totalPasses)); try { //Compute the path to the new directory. DirectoryInfo sourceDirectory = file.Directory; DirectoryInfo destDirectory = new DirectoryInfo( SourceToDestinationPath(file.DirectoryName)); //Make sure all necessary folders exist before the copy. if (!destDirectory.Exists) { destDirectory.Create(); } //Then copy the file. file.CopyTo(System.IO.Path.Combine(destDirectory.FullName, file.Name), delegate(long TotalFileSize, long TotalBytesTransferred) { return(CopyProgress(copyProgress, file, TotalFileSize, TotalBytesTransferred)); }); } catch (OperationCanceledException) { //The copy was cancelled: Complete the copy part. copyProgress.MarkComplete(); //We need to erase the partially copied copy of the file. SteppedProgressManager destroyProgress = new SteppedProgressManager(); Progress.Steps.Add(new SteppedProgressManagerStep(destroyProgress, 0.5f, S._("Erasing incomplete destination file"))); EraseFile(file, destroyProgress); //Rethrow the exception. throw; } //We copied the file over; erase the source file SteppedProgressManager eraseProgress = new SteppedProgressManager(); fileProgress.Steps.Add(new SteppedProgressManagerStep(eraseProgress, (totalPasses - 1) / (float)totalPasses, S._("Erasing source files..."))); EraseFile(file, eraseProgress); } //Then copy the timestamps from the source folders and delete the source. ProgressManager folderDeleteProgress = new ProgressManager(); Progress.Steps.Add(new SteppedProgressManagerStep(folderDeleteProgress, 0.0f, S._("Removing folders..."))); Action <DirectoryInfo> CopyTimesAndDelete = null; CopyTimesAndDelete = delegate(DirectoryInfo subDirectory) { foreach (DirectoryInfo child in subDirectory.GetDirectories()) { CopyTimesAndDelete(child); } //Update progress. folderDeleteProgress.Tag = subDirectory.FullName; //Get the directory which we copied to and copy the file times to the //destination directory DirectoryInfo destDirectory = new DirectoryInfo( SourceToDestinationPath(subDirectory.FullName)); if (!destDirectory.Exists) { destDirectory.Create(); } destDirectory.CopyTimes(subDirectory); //Then delete the source directory. IFileSystem fsManager = Host.Instance.FileSystems[ VolumeInfo.FromMountPoint(Path)]; fsManager.DeleteFolder(subDirectory, true); }; CopyTimesAndDelete(info); }