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

Revision 1359, 25.9 KB checked in by lowjoel, 5 years ago (diff)

Set svn:eol-style to native

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