source: trunk/eraser/Eraser.DefaultPlugins/ErasureTargets/UnusedSpaceErasureTarget.cs @ 2515

Revision 2515, 10.4 KB checked in by lowjoel, 2 years ago (diff)

Set svn:keywords and svn:eol-style on all the source files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Rev URL
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.Linq;
25using System.Text;
26
27using System.Runtime.Serialization;
28using System.Runtime.InteropServices;
29using System.Security.Permissions;
30using System.IO;
31
32using Eraser.Util;
33using Eraser.Util.ExtensionMethods;
34using Eraser.Plugins;
35using Eraser.Plugins.ExtensionPoints;
36using Eraser.Plugins.Registrars;
37
38namespace Eraser.DefaultPlugins
39{
40    /// <summary>
41    /// Class representing a unused space erase.
42    /// </summary>
43    [Serializable]
44    [Guid("A627BEC4-CAFC-46ce-92AD-209157C3177A")]
45    class UnusedSpaceErasureTarget : ErasureTargetBase
46    {
47        #region Serialization code
48        protected UnusedSpaceErasureTarget(SerializationInfo info, StreamingContext context)
49            : base(info, context)
50        {
51            Drive = (string)info.GetValue("Drive", typeof(string));
52            EraseClusterTips = (bool)info.GetValue("EraseClusterTips", typeof(bool));
53        }
54
55        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
56        public override void GetObjectData(SerializationInfo info, StreamingContext context)
57        {
58            base.GetObjectData(info, context);
59            info.AddValue("Drive", Drive);
60            info.AddValue("EraseClusterTips", EraseClusterTips);
61        }
62        #endregion
63
64        /// <summary>
65        /// Constructor.
66        /// </summary>
67        public UnusedSpaceErasureTarget()
68            : base()
69        {
70        }
71
72        public override Guid Guid
73        {
74            get { return GetType().GUID; }
75        }
76
77        public override string ToString()
78        {
79            return S._("Unused disk space ({0})", Drive);
80        }
81
82        public override string Name
83        {
84            get { return S._("Unused disk space"); }
85        }
86
87        public sealed override IErasureMethod EffectiveMethod
88        {
89            get
90            {
91                if (Method != ErasureMethodRegistrar.Default)
92                    return base.EffectiveMethod;
93
94                return Host.Instance.ErasureMethods[
95                    Host.Instance.Settings.DefaultUnusedSpaceErasureMethod];
96            }
97        }
98
99        public override bool SupportsMethod(IErasureMethod method)
100        {
101            return method == ErasureMethodRegistrar.Default ||
102                method is IUnusedSpaceErasureMethod;
103        }
104
105        /// <summary>
106        /// Override the base class property so that we won't need to keep casting
107        /// </summary>
108        protected new SteppedProgressManager Progress
109        {
110            get
111            {
112                return (SteppedProgressManager)base.Progress;
113            }
114            set
115            {
116                base.Progress = value;
117            }
118        }
119
120        public override IErasureTargetConfigurer Configurer
121        {
122            get { return new UnusedSpaceErasureTargetConfigurer(); }
123        }
124
125        /// <summary>
126        /// The drive to erase
127        /// </summary>
128        public string Drive { get; set; }
129
130        /// <summary>
131        /// Whether cluster tips should be erased.
132        /// </summary>
133        public bool EraseClusterTips { get; set; }
134
135        public override void Execute()
136        {
137            //Check for sufficient privileges to run the unused space erasure.
138            if (!Security.IsAdministrator())
139            {
140                if (Environment.OSVersion.Platform == PlatformID.Win32NT &&
141                    Environment.OSVersion.Version >= new Version(6, 0))
142                {
143                    Logger.Log(S._("The program does not have the required permissions to erase " +
144                        "the unused space on disk. Run the program as an administrator and retry " +
145                        "the operation."), LogLevel.Error);
146                }
147                else
148                {
149                    Logger.Log(S._("The program does not have the required permissions to erase " +
150                        "the unused space on disk."), LogLevel.Error);
151                }
152
153                return;
154            }
155
156            //Check whether System Restore has any available checkpoints.
157            if (SystemRestore.GetInstances().Count != 0)
158            {
159                Logger.Log(S._("This computer has had System Restore or Volume Shadow Copies " +
160                    "enabled. This may allow copies of files stored on the disk to be recovered " +
161                    "and pose a security concern.", Drive), LogLevel.Warning);
162            }
163
164            //If the user is under disk quotas, log a warning message
165            if (VolumeInfo.FromMountPoint(Drive).HasQuota)
166            {
167                Logger.Log(S._("The drive {0} has disk quotas active. This will prevent the " +
168                    "complete erasure of unused space and may pose a security concern.",
169                    Drive), LogLevel.Warning);
170            }
171
172            //Get the erasure method if the user specified he wants the default.
173            IErasureMethod method = EffectiveMethod;
174
175            //Make a folder to dump our temporary files in
176            DirectoryInfo info = new DirectoryInfo(Drive);
177            VolumeInfo volInfo = VolumeInfo.FromMountPoint(Drive);
178            IFileSystem fsManager = Host.Instance.FileSystems[volInfo];
179
180            //Start sampling the speed of the task.
181            Progress = new SteppedProgressManager();
182
183            //Erase the cluster tips of every file on the drive.
184            if (EraseClusterTips)
185            {
186                //Define the callback handlers
187                ProgressManager tipSearch = new ProgressManager();
188                tipSearch.MarkIndeterminate();
189                Progress.Steps.Add(new SteppedProgressManagerStep(tipSearch,
190                    0.0f, S._("Searching for files' cluster tips...")));
191                ClusterTipsSearchProgress searchProgress = delegate(string path)
192                {
193                    if (Task.Canceled)
194                        throw new OperationCanceledException(S._("The task was cancelled."));
195
196                    tipSearch.Tag = path;
197                };
198
199                ProgressManager tipProgress = new ProgressManager();
200                Progress.Steps.Add(new SteppedProgressManagerStep(tipProgress, 0.1f,
201                    S._("Erasing cluster tips...")));
202                ClusterTipsEraseProgress eraseProgress =
203                    delegate(int currentFile, int totalFiles, string currentFilePath)
204                    {
205                        tipSearch.MarkComplete();
206                        tipProgress.Total = totalFiles;
207                        tipProgress.Completed = currentFile;
208                        tipProgress.Tag = currentFilePath;
209
210                        if (Task.Canceled)
211                            throw new OperationCanceledException(S._("The task was cancelled."));
212                    };
213
214                //Start counting statistics
215                fsManager.EraseClusterTips(VolumeInfo.FromMountPoint(Drive),
216                    method, searchProgress, eraseProgress);
217                tipProgress.MarkComplete();
218            }
219
220            bool lowDiskSpaceNotifications = Shell.LowDiskSpaceNotificationsEnabled;
221            info = info.CreateSubdirectory(Path.GetFileName(
222                FileSystemBase.GenerateRandomFileName(info, 18)));
223            try
224            {
225                //Set the folder's compression flag off since we want to use as much
226                //space as possible
227                if (info.IsCompressed())
228                    info.Uncompress();
229
230                //Disable the low disk space notifications
231                Shell.LowDiskSpaceNotificationsEnabled = false;
232
233                //Fill the disk
234                EraseUnusedSpace(volInfo, info, fsManager, method);
235
236                //Erase old resident file system table files
237                ProgressManager residentProgress = new ProgressManager();
238                Progress.Steps.Add(new SteppedProgressManagerStep(residentProgress,
239                    0.05f, S._("Old resident file system table files")));
240                fsManager.EraseOldFileSystemResidentFiles(volInfo, info, method,
241                    delegate(int currentFile, int totalFiles)
242                    {
243                        residentProgress.Completed = currentFile;
244                        residentProgress.Total = totalFiles;
245
246                        if (Task.Canceled)
247                            throw new OperationCanceledException(S._("The task was cancelled."));
248                    }
249                );
250
251                residentProgress.MarkComplete();
252            }
253            finally
254            {
255                //Remove the folder holding all our temporary files.
256                ProgressManager tempFiles = new ProgressManager();
257                Progress.Steps.Add(new SteppedProgressManagerStep(tempFiles,
258                    0.0f, S._("Removing temporary files...")));
259                info.Delete(true);
260                tempFiles.MarkComplete();
261
262                //Reset the low disk space notifications
263                Shell.LowDiskSpaceNotificationsEnabled = lowDiskSpaceNotifications;
264            }
265
266            //Then clean the old file system entries
267            ProgressManager structureProgress = new ProgressManager();
268            Progress.Steps.Add(new SteppedProgressManagerStep(structureProgress,
269                0.05f, S._("Erasing unused directory structures...")));
270            fsManager.EraseDirectoryStructures(volInfo,
271                delegate(int currentFile, int totalFiles)
272                {
273                    if (Task.Canceled)
274                        throw new OperationCanceledException(S._("The task was cancelled."));
275
276                    //Compute the progress
277                    structureProgress.Total = totalFiles;
278                    structureProgress.Completed = currentFile;
279                }
280            );
281
282            structureProgress.MarkComplete();
283            Progress = null;
284        }
285
286        private void EraseUnusedSpace(VolumeInfo volInfo, DirectoryInfo info, IFileSystem fsInfo,
287            IErasureMethod method)
288        {
289            ProgressManager mainProgress = new ProgressManager();
290            Progress.Steps.Add(new SteppedProgressManagerStep(mainProgress,
291                EraseClusterTips ? 0.8f : 0.9f, S._("Erasing unused space...")));
292
293            //Continue creating files while there is free space.
294            while (volInfo.AvailableFreeSpace > 0)
295            {
296                //Generate a non-existant file name
297                string currFile = FileSystemBase.GenerateRandomFileName(info, 18);
298
299                //Create the stream
300                FileStream stream = new FileStream(currFile, FileMode.CreateNew,
301                    FileAccess.Write, FileShare.None, 8, FileOptions.WriteThrough);
302                try
303                {
304                    //Set the length of the file to be the amount of free space left
305                    //or the maximum size of one of these dumps.
306                    mainProgress.Total = mainProgress.Completed +
307                        method.CalculateEraseDataSize(null, volInfo.AvailableFreeSpace);
308                    long streamLength = Math.Min(PassBasedErasureMethod.FreeSpaceFileUnit,
309                        volInfo.AvailableFreeSpace);
310
311                    //Handle IO exceptions gracefully, because the filesystem
312                    //may require more space than demanded by us for file allocation.
313                    while (true)
314                        try
315                        {
316                            stream.SetLength(streamLength);
317                            break;
318                        }
319                        catch (IOException)
320                        {
321                            if (streamLength > volInfo.ClusterSize)
322                                streamLength -= volInfo.ClusterSize;
323                            else
324                                throw;
325                        }
326
327                    //Then run the erase task
328                    method.Erase(stream, long.MaxValue, Host.Instance.Prngs.ActivePrng,
329                        delegate(long lastWritten, long totalData, int currentPass)
330                        {
331                            mainProgress.Completed += lastWritten;
332                            mainProgress.Tag = new int[] { currentPass, method.Passes };
333
334                            if (Task.Canceled)
335                                throw new OperationCanceledException(S._("The task was cancelled."));
336                        }
337                    );
338                }
339                finally
340                {
341                    stream.Close();
342                    fsInfo.ResetFileTimes(new FileInfo(currFile));
343                }
344            }
345
346            //Mark the main bulk of the progress as complete
347            mainProgress.MarkComplete();
348        }
349    }
350}
Note: See TracBrowser for help on using the repository browser.