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

Revision 1102, 26.6 KB checked in by lowjoel, 6 years ago (diff)

A whole host of scheduler fixes:

  • When cancelling scheduled tasks we removed the scheduled version of the task as well so tasks will no longer run on the schedule
  • When editing tasks the schedules were not updated and scheduled tasks still ran on the old schedule
  • Determining whether the task was queued manually for execution was a little unpredictable, this is now fixed
  • For consistency, when tasks are queued we will prevent editing of tasks

And a few stylistic fixes

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