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

Revision 1662, 26.5 KB checked in by lowjoel, 5 years ago (diff)

Fixed regression in r1102: the check on Exists ensures that the DirectoryNotFoundException? will not be raised -- however, it doesn't guard against UnauthorizedAccessException?, so we should be guarding against that instead.

  • 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                try
721                {
722                    foreach (DirectoryInfo dir in info.GetDirectories())
723                        result.AddRange(GetFiles(dir));
724
725                    if (IncludeMask.Length == 0)
726                        result.AddRange(info.GetFiles());
727                    else
728                        result.AddRange(info.GetFiles(IncludeMask, SearchOption.TopDirectoryOnly));
729                }
730                catch (UnauthorizedAccessException e)
731                {
732                    Task.Log.LastSessionEntries.Add(new LogEntry(S._("Could not erase files and " +
733                        "subfolders in {0} because {1}", info.FullName, e.Message), LogLevel.Error));
734                }
735            }
736
737            return result.ToArray();
738        }
739
740        /// <summary>
741        /// A wildcard expression stating the condition for the set of files to include.
742        /// The include mask is applied before the exclude mask is applied. If this value
743        /// is empty, all files and folders within the folder specified is included.
744        /// </summary>
745        public string IncludeMask { get; set; }
746
747        /// <summary>
748        /// A wildcard expression stating the condition for removing files from the set
749        /// of included files. If this value is omitted, all files and folders extracted
750        /// by the inclusion mask is erased.
751        /// </summary>
752        public string ExcludeMask { get; set; }
753
754        /// <summary>
755        /// Determines if Eraser should delete the folder after the erase process.
756        /// </summary>
757        public bool DeleteIfEmpty { get; set; }
758    }
759
760    [Serializable]
761    public class RecycleBinTarget : FileSystemObjectTarget
762    {
763        #region Serialization code
764        protected RecycleBinTarget(SerializationInfo info, StreamingContext context)
765            : base(info, context)
766        {
767        }
768        #endregion
769
770        public RecycleBinTarget()
771        {
772        }
773
774        internal override List<string> GetPaths(out long totalSize)
775        {
776            totalSize = 0;
777            List<string> result = new List<string>();
778            string[] rootDirectory = new string[] {
779                    "$RECYCLE.BIN",
780                    "RECYCLER"
781                };
782
783            foreach (DriveInfo drive in DriveInfo.GetDrives())
784            {
785                foreach (string rootDir in rootDirectory)
786                {
787                    DirectoryInfo dir = new DirectoryInfo(
788                        System.IO.Path.Combine(
789                            System.IO.Path.Combine(drive.Name, rootDir),
790                            System.Security.Principal.WindowsIdentity.GetCurrent().
791                                User.ToString()));
792                    if (!dir.Exists)
793                        continue;
794
795                    GetRecyclerFiles(dir, ref result, ref totalSize);
796                }
797            }
798
799            return result;
800        }
801
802        /// <summary>
803        /// Retrieves all files within this folder, without exclusions.
804        /// </summary>
805        /// <param name="info">The DirectoryInfo object representing the folder to traverse.</param>
806        /// <param name="paths">The list of files to store path information in.</param>
807        /// <param name="totalSize">Receives the total size of the files.</param>
808        private void GetRecyclerFiles(DirectoryInfo info, ref List<string> paths,
809            ref long totalSize)
810        {
811            try
812            {
813                foreach (FileSystemInfo fsInfo in info.GetFileSystemInfos())
814                {
815                    FileInfo fileInfo = fsInfo as FileInfo;
816                    if (fileInfo != null)
817                    {
818                        totalSize += fileInfo.Length;
819                        GetPathADSes(paths, out totalSize, fileInfo.FullName);
820                        paths.Add(fileInfo.FullName);
821                    }
822                    else
823                        GetRecyclerFiles((DirectoryInfo)fsInfo, ref paths, ref totalSize);
824                }
825            }
826            catch (UnauthorizedAccessException e)
827            {
828                Task.Log.LastSessionEntries.Add(new LogEntry(e.Message, LogLevel.Error));
829            }
830        }
831
832        /// <summary>
833        /// Retrieves the text to display representing this task.
834        /// </summary>
835        public override string UIText
836        {
837            get
838            {
839                return S._("Recycle Bin");
840            }
841        }
842    }
843
844    /// <summary>
845    /// Maintains a collection of erasure targets.
846    /// </summary>
847    [Serializable]
848    public class ErasureTargetsCollection : IList<ErasureTarget>, ICollection<ErasureTarget>,
849        IEnumerable<ErasureTarget>, ISerializable
850    {
851        #region Constructors
852        internal ErasureTargetsCollection(Task owner)
853        {
854            this.list = new List<ErasureTarget>();
855            this.owner = owner;
856        }
857
858        internal ErasureTargetsCollection(Task owner, int capacity)
859            : this(owner)
860        {
861            list.Capacity = capacity;
862        }
863
864        internal ErasureTargetsCollection(Task owner, IEnumerable<ErasureTarget> targets)
865            : this(owner)
866        {
867            list.AddRange(targets);
868        }
869        #endregion
870
871        #region Serialization Code
872        protected ErasureTargetsCollection(SerializationInfo info, StreamingContext context)
873        {
874            list = (List<ErasureTarget>)info.GetValue("list", typeof(List<ErasureTarget>));
875        }
876
877        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
878        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
879        {
880            info.AddValue("list", list);
881        }
882        #endregion
883
884        #region IEnumerable<ErasureTarget> Members
885        public IEnumerator<ErasureTarget> GetEnumerator()
886        {
887            return list.GetEnumerator();
888        }
889        #endregion
890
891        #region IEnumerable Members
892        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
893        {
894            return GetEnumerator();
895        }
896        #endregion
897
898        #region ICollection<ErasureTarget> Members
899        public void Add(ErasureTarget item)
900        {
901            item.Task = owner;
902            list.Add(item);
903        }
904
905        public void Clear()
906        {
907            foreach (ErasureTarget item in list)
908                Remove(item);
909        }
910
911        public bool Contains(ErasureTarget item)
912        {
913            return list.Contains(item);
914        }
915
916        public void CopyTo(ErasureTarget[] array, int arrayIndex)
917        {
918            list.CopyTo(array, arrayIndex);
919        }
920
921        public int Count
922        {
923            get
924            {
925                return list.Count;
926            }
927        }
928
929        public bool IsReadOnly
930        {
931            get
932            {
933                return false;
934            }
935        }
936
937        public bool Remove(ErasureTarget item)
938        {
939            int index = list.IndexOf(item);
940            if (index < 0)
941                return false;
942
943            RemoveAt(index);
944            return true;
945        }
946        #endregion
947
948        #region IList<ErasureTarget> Members
949        public int IndexOf(ErasureTarget item)
950        {
951            return list.IndexOf(item);
952        }
953
954        public void Insert(int index, ErasureTarget item)
955        {
956            item.Task = owner;
957            list.Insert(index, item);
958        }
959
960        public void RemoveAt(int index)
961        {
962            list.RemoveAt(index);
963        }
964
965        public ErasureTarget this[int index]
966        {
967            get
968            {
969                return list[index];
970            }
971            set
972            {
973                list[index] = value;
974            }
975        }
976        #endregion
977
978        /// <summary>
979        /// The owner of this list of targets.
980        /// </summary>
981        public Task Owner
982        {
983            get
984            {
985                return owner;
986            }
987            internal set
988            {
989                owner = value;
990                foreach (ErasureTarget target in list)
991                    target.Task = owner;
992            }
993        }
994
995        /// <summary>
996        /// The owner of this list of targets. All targets added to this list
997        /// will have the owner set to this object.
998        /// </summary>
999        private Task owner;
1000
1001        /// <summary>
1002        /// The list bring the data store behind this object.
1003        /// </summary>
1004        private List<ErasureTarget> list;
1005    }
1006
1007    /// <summary>
1008    /// A base event class for all event arguments involving a task.
1009    /// </summary>
1010    public class TaskEventArgs : EventArgs
1011    {
1012        /// <summary>
1013        /// Constructor.
1014        /// </summary>
1015        /// <param name="task">The task being referred to by this event.</param>
1016        public TaskEventArgs(Task task)
1017        {
1018            Task = task;
1019        }
1020
1021        /// <summary>
1022        /// The executing task.
1023        /// </summary>
1024        public Task Task { get; private set; }
1025    }
1026
1027    /// <summary>
1028    /// Stores extra information in the <see cref="ProgressChangedEventArgs"/>
1029    /// structure that is not conveyed in the ProgressManagerBase classes.
1030    /// </summary>
1031    public class TaskProgressChangedEventArgs
1032    {
1033        /// <summary>
1034        /// Constructor.
1035        /// </summary>
1036        /// <param name="itemName">The item whose erasure progress is being erased.</param>
1037        /// <param name="itemPass">The current pass number for this item.</param>
1038        /// <param name="itemTotalPasses">The total number of passes to complete erasure
1039        /// of this item.</param>
1040        public TaskProgressChangedEventArgs(string itemName, int itemPass,
1041            int itemTotalPasses)
1042        {
1043            ItemName = itemName;
1044            ItemPass = itemPass;
1045            ItemTotalPasses = itemTotalPasses;
1046        }
1047
1048        /// <summary>
1049        /// The file name of the item being erased.
1050        /// </summary>
1051        public string ItemName { get; private set; }
1052
1053        /// <summary>
1054        /// The pass number of a multi-pass erasure method.
1055        /// </summary>
1056        public int ItemPass { get; private set; }
1057
1058        /// <summary>
1059        /// The total number of passes to complete before this erasure method is
1060        /// completed.
1061        /// </summary>
1062        public int ItemTotalPasses { get; private set; }
1063    }
1064}
Note: See TracBrowser for help on using the repository browser.