source: branches/eraser6/CodeReview/Eraser.Manager/Task.cs @ 1792

Revision 1792, 26.8 KB checked in by lowjoel, 5 years ago (diff)

Implemented an IRegistrar interface for all registrars, and an IRegisterable interface for all classes which need to be registered with IRegistrar, and migrated the Entropy and Erasure Method classes to the new interfaces. Addresses #276: Implement Eraser Registrar Interface

  • 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.Text;
25using System.IO;
26using System.Text.RegularExpressions;
27using System.Runtime.Serialization;
28using System.Security.Permissions;
29using System.Threading;
30
31using Eraser.Util;
32using Eraser.Util.ExtensionMethods;
33
34namespace Eraser.Manager
35{
36    /// <summary>
37    /// Deals with an erase task.
38    /// </summary>
39    [Serializable]
40    public class Task : ISerializable
41    {
42        #region Serialization code
43        protected Task(SerializationInfo info, StreamingContext context)
44        {
45            Name = (string)info.GetValue("Name", typeof(string));
46            Executor = context.Context as Executor;
47            Targets = (ErasureTargetsCollection)info.GetValue("Targets", typeof(ErasureTargetsCollection));
48            Targets.Owner = this;
49            Log = (List<LogSink>)info.GetValue("Log", typeof(List<LogSink>));
50            Canceled = false;
51
52            Schedule schedule = (Schedule)info.GetValue("Schedule", typeof(Schedule));
53            if (schedule.GetType() == Schedule.RunManually.GetType())
54                Schedule = Schedule.RunManually;
55            else if (schedule.GetType() == Schedule.RunNow.GetType())
56                Schedule = Schedule.RunNow;
57            else if (schedule.GetType() == Schedule.RunOnRestart.GetType())
58                Schedule = Schedule.RunOnRestart;
59            else if (schedule is RecurringSchedule)
60                Schedule = schedule;
61            else
62                throw new InvalidDataException(S._("An invalid type was found when loading " +
63                    "the task schedule"));
64        }
65
66        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
67        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
68        {
69            info.AddValue("Name", Name);
70            info.AddValue("Schedule", Schedule);
71            info.AddValue("Targets", Targets);
72            info.AddValue("Log", Log);
73        }
74        #endregion
75
76        /// <summary>
77        /// Constructor.
78        /// </summary>
79        public Task()
80        {
81            Name = string.Empty;
82            Targets = new ErasureTargetsCollection(this);
83            Schedule = Schedule.RunNow;
84            Canceled = false;
85            Log = new List<LogSink>();
86        }
87
88        /// <summary>
89        /// Cancels the task from running, or, if the task is queued for running,
90        /// removes the task from the queue.
91        /// </summary>
92        public void Cancel()
93        {
94            Executor.UnqueueTask(this);
95            Canceled = true;
96        }
97
98        /// <summary>
99        /// The Executor object which is managing this task.
100        /// </summary>
101        public Executor Executor { get; internal set; }
102
103        /// <summary>
104        /// The name for this task. This is just an opaque value for the user to
105        /// recognize the task.
106        /// </summary>
107        public string Name { get; set; }
108
109        /// <summary>
110        /// The name of the task, used for display in UI elements.
111        /// </summary>
112        public string UIText
113        {
114            get
115            {
116                //Simple case, the task name was given by the user.
117                if (Name.Length != 0)
118                    return Name;
119
120                string result = string.Empty;
121                if (Targets.Count < 5)
122                {
123                    //Simpler case, small set of data.
124                    foreach (ErasureTarget tgt in Targets)
125                        result += tgt.UIText + ", ";
126
127                    return result.Remove(result.Length - 2);
128                }
129                else
130                {
131                    //Ok, we've quite a few entries, get the first, the mid and the end.
132                    result = Targets[0].UIText + ", ";
133                    result += Targets[Targets.Count / 2].UIText + ", ";
134                    result += Targets[Targets.Count - 1].UIText;
135
136                    return S._("{0} and {1} other targets", result, Targets.Count - 3);
137                }
138            }
139        }
140
141        /// <summary>
142        /// Gets the status of the task - whether it is being executed.
143        /// </summary>
144        public bool Executing { get; private set; }
145
146        /// <summary>
147        /// Gets whether this task is currently queued to run. This is true only
148        /// if the queue it is in is an explicit request, i.e will run when the
149        /// executor is idle.
150        /// </summary>
151        public bool Queued
152        {
153            get
154            {
155                return Executor.IsTaskQueued(this);
156            }
157        }
158
159        /// <summary>
160        /// Gets whether the task has been cancelled from execution.
161        /// </summary>
162        public bool Canceled
163        {
164            get;
165            internal set;
166        }
167
168        /// <summary>
169        /// The set of data to erase when this task is executed.
170        /// </summary>
171        public ErasureTargetsCollection Targets { get; private set; }
172
173        /// <summary>
174        /// The schedule for running the task.
175        /// </summary>
176        public Schedule Schedule
177        {
178            get
179            {
180                return schedule;
181            }
182            set
183            {
184                if (value.Owner != null)
185                    throw new ArgumentException("The schedule provided can only " +
186                        "belong to one task at a time");
187
188                if (schedule is RecurringSchedule)
189                    ((RecurringSchedule)schedule).Owner = null;
190                schedule = value;
191                if (schedule is RecurringSchedule)
192                    ((RecurringSchedule)schedule).Owner = this;
193                OnTaskEdited();
194            }
195        }
196
197        /// <summary>
198        /// The log entries which this task has accumulated.
199        /// </summary>
200        public List<LogSink> Log { get; private set; }
201
202        /// <summary>
203        /// The progress manager object which manages the progress of this task.
204        /// </summary>
205        public SteppedProgressManager Progress
206        {
207            get
208            {
209                if (!Executing)
210                    throw new InvalidOperationException("The progress of an erasure can only " +
211                        "be queried when the task is being executed.");
212
213                return progress;
214            }
215            private set
216            {
217                progress = value;
218            }
219        }
220
221        private Schedule schedule;
222        private SteppedProgressManager progress;
223
224        #region Events
225        /// <summary>
226        /// The task has been edited.
227        /// </summary>
228        public EventHandler TaskEdited { get; set; }
229
230        /// <summary>
231        /// The start of the execution of a task.
232        /// </summary>
233        public EventHandler TaskStarted { get; set; }
234
235        /// <summary>
236        /// The event object holding all event handlers.
237        /// </summary>
238        public EventHandler<ProgressChangedEventArgs> ProgressChanged { get; set; }
239
240        /// <summary>
241        /// The completion of the execution of a task.
242        /// </summary>
243        public EventHandler TaskFinished { get; set; }
244
245        /// <summary>
246        /// Broadcasts the task edited event.
247        /// </summary>
248        internal void OnTaskEdited()
249        {
250            if (TaskEdited != null)
251                TaskEdited(this, EventArgs.Empty);
252        }
253
254        /// <summary>
255        /// Broadcasts the task execution start event.
256        /// </summary>
257        internal void OnTaskStarted()
258        {
259            if (TaskStarted != null)
260                TaskStarted(this, EventArgs.Empty);
261            Executing = true;
262            Progress = new SteppedProgressManager();
263        }
264
265        /// <summary>
266        /// Broadcasts a ProgressChanged event. The sender will be the erasure target
267        /// which broadcast this event; e.UserState will contain extra information
268        /// about the progress which is stored as a TaskProgressChangedEventArgs
269        /// object.
270        /// </summary>
271        /// <param name="sender">The <see cref="ErasureTarget"/> which is reporting
272        /// progress.</param>
273        /// <param name="e">The new progress value.</param>
274        /// <exception cref="ArgumentException">e.UserState must be of the type
275        /// <see cref="TaskProgressEventargs"/></exception>
276        /// <exception cref="ArgumentNullException">Both sender and e cannot be null.</exception>
277        internal void OnProgressChanged(ErasureTarget sender, ProgressChangedEventArgs e)
278        {
279            if (sender == null)
280                throw new ArgumentNullException("sender");
281            if (e == null)
282                throw new ArgumentNullException("sender");
283            if (e.UserState.GetType() != typeof(TaskProgressChangedEventArgs))
284                throw new ArgumentException("The Task.OnProgressChanged event expects a " +
285                    "TaskProgressEventArgs argument for the ProgressChangedEventArgs' UserState " +
286                    "object.", "e");
287
288            if (ProgressChanged != null)
289                ProgressChanged(sender, e);
290        }
291
292        /// <summary>
293        /// Broadcasts the task execution completion event.
294        /// </summary>
295        internal void OnTaskFinished()
296        {
297            if (TaskFinished != null)
298                TaskFinished(this, EventArgs.Empty);
299            Executing = false;
300            Progress = null;
301        }
302        #endregion
303    }
304
305    /// <summary>
306    /// Represents a generic target of erasure
307    /// </summary>
308    [Serializable]
309    public abstract class ErasureTarget : ISerializable
310    {
311        #region Serialization code
312        protected ErasureTarget(SerializationInfo info, StreamingContext context)
313        {
314            Guid methodGuid = (Guid)info.GetValue("Method", typeof(Guid));
315            if (methodGuid == Guid.Empty)
316                method = ErasureMethodRegistrar.Default;
317            else
318                method = ManagerLibrary.Instance.ErasureMethodManager[methodGuid];
319        }
320
321        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
322        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
323        {
324            info.AddValue("Method", method.Guid);
325        }
326        #endregion
327
328        /// <summary>
329        /// Constructor.
330        /// </summary>
331        protected ErasureTarget()
332        {
333        }
334
335        /// <summary>
336        /// The method used for erasing the file. If the variable is equal to
337        /// ErasureMethodManager.Default then the default is queried for the
338        /// task type. Check the <see cref="MethodDefined"/> property to see if
339        /// this variable was set on deliberately or if the result of the get
340        /// call is from the inferred default.
341        /// </summary>
342        public virtual ErasureMethod Method
343        {
344            get
345            {
346                return method;
347            }
348            set
349            {
350                method = value;
351                MethodDefined = method != ErasureMethodRegistrar.Default;
352            }
353        }
354
355        /// <summary>
356        /// Checks whether a method has been selected for this target. This is
357        /// because the Method property will return non-default erasure methods
358        /// only.
359        /// </summary>
360        public bool MethodDefined { get; private set; }
361
362        /// <summary>
363        /// The task which owns this target.
364        /// </summary>
365        public Task Task { get; internal set; }
366
367        /// <summary>
368        /// Retrieves the text to display representing this task.
369        /// </summary>
370        public abstract string UIText
371        {
372            get;
373        }
374
375        /// <summary>
376        /// Retrieves the amount of data that needs to be written in order to
377        /// complete the erasure.
378        /// </summary>
379        public abstract long TotalData
380        {
381            get;
382        }
383
384        /// <summary>
385        /// Erasure method to use for the target.
386        /// </summary>
387        private ErasureMethod method;
388
389        /// <summary>
390        /// The progress of this target.
391        /// </summary>
392        public ProgressManagerBase Progress
393        {
394            get;
395            internal set;
396        }
397    }
398
399    /// <summary>
400    /// Class representing a tangible object (file/folder) to be erased.
401    /// </summary>
402    [Serializable]
403    public abstract class FileSystemObjectTarget : ErasureTarget
404    {
405        #region Serialization code
406        protected FileSystemObjectTarget(SerializationInfo info, StreamingContext context)
407            : base(info, context)
408        {
409            Path = (string)info.GetValue("Path", typeof(string));
410        }
411
412        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
413        public override void GetObjectData(SerializationInfo info, StreamingContext context)
414        {
415            base.GetObjectData(info, context);
416            info.AddValue("Path", Path);
417        }
418        #endregion
419
420        /// <summary>
421        /// Constructor.
422        /// </summary>
423        protected FileSystemObjectTarget()
424            : base()
425        {
426            Method = ErasureMethodRegistrar.Default;
427        }
428
429        /// <summary>
430        /// Retrieves the list of files/folders to erase as a list.
431        /// </summary>
432        /// <param name="totalSize">Returns the total size in bytes of the
433        /// items.</param>
434        /// <returns>A list containing the paths to all the files to be erased.</returns>
435        internal abstract List<string> GetPaths(out long totalSize);
436
437        /// <summary>
438        /// Adds ADSes of the given file to the list.
439        /// </summary>
440        /// <param name="list">The list to add the ADS paths to.</param>
441        /// <param name="file">The file to look for ADSes</param>
442        protected void GetPathADSes(ICollection<string> list, out long totalSize, string file)
443        {
444            totalSize = 0;
445
446            try
447            {
448                //Get the ADS names
449                IList<string> adses = new FileInfo(file).GetADSes();
450
451                //Then prepend the path.
452                foreach (string adsName in adses)
453                {
454                    string adsPath = file + ':' + adsName;
455                    list.Add(adsPath);
456                    StreamInfo info = new StreamInfo(adsPath);
457                    totalSize += info.Length;
458                }
459            }
460            catch (IOException)
461            {
462                if (System.Runtime.InteropServices.Marshal.GetLastWin32Error() ==
463                    Win32ErrorCode.SharingViolation)
464                {
465                    //The system cannot open the file, try to force the file handle to close.
466                    if (!ManagerLibrary.Settings.ForceUnlockLockedFiles)
467                        throw;
468
469                    foreach (OpenHandle handle in OpenHandle.Items)
470                        if (handle.Path == file && handle.Close())
471                        {
472                            GetPathADSes(list, out totalSize, file);
473                            return;
474                        }
475                }
476                else
477                    throw;
478            }
479            catch (UnauthorizedAccessException e)
480            {
481                //The system cannot read the file, assume no ADSes for lack of
482                //more information.
483                Logger.Log(e.Message, LogLevel.Error);
484            }
485        }
486
487        /// <summary>
488        /// The path to the file or folder referred to by this object.
489        /// </summary>
490        public string Path { get; set; }
491
492        public sealed override ErasureMethod Method
493        {
494            get
495            {
496                if (base.MethodDefined)
497                    return base.Method;
498                return ManagerLibrary.Instance.ErasureMethodManager[
499                    ManagerLibrary.Settings.DefaultFileErasureMethod];
500            }
501            set
502            {
503                base.Method = value;
504            }
505        }
506
507        public override string UIText
508        {
509            get
510            {
511                string fileName = System.IO.Path.GetFileName(Path);
512                string directoryName = System.IO.Path.GetDirectoryName(Path);
513                return string.IsNullOrEmpty(fileName) ? 
514                        (string.IsNullOrEmpty(directoryName) ? Path : directoryName)
515                    : fileName;
516            }
517        }
518
519        public override long TotalData
520        {
521            get
522            {
523                long totalSize = 0;
524                List<string> paths = GetPaths(out totalSize);
525                return Method.CalculateEraseDataSize(paths, totalSize);
526            }
527        }
528    }
529
530    /// <summary>
531    /// Class representing a unused space erase.
532    /// </summary>
533    [Serializable]
534    public class UnusedSpaceTarget : ErasureTarget
535    {
536        #region Serialization code
537        protected UnusedSpaceTarget(SerializationInfo info, StreamingContext context)
538            : base(info, context)
539        {
540            Drive = (string)info.GetValue("Drive", typeof(string));
541            EraseClusterTips = (bool)info.GetValue("EraseClusterTips", typeof(bool));
542        }
543
544        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
545        public override void GetObjectData(SerializationInfo info, StreamingContext context)
546        {
547            base.GetObjectData(info, context);
548            info.AddValue("Drive", Drive);
549            info.AddValue("EraseClusterTips", EraseClusterTips);
550        }
551        #endregion
552
553        /// <summary>
554        /// Constructor.
555        /// </summary>
556        public UnusedSpaceTarget()
557            : base()
558        {
559            Method = ErasureMethodRegistrar.Default;
560        }
561
562        public override sealed ErasureMethod Method
563        {
564            get
565            {
566                if (base.MethodDefined)
567                    return base.Method;
568                return ManagerLibrary.Instance.ErasureMethodManager[
569                    ManagerLibrary.Settings.DefaultUnusedSpaceErasureMethod];
570            }
571            set
572            {
573                base.Method = value;
574            }
575        }
576
577        public override string UIText
578        {
579            get { return S._("Unused disk space ({0})", Drive); }
580        }
581
582        public override long TotalData
583        {
584            get
585            {
586                VolumeInfo info = VolumeInfo.FromMountPoint(Drive);
587                return Method.CalculateEraseDataSize(null, info.AvailableFreeSpace);
588            }
589        }
590
591        /// <summary>
592        /// The drive to erase
593        /// </summary>
594        public string Drive { get; set; }
595
596        /// <summary>
597        /// Whether cluster tips should be erased.
598        /// </summary>
599        public bool EraseClusterTips { get; set; }
600    }
601
602    /// <summary>
603    /// Class representing a file to be erased.
604    /// </summary>
605    [Serializable]
606    public class FileTarget : FileSystemObjectTarget
607    {
608        #region Serialization code
609        protected FileTarget(SerializationInfo info, StreamingContext context)
610            : base(info, context)
611        {
612        }
613        #endregion
614
615        /// <summary>
616        /// Constructor.
617        /// </summary>
618        public FileTarget()
619        {
620        }
621
622        internal override List<string> GetPaths(out long totalSize)
623        {
624            totalSize = 0;
625            List<string> result = new List<string>();
626            FileInfo fileInfo = new FileInfo(Path);
627
628            if (fileInfo.Exists)
629            {
630                GetPathADSes(result, out totalSize, Path);
631                totalSize += fileInfo.Length;
632            }
633
634            result.Add(Path);
635            return result;
636        }
637    }
638
639    /// <summary>
640    /// Represents a folder and its files which are to be erased.
641    /// </summary>
642    [Serializable]
643    public class FolderTarget : FileSystemObjectTarget
644    {
645        #region Serialization code
646        protected FolderTarget(SerializationInfo info, StreamingContext context)
647            : base(info, context)
648        {
649            IncludeMask = (string)info.GetValue("IncludeMask", typeof(string));
650            ExcludeMask = (string)info.GetValue("ExcludeMask", typeof(string));
651            DeleteIfEmpty = (bool)info.GetValue("DeleteIfEmpty", typeof(bool));
652        }
653
654        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
655        public override void GetObjectData(SerializationInfo info, StreamingContext context)
656        {
657            base.GetObjectData(info, context);
658            info.AddValue("IncludeMask", IncludeMask);
659            info.AddValue("ExcludeMask", ExcludeMask);
660            info.AddValue("DeleteIfEmpty", DeleteIfEmpty);
661        }
662        #endregion
663
664        /// <summary>
665        /// Constructor.
666        /// </summary>
667        public FolderTarget()
668        {
669            IncludeMask = string.Empty;
670            ExcludeMask = string.Empty;
671            DeleteIfEmpty = true;
672        }
673
674        internal override List<string> GetPaths(out long totalSize)
675        {
676            //Get a list to hold all the resulting paths.
677            List<string> result = new List<string>();
678
679            //Open the root of the search, including every file matching the pattern
680            DirectoryInfo dir = new DirectoryInfo(Path);
681
682            //List recursively all the files which match the include pattern.
683            FileInfo[] files = GetFiles(dir);
684
685            //Then exclude each file and finalize the list and total file size
686            totalSize = 0;
687            if (ExcludeMask.Length != 0)
688            {
689                string regex = Regex.Escape(ExcludeMask).Replace("\\*", ".*").
690                    Replace("\\?", ".");
691                Regex excludePattern = new Regex(regex, RegexOptions.IgnoreCase);
692                foreach (FileInfo file in files)
693                    if (file.Exists &&
694                        (file.Attributes & FileAttributes.ReparsePoint) == 0 &&
695                        excludePattern.Matches(file.FullName).Count == 0)
696                    {
697                        totalSize += file.Length;
698                        GetPathADSes(result, out totalSize, file.FullName);
699                        result.Add(file.FullName);
700                    }
701            }
702            else
703                foreach (FileInfo file in files)
704                {
705                    if (!file.Exists || (file.Attributes & FileAttributes.ReparsePoint) != 0)
706                        continue;
707
708                    //Get the size of the file and its ADSes
709                    totalSize += file.Length;
710                    long adsesSize = 0;
711                    GetPathADSes(result, out adsesSize, file.FullName);
712                    totalSize += adsesSize;
713
714                    //Append this file to the list of files to erase.
715                    result.Add(file.FullName);
716                }
717
718            //Return the filtered list.
719            return result;
720        }
721
722        /// <summary>
723        /// Gets all files in the provided directory.
724        /// </summary>
725        /// <param name="info">The directory to look files in.</param>
726        /// <returns>A list of files found in the directory matching the IncludeMask
727        /// property.</returns>
728        private FileInfo[] GetFiles(DirectoryInfo info)
729        {
730            List<FileInfo> result = new List<FileInfo>();
731            if (info.Exists)
732            {
733                try
734                {
735                    foreach (DirectoryInfo dir in info.GetDirectories())
736                        result.AddRange(GetFiles(dir));
737
738                    if (IncludeMask.Length == 0)
739                        result.AddRange(info.GetFiles());
740                    else
741                        result.AddRange(info.GetFiles(IncludeMask, SearchOption.TopDirectoryOnly));
742                }
743                catch (UnauthorizedAccessException e)
744                {
745                    Logger.Log(S._("Could not erase files and subfolders in {0} because {1}",
746                        info.FullName, e.Message), LogLevel.Error);
747                }
748            }
749
750            return result.ToArray();
751        }
752
753        /// <summary>
754        /// A wildcard expression stating the condition for the set of files to include.
755        /// The include mask is applied before the exclude mask is applied. If this value
756        /// is empty, all files and folders within the folder specified is included.
757        /// </summary>
758        public string IncludeMask { get; set; }
759
760        /// <summary>
761        /// A wildcard expression stating the condition for removing files from the set
762        /// of included files. If this value is omitted, all files and folders extracted
763        /// by the inclusion mask is erased.
764        /// </summary>
765        public string ExcludeMask { get; set; }
766
767        /// <summary>
768        /// Determines if Eraser should delete the folder after the erase process.
769        /// </summary>
770        public bool DeleteIfEmpty { get; set; }
771    }
772
773    [Serializable]
774    public class RecycleBinTarget : FileSystemObjectTarget
775    {
776        #region Serialization code
777        protected RecycleBinTarget(SerializationInfo info, StreamingContext context)
778            : base(info, context)
779        {
780        }
781        #endregion
782
783        public RecycleBinTarget()
784        {
785        }
786
787        internal override List<string> GetPaths(out long totalSize)
788        {
789            totalSize = 0;
790            List<string> result = new List<string>();
791            string[] rootDirectory = new string[] {
792                    "$RECYCLE.BIN",
793                    "RECYCLER"
794                };
795
796            foreach (DriveInfo drive in DriveInfo.GetDrives())
797            {
798                foreach (string rootDir in rootDirectory)
799                {
800                    DirectoryInfo dir = new DirectoryInfo(
801                        System.IO.Path.Combine(
802                            System.IO.Path.Combine(drive.Name, rootDir),
803                            System.Security.Principal.WindowsIdentity.GetCurrent().
804                                User.ToString()));
805                    if (!dir.Exists)
806                        continue;
807
808                    GetRecyclerFiles(dir, result, ref totalSize);
809                }
810            }
811
812            return result;
813        }
814
815        /// <summary>
816        /// Retrieves all files within this folder, without exclusions.
817        /// </summary>
818        /// <param name="info">The DirectoryInfo object representing the folder to traverse.</param>
819        /// <param name="paths">The list of files to store path information in.</param>
820        /// <param name="totalSize">Receives the total size of the files.</param>
821        private void GetRecyclerFiles(DirectoryInfo info, List<string> paths,
822            ref long totalSize)
823        {
824            try
825            {
826                foreach (FileInfo fileInfo in info.GetFiles())
827                {
828                    if (!fileInfo.Exists || (fileInfo.Attributes & FileAttributes.ReparsePoint) != 0)
829                        continue;
830
831                    totalSize += fileInfo.Length;
832                    GetPathADSes(paths, out totalSize, fileInfo.FullName);
833                    paths.Add(fileInfo.FullName);
834                }
835
836                foreach (DirectoryInfo directoryInfo in info.GetDirectories())
837                    if ((directoryInfo.Attributes & FileAttributes.ReparsePoint) == 0)
838                        GetRecyclerFiles(directoryInfo, paths, ref totalSize);
839            }
840            catch (UnauthorizedAccessException e)
841            {
842                Logger.Log(e.Message, LogLevel.Error);
843            }
844        }
845
846        /// <summary>
847        /// Retrieves the text to display representing this task.
848        /// </summary>
849        public override string UIText
850        {
851            get
852            {
853                return S._("Recycle Bin");
854            }
855        }
856    }
857
858    /// <summary>
859    /// Maintains a collection of erasure targets.
860    /// </summary>
861    [Serializable]
862    public class ErasureTargetsCollection : IList<ErasureTarget>, ISerializable
863    {
864        #region Constructors
865        internal ErasureTargetsCollection(Task owner)
866        {
867            this.list = new List<ErasureTarget>();
868            this.owner = owner;
869        }
870
871        internal ErasureTargetsCollection(Task owner, int capacity)
872            : this(owner)
873        {
874            list.Capacity = capacity;
875        }
876
877        internal ErasureTargetsCollection(Task owner, IEnumerable<ErasureTarget> targets)
878            : this(owner)
879        {
880            list.AddRange(targets);
881        }
882        #endregion
883
884        #region Serialization Code
885        protected ErasureTargetsCollection(SerializationInfo info, StreamingContext context)
886        {
887            list = (List<ErasureTarget>)info.GetValue("list", typeof(List<ErasureTarget>));
888        }
889
890        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
891        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
892        {
893            info.AddValue("list", list);
894        }
895        #endregion
896
897        #region IEnumerable<ErasureTarget> Members
898        public IEnumerator<ErasureTarget> GetEnumerator()
899        {
900            return list.GetEnumerator();
901        }
902        #endregion
903
904        #region IEnumerable Members
905        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
906        {
907            return GetEnumerator();
908        }
909        #endregion
910
911        #region ICollection<ErasureTarget> Members
912        public void Add(ErasureTarget item)
913        {
914            item.Task = owner;
915            list.Add(item);
916        }
917
918        public void Clear()
919        {
920            foreach (ErasureTarget item in list)
921                Remove(item);
922        }
923
924        public bool Contains(ErasureTarget item)
925        {
926            return list.Contains(item);
927        }
928
929        public void CopyTo(ErasureTarget[] array, int arrayIndex)
930        {
931            list.CopyTo(array, arrayIndex);
932        }
933
934        public int Count
935        {
936            get
937            {
938                return list.Count;
939            }
940        }
941
942        public bool IsReadOnly
943        {
944            get
945            {
946                return false;
947            }
948        }
949
950        public bool Remove(ErasureTarget item)
951        {
952            int index = list.IndexOf(item);
953            if (index < 0)
954                return false;
955
956            RemoveAt(index);
957            return true;
958        }
959        #endregion
960
961        #region IList<ErasureTarget> Members
962        public int IndexOf(ErasureTarget item)
963        {
964            return list.IndexOf(item);
965        }
966
967        public void Insert(int index, ErasureTarget item)
968        {
969            item.Task = owner;
970            list.Insert(index, item);
971        }
972
973        public void RemoveAt(int index)
974        {
975            list.RemoveAt(index);
976        }
977
978        public ErasureTarget this[int index]
979        {
980            get
981            {
982                return list[index];
983            }
984            set
985            {
986                list[index] = value;
987            }
988        }
989        #endregion
990
991        /// <summary>
992        /// The owner of this list of targets.
993        /// </summary>
994        public Task Owner
995        {
996            get
997            {
998                return owner;
999            }
1000            internal set
1001            {
1002                owner = value;
1003                foreach (ErasureTarget target in list)
1004                    target.Task = owner;
1005            }
1006        }
1007
1008        /// <summary>
1009        /// The owner of this list of targets. All targets added to this list
1010        /// will have the owner set to this object.
1011        /// </summary>
1012        private Task owner;
1013
1014        /// <summary>
1015        /// The list bring the data store behind this object.
1016        /// </summary>
1017        private List<ErasureTarget> list;
1018    }
1019
1020    /// <summary>
1021    /// A base event class for all event arguments involving a task.
1022    /// </summary>
1023    public class TaskEventArgs : EventArgs
1024    {
1025        /// <summary>
1026        /// Constructor.
1027        /// </summary>
1028        /// <param name="task">The task being referred to by this event.</param>
1029        public TaskEventArgs(Task task)
1030        {
1031            Task = task;
1032        }
1033
1034        /// <summary>
1035        /// The executing task.
1036        /// </summary>
1037        public Task Task { get; private set; }
1038    }
1039
1040    /// <summary>
1041    /// Stores extra information in the <see cref="ProgressChangedEventArgs"/>
1042    /// structure that is not conveyed in the ProgressManagerBase classes.
1043    /// </summary>
1044    public class TaskProgressChangedEventArgs
1045    {
1046        /// <summary>
1047        /// Constructor.
1048        /// </summary>
1049        /// <param name="itemName">The item whose erasure progress is being erased.</param>
1050        /// <param name="itemPass">The current pass number for this item.</param>
1051        /// <param name="itemTotalPasses">The total number of passes to complete erasure
1052        /// of this item.</param>
1053        public TaskProgressChangedEventArgs(string itemName, int itemPass,
1054            int itemTotalPasses)
1055        {
1056            ItemName = itemName;
1057            ItemPass = itemPass;
1058            ItemTotalPasses = itemTotalPasses;
1059        }
1060
1061        /// <summary>
1062        /// The file name of the item being erased.
1063        /// </summary>
1064        public string ItemName { get; private set; }
1065
1066        /// <summary>
1067        /// The pass number of a multi-pass erasure method.
1068        /// </summary>
1069        public int ItemPass { get; private set; }
1070
1071        /// <summary>
1072        /// The total number of passes to complete before this erasure method is
1073        /// completed.
1074        /// </summary>
1075        public int ItemTotalPasses { get; private set; }
1076    }
1077}
Note: See TracBrowser for help on using the repository browser.