source: trunk/eraser/Eraser.DefaultPlugins/ErasureTargets/FolderErasureTarget.cs @ 2948

Revision 2805, 9.3 KB checked in by gtrant, 19 months ago (diff)

Update to 2013 and fixes in local compile

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Rev URL
Line 
1/*
2 * $Id$
3 * Copyright 2008-2013 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.Text.RegularExpressions;
28using System.Runtime.Serialization;
29using System.Runtime.InteropServices;
30using System.Xml;
31using System.Xml.Serialization;
32using System.Security.Permissions;
33using System.IO;
34using System.Globalization;
35
36using Eraser.Util;
37using Eraser.Plugins;
38using Eraser.Plugins.ExtensionPoints;
39
40namespace Eraser.DefaultPlugins
41{
42    /// <summary>
43    /// Represents a folder and its files which are to be erased.
44    /// </summary>
45    [Serializable]
46    [Guid("F50B0A44-3AB1-4cab-B81E-1713AC3D28C9")]
47    public class FolderErasureTarget : FileSystemObjectErasureTarget
48    {
49        #region Serialization code
50        protected FolderErasureTarget(SerializationInfo info, StreamingContext context)
51            : base(info, context)
52        {
53            IncludeMask = (string)info.GetValue("IncludeMask", typeof(string));
54            ExcludeMask = (string)info.GetValue("ExcludeMask", typeof(string));
55            DeleteIfEmpty = (bool)info.GetValue("DeleteIfEmpty", typeof(bool));
56        }
57
58        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
59        public override void GetObjectData(SerializationInfo info, StreamingContext context)
60        {
61            base.GetObjectData(info, context);
62            info.AddValue("IncludeMask", IncludeMask);
63            info.AddValue("ExcludeMask", ExcludeMask);
64            info.AddValue("DeleteIfEmpty", DeleteIfEmpty);
65        }
66
67        protected override void ReadXml(XmlReader reader, bool advance)
68        {
69            base.ReadXml(reader, false);
70            IncludeMask = reader.GetAttribute("includeMask");
71            ExcludeMask = reader.GetAttribute("excludeMask");
72
73            if (reader.HasAttributes)
74            {
75                bool deleteIfEmpty = true;
76                bool.TryParse(reader.GetAttribute("deleteIfEmpty"), out deleteIfEmpty);
77                DeleteIfEmpty = deleteIfEmpty;
78            }
79
80            if (advance)
81                reader.Read();
82        }
83
84        public override void WriteXml(XmlWriter writer)
85        {
86            writer.WriteAttributeString("includeMask", IncludeMask);
87            writer.WriteAttributeString("excludeMask", ExcludeMask);
88            writer.WriteAttributeString("deleteIfEmpty",
89                DeleteIfEmpty.ToString(CultureInfo.InvariantCulture));
90            base.WriteXml(writer);
91        }
92        #endregion
93
94        /// <summary>
95        /// Constructor.
96        /// </summary>
97        public FolderErasureTarget()
98        {
99            IncludeMask = string.Empty;
100            ExcludeMask = string.Empty;
101            DeleteIfEmpty = true;
102        }
103
104        public override Guid Guid
105        {
106            get { return GetType().GUID; }
107        }
108
109        public override string Name
110        {
111            get { return S._("Files in Folder"); }
112        }
113
114        public override IErasureTargetConfigurer Configurer
115        {
116            get { return new FolderErasureTargetConfigurer(); }
117        }
118
119        protected override List<StreamInfo> GetPaths()
120        {
121            //Get a list to hold all the resulting streams.
122            List<StreamInfo> result = new List<StreamInfo>();
123
124            //Open the root of the search, including every file matching the pattern
125            DirectoryInfo dir = new DirectoryInfo(Path);
126
127            //List recursively all the files which match the include pattern.
128            FileInfo[] files = GetFiles(dir);
129
130            //Then exclude each file and finalize the list and total file size
131            Regex includePattern = string.IsNullOrEmpty(IncludeMask) ? null :
132                new Regex(
133                    Regex.Escape(ExcludeMask).Replace("\\*", ".*").Replace("\\?", "."),
134                    RegexOptions.IgnoreCase | RegexOptions.Compiled);
135            Regex excludePattern = string.IsNullOrEmpty(ExcludeMask) ? null :
136                new Regex(
137                    Regex.Escape(ExcludeMask).Replace("\\*", ".*").Replace("\\?", "."),
138                    RegexOptions.IgnoreCase | RegexOptions.Compiled);
139            foreach (FileInfo file in files)
140            {
141                //Check that the file is included
142                if (includePattern != null && !includePattern.Match(file.FullName).Success)
143                    continue;
144
145                //Check that the file is not excluded
146                if (excludePattern != null && excludePattern.Match(file.FullName).Success)
147                    continue;
148
149                try
150                {
151                    //Add the size of the file and its alternate data streams
152                    result.AddRange(GetPathADSes(file));
153
154                    //And the file itself
155                    result.Add(new StreamInfo(file.FullName));
156                }
157                catch (FileNotFoundException)
158                {
159                    Logger.Log(S._("The file {0} was not erased because it was deleted " +
160                        "before it could be erased.", file.FullName), LogLevel.Information);
161                }
162                catch (DirectoryNotFoundException)
163                {
164                    Logger.Log(S._("The file {0} was not erased because the containing " +
165                        "directory was deleted before it could be erased.", file.FullName),
166                        LogLevel.Information);
167                }
168                catch (SharingViolationException)
169                {
170                    Logger.Log(S._("Could not list the Alternate Data Streams for file {0} " +
171                        "because the file is being used by another process. The file will not " +
172                        "be erased.", file.FullName), LogLevel.Error);
173                }
174            }
175
176            //Return the filtered list.
177            return result;
178        }
179
180        /// <summary>
181        /// A wildcard expression stating the condition for the set of files to include.
182        /// The include mask is applied before the exclude mask is applied. If this value
183        /// is empty, all files and folders within the folder specified is included.
184        /// </summary>
185        public string IncludeMask { get; set; }
186
187        /// <summary>
188        /// A wildcard expression stating the condition for removing files from the set
189        /// of included files. If this value is omitted, all files and folders extracted
190        /// by the inclusion mask is erased.
191        /// </summary>
192        public string ExcludeMask { get; set; }
193
194        /// <summary>
195        /// Determines if Eraser should delete the folder after the erase process.
196        /// </summary>
197        public bool DeleteIfEmpty { get; set; }
198
199        public override void Execute()
200        {
201            Progress = new SteppedProgressManager();
202
203            try
204            {
205                base.Execute();
206
207                //Remove the contents of the folder, deleting the folder if it is empty
208                //at the end of it.
209                EraseFolder();
210            }
211            finally
212            {
213                Progress = null;
214            }
215        }
216
217        /// <summary>
218        /// Erases the folder after all files have been deleted. This folder does not
219        /// delete folders which have files within it.
220        /// </summary>
221        private void EraseFolder()
222        {
223            //Update the progress to show that folders are being removed.
224            ProgressManager step = new ProgressManager();
225            Progress.Steps.Add(new SteppedProgressManagerStep(step,
226                0.0f, S._("Removing folders...")));
227
228            //Erase all subdirectories which are not reparse points.
229            DirectoryInfo directory = new DirectoryInfo(Path);
230            if ((directory.Attributes & FileAttributes.ReparsePoint) == 0)
231                foreach (DirectoryInfo subDir in directory.GetDirectories())
232                    EraseFolder(subDir, step);
233
234            //Does the user want this directory to be erased if there are no more
235            //entries within it?
236            if (DeleteIfEmpty)
237            {
238                //See if this is the root of a volume.
239                bool isVolumeRoot = directory.Parent == null;
240                foreach (VolumeInfo volume in VolumeInfo.Volumes)
241                    if (volume.IsReady)
242                        foreach (DirectoryInfo mountPoint in volume.MountPoints)
243                            if (directory.FullName == mountPoint.FullName)
244                                isVolumeRoot = true;
245
246                //If the folder is a mount point, then don't delete it. If it isn't,
247                //search for files under the folder to see if it is empty.
248                if (!isVolumeRoot && directory.Exists)
249                {
250                    IFileSystem fsManager = Host.Instance.FileSystems[
251                        VolumeInfo.FromMountPoint(Path)];
252                    if ((directory.Attributes & FileAttributes.ReparsePoint) == 0)
253                    {
254                        if (directory.GetFiles("*", SearchOption.AllDirectories).Length == 0)
255                            fsManager.DeleteFolder(directory, true);
256                    }
257                    else
258                    {
259                        fsManager.DeleteFolder(directory, false);
260                    }
261                }
262            }
263        }
264
265        private void EraseFolder(DirectoryInfo info, ProgressManager progress)
266        {
267            //Skip all symbolic links and junctions as we want to retain the
268            //contents of those directories.
269            if ((info.Attributes & FileAttributes.ReparsePoint) != 0)
270                return;
271
272            //Iterate over each directory and erase the subdirectories.
273            foreach (DirectoryInfo subDir in info.GetDirectories())
274                EraseFolder(subDir, progress);
275
276            //Public progress updates.
277            progress.Tag = info.FullName;
278
279            //Ensure that the current directory is empty before deleting.
280            FileSystemInfo[] files = info.GetFileSystemInfos();
281            if (files.Length == 0)
282            {
283                try
284                {
285                    Host.Instance.FileSystems[VolumeInfo.FromMountPoint(Path)].
286                        DeleteFolder(info, true);
287                }
288                catch (DirectoryNotFoundException)
289                {
290                    Logger.Log(new LogEntry(S._("The folder {0} was not erased because " +
291                        "the containing directory was deleted before it could be erased.",
292                        info.FullName), LogLevel.Information));
293                }
294                catch (UnauthorizedAccessException)
295                {
296                    Logger.Log(new LogEntry(S._("The folder {0} could not be deleted because " +
297                        "the folder's permissions prevents the deletion of the folder.",
298                        info.FullName), LogLevel.Error));
299                }
300            }
301        }
302    }
303}
Note: See TracBrowser for help on using the repository browser.