source: branches/eraser6/XmlTaskLists/Eraser.DefaultPlugins/ErasureTargets/UnusedSpaceErasureTarget.cs @ 2584

Revision 2584, 10.4 KB checked in by lowjoel, 3 years ago (diff)

Switch the Default Plugin's erasure targets to follow the new IXmlSerializable interface.

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