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

Revision 1872, 26.8 KB checked in by lowjoel, 4 years ago (diff)

Define a discrete SharingViolationException? which is thrown when a file is currently in use. This makes handling such errors easier.

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