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

Revision 2585, 8.2 KB checked in by lowjoel, 3 years ago (diff)

Partially reverted r2583-r2584: We should not remove the normal binary serialization code, since RemoteExecutor? still depends on it.

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