public override void EraseOldFileSystemResidentFiles(VolumeInfo volume, DirectoryInfo tempDirectory, IErasureMethod method, FileSystemEntriesEraseProgress callback) { //Squeeze files smaller than one MFT record until the volume and the MFT is full. long MFTRecordSize = NtfsApi.GetMftRecordSegmentSize(volume); long lastFileSize = MFTRecordSize; try { for ( ; ;) { //Open this stream string fileName = GenerateRandomFileName(tempDirectory, 18); FileStream strm = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write, FileShare.None, 8, FileOptions.WriteThrough); try { //Stretch the file size to use up some of the resident space. strm.SetLength(lastFileSize); //Then run the erase task method.Erase(strm, long.MaxValue, Host.Instance.Prngs.ActivePrng, null); //Call the callback function if one is provided. We'll provide a dummy //value since we really have no idea how much of the MFT we can clean. if (callback != null) { callback((int)(MFTRecordSize - lastFileSize), (int)MFTRecordSize); } } catch (IOException) { if (lastFileSize-- == 0) { break; } } finally { //Close the stream handle strm.Close(); //Then reset the time the file was created. ResetFileTimes(new FileInfo(fileName)); } } } catch (IOException) { //OK, enough squeezing: there isn't enough space to even create a new MFT record. } }
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 override void EraseDirectoryStructures(VolumeInfo info, FileSystemEntriesEraseProgress callback) { //Create a directory to hold all the temporary files DirectoryInfo tempDir = new DirectoryInfo(GenerateRandomFileName( info.MountPoints[0], 32)); tempDir.Create(); try { //Get the size of the MFT long mftSize = NtfsApi.GetMftValidSize(info); long mftRecordSegmentSize = NtfsApi.GetMftRecordSegmentSize(info); int pollingInterval = (int)Math.Min(Math.Max(1, mftSize / info.ClusterSize / 20), 128); int totalFiles = (int)Math.Max(1L, mftSize / mftRecordSegmentSize); int filesCreated = 0; while (true) { ++filesCreated; string fileName = GenerateRandomFileName(tempDir, 220); File.Create(fileName).Close(); ResetFileTimes(new FileInfo(fileName)); if (filesCreated % pollingInterval == 0) { //Call back to our progress function: this is the first half of the //procedure so divide the effective progress by 2. if (callback != null) { int halfFilesCreated = filesCreated / 2; callback(halfFilesCreated, Math.Max(halfFilesCreated, totalFiles)); } //Check if the MFT has grown. if (mftSize < NtfsApi.GetMftValidSize(info)) { break; } } } } catch (IOException) { } finally { //Clear up all the temporary files FileInfo[] files = tempDir.GetFiles("*", SearchOption.AllDirectories); for (int i = 0; i < files.Length; ++i) { if (callback != null && i % 50 == 0) { callback(files.Length + i, files.Length * 2); } files[i].Delete(); } DeleteFolder(tempDir, true); } }