source: branches/eraser6/pluginsRewrite/Eraser.DefaultPlugins/ErasureTargets/FolderErasureTarget.cs @ 2486

Revision 2486, 7.4 KB checked in by lowjoel, 2 years ago (diff)

Report progress updates by pushing information to the SteppedProgressManager? instance associated with each erasure target. Furthermore, do not manipulate the state of the Task object, instead, let the Task object manage its own Progress state.

Because of this, a new property Tag is created in ProgressManagerBase?, to hold state information.

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