source: trunk/eraser6/Eraser.Manager/Task.cs @ 1515

Revision 1515, 26.5 KB checked in by lowjoel, 4 years ago (diff)

Merged the SpeedMeter? branch to trunk. Fixes #90: Generic speed meter

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