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

Revision 2081, 7.4 KB checked in by lowjoel, 4 years ago (diff)

Forward port from Eraser 6.0: Completely fixes the bug address in r1041: GetPathADSes takes a value by "out", meaning whatever value the totalSize variable had before would have been overwritten. Fixed the code to work properly now. This would have reported the wrong amount of data that needs to be written to erase the file.

  • 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.Manager;
34using Eraser.Util;
35
36namespace Eraser.DefaultPlugins
37{
38    /// <summary>
39    /// Represents a folder and its files which are to be erased.
40    /// </summary>
41    [Serializable]
42    [Guid("F50B0A44-3AB1-4cab-B81E-1713AC3D28C9")]
43    public class FolderErasureTarget : FileSystemObjectErasureTarget
44    {
45        #region Serialization code
46        protected FolderErasureTarget(SerializationInfo info, StreamingContext context)
47            : base(info, context)
48        {
49            IncludeMask = (string)info.GetValue("IncludeMask", typeof(string));
50            ExcludeMask = (string)info.GetValue("ExcludeMask", typeof(string));
51            DeleteIfEmpty = (bool)info.GetValue("DeleteIfEmpty", typeof(bool));
52        }
53
54        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
55        public override void GetObjectData(SerializationInfo info, StreamingContext context)
56        {
57            base.GetObjectData(info, context);
58            info.AddValue("IncludeMask", IncludeMask);
59            info.AddValue("ExcludeMask", ExcludeMask);
60            info.AddValue("DeleteIfEmpty", DeleteIfEmpty);
61        }
62        #endregion
63
64        /// <summary>
65        /// Constructor.
66        /// </summary>
67        public FolderErasureTarget()
68        {
69            IncludeMask = string.Empty;
70            ExcludeMask = string.Empty;
71            DeleteIfEmpty = true;
72        }
73
74        public override Guid Guid
75        {
76            get { return GetType().GUID; }
77        }
78
79        public override string Name
80        {
81            get { return S._("Files in Folder"); }
82        }
83
84        public override IErasureTargetConfigurer Configurer
85        {
86            get { return new FolderErasureTargetConfigurer(); }
87        }
88
89        protected override List<string> GetPaths(out long totalSize)
90        {
91            //Get a list to hold all the resulting paths.
92            List<string> result = new List<string>();
93
94            //Open the root of the search, including every file matching the pattern
95            DirectoryInfo dir = new DirectoryInfo(Path);
96
97            //List recursively all the files which match the include pattern.
98            FileInfo[] files = GetFiles(dir);
99
100            //Then exclude each file and finalize the list and total file size
101            totalSize = 0;
102            if (ExcludeMask.Length != 0)
103            {
104                string regex = Regex.Escape(ExcludeMask).Replace("\\*", ".*").
105                    Replace("\\?", ".");
106                Regex excludePattern = new Regex(regex, RegexOptions.IgnoreCase);
107                foreach (FileInfo file in files)
108                    if (file.Exists &&
109                        (file.Attributes & FileAttributes.ReparsePoint) == 0 &&
110                        excludePattern.Matches(file.FullName).Count == 0)
111                    {
112                        totalSize += file.Length;
113                        long adsesSize = 0;
114                        GetPathADSes(result, out adsesSize, file.FullName);
115                        totalSize += adsesSize;
116                        result.Add(file.FullName);
117                    }
118            }
119            else
120                foreach (FileInfo file in files)
121                {
122                    if (!file.Exists || (file.Attributes & FileAttributes.ReparsePoint) != 0)
123                        continue;
124
125                    //Get the size of the file and its ADSes
126                    totalSize += file.Length;
127                    long adsesSize = 0;
128                    GetPathADSes(result, out adsesSize, file.FullName);
129                    totalSize += adsesSize;
130
131                    //Append this file to the list of files to erase.
132                    result.Add(file.FullName);
133                }
134
135            //Return the filtered list.
136            return result;
137        }
138
139        /// <summary>
140        /// Gets all files in the provided directory.
141        /// </summary>
142        /// <param name="info">The directory to look files in.</param>
143        /// <returns>A list of files found in the directory matching the IncludeMask
144        /// property.</returns>
145        private FileInfo[] GetFiles(DirectoryInfo info)
146        {
147            List<FileInfo> result = new List<FileInfo>();
148            if (info.Exists)
149            {
150                try
151                {
152                    foreach (DirectoryInfo dir in info.GetDirectories())
153                        result.AddRange(GetFiles(dir));
154
155                    if (IncludeMask.Length == 0)
156                        result.AddRange(info.GetFiles());
157                    else
158                        result.AddRange(info.GetFiles(IncludeMask, SearchOption.TopDirectoryOnly));
159                }
160                catch (UnauthorizedAccessException e)
161                {
162                    Logger.Log(S._("Could not erase files and subfolders in {0} because {1}",
163                        info.FullName, e.Message), LogLevel.Error);
164                }
165            }
166
167            return result.ToArray();
168        }
169
170        /// <summary>
171        /// A wildcard expression stating the condition for the set of files to include.
172        /// The include mask is applied before the exclude mask is applied. If this value
173        /// is empty, all files and folders within the folder specified is included.
174        /// </summary>
175        public string IncludeMask { get; set; }
176
177        /// <summary>
178        /// A wildcard expression stating the condition for removing files from the set
179        /// of included files. If this value is omitted, all files and folders extracted
180        /// by the inclusion mask is erased.
181        /// </summary>
182        public string ExcludeMask { get; set; }
183
184        /// <summary>
185        /// Determines if Eraser should delete the folder after the erase process.
186        /// </summary>
187        public bool DeleteIfEmpty { get; set; }
188
189        public override void Execute()
190        {
191            Progress = new SteppedProgressManager();
192            try
193            {
194                base.Execute();
195
196                //If the user requested a folder removal, do it.
197                if (Directory.Exists(Path))
198                {
199                    ProgressManager step = new ProgressManager();
200                    Progress.Steps.Add(new SteppedProgressManagerStep(step,
201                        0.0f, S._("Removing folders...")));
202
203                    //Remove all subfolders which are empty.
204                    FileSystem fsManager = ManagerLibrary.Instance.FileSystemRegistrar[
205                        VolumeInfo.FromMountPoint(Path)];
206                    Action<DirectoryInfo> eraseEmptySubFolders = null;
207                    eraseEmptySubFolders = delegate(DirectoryInfo info)
208                    {
209                        foreach (DirectoryInfo subDir in info.GetDirectories())
210                            eraseEmptySubFolders(subDir);
211                        OnProgressChanged(this, new ProgressChangedEventArgs(step,
212                            new TaskProgressChangedEventArgs(info.FullName, 0, 0)));
213
214                        FileSystemInfo[] files = info.GetFileSystemInfos();
215                        if (files.Length == 0)
216                            fsManager.DeleteFolder(info);
217                    };
218
219                    DirectoryInfo directory = new DirectoryInfo(Path);
220                    foreach (DirectoryInfo subDir in directory.GetDirectories())
221                        eraseEmptySubFolders(subDir);
222
223                    if (DeleteIfEmpty)
224                    {
225                        //See if this is the root of a volume.
226                        bool isVolumeRoot = directory.Parent == null;
227                        foreach (VolumeInfo volume in VolumeInfo.Volumes)
228                            foreach (string mountPoint in volume.MountPoints)
229                                if (directory.FullName == mountPoint)
230                                    isVolumeRoot = true;
231
232                        //If the folder is a mount point, then don't delete it. If it isn't,
233                        //search for files under the folder to see if it is empty.
234                        if (!isVolumeRoot && directory.Exists &&
235                            directory.GetFiles("*", SearchOption.AllDirectories).Length == 0)
236                        {
237                            fsManager.DeleteFolder(directory);
238                        }
239                    }
240                }
241            }
242            finally
243            {
244                Progress = null;
245            }
246        }
247    }
248}
Note: See TracBrowser for help on using the repository browser.