source: branches/eraser6/XmlTaskLists/Eraser.DefaultPlugins/ErasureTargets/FolderErasureTarget.cs @ 2587

Revision 2587, 8.3 KB checked in by lowjoel, 3 years ago (diff)

XmlSerializer? can only deal with public types.

  • 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.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        public override void ReadXml(XmlReader reader)
68        {
69            base.ReadXml(reader);
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
81        public override void WriteXml(XmlWriter writer)
82        {
83            base.WriteXml(writer);
84            writer.WriteAttributeString("includeMask", IncludeMask);
85            writer.WriteAttributeString("excludeMask", ExcludeMask);
86            writer.WriteAttributeString("deleteIfEmpty",
87                DeleteIfEmpty.ToString(CultureInfo.InvariantCulture));
88        }
89        #endregion
90
91        /// <summary>
92        /// Constructor.
93        /// </summary>
94        public FolderErasureTarget()
95        {
96            IncludeMask = string.Empty;
97            ExcludeMask = string.Empty;
98            DeleteIfEmpty = true;
99        }
100
101        public override Guid Guid
102        {
103            get { return GetType().GUID; }
104        }
105
106        public override string Name
107        {
108            get { return S._("Files in Folder"); }
109        }
110
111        public override IErasureTargetConfigurer Configurer
112        {
113            get { return new FolderErasureTargetConfigurer(); }
114        }
115
116        protected override List<StreamInfo> GetPaths()
117        {
118            //Get a list to hold all the resulting streams.
119            List<StreamInfo> result = new List<StreamInfo>();
120
121            //Open the root of the search, including every file matching the pattern
122            DirectoryInfo dir = new DirectoryInfo(Path);
123
124            //List recursively all the files which match the include pattern.
125            FileInfo[] files = GetFiles(dir);
126
127            //Then exclude each file and finalize the list and total file size
128            Regex includePattern = string.IsNullOrEmpty(IncludeMask) ? null :
129                new Regex(
130                    Regex.Escape(ExcludeMask).Replace("\\*", ".*").Replace("\\?", "."),
131                    RegexOptions.IgnoreCase | RegexOptions.Compiled);
132            Regex excludePattern = string.IsNullOrEmpty(ExcludeMask) ? null :
133                new Regex(
134                    Regex.Escape(ExcludeMask).Replace("\\*", ".*").Replace("\\?", "."),
135                    RegexOptions.IgnoreCase | RegexOptions.Compiled);
136            foreach (FileInfo file in files)
137            {
138                //Check that the file is included
139                if (includePattern != null && !includePattern.Match(file.FullName).Success)
140                    continue;
141
142                //Check that the file is not excluded
143                if (excludePattern != null && excludePattern.Match(file.FullName).Success)
144                    continue;
145
146                //Add the size of the file and its alternate data streams
147                result.AddRange(GetPathADSes(file));
148
149                //And the file itself
150                result.Add(new StreamInfo(file.FullName));
151            }
152
153            //Return the filtered list.
154            return result;
155        }
156
157        /// <summary>
158        /// A wildcard expression stating the condition for the set of files to include.
159        /// The include mask is applied before the exclude mask is applied. If this value
160        /// is empty, all files and folders within the folder specified is included.
161        /// </summary>
162        public string IncludeMask { get; set; }
163
164        /// <summary>
165        /// A wildcard expression stating the condition for removing files from the set
166        /// of included files. If this value is omitted, all files and folders extracted
167        /// by the inclusion mask is erased.
168        /// </summary>
169        public string ExcludeMask { get; set; }
170
171        /// <summary>
172        /// Determines if Eraser should delete the folder after the erase process.
173        /// </summary>
174        public bool DeleteIfEmpty { get; set; }
175
176        public override void Execute()
177        {
178            Progress = new SteppedProgressManager();
179
180            try
181            {
182                base.Execute();
183
184                //Remove the contents of the folder, deleting the folder if it is empty
185                //at the end of it.
186                EraseFolder();
187            }
188            finally
189            {
190                Progress = null;
191            }
192        }
193
194        /// <summary>
195        /// Erases the folder after all files have been deleted. This folder does not
196        /// delete folders which have files within it.
197        /// </summary>
198        private void EraseFolder()
199        {
200            //Update the progress to show that folders are being removed.
201            ProgressManager step = new ProgressManager();
202            Progress.Steps.Add(new SteppedProgressManagerStep(step,
203                0.0f, S._("Removing folders...")));
204
205            //Erase all subdirectories which are not reparse points.
206            DirectoryInfo directory = new DirectoryInfo(Path);
207            if ((directory.Attributes & FileAttributes.ReparsePoint) == 0)
208                foreach (DirectoryInfo subDir in directory.GetDirectories())
209                    EraseFolder(subDir, step);
210
211            //Does the user want this directory to be erased if there are no more
212            //entries within it?
213            if (DeleteIfEmpty)
214            {
215                //See if this is the root of a volume.
216                bool isVolumeRoot = directory.Parent == null;
217                foreach (VolumeInfo volume in VolumeInfo.Volumes)
218                    if (volume.IsReady)
219                        foreach (DirectoryInfo mountPoint in volume.MountPoints)
220                            if (directory.FullName == mountPoint.FullName)
221                                isVolumeRoot = true;
222
223                //If the folder is a mount point, then don't delete it. If it isn't,
224                //search for files under the folder to see if it is empty.
225                if (!isVolumeRoot && directory.Exists)
226                {
227                    IFileSystem fsManager = Host.Instance.FileSystems[
228                        VolumeInfo.FromMountPoint(Path)];
229                    if ((directory.Attributes & FileAttributes.ReparsePoint) == 0)
230                    {
231                        if (directory.GetFiles("*", SearchOption.AllDirectories).Length == 0)
232                            fsManager.DeleteFolder(directory, true);
233                    }
234                    else
235                    {
236                        fsManager.DeleteFolder(directory, false);
237                    }
238                }
239            }
240        }
241
242        private void EraseFolder(DirectoryInfo info, ProgressManager progress)
243        {
244            //Skip all symbolic links and junctions as we want to retain the
245            //contents of those directories.
246            if ((info.Attributes & FileAttributes.ReparsePoint) != 0)
247                return;
248
249            //Iterate over each directory and erase the subdirectories.
250            foreach (DirectoryInfo subDir in info.GetDirectories())
251                EraseFolder(subDir, progress);
252
253            //Public progress updates.
254            progress.Tag = info.FullName;
255
256            //Ensure that the current directory is empty before deleting.
257            FileSystemInfo[] files = info.GetFileSystemInfos();
258            if (files.Length == 0)
259            {
260                try
261                {
262                    Host.Instance.FileSystems[VolumeInfo.FromMountPoint(Path)].
263                        DeleteFolder(info, true);
264                }
265                catch (UnauthorizedAccessException)
266                {
267                    Logger.Log(new LogEntry(S._("The folder {0} could not be deleted because " +
268                        "the folder's permissions prevents the deletion of the folder.",
269                        info.FullName), LogLevel.Error));
270                }
271            }
272        }
273    }
274}
Note: See TracBrowser for help on using the repository browser.