source: trunk/eraser/Eraser.DefaultPlugins/ErasureTargets/FileSystemObjectErasureTarget.cs @ 2149

Revision 2149, 10.0 KB checked in by lowjoel, 4 years ago (diff)

Modified all dependent code to compile after the change in the previous revision.

  • 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.Linq;
25using System.Text;
26
27using System.Runtime.Serialization;
28using System.Runtime.InteropServices;
29using System.Security.Permissions;
30using System.IO;
31
32using Eraser.Manager;
33using Eraser.Util;
34using Eraser.Util.ExtensionMethods;
35
36namespace Eraser.DefaultPlugins
37{
38    /// <summary>
39    /// Class representing a tangible object (file/folder) to be erased.
40    /// </summary>
41    [Serializable]
42    public abstract class FileSystemObjectErasureTarget : ErasureTarget
43    {
44        #region Serialization code
45        protected FileSystemObjectErasureTarget(SerializationInfo info, StreamingContext context)
46            : base(info, context)
47        {
48            Path = (string)info.GetValue("Path", typeof(string));
49        }
50
51        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
52        public override void GetObjectData(SerializationInfo info, StreamingContext context)
53        {
54            base.GetObjectData(info, context);
55            info.AddValue("Path", Path);
56        }
57        #endregion
58
59        /// <summary>
60        /// Constructor.
61        /// </summary>
62        protected FileSystemObjectErasureTarget()
63            : base()
64        {
65        }
66
67        /// <summary>
68        /// The Progress of this target's erasure. This property must be set
69        /// before <see cref="FileSystemObjectErasureTarget.Execute"/> is called.
70        /// </summary>
71        protected new SteppedProgressManager Progress
72        {
73            get
74            {
75                return (SteppedProgressManager)base.Progress;
76            }
77            set
78            {
79                base.Progress = value;
80            }
81        }
82
83        /// <summary>
84        /// Retrieves the list of files/folders to erase as a list.
85        /// </summary>
86        /// <returns>A list containing the paths to all the files to be erased.</returns>
87        protected abstract List<StreamInfo> GetPaths();
88
89        /// <summary>
90        /// Gets all files in the provided directory.
91        /// </summary>
92        /// <param name="info">The directory to look files in.</param>
93        /// <returns>A list of files found in the directory matching the IncludeMask
94        /// property.</returns>
95        protected static FileInfo[] GetFiles(DirectoryInfo info)
96        {
97            List<FileInfo> result = new List<FileInfo>();
98            if (info.Exists)
99            {
100                try
101                {
102                    foreach (DirectoryInfo dir in info.GetDirectories())
103                        result.AddRange(GetFiles(dir));
104                    result.AddRange(info.GetFiles());
105                }
106                catch (UnauthorizedAccessException e)
107                {
108                    Logger.Log(S._("Could not erase files and subfolders in {0} because {1}",
109                        info.FullName, e.Message), LogLevel.Error);
110                }
111            }
112
113            return result.ToArray();
114        }
115
116        /// <summary>
117        /// Adds ADSes of the given file to the list, forcing the open handles to the
118        /// files closed if necessary.
119        /// </summary>
120        /// <param name="file">The file to look for ADSes</param>
121        protected static StreamInfo[] GetPathADSes(FileInfo file)
122        {
123            try
124            {
125                return file.GetADSes().ToArray();
126            }
127            catch (FileNotFoundException)
128            {
129            }
130            catch (SharingViolationException)
131            {
132                //The system cannot open the file, try to force the file handle to close.
133                if (!ManagerLibrary.Settings.ForceUnlockLockedFiles)
134                    throw;
135
136                StringBuilder processStr = new StringBuilder();
137                foreach (OpenHandle handle in OpenHandle.Close(file.FullName))
138                {
139                    try
140                    {
141                        processStr.AppendFormat(
142                            System.Globalization.CultureInfo.InvariantCulture,
143                            "{0}, ", handle.Process.MainModule.FileName);
144                    }
145                    catch (System.ComponentModel.Win32Exception)
146                    {
147                        processStr.AppendFormat(
148                            System.Globalization.CultureInfo.InvariantCulture,
149                            "Process ID {0}, ", handle.Process.Id);
150                    }
151                }
152
153                if (processStr.Length == 0)
154                    return GetPathADSes(file);
155                else
156                    throw;
157            }
158            catch (UnauthorizedAccessException e)
159            {
160                //The system cannot read the file, assume no ADSes for lack of
161                //more information.
162                Logger.Log(e.Message, LogLevel.Error);
163            }
164
165            return new StreamInfo[0];
166        }
167
168        /// <summary>
169        /// The path to the file or folder referred to by this object.
170        /// </summary>
171        public string Path { get; set; }
172
173        public sealed override ErasureMethod EffectiveMethod
174        {
175            get
176            {
177                if (Method != ErasureMethodRegistrar.Default)
178                    return base.EffectiveMethod;
179
180                return ManagerLibrary.Instance.ErasureMethodRegistrar[
181                    ManagerLibrary.Settings.DefaultFileErasureMethod];
182            }
183        }
184
185        public override string UIText
186        {
187            get
188            {
189                string fileName = System.IO.Path.GetFileName(Path);
190                string directoryName = System.IO.Path.GetDirectoryName(Path);
191                return string.IsNullOrEmpty(fileName) ?
192                        (string.IsNullOrEmpty(directoryName) ? Path : directoryName)
193                    : fileName;
194            }
195        }
196
197        /// <summary>
198        /// Erases the streams returned by the <see cref="GetPaths"/> function.
199        /// </summary>
200        /// <remarks>The <see cref="Progress"/> property must be defined prior
201        /// to the execution of this function.</remarks>
202        public override void Execute()
203        {
204            //Retrieve the list of files to erase.
205            List<StreamInfo> paths = GetPaths();
206            long dataTotal = paths.Sum(x => x.Length);
207
208            //Set the event's current target status.
209            if (Progress == null)
210                throw new InvalidOperationException("The Progress property must not be null.");
211            Task.Progress.Steps.Add(new SteppedProgressManagerStep(Progress,
212                1.0f / Task.Targets.Count));
213
214            //Iterate over every path, and erase the path.
215            for (int i = 0; i < paths.Count; ++i)
216            {
217                ProgressManager step = new ProgressManager();
218                Progress.Steps.Add(new SteppedProgressManagerStep(step,
219                    paths[i].Length / (float)dataTotal, S._("Erasing files...")));
220                EraseStream(paths[i], step);
221                step.MarkComplete();
222            }
223        }
224
225        /// <summary>
226        /// Erases the provided stream, and updates progress using the provided
227        /// progress manager.
228        /// </summary>
229        /// <param name="info">The information regarding the stream that needs erasure.</param>
230        /// <param name="progress">The progress manager for the erasure of the current
231        /// stream.</param>
232        protected void EraseStream(StreamInfo info, ProgressManager progress)
233        {
234            //Check that the file exists - we do not want to bother erasing nonexistant files
235            if (!info.Exists)
236            {
237                Logger.Log(S._("The file {0} was not erased as the file does not exist.",
238                    info.FileName), LogLevel.Notice);
239                return;
240            }
241
242            //Get the filesystem provider to handle the secure file erasures
243            FileSystem fsManager = ManagerLibrary.Instance.FileSystemRegistrar[
244                VolumeInfo.FromMountPoint(info.DirectoryName)];
245
246            bool isReadOnly = false;
247
248            try
249            {
250                //Update the task progress
251                ErasureMethod method = EffectiveMethod;
252                OnProgressChanged(this, new ProgressChangedEventArgs(progress,
253                    new TaskProgressChangedEventArgs(info.FullName, 0, method.Passes)));
254
255                //Remove the read-only flag, if it is set.
256                if (isReadOnly = info.IsReadOnly)
257                    info.IsReadOnly = false;
258
259                //Make sure the file does not have any attributes which may affect
260                //the erasure process
261                if ((info.Attributes & FileAttributes.Compressed) != 0 ||
262                    (info.Attributes & FileAttributes.Encrypted) != 0 ||
263                    (info.Attributes & FileAttributes.SparseFile) != 0)
264                {
265                    //Log the error
266                    Logger.Log(S._("The file {0} could not be erased because the file was " +
267                        "either compressed, encrypted or a sparse file.", info.FullName),
268                        LogLevel.Error);
269                    return;
270                }
271
272                //Do not erase reparse points, as they will cause other references to the file
273                //to be to garbage.
274                if ((info.Attributes & FileAttributes.ReparsePoint) == 0)
275                    fsManager.EraseFileSystemObject(info, method,
276                        delegate(long lastWritten, long totalData, int currentPass)
277                        {
278                            if (Task.Canceled)
279                                throw new OperationCanceledException(S._("The task was cancelled."));
280
281                            progress.Total = totalData;
282                            progress.Completed += lastWritten;
283                            OnProgressChanged(this, new ProgressChangedEventArgs(progress,
284                                new TaskProgressChangedEventArgs(info.FullName, currentPass, method.Passes)));
285                        });
286                else
287                    Logger.Log(S._("The file {0} is a hard link or a symbolic link thus the " +
288                        "contents of the file was not erased.", LogLevel.Notice));
289
290                //Remove the file.
291                FileInfo fileInfo = info.File;
292                if (fileInfo != null)
293                    fsManager.DeleteFile(fileInfo);
294                progress.MarkComplete();
295            }
296            catch (UnauthorizedAccessException)
297            {
298                Logger.Log(S._("The file {0} could not be erased because the file's " +
299                    "permissions prevent access to the file.", info.FullName), LogLevel.Error);
300            }
301            catch (SharingViolationException)
302            {
303                if (!ManagerLibrary.Settings.ForceUnlockLockedFiles)
304                    throw;
305
306                StringBuilder processStr = new StringBuilder();
307                foreach (OpenHandle handle in OpenHandle.Close(info.FullName))
308                {
309                    try
310                    {
311                        processStr.AppendFormat(
312                            System.Globalization.CultureInfo.InvariantCulture,
313                            "{0}, ", handle.Process.MainModule.FileName);
314                    }
315                    catch (System.ComponentModel.Win32Exception)
316                    {
317                        processStr.AppendFormat(
318                            System.Globalization.CultureInfo.InvariantCulture,
319                            "Process ID {0}, ", handle.Process.Id);
320                    }
321                }
322
323                if (processStr.Length != 0)
324                    Logger.Log(S._("Could not force closure of file \"{0}\" {1}",
325                            info.FileName, S._("(locked by {0})",
326                                processStr.ToString().Remove(processStr.Length - 2)).Trim()),
327                        LogLevel.Error);
328            }
329            finally
330            {
331                //Re-set the read-only flag if the file exists (i.e. there was an error)
332                if (isReadOnly && info.Exists && !info.IsReadOnly)
333                    info.IsReadOnly = isReadOnly;
334            }
335        }
336    }
337}
Note: See TracBrowser for help on using the repository browser.