public override void Erase(Stream stream, long erasureLength, IPrng prng, ErasureMethodProgressFunction callback) { //Randomize the order of the passes ErasureMethodPass[] randomizedPasses = PassesSet; if (RandomizePasses) { randomizedPasses = ShufflePasses(randomizedPasses); } //Remember the starting position of the stream. long strmStart = stream.Position; long strmLength = Math.Min(stream.Length - strmStart, erasureLength); long totalData = CalculateEraseDataSize(null, strmLength); //Allocate memory for a buffer holding data for the pass. byte[] buffer = new byte[Math.Min(DiskOperationUnit, strmLength)]; //Run every pass! for (int pass = 0; pass < Passes; ++pass) { //Do a progress callback first. if (callback != null) { callback(0, totalData, pass + 1); } //Start from the beginning again stream.Seek(strmStart, SeekOrigin.Begin); //Write the buffer to disk. long toWrite = strmLength; int dataStopped = buffer.Length; while (toWrite > 0) { //Calculate how much of the buffer to write to disk. int amount = (int)Math.Min(toWrite, buffer.Length - dataStopped); //If we have no data left, get more! if (amount == 0) { randomizedPasses[pass].Execute(buffer, prng); dataStopped = 0; continue; } //Write the data. stream.Write(buffer, dataStopped, amount); stream.Flush(); dataStopped += amount; toWrite -= amount; //Do a progress callback. if (callback != null) { callback(amount, totalData, pass + 1); } } } }
public override void EraseFileSystemObject(StreamInfo info, ErasureMethod method, ErasureMethodProgressFunction callback) { VolumeInfo volume = VolumeInfo.FromMountpoint(info.DirectoryName); if (info.Length < Math.Max(volume.ClusterSize, 1024)) { using (FileStream strm = info.Open(FileMode.Open, FileAccess.Write, FileShare.None)) { method.Erase(strm, long.MaxValue, PrngManager.GetInstance(ManagerLibrary.Settings.ActivePrng), null); } } long fileArea = GetFileArea(info.FullName); if (fileArea == 0) return; using (FileStream strm = info.Open(FileMode.Open, FileAccess.Write, FileShare.None, FileOptions.WriteThrough)) { strm.SetLength(fileArea); method.Erase(strm, long.MaxValue, PrngManager.GetInstance(ManagerLibrary.Settings.ActivePrng), callback ); strm.Seek(0, SeekOrigin.Begin); strm.SetLength(0); } }
public override void EraseFileSystemObject(StreamInfo info, IErasureMethod method, ErasureMethodProgressFunction callback) { //Create the file stream, and call the erasure method to write to //the stream. long fileArea = GetFileArea(info); 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); //If the stream is empty, there's nothing to overwrite. Continue //to the next entry if (strm.Length != 0) { //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); } }
public override void Erase(Stream strm, long erasureLength, IPrng prng, ErasureMethodProgressFunction callback) { //If we have no default or we are the default then throw an exception if (method == null || method.Guid == Guid) { throw new InvalidOperationException(S._("The First/last 16KB erasure method " + "requires another erasure method to erase the file.\n\nThis must " + "be set in the Plugin Settings dialog.")); } //Make sure that the erasureLength passed in here is the maximum value //for the size of long, since we don't want to write extra or write //less. if (erasureLength != long.MaxValue) { throw new ArgumentException("The amount of data erased should not be " + "limited, since this is a self-limiting erasure method."); } //If the target stream is shorter than or equal to 32kb, just forward it to //the default function. if (strm.Length < DataSize * 2) { method.Erase(strm, erasureLength, prng, callback); return; } //We need to intercept the callback function as we run the erasure method //twice on two parts of the file. long dataSize = method.CalculateEraseDataSize(null, DataSize * 2); ErasureMethodProgressFunction customCallback = delegate(long lastWritten, long totalData, int currentPass) { callback(lastWritten, dataSize, currentPass); }; //Seek to the beginning and write 16kb. strm.Seek(0, SeekOrigin.Begin); method.Erase(strm, dataSize, prng, callback == null ? null: customCallback); //Seek to the end - 16kb, and write. strm.Seek(-dataSize, SeekOrigin.End); method.Erase(strm, long.MaxValue, prng, callback == null ? null : customCallback); }
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); } }
public virtual void EraseDriveSpace(Stream stream, IPrng prng, ErasureMethodProgressFunction callback) { Erase(stream, long.MaxValue, prng, callback); }
public void Erase(Stream strm, long erasureLength, IPrng prng, ErasureMethodProgressFunction callback) { throw new InvalidOperationException("The DefaultMethod class should never " + "be used and should instead be replaced before execution!"); }
public abstract void EraseFileSystemObject(StreamInfo info, ErasureMethod method, ErasureMethodProgressFunction callback);
public override void Erase(Stream stream, long erasureLength, Prng prng, ErasureMethodProgressFunction callback) { ErasureMethodPass[] randomizedPasses = PassesSet; if (RandomizePasses) randomizedPasses = ShufflePasses(randomizedPasses); long strmStart = stream.Position; long strmLength = Math.Min(stream.Length - strmStart, erasureLength); long totalData = CalculateEraseDataSize(null, strmLength); byte[] buffer = new byte[Math.Min(DiskOperationUnit, strmLength)]; for (int pass = 0; pass < Passes; ++pass) { if (callback != null) callback(0, totalData, pass + 1); stream.Seek(strmStart, SeekOrigin.Begin); long toWrite = strmLength; int dataStopped = buffer.Length; while (toWrite > 0) { int amount = (int)Math.Min(toWrite, buffer.Length - dataStopped); if (amount == 0) { randomizedPasses[pass].Execute(buffer, prng); dataStopped = 0; continue; } stream.Write(buffer, dataStopped, amount); stream.Flush(); toWrite -= amount; if (callback != null) callback(amount, totalData, pass + 1); } } }
/// <summary> /// Attempts to erase a stream, trying to close all open handles if a process has /// a lock on the file. /// </summary> /// <param name="fsManager">The file system provider used to erase the stream.</param> /// <param name="method">The erasure method to use to erase the stream.</param> /// <param name="info">The stream to erase.</param> /// <param name="callback">The erasure progress callback.</param> private void TryEraseStream(IFileSystem fsManager, IErasureMethod method, StreamInfo info, ErasureMethodProgressFunction callback) { for (int i = 0; ; ++i) { try { //Make sure the file does not have any attributes which may affect //the erasure process if ((info.Attributes & FileAttributes.Compressed) != 0 || (info.Attributes & FileAttributes.Encrypted) != 0 || (info.Attributes & FileAttributes.SparseFile) != 0) { //Log the error Logger.Log(S._("The file {0} could not be erased because the file was " + "either compressed, encrypted or a sparse file.", info.FullName), LogLevel.Error); return; } //Do not erase reparse points, as they will cause other references to the file //to be to garbage. if ((info.Attributes & FileAttributes.ReparsePoint) == 0) { fsManager.EraseFileSystemObject(info, method, callback); } else { Logger.Log(S._("The file {0} is a hard link or a symbolic link thus the " + "contents of the file was not erased.", info.FullName), LogLevel.Notice); } return; } catch (FileNotFoundException) { Logger.Log(S._("The file {0} was not erased because it was " + "deleted before it could be erased.", info.FullName), LogLevel.Information); } catch (DirectoryNotFoundException) { Logger.Log(S._("The file {0} was not erased because the containing " + "directory was deleted before it could be erased.", info.FullName), LogLevel.Information); } catch (SharingViolationException) { if (!Host.Instance.Settings.ForceUnlockLockedFiles) { throw; } //Try closing all open handles. If it succeeds, we can run the erase again. //To prevent Eraser from deadlocking, we will only attempt this once. Some //programs may be aggressive and keep a handle open in a tight loop. List <OpenHandle> remainingHandles = OpenHandle.Close(info.FullName); if (i == 0 && remainingHandles.Count == 0) { continue; } //Either we could not close all instances, or we already tried twice. Report //the error. string processes = string.Empty; { StringBuilder processStr = new StringBuilder(); foreach (OpenHandle handle in remainingHandles) { try { processStr.AppendFormat( System.Globalization.CultureInfo.InvariantCulture, "{0}, ", handle.Process.MainModule.FileName); } catch (System.ComponentModel.Win32Exception) { processStr.AppendFormat( System.Globalization.CultureInfo.InvariantCulture, "Process ID {0}, ", handle.Process.Id); } } if (processStr.Length > 2) { processes = processStr.ToString().Remove(processStr.Length - 2).Trim(); } else { processes = S._("(unknown)"); } } throw new SharingViolationException(S._( "Could not force closure of file \"{0}\" {1}", info.FileName, S._("(locked by {0})", processes))); } } }
/// <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; } } }
public override void Erase(Stream strm, long erasureLength, Prng prng, ErasureMethodProgressFunction callback) { if (method == null || method.Guid == Guid) throw new InvalidOperationException(S._("The First/last 16KB erasure method " + "requires another erasure method to erase the file.\n\nThis must " + "be set in the Plugin Settings dialog.")); if (erasureLength != long.MaxValue) throw new ArgumentException(S._("The amount of data erased should not be " + "limited, since this is a self-limiting erasure method.")); if (strm.Length < dataSize) { method.Erase(strm, erasureLength, prng, callback); return; } strm.Seek(0, SeekOrigin.Begin); method.Erase(strm, dataSize, prng, callback); strm.Seek(-dataSize, SeekOrigin.End); method.Erase(strm, long.MaxValue, prng, callback); }
public abstract void EraseFileSystemObject(StreamInfo info, IErasureMethod method, ErasureMethodProgressFunction callback);
public abstract void Erase(Stream stream, long erasureLength, Prng prng, ErasureMethodProgressFunction callback);
public virtual void EraseUnusedSpace(Stream stream, Prng prng, ErasureMethodProgressFunction callback) { Erase(stream, long.MaxValue, prng, callback); }
public override void EraseFileSystemObject(StreamInfo info, ErasureMethod method, ErasureMethodProgressFunction callback) { long fileArea = GetFileArea(info.FullName); using (FileStream strm = info.Open(FileMode.Open, FileAccess.Write, FileShare.None, FileOptions.WriteThrough)) { strm.SetLength(fileArea); if (strm.Length != 0) { method.Erase(strm, long.MaxValue, PrngManager.GetInstance(ManagerLibrary.Settings.ActivePrng), callback ); } strm.Seek(0, SeekOrigin.Begin); strm.SetLength(0); } }
public abstract void Erase(Stream stream, long erasureLength, IPrng prng, ErasureMethodProgressFunction callback);
public override void Erase(Stream strm, long erasureLength, Prng prng, ErasureMethodProgressFunction callback) { throw new InvalidOperationException(S._("The DefaultMethod class should never " + "be used and should instead be replaced before execution!")); }