source: trunk/eraser6/Eraser.DefaultPlugins/FileSystems/Ntfs.cs @ 1859

Revision 1859, 6.0 KB checked in by lowjoel, 5 years ago (diff)

For NTFS MFT Record lengths we need volume (data) read access so instead catch unauthorized access exceptions (i.e. when running under a split user token in 7) and return using the heuristic of one of volume cluster size and 1024 bytes, whichever is smaller

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008-2010 The Eraser Project
4 * Original Author: Joel Low <lowjoel@users.sourceforge.net>
5 * Modified By:
6 *
7 * This file is part of Eraser.
8 *
9 * Eraser is free software: you can redistribute it and/or modify it under the
10 * terms of the GNU General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option) any later
12 * version.
13 *
14 * Eraser is distributed in the hope that it will be useful, but WITHOUT ANY
15 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
16 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17 *
18 * A copy of the GNU General Public License can be found at
19 * <http://www.gnu.org/licenses/>.
20 */
21
22using System;
23using System.Collections.Generic;
24using System.Text;
25using System.Runtime.InteropServices;
26
27using System.IO;
28using Eraser.Manager;
29using Eraser.Util;
30
31namespace Eraser.DefaultPlugins
32{
33    /// <summary>
34    /// Provides functions to handle erasures specific to NTFS volumes.
35    /// </summary>
36    [Guid("34399F62-0AD4-411c-8C71-5E1E6213545C")]
37    public class NtfsFileSystem : WindowsFileSystem
38    {
39        public override Guid Guid
40        {
41            get { return GetType().GUID; }
42        }
43
44        public override string Name
45        {
46            get { return "NTFS"; }
47        }
48
49        public override void EraseOldFileSystemResidentFiles(VolumeInfo volume,
50            DirectoryInfo tempDirectory, ErasureMethod method,
51            FileSystemEntriesEraseProgress callback)
52        {
53            try
54            {
55                //Squeeze one-byte files until the volume or the MFT is full.
56                long oldMFTSize = NtfsApi.GetMftValidSize(volume);
57
58                for ( ; ; )
59                {
60                    //Open this stream
61                    using (FileStream strm = new FileStream(
62                        GenerateRandomFileName(tempDirectory, 18), FileMode.CreateNew,
63                        FileAccess.Write, FileShare.None, 8, FileOptions.WriteThrough))
64                    {
65                        long streamSize = 0;
66                        try
67                        {
68                            while (true)
69                            {
70                                //Stretch the file size to use up some of the resident space.
71                                strm.SetLength(++streamSize);
72
73                                //Then run the erase task
74                                method.Erase(strm, long.MaxValue,
75                                    ManagerLibrary.Instance.PrngRegistrar[ManagerLibrary.Settings.ActivePrng],
76                                    null);
77
78                                //Call the callback function if one is provided. We'll provide a dummy
79                                //value since we really have no idea how much of the MFT we can clean.
80                                if (callback != null)
81                                    callback(0, 1);
82                            }
83                        }
84                        catch (IOException)
85                        {
86                            if (streamSize == 1)
87                                return;
88                        }
89                    }
90
91                    //We can stop when the MFT has grown.
92                    if (NtfsApi.GetMftValidSize(volume) > oldMFTSize)
93                        break;
94                }
95            }
96            catch (IOException)
97            {
98                //OK, enough squeezing: there isn't enough space to even create a new MFT record.
99            }
100        }
101
102        public override void EraseDirectoryStructures(VolumeInfo info,
103            FileSystemEntriesEraseProgress callback)
104        {
105            //Create a directory to hold all the temporary files
106            DirectoryInfo tempDir = new DirectoryInfo(FileSystem.GenerateRandomFileName(
107                new DirectoryInfo(info.MountPoints[0]), 32));
108            tempDir.Create();
109
110            try
111            {
112                //Get the size of the MFT
113                long mftSize = NtfsApi.GetMftValidSize(info);
114                long mftRecordSegmentSize = NtfsApi.GetMftRecordSegmentSize(info);
115                int pollingInterval = (int)Math.Min(Math.Max(1, mftSize / info.ClusterSize / 20), 128);
116                int totalFiles = (int)Math.Max(1L, mftSize / mftRecordSegmentSize);
117                int filesCreated = 0;
118
119                while (true)
120                {
121                    ++filesCreated;
122                    using (FileStream strm = new FileStream(FileSystem.GenerateRandomFileName(
123                        tempDir, 220), FileMode.CreateNew, FileAccess.Write))
124                    {
125                    }
126
127                    if (filesCreated % pollingInterval == 0)
128                    {
129                        //Call back to our progress function: this is the first half of the
130                        //procedure so divide the effective progress by 2.
131                        if (callback != null)
132                        {
133                            int halfFilesCreated = filesCreated / 2;
134                            callback(halfFilesCreated, Math.Max(halfFilesCreated, totalFiles));
135                        }
136
137                        //Check if the MFT has grown.
138                        if (mftSize < NtfsApi.GetMftValidSize(info))
139                            break;
140                    }
141                }
142            }
143            catch (IOException)
144            {
145            }
146            finally
147            {
148                //Clear up all the temporary files
149                FileInfo[] files = tempDir.GetFiles("*", SearchOption.AllDirectories);
150                for (int i = 0; i < files.Length; ++i)
151                {
152                    if (callback != null && i % 50 == 0)
153                        callback(files.Length + i, files.Length * 2);
154                    DeleteFile(files[i]);
155                }
156
157                DeleteFolder(tempDir);
158            }
159        }
160
161        public override void EraseFileSystemObject(StreamInfo info, ErasureMethod method,
162            ErasureMethodProgressFunction callback)
163        {
164            //Check if the file fits in one cluster - if it does it may be MFT resident
165            //TODO: any more deterministic way of finding out?
166            VolumeInfo volume = VolumeInfo.FromMountPoint(info.DirectoryName);
167            if (info.Length < NtfsApi.GetMftRecordSegmentSize(volume))
168            {
169                //Yes it does, erase exactly to the file length
170                using (FileStream strm = info.Open(FileMode.Open, FileAccess.Write,
171                    FileShare.None))
172                {
173                    method.Erase(strm, long.MaxValue,
174                        ManagerLibrary.Instance.PrngRegistrar[ManagerLibrary.Settings.ActivePrng],
175                        null);
176                }
177            }
178
179            //Create the file stream, and call the erasure method to write to
180            //the stream.
181            long fileArea = GetFileArea(info.FullName);
182
183            //If the stream is empty, there's nothing to overwrite. Continue
184            //to the next entry
185            if (fileArea == 0)
186                return;
187
188            using (FileStream strm = info.Open(FileMode.Open, FileAccess.Write,
189                FileShare.None, FileOptions.WriteThrough))
190            {
191                //Set the end of the stream after the wrap-round the cluster size
192                strm.SetLength(fileArea);
193
194                //Then erase the file.
195                method.Erase(strm, long.MaxValue,
196                    ManagerLibrary.Instance.PrngRegistrar[ManagerLibrary.Settings.ActivePrng],
197                    callback
198                );
199
200                //Set the length of the file to 0.
201                strm.Seek(0, SeekOrigin.Begin);
202                strm.SetLength(0);
203            }
204        }
205
206        protected override DateTime MinTimestamp
207        {
208            get
209            {
210                return new DateTime(1601, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
211            }
212        }
213    }
214}
Note: See TracBrowser for help on using the repository browser.