source: branches/eraser6/pluginsRewrite/Eraser.Plugins/ExtensionPoints/FileSystem.cs @ 2352

Revision 2352, 12.3 KB checked in by lowjoel, 3 years ago (diff)

Shifted all the plugin-extensible code to the Plugins assembly (Plugins.ExtensionPoints?). The code does not yet compile, because there are some inter-dependencies on the registrars.

Line 
1/*
2 * $Id: FileSystem.cs 2161 2010-06-13 02:30:16Z lowjoel $
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.Linq;
25using System.Text;
26
27using System.IO;
28using Eraser.Util;
29
30namespace Eraser.Plugins.ExtensionPoints
31{
32    /// <summary>
33    /// Provides functions to handle erasures specfic to file systems.
34    /// </summary>
35    public abstract class FileSystem : IRegisterable
36    {
37        /// <summary>
38        /// Generates a random file name with the given length.
39        /// </summary>
40        /// <remarks>The generated file name is guaranteed not to exist.</remarks>
41        /// <param name="info">The directory to generate the file name in. This
42        /// parameter can be null to indicate merely a random file name</param>
43        /// <param name="length">The length of the file name to generate.</param>
44        /// <returns>A full path to a file containing random file name.</returns>
45        public static string GenerateRandomFileName(DirectoryInfo info, int length)
46        {
47            //Get the PRNG we are going to use
48            Prng prng = ManagerLibrary.Instance.PrngRegistrar[ManagerLibrary.Settings.ActivePrng];
49
50            //Initialsie the base name, if any.
51            string resultPrefix = info == null ? string.Empty : info.FullName +
52                Path.DirectorySeparatorChar;
53
54            //Variables to store the intermediates.
55            byte[] resultAry = new byte[length];
56            string result = string.Empty;
57            List<string> prohibitedFileNames = new List<string>(new string[] {
58                "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4",
59                "COM5", "COM6", "COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3",
60                "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"
61            });
62
63            do
64            {
65                prng.NextBytes(resultAry);
66
67                //Validate the name
68                string validFileNameChars = "0123456789abcdefghijklmnopqrstuvwxyz" +
69                    "ABCDEFGHIJKLMNOPQRSTUVWXYZ _+=-()[]{}',`~!";
70                for (int j = 0, k = resultAry.Length; j < k; ++j)
71                {
72                    resultAry[j] = (byte)validFileNameChars[
73                        (int)resultAry[j] % validFileNameChars.Length];
74
75                    if (j == 0 || j == k - 1)
76                        //The first or last character cannot be whitespace
77                        while (Char.IsWhiteSpace((char)resultAry[j]))
78                            resultAry[j] = (byte)validFileNameChars[
79                                (int)resultAry[j] % validFileNameChars.Length];
80                }
81
82                result = Encoding.UTF8.GetString(resultAry);
83            }
84            while (info != null &&
85                prohibitedFileNames.IndexOf(Path.GetFileNameWithoutExtension(result)) != -1 ||
86                (Directory.Exists(resultPrefix + result) || File.Exists(resultPrefix + result)));
87            return resultPrefix + result;
88        }
89
90        /// <summary>
91        /// Gets a random file from within the provided directory.
92        /// </summary>
93        /// <param name="info">The directory to get a random file name from.</param>
94        /// <returns>A string containing the full path to the file.</returns>
95        public static string GetRandomFile(DirectoryInfo info)
96        {
97            //First retrieve the list of files and folders in the provided directory.
98            FileSystemInfo[] entries = null;
99            try
100            {
101                entries = info.GetFileSystemInfos();
102            }
103            catch (DirectoryNotFoundException)
104            {
105                return string.Empty;
106            }
107            if (entries.Length == 0)
108                return string.Empty;
109
110            //Find a random entry.
111            Prng prng = ManagerLibrary.Instance.PrngRegistrar[ManagerLibrary.Settings.ActivePrng];
112            string result = string.Empty;
113            while (result.Length == 0)
114            {
115                int index = prng.Next(entries.Length - 1);
116                if (entries[index] is DirectoryInfo)
117                    result = GetRandomFile((DirectoryInfo)entries[index]);
118                else
119                    result = ((FileInfo)entries[index]).FullName;
120            }
121
122            return result;
123        }
124
125        /// <summary>
126        /// Writes a file for plausible deniability over the current stream.
127        /// </summary>
128        /// <param name="stream">The stream to write the data to.</param>
129        protected static void CopyPlausibleDeniabilityFile(Stream stream)
130        {
131            //Get the template file to copy
132            FileInfo shadowFileInfo;
133            {
134                string shadowFile = null;
135                List<string> entries = new List<string>(
136                    ManagerLibrary.Settings.PlausibleDeniabilityFiles);
137                Prng prng = ManagerLibrary.Instance.PrngRegistrar[ManagerLibrary.Settings.ActivePrng];
138                do
139                {
140                    if (entries.Count == 0)
141                        throw new FatalException(S._("Plausible deniability was selected, " +
142                            "but no decoy files were found. The current file has been only " +
143                            "replaced with random data."));
144
145                    //Get an item from the list of files, and then check that the item exists.
146                    int index = prng.Next(entries.Count - 1);
147                    shadowFile = entries[index];
148                    if (File.Exists(shadowFile) || Directory.Exists(shadowFile))
149                    {
150                        if ((File.GetAttributes(shadowFile) & FileAttributes.Directory) != 0)
151                        {
152                            DirectoryInfo dir = new DirectoryInfo(shadowFile);
153                            FileInfo[] files = dir.GetFiles("*", SearchOption.AllDirectories);
154                            entries.Capacity += files.Length;
155                            foreach (FileInfo f in files)
156                                entries.Add(f.FullName);
157                        }
158                        else
159                            shadowFile = entries[index];
160                    }
161                    else
162                        shadowFile = null;
163
164                    entries.RemoveAt(index);
165                }
166                while (string.IsNullOrEmpty(shadowFile));
167                shadowFileInfo = new FileInfo(shadowFile);
168            }
169
170            //Dump the copy (the first 4MB, or less, depending on the file size and size of
171            //the original file)
172            long amountToCopy = Math.Min(stream.Length,
173                Math.Min(4 * 1024 * 1024, shadowFileInfo.Length));
174            using (FileStream shadowFileStream = shadowFileInfo.OpenRead())
175            {
176                while (stream.Position < amountToCopy)
177                {
178                    byte[] buf = new byte[524288];
179                    int bytesRead = shadowFileStream.Read(buf, 0, buf.Length);
180
181                    //Stop bothering if the input stream is at the end
182                    if (bytesRead == 0)
183                        break;
184
185                    //Dump the read contents onto the file to be deleted
186                    stream.Write(buf, 0,
187                        (int)Math.Min(bytesRead, amountToCopy - stream.Position));
188                }
189            }
190        }
191
192        /// <summary>
193        /// The Guid of the current filesystem.
194        /// </summary>
195        public abstract Guid Guid
196        {
197            get;
198        }
199
200        /// <summary>
201        /// The name of the current filesystem.
202        /// </summary>
203        public abstract string Name
204        {
205            get;
206        }
207
208        /// <summary>
209        /// Resets the created, modified, accessed and last update times for the given
210        /// <paramref name="info"/>.
211        /// </summary>
212        /// <param name="info">The file to reset times.</param>
213        public abstract void ResetFileTimes(FileSystemInfo info);
214
215        /// <summary>
216        /// Securely deletes the file reference from the directory structures
217        /// as well as resetting the Date Created, Date Accessed and Date Modified
218        /// records.
219        /// </summary>
220        /// <param name="info">The file to delete.</param>
221        public abstract void DeleteFile(FileInfo info);
222
223        /// <summary>
224        /// Securely deletes the folder reference from the directory structures
225        /// as well as all subfolders and files, resetting the Date Created, Date
226        /// Accessed and Date Modified records.
227        /// </summary>
228        /// <param name="info">The folder to delete</param>
229        /// <param name="recursive">True if the folder and all its subfolders and
230        /// files to be securely deleted.</param>
231        public abstract void DeleteFolder(DirectoryInfo info, bool recursive);
232
233        /// <seealso cref="DeleteFolder"/>
234        /// <param name="info">The folder to delete.</param>
235        public void DeleteFolder(DirectoryInfo info)
236        {
237            DeleteFolder(info, true);
238        }
239
240        /// <summary>
241        /// The function prototype for cluster tip search progress callbacks. This is
242        /// called when the cluster tips are being searched.
243        /// </summary>
244        /// <param name="currentPath">The directory being searched</param>
245        public delegate void ClusterTipsSearchProgress(string currentPath);
246
247        /// <summary>
248        /// The function prototype for cluster tip erasure callbacks. This is called when
249        /// the cluster tips are being erased.
250        /// </summary>
251        /// <param name="currentFile">The current file index being erased.</param>
252        /// <param name="totalFiles">The total number of files to be erased.</param>
253        /// <param name="currentFilePath">The path to the current file being erased.</param>
254        public delegate void ClusterTipsEraseProgress(int currentFile, int totalFiles,
255            string currentFilePath);
256
257        /// <summary>
258        /// The prototype of callbacks handling the file system table erase progress.
259        /// </summary>
260        /// <param name="currentFile">The current file being erased.</param>
261        /// <param name="totalFiles">The estimated number of files that must be
262        /// erased.</param>
263        public delegate void FileSystemEntriesEraseProgress(int currentFile, int totalFiles);
264
265        /// <summary>
266        /// Erases all file cluster tips in the given volume.
267        /// </summary>
268        /// <param name="info">The volume to search for file cluster tips and erase them.</param>
269        /// <param name="method">The erasure method being employed.</param>
270        /// <param name="log">The log manager instance that tracks log messages.</param>
271        /// <param name="searchCallback">The callback function for search progress.</param>
272        /// <param name="eraseCallback">The callback function for erasure progress.</param>
273        public abstract void EraseClusterTips(VolumeInfo info, ErasureMethod method,
274            ClusterTipsSearchProgress searchCallback, ClusterTipsEraseProgress eraseCallback);
275
276        /// <summary>
277        /// Erases old file system table-resident files. This creates small one-byte
278        /// files until disk is full. This will erase unused space which was used for
279        /// files resident in the file system table.
280        /// </summary>
281        /// <param name="volume">The directory information structure containing
282        /// the path to store the temporary one-byte files. The file system table
283        /// of that drive will be erased.</param>
284        /// <param name="tempDirectory">The directory structure containing the path
285        /// to store temporary files used for resident file cleaning.</param>
286        /// <param name="method">The method used to erase the files.</param>
287        public abstract void EraseOldFileSystemResidentFiles(VolumeInfo volume,
288            DirectoryInfo tempDirectory, ErasureMethod method,
289            FileSystemEntriesEraseProgress callback);
290
291        /// <summary>
292        /// Erases the unused space in the main filesystem structures by creating,
293        /// files until the table grows.
294        ///
295        /// This will overwrite unused portions of the table which were previously
296        /// used to store file entries.
297        /// </summary>
298        /// <param name="info">The directory information structure containing
299        /// the path to store the temporary files.</param>
300        /// <param name="callback">The callback function to handle the progress
301        /// of the file system entry erasure.</param>
302        public abstract void EraseDirectoryStructures(VolumeInfo info,
303            FileSystemEntriesEraseProgress callback);
304
305        /// <summary>
306        /// Erases the file system object from the drive.
307        /// </summary>
308        /// <param name="info"></param>
309        public abstract void EraseFileSystemObject(StreamInfo info, ErasureMethod method,
310            ErasureMethod.ErasureMethodProgressFunction callback);
311
312        //TODO: This is supposed to be in VolumeInfo!
313        /// <summary>
314        /// Retrieves the size of the file on disk, calculated by the amount of
315        /// clusters allocated by it.
316        /// </summary>
317        /// <param name="streamInfo">The Stream to get the area for.</param>
318        /// <returns>The area of the file.</returns>
319        public abstract long GetFileArea(StreamInfo filePath);
320
321        /// <summary>
322        /// The number of times file names are renamed to erase the file name from
323        /// the file system table.
324        /// </summary>
325        public const int FileNameErasePasses = 7;
326
327        /// <summary>
328        /// The maximum number of times Eraser tries to erase a file/folder before
329        /// it gives up.
330        /// </summary>
331        public const int FileNameEraseTries = 50;
332    }
333}
Note: See TracBrowser for help on using the repository browser.