source: trunk/eraser/Eraser.Manager/ErasureTarget.cs @ 2023

Revision 2023, 19.5 KB checked in by lowjoel, 4 years ago (diff)

Create placeholders to configure the different erasure target types.

  • 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.Security.Permissions;
29using System.IO;
30using System.Runtime.Serialization;
31
32using Eraser.Util;
33using Eraser.Util.ExtensionMethods;
34
35namespace Eraser.Manager
36{
37    /// <summary>
38    /// Represents a generic target of erasure
39    /// </summary>
40    [Serializable]
41    public abstract class ErasureTarget : ISerializable
42    {
43        #region Serialization code
44        protected ErasureTarget(SerializationInfo info, StreamingContext context)
45        {
46            Guid methodGuid = (Guid)info.GetValue("Method", typeof(Guid));
47            if (methodGuid == Guid.Empty)
48                Method = ErasureMethodRegistrar.Default;
49            else
50                Method = ManagerLibrary.Instance.ErasureMethodRegistrar[methodGuid];
51        }
52
53        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
54        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
55        {
56            info.AddValue("Method", Method.Guid);
57        }
58        #endregion
59
60        /// <summary>
61        /// Constructor.
62        /// </summary>
63        protected ErasureTarget()
64        {
65            Method = ErasureMethodRegistrar.Default;
66        }
67
68        /// <summary>
69        /// The task which owns this target.
70        /// </summary>
71        public Task Task { get; internal set; }
72
73        /// <summary>
74        /// The method used for erasing the file.
75        /// </summary>
76        public ErasureMethod Method
77        {
78            get;
79            set;
80        }
81
82        /// <summary>
83        /// Gets the effective erasure method for the current target (i.e., returns
84        /// the correct erasure method for cases where the <see cref="Method"/>
85        /// property is <see cref="ErasureMethodRegistrar.Default"/>
86        /// </summary>
87        /// <returns>The Erasure method which the target should be erased with.
88        /// This function will never return <see cref="ErasureMethodRegistrar.Default"/></returns>
89        public virtual ErasureMethod EffectiveMethod
90        {
91            get
92            {
93                if (Method != ErasureMethodRegistrar.Default)
94                    return Method;
95
96                throw new InvalidOperationException("The effective method of the erasure " +
97                    "target cannot be ErasureMethodRegistrar.Default");
98            }
99        }
100
101        /// <summary>
102        /// Retrieves the text to display representing this task.
103        /// </summary>
104        public abstract string UIText
105        {
106            get;
107        }
108
109        /// <summary>
110        /// The progress of this target.
111        /// </summary>
112        public ProgressManagerBase Progress
113        {
114            get;
115            internal set;
116        }
117
118        /// <summary>
119        /// Gets a control which contains settings for configuring this task, or
120        /// null if this erasure target has no settings to be set.
121        /// </summary>
122        /// <remarks>The result should be able to be passed to the <see cref="Configure"/>
123        /// function, and settings for this task will be according to the returned
124        /// control.</remarks>
125        public abstract System.Windows.Forms.Control SettingsPanel
126        {
127            get;
128        }
129
130        /// <summary>
131        /// Configures the current task based on settings specified in the control
132        /// returned by the <see cref="SettingsPanel"/> property.
133        /// </summary>
134        /// <param name="settingsPanel">A settings panel returned by the
135        /// <see cref="SettingsPanel"/> property, which contains the user-selected
136        /// settings.</param>
137        public abstract void Configure(System.Windows.Forms.Control settingsPanel);
138
139        /// <summary>
140        /// Executes the given task.
141        /// </summary>
142        /// <param name="progress">The progress manager instance which is used to
143        /// track the progress of the current target's erasure.</param>
144        public virtual void Execute(ProgressManagerBase progress)
145        {
146        }
147    }
148
149    /// <summary>
150    /// Class representing a tangible object (file/folder) to be erased.
151    /// </summary>
152    [Serializable]
153    public abstract class FileSystemObjectTarget : ErasureTarget
154    {
155        #region Serialization code
156        protected FileSystemObjectTarget(SerializationInfo info, StreamingContext context)
157            : base(info, context)
158        {
159            Path = (string)info.GetValue("Path", typeof(string));
160        }
161
162        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
163        public override void GetObjectData(SerializationInfo info, StreamingContext context)
164        {
165            base.GetObjectData(info, context);
166            info.AddValue("Path", Path);
167        }
168        #endregion
169
170        /// <summary>
171        /// Constructor.
172        /// </summary>
173        protected FileSystemObjectTarget()
174            : base()
175        {
176        }
177
178        /// <summary>
179        /// Retrieves the list of files/folders to erase as a list.
180        /// </summary>
181        /// <param name="totalSize">Returns the total size in bytes of the
182        /// items.</param>
183        /// <returns>A list containing the paths to all the files to be erased.</returns>
184        internal abstract List<string> GetPaths(out long totalSize);
185
186        /// <summary>
187        /// Adds ADSes of the given file to the list.
188        /// </summary>
189        /// <param name="list">The list to add the ADS paths to.</param>
190        /// <param name="file">The file to look for ADSes</param>
191        protected void GetPathADSes(ICollection<string> list, out long totalSize, string file)
192        {
193            totalSize = 0;
194
195            try
196            {
197                //Get the ADS names
198                IList<string> adses = new FileInfo(file).GetADSes();
199
200                //Then prepend the path.
201                foreach (string adsName in adses)
202                {
203                    string adsPath = file + ':' + adsName;
204                    list.Add(adsPath);
205                    StreamInfo info = new StreamInfo(adsPath);
206                    totalSize += info.Length;
207                }
208            }
209            catch (FileNotFoundException)
210            {
211            }
212            catch (SharingViolationException)
213            {
214                //The system cannot open the file, try to force the file handle to close.
215                if (!ManagerLibrary.Settings.ForceUnlockLockedFiles)
216                    throw;
217
218                foreach (OpenHandle handle in OpenHandle.Items)
219                    if (handle.Path == file && handle.Close())
220                    {
221                        GetPathADSes(list, out totalSize, file);
222                        return;
223                    }
224            }
225            catch (UnauthorizedAccessException e)
226            {
227                //The system cannot read the file, assume no ADSes for lack of
228                //more information.
229                Logger.Log(e.Message, LogLevel.Error);
230            }
231        }
232
233        /// <summary>
234        /// The path to the file or folder referred to by this object.
235        /// </summary>
236        public string Path { get; set; }
237
238        public sealed override ErasureMethod EffectiveMethod
239        {
240            get
241            {
242                if (Method == ErasureMethodRegistrar.Default)
243                    return base.EffectiveMethod;
244
245                return ManagerLibrary.Instance.ErasureMethodRegistrar[
246                    ManagerLibrary.Settings.DefaultFileErasureMethod];
247            }
248        }
249
250        public override string UIText
251        {
252            get
253            {
254                string fileName = System.IO.Path.GetFileName(Path);
255                string directoryName = System.IO.Path.GetDirectoryName(Path);
256                return string.IsNullOrEmpty(fileName) ?
257                        (string.IsNullOrEmpty(directoryName) ? Path : directoryName)
258                    : fileName;
259            }
260        }
261    }
262
263    /// <summary>
264    /// Class representing a unused space erase.
265    /// </summary>
266    [Serializable]
267    public class UnusedSpaceTarget : ErasureTarget
268    {
269        #region Serialization code
270        protected UnusedSpaceTarget(SerializationInfo info, StreamingContext context)
271            : base(info, context)
272        {
273            Drive = (string)info.GetValue("Drive", typeof(string));
274            EraseClusterTips = (bool)info.GetValue("EraseClusterTips", typeof(bool));
275        }
276
277        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
278        public override void GetObjectData(SerializationInfo info, StreamingContext context)
279        {
280            base.GetObjectData(info, context);
281            info.AddValue("Drive", Drive);
282            info.AddValue("EraseClusterTips", EraseClusterTips);
283        }
284        #endregion
285
286        /// <summary>
287        /// Constructor.
288        /// </summary>
289        public UnusedSpaceTarget()
290            : base()
291        {
292        }
293
294        public sealed override ErasureMethod EffectiveMethod
295        {
296            get
297            {
298                if (Method == ErasureMethodRegistrar.Default)
299                    return base.EffectiveMethod;
300
301                return ManagerLibrary.Instance.ErasureMethodRegistrar[
302                    ManagerLibrary.Settings.DefaultUnusedSpaceErasureMethod];
303            }
304        }
305
306        public override string UIText
307        {
308            get { return S._("Unused disk space ({0})", Drive); }
309        }
310
311        public override System.Windows.Forms.Control SettingsPanel
312        {
313            get { return new UnusedSpaceErasureTargetSettings(); }
314        }
315
316        public override void Configure(System.Windows.Forms.Control settingsPanel)
317        {
318            throw new NotImplementedException();
319        }
320
321        /// <summary>
322        /// The drive to erase
323        /// </summary>
324        public string Drive { get; set; }
325
326        /// <summary>
327        /// Whether cluster tips should be erased.
328        /// </summary>
329        public bool EraseClusterTips { get; set; }
330    }
331
332    /// <summary>
333    /// Class representing a file to be erased.
334    /// </summary>
335    [Serializable]
336    public class FileTarget : FileSystemObjectTarget
337    {
338        #region Serialization code
339        protected FileTarget(SerializationInfo info, StreamingContext context)
340            : base(info, context)
341        {
342        }
343        #endregion
344
345        /// <summary>
346        /// Constructor.
347        /// </summary>
348        public FileTarget()
349        {
350        }
351
352        public override System.Windows.Forms.Control SettingsPanel
353        {
354            get { return new FileErasureTargetSettings(); }
355        }
356
357        public override void Configure(System.Windows.Forms.Control settingsPanel)
358        {
359            throw new NotImplementedException();
360        }
361
362        internal override List<string> GetPaths(out long totalSize)
363        {
364            totalSize = 0;
365            List<string> result = new List<string>();
366            FileInfo fileInfo = new FileInfo(Path);
367
368            if (fileInfo.Exists)
369            {
370                GetPathADSes(result, out totalSize, Path);
371                totalSize += fileInfo.Length;
372            }
373
374            result.Add(Path);
375            return result;
376        }
377    }
378
379    /// <summary>
380    /// Represents a folder and its files which are to be erased.
381    /// </summary>
382    [Serializable]
383    public class FolderTarget : FileSystemObjectTarget
384    {
385        #region Serialization code
386        protected FolderTarget(SerializationInfo info, StreamingContext context)
387            : base(info, context)
388        {
389            IncludeMask = (string)info.GetValue("IncludeMask", typeof(string));
390            ExcludeMask = (string)info.GetValue("ExcludeMask", typeof(string));
391            DeleteIfEmpty = (bool)info.GetValue("DeleteIfEmpty", typeof(bool));
392        }
393
394        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
395        public override void GetObjectData(SerializationInfo info, StreamingContext context)
396        {
397            base.GetObjectData(info, context);
398            info.AddValue("IncludeMask", IncludeMask);
399            info.AddValue("ExcludeMask", ExcludeMask);
400            info.AddValue("DeleteIfEmpty", DeleteIfEmpty);
401        }
402        #endregion
403
404        /// <summary>
405        /// Constructor.
406        /// </summary>
407        public FolderTarget()
408        {
409            IncludeMask = string.Empty;
410            ExcludeMask = string.Empty;
411            DeleteIfEmpty = true;
412        }
413
414        public override System.Windows.Forms.Control SettingsPanel
415        {
416            get { return new FolderErasureTargetSettings(); }
417        }
418
419        public override void Configure(System.Windows.Forms.Control settingsPanel)
420        {
421            throw new NotImplementedException();
422        }
423
424        internal override List<string> GetPaths(out long totalSize)
425        {
426            //Get a list to hold all the resulting paths.
427            List<string> result = new List<string>();
428
429            //Open the root of the search, including every file matching the pattern
430            DirectoryInfo dir = new DirectoryInfo(Path);
431
432            //List recursively all the files which match the include pattern.
433            FileInfo[] files = GetFiles(dir);
434
435            //Then exclude each file and finalize the list and total file size
436            totalSize = 0;
437            if (ExcludeMask.Length != 0)
438            {
439                string regex = Regex.Escape(ExcludeMask).Replace("\\*", ".*").
440                    Replace("\\?", ".");
441                Regex excludePattern = new Regex(regex, RegexOptions.IgnoreCase);
442                foreach (FileInfo file in files)
443                    if (file.Exists &&
444                        (file.Attributes & FileAttributes.ReparsePoint) == 0 &&
445                        excludePattern.Matches(file.FullName).Count == 0)
446                    {
447                        totalSize += file.Length;
448                        GetPathADSes(result, out totalSize, file.FullName);
449                        result.Add(file.FullName);
450                    }
451            }
452            else
453                foreach (FileInfo file in files)
454                {
455                    if (!file.Exists || (file.Attributes & FileAttributes.ReparsePoint) != 0)
456                        continue;
457
458                    //Get the size of the file and its ADSes
459                    totalSize += file.Length;
460                    long adsesSize = 0;
461                    GetPathADSes(result, out adsesSize, file.FullName);
462                    totalSize += adsesSize;
463
464                    //Append this file to the list of files to erase.
465                    result.Add(file.FullName);
466                }
467
468            //Return the filtered list.
469            return result;
470        }
471
472        /// <summary>
473        /// Gets all files in the provided directory.
474        /// </summary>
475        /// <param name="info">The directory to look files in.</param>
476        /// <returns>A list of files found in the directory matching the IncludeMask
477        /// property.</returns>
478        private FileInfo[] GetFiles(DirectoryInfo info)
479        {
480            List<FileInfo> result = new List<FileInfo>();
481            if (info.Exists)
482            {
483                try
484                {
485                    foreach (DirectoryInfo dir in info.GetDirectories())
486                        result.AddRange(GetFiles(dir));
487
488                    if (IncludeMask.Length == 0)
489                        result.AddRange(info.GetFiles());
490                    else
491                        result.AddRange(info.GetFiles(IncludeMask, SearchOption.TopDirectoryOnly));
492                }
493                catch (UnauthorizedAccessException e)
494                {
495                    Logger.Log(S._("Could not erase files and subfolders in {0} because {1}",
496                        info.FullName, e.Message), LogLevel.Error);
497                }
498            }
499
500            return result.ToArray();
501        }
502
503        /// <summary>
504        /// A wildcard expression stating the condition for the set of files to include.
505        /// The include mask is applied before the exclude mask is applied. If this value
506        /// is empty, all files and folders within the folder specified is included.
507        /// </summary>
508        public string IncludeMask { get; set; }
509
510        /// <summary>
511        /// A wildcard expression stating the condition for removing files from the set
512        /// of included files. If this value is omitted, all files and folders extracted
513        /// by the inclusion mask is erased.
514        /// </summary>
515        public string ExcludeMask { get; set; }
516
517        /// <summary>
518        /// Determines if Eraser should delete the folder after the erase process.
519        /// </summary>
520        public bool DeleteIfEmpty { get; set; }
521    }
522
523    [Serializable]
524    public class RecycleBinTarget : FileSystemObjectTarget
525    {
526        #region Serialization code
527        protected RecycleBinTarget(SerializationInfo info, StreamingContext context)
528            : base(info, context)
529        {
530        }
531        #endregion
532
533        public RecycleBinTarget()
534        {
535        }
536
537        public override System.Windows.Forms.Control SettingsPanel
538        {
539            get { return null; }
540        }
541
542        public override void Configure(System.Windows.Forms.Control settingsPanel)
543        {
544            throw new InvalidOperationException("The RecycleBinTarget class has no settings to " +
545                "be set.");
546        }
547
548        internal override List<string> GetPaths(out long totalSize)
549        {
550            totalSize = 0;
551            List<string> result = new List<string>();
552            string[] rootDirectory = new string[] {
553                    "$RECYCLE.BIN",
554                    "RECYCLER"
555                };
556
557            foreach (DriveInfo drive in DriveInfo.GetDrives())
558            {
559                foreach (string rootDir in rootDirectory)
560                {
561                    DirectoryInfo dir = new DirectoryInfo(
562                        System.IO.Path.Combine(
563                            System.IO.Path.Combine(drive.Name, rootDir),
564                            System.Security.Principal.WindowsIdentity.GetCurrent().
565                                User.ToString()));
566                    if (!dir.Exists)
567                        continue;
568
569                    GetRecyclerFiles(dir, result, ref totalSize);
570                }
571            }
572
573            return result;
574        }
575
576        /// <summary>
577        /// Retrieves all files within this folder, without exclusions.
578        /// </summary>
579        /// <param name="info">The DirectoryInfo object representing the folder to traverse.</param>
580        /// <param name="paths">The list of files to store path information in.</param>
581        /// <param name="totalSize">Receives the total size of the files.</param>
582        private void GetRecyclerFiles(DirectoryInfo info, List<string> paths,
583            ref long totalSize)
584        {
585            try
586            {
587                foreach (FileInfo fileInfo in info.GetFiles())
588                {
589                    if (!fileInfo.Exists || (fileInfo.Attributes & FileAttributes.ReparsePoint) != 0)
590                        continue;
591
592                    long adsSize = 0;
593                    GetPathADSes(paths, out adsSize, fileInfo.FullName);
594                    totalSize += adsSize;
595                    totalSize += fileInfo.Length;
596                    paths.Add(fileInfo.FullName);
597                }
598
599                foreach (DirectoryInfo directoryInfo in info.GetDirectories())
600                    if ((directoryInfo.Attributes & FileAttributes.ReparsePoint) == 0)
601                        GetRecyclerFiles(directoryInfo, paths, ref totalSize);
602            }
603            catch (UnauthorizedAccessException e)
604            {
605                Logger.Log(e.Message, LogLevel.Error);
606            }
607        }
608
609        /// <summary>
610        /// Retrieves the text to display representing this task.
611        /// </summary>
612        public override string UIText
613        {
614            get
615            {
616                return S._("Recycle Bin");
617            }
618        }
619    }
620
621    /// <summary>
622    /// Maintains a collection of erasure targets.
623    /// </summary>
624    [Serializable]
625    public class ErasureTargetsCollection : IList<ErasureTarget>, ISerializable
626    {
627        #region Constructors
628        internal ErasureTargetsCollection(Task owner)
629        {
630            this.list = new List<ErasureTarget>();
631            this.owner = owner;
632        }
633
634        internal ErasureTargetsCollection(Task owner, int capacity)
635            : this(owner)
636        {
637            list.Capacity = capacity;
638        }
639
640        internal ErasureTargetsCollection(Task owner, IEnumerable<ErasureTarget> targets)
641            : this(owner)
642        {
643            list.AddRange(targets);
644        }
645        #endregion
646
647        #region Serialization Code
648        protected ErasureTargetsCollection(SerializationInfo info, StreamingContext context)
649        {
650            list = (List<ErasureTarget>)info.GetValue("list", typeof(List<ErasureTarget>));
651        }
652
653        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
654        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
655        {
656            info.AddValue("list", list);
657        }
658        #endregion
659
660        #region IEnumerable<ErasureTarget> Members
661        public IEnumerator<ErasureTarget> GetEnumerator()
662        {
663            return list.GetEnumerator();
664        }
665        #endregion
666
667        #region IEnumerable Members
668        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
669        {
670            return GetEnumerator();
671        }
672        #endregion
673
674        #region ICollection<ErasureTarget> Members
675        public void Add(ErasureTarget item)
676        {
677            item.Task = owner;
678            list.Add(item);
679        }
680
681        public void Clear()
682        {
683            foreach (ErasureTarget item in list)
684                Remove(item);
685        }
686
687        public bool Contains(ErasureTarget item)
688        {
689            return list.Contains(item);
690        }
691
692        public void CopyTo(ErasureTarget[] array, int arrayIndex)
693        {
694            list.CopyTo(array, arrayIndex);
695        }
696
697        public int Count
698        {
699            get
700            {
701                return list.Count;
702            }
703        }
704
705        public bool IsReadOnly
706        {
707            get
708            {
709                return false;
710            }
711        }
712
713        public bool Remove(ErasureTarget item)
714        {
715            int index = list.IndexOf(item);
716            if (index < 0)
717                return false;
718
719            RemoveAt(index);
720            return true;
721        }
722        #endregion
723
724        #region IList<ErasureTarget> Members
725        public int IndexOf(ErasureTarget item)
726        {
727            return list.IndexOf(item);
728        }
729
730        public void Insert(int index, ErasureTarget item)
731        {
732            item.Task = owner;
733            list.Insert(index, item);
734        }
735
736        public void RemoveAt(int index)
737        {
738            list.RemoveAt(index);
739        }
740
741        public ErasureTarget this[int index]
742        {
743            get
744            {
745                return list[index];
746            }
747            set
748            {
749                list[index] = value;
750            }
751        }
752        #endregion
753
754        /// <summary>
755        /// The owner of this list of targets.
756        /// </summary>
757        public Task Owner
758        {
759            get
760            {
761                return owner;
762            }
763            internal set
764            {
765                owner = value;
766                foreach (ErasureTarget target in list)
767                    target.Task = owner;
768            }
769        }
770
771        /// <summary>
772        /// The owner of this list of targets. All targets added to this list
773        /// will have the owner set to this object.
774        /// </summary>
775        private Task owner;
776
777        /// <summary>
778        /// The list bring the data store behind this object.
779        /// </summary>
780        private List<ErasureTarget> list;
781    }
782}
Note: See TracBrowser for help on using the repository browser.