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

Revision 1853, 26.9 KB checked in by lowjoel, 5 years ago (diff)

If we can't find the file when enumerating ADSes we'll just silently ignore since we can't do anything about it.

  • 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 (IOException)
464            {
465                if (System.Runtime.InteropServices.Marshal.GetLastWin32Error() ==
466                    Win32ErrorCode.SharingViolation)
467                {
468                    //The system cannot open the file, try to force the file handle to close.
469                    if (!ManagerLibrary.Settings.ForceUnlockLockedFiles)
470                        throw;
471
472                    foreach (OpenHandle handle in OpenHandle.Items)
473                        if (handle.Path == file && handle.Close())
474                        {
475                            GetPathADSes(list, out totalSize, file);
476                            return;
477                        }
478                }
479                else
480                    throw;
481            }
482            catch (UnauthorizedAccessException e)
483            {
484                //The system cannot read the file, assume no ADSes for lack of
485                //more information.
486                Logger.Log(e.Message, LogLevel.Error);
487            }
488        }
489
490        /// <summary>
491        /// The path to the file or folder referred to by this object.
492        /// </summary>
493        public string Path { get; set; }
494
495        public sealed override ErasureMethod Method
496        {
497            get
498            {
499                if (base.MethodDefined)
500                    return base.Method;
501                return ManagerLibrary.Instance.ErasureMethodRegistrar[
502                    ManagerLibrary.Settings.DefaultFileErasureMethod];
503            }
504            set
505            {
506                base.Method = value;
507            }
508        }
509
510        public override string UIText
511        {
512            get
513            {
514                string fileName = System.IO.Path.GetFileName(Path);
515                string directoryName = System.IO.Path.GetDirectoryName(Path);
516                return string.IsNullOrEmpty(fileName) ? 
517                        (string.IsNullOrEmpty(directoryName) ? Path : directoryName)
518                    : fileName;
519            }
520        }
521
522        public override long TotalData
523        {
524            get
525            {
526                long totalSize = 0;
527                List<string> paths = GetPaths(out totalSize);
528                return Method.CalculateEraseDataSize(paths, totalSize);
529            }
530        }
531    }
532
533    /// <summary>
534    /// Class representing a unused space erase.
535    /// </summary>
536    [Serializable]
537    public class UnusedSpaceTarget : ErasureTarget
538    {
539        #region Serialization code
540        protected UnusedSpaceTarget(SerializationInfo info, StreamingContext context)
541            : base(info, context)
542        {
543            Drive = (string)info.GetValue("Drive", typeof(string));
544            EraseClusterTips = (bool)info.GetValue("EraseClusterTips", typeof(bool));
545        }
546
547        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
548        public override void GetObjectData(SerializationInfo info, StreamingContext context)
549        {
550            base.GetObjectData(info, context);
551            info.AddValue("Drive", Drive);
552            info.AddValue("EraseClusterTips", EraseClusterTips);
553        }
554        #endregion
555
556        /// <summary>
557        /// Constructor.
558        /// </summary>
559        public UnusedSpaceTarget()
560            : base()
561        {
562            Method = ErasureMethodRegistrar.Default;
563        }
564
565        public override sealed ErasureMethod Method
566        {
567            get
568            {
569                if (base.MethodDefined)
570                    return base.Method;
571                return ManagerLibrary.Instance.ErasureMethodRegistrar[
572                    ManagerLibrary.Settings.DefaultUnusedSpaceErasureMethod];
573            }
574            set
575            {
576                base.Method = value;
577            }
578        }
579
580        public override string UIText
581        {
582            get { return S._("Unused disk space ({0})", Drive); }
583        }
584
585        public override long TotalData
586        {
587            get
588            {
589                VolumeInfo info = VolumeInfo.FromMountPoint(Drive);
590                return Method.CalculateEraseDataSize(null, info.AvailableFreeSpace);
591            }
592        }
593
594        /// <summary>
595        /// The drive to erase
596        /// </summary>
597        public string Drive { get; set; }
598
599        /// <summary>
600        /// Whether cluster tips should be erased.
601        /// </summary>
602        public bool EraseClusterTips { get; set; }
603    }
604
605    /// <summary>
606    /// Class representing a file to be erased.
607    /// </summary>
608    [Serializable]
609    public class FileTarget : FileSystemObjectTarget
610    {
611        #region Serialization code
612        protected FileTarget(SerializationInfo info, StreamingContext context)
613            : base(info, context)
614        {
615        }
616        #endregion
617
618        /// <summary>
619        /// Constructor.
620        /// </summary>
621        public FileTarget()
622        {
623        }
624
625        internal override List<string> GetPaths(out long totalSize)
626        {
627            totalSize = 0;
628            List<string> result = new List<string>();
629            FileInfo fileInfo = new FileInfo(Path);
630
631            if (fileInfo.Exists)
632            {
633                GetPathADSes(result, out totalSize, Path);
634                totalSize += fileInfo.Length;
635            }
636
637            result.Add(Path);
638            return result;
639        }
640    }
641
642    /// <summary>
643    /// Represents a folder and its files which are to be erased.
644    /// </summary>
645    [Serializable]
646    public class FolderTarget : FileSystemObjectTarget
647    {
648        #region Serialization code
649        protected FolderTarget(SerializationInfo info, StreamingContext context)
650            : base(info, context)
651        {
652            IncludeMask = (string)info.GetValue("IncludeMask", typeof(string));
653            ExcludeMask = (string)info.GetValue("ExcludeMask", typeof(string));
654            DeleteIfEmpty = (bool)info.GetValue("DeleteIfEmpty", typeof(bool));
655        }
656
657        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
658        public override void GetObjectData(SerializationInfo info, StreamingContext context)
659        {
660            base.GetObjectData(info, context);
661            info.AddValue("IncludeMask", IncludeMask);
662            info.AddValue("ExcludeMask", ExcludeMask);
663            info.AddValue("DeleteIfEmpty", DeleteIfEmpty);
664        }
665        #endregion
666
667        /// <summary>
668        /// Constructor.
669        /// </summary>
670        public FolderTarget()
671        {
672            IncludeMask = string.Empty;
673            ExcludeMask = string.Empty;
674            DeleteIfEmpty = true;
675        }
676
677        internal override List<string> GetPaths(out long totalSize)
678        {
679            //Get a list to hold all the resulting paths.
680            List<string> result = new List<string>();
681
682            //Open the root of the search, including every file matching the pattern
683            DirectoryInfo dir = new DirectoryInfo(Path);
684
685            //List recursively all the files which match the include pattern.
686            FileInfo[] files = GetFiles(dir);
687
688            //Then exclude each file and finalize the list and total file size
689            totalSize = 0;
690            if (ExcludeMask.Length != 0)
691            {
692                string regex = Regex.Escape(ExcludeMask).Replace("\\*", ".*").
693                    Replace("\\?", ".");
694                Regex excludePattern = new Regex(regex, RegexOptions.IgnoreCase);
695                foreach (FileInfo file in files)
696                    if (file.Exists &&
697                        (file.Attributes & FileAttributes.ReparsePoint) == 0 &&
698                        excludePattern.Matches(file.FullName).Count == 0)
699                    {
700                        totalSize += file.Length;
701                        GetPathADSes(result, out totalSize, file.FullName);
702                        result.Add(file.FullName);
703                    }
704            }
705            else
706                foreach (FileInfo file in files)
707                {
708                    if (!file.Exists || (file.Attributes & FileAttributes.ReparsePoint) != 0)
709                        continue;
710
711                    //Get the size of the file and its ADSes
712                    totalSize += file.Length;
713                    long adsesSize = 0;
714                    GetPathADSes(result, out adsesSize, file.FullName);
715                    totalSize += adsesSize;
716
717                    //Append this file to the list of files to erase.
718                    result.Add(file.FullName);
719                }
720
721            //Return the filtered list.
722            return result;
723        }
724
725        /// <summary>
726        /// Gets all files in the provided directory.
727        /// </summary>
728        /// <param name="info">The directory to look files in.</param>
729        /// <returns>A list of files found in the directory matching the IncludeMask
730        /// property.</returns>
731        private FileInfo[] GetFiles(DirectoryInfo info)
732        {
733            List<FileInfo> result = new List<FileInfo>();
734            if (info.Exists)
735            {
736                try
737                {
738                    foreach (DirectoryInfo dir in info.GetDirectories())
739                        result.AddRange(GetFiles(dir));
740
741                    if (IncludeMask.Length == 0)
742                        result.AddRange(info.GetFiles());
743                    else
744                        result.AddRange(info.GetFiles(IncludeMask, SearchOption.TopDirectoryOnly));
745                }
746                catch (UnauthorizedAccessException e)
747                {
748                    Logger.Log(S._("Could not erase files and subfolders in {0} because {1}",
749                        info.FullName, e.Message), LogLevel.Error);
750                }
751            }
752
753            return result.ToArray();
754        }
755
756        /// <summary>
757        /// A wildcard expression stating the condition for the set of files to include.
758        /// The include mask is applied before the exclude mask is applied. If this value
759        /// is empty, all files and folders within the folder specified is included.
760        /// </summary>
761        public string IncludeMask { get; set; }
762
763        /// <summary>
764        /// A wildcard expression stating the condition for removing files from the set
765        /// of included files. If this value is omitted, all files and folders extracted
766        /// by the inclusion mask is erased.
767        /// </summary>
768        public string ExcludeMask { get; set; }
769
770        /// <summary>
771        /// Determines if Eraser should delete the folder after the erase process.
772        /// </summary>
773        public bool DeleteIfEmpty { get; set; }
774    }
775
776    [Serializable]
777    public class RecycleBinTarget : FileSystemObjectTarget
778    {
779        #region Serialization code
780        protected RecycleBinTarget(SerializationInfo info, StreamingContext context)
781            : base(info, context)
782        {
783        }
784        #endregion
785
786        public RecycleBinTarget()
787        {
788        }
789
790        internal override List<string> GetPaths(out long totalSize)
791        {
792            totalSize = 0;
793            List<string> result = new List<string>();
794            string[] rootDirectory = new string[] {
795                    "$RECYCLE.BIN",
796                    "RECYCLER"
797                };
798
799            foreach (DriveInfo drive in DriveInfo.GetDrives())
800            {
801                foreach (string rootDir in rootDirectory)
802                {
803                    DirectoryInfo dir = new DirectoryInfo(
804                        System.IO.Path.Combine(
805                            System.IO.Path.Combine(drive.Name, rootDir),
806                            System.Security.Principal.WindowsIdentity.GetCurrent().
807                                User.ToString()));
808                    if (!dir.Exists)
809                        continue;
810
811                    GetRecyclerFiles(dir, result, ref totalSize);
812                }
813            }
814
815            return result;
816        }
817
818        /// <summary>
819        /// Retrieves all files within this folder, without exclusions.
820        /// </summary>
821        /// <param name="info">The DirectoryInfo object representing the folder to traverse.</param>
822        /// <param name="paths">The list of files to store path information in.</param>
823        /// <param name="totalSize">Receives the total size of the files.</param>
824        private void GetRecyclerFiles(DirectoryInfo info, List<string> paths,
825            ref long totalSize)
826        {
827            try
828            {
829                foreach (FileInfo fileInfo in info.GetFiles())
830                {
831                    if (!fileInfo.Exists || (fileInfo.Attributes & FileAttributes.ReparsePoint) != 0)
832                        continue;
833
834                    long adsSize = 0;
835                    GetPathADSes(paths, out adsSize, fileInfo.FullName);
836                    totalSize += adsSize;
837                    totalSize += fileInfo.Length;
838                    paths.Add(fileInfo.FullName);
839                }
840
841                foreach (DirectoryInfo directoryInfo in info.GetDirectories())
842                    if ((directoryInfo.Attributes & FileAttributes.ReparsePoint) == 0)
843                        GetRecyclerFiles(directoryInfo, paths, ref totalSize);
844            }
845            catch (UnauthorizedAccessException e)
846            {
847                Logger.Log(e.Message, LogLevel.Error);
848            }
849        }
850
851        /// <summary>
852        /// Retrieves the text to display representing this task.
853        /// </summary>
854        public override string UIText
855        {
856            get
857            {
858                return S._("Recycle Bin");
859            }
860        }
861    }
862
863    /// <summary>
864    /// Maintains a collection of erasure targets.
865    /// </summary>
866    [Serializable]
867    public class ErasureTargetsCollection : IList<ErasureTarget>, ISerializable
868    {
869        #region Constructors
870        internal ErasureTargetsCollection(Task owner)
871        {
872            this.list = new List<ErasureTarget>();
873            this.owner = owner;
874        }
875
876        internal ErasureTargetsCollection(Task owner, int capacity)
877            : this(owner)
878        {
879            list.Capacity = capacity;
880        }
881
882        internal ErasureTargetsCollection(Task owner, IEnumerable<ErasureTarget> targets)
883            : this(owner)
884        {
885            list.AddRange(targets);
886        }
887        #endregion
888
889        #region Serialization Code
890        protected ErasureTargetsCollection(SerializationInfo info, StreamingContext context)
891        {
892            list = (List<ErasureTarget>)info.GetValue("list", typeof(List<ErasureTarget>));
893        }
894
895        [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
896        public virtual void GetObjectData(SerializationInfo info, StreamingContext context)
897        {
898            info.AddValue("list", list);
899        }
900        #endregion
901
902        #region IEnumerable<ErasureTarget> Members
903        public IEnumerator<ErasureTarget> GetEnumerator()
904        {
905            return list.GetEnumerator();
906        }
907        #endregion
908
909        #region IEnumerable Members
910        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
911        {
912            return GetEnumerator();
913        }
914        #endregion
915
916        #region ICollection<ErasureTarget> Members
917        public void Add(ErasureTarget item)
918        {
919            item.Task = owner;
920            list.Add(item);
921        }
922
923        public void Clear()
924        {
925            foreach (ErasureTarget item in list)
926                Remove(item);
927        }
928
929        public bool Contains(ErasureTarget item)
930        {
931            return list.Contains(item);
932        }
933
934        public void CopyTo(ErasureTarget[] array, int arrayIndex)
935        {
936            list.CopyTo(array, arrayIndex);
937        }
938
939        public int Count
940        {
941            get
942            {
943                return list.Count;
944            }
945        }
946
947        public bool IsReadOnly
948        {
949            get
950            {
951                return false;
952            }
953        }
954
955        public bool Remove(ErasureTarget item)
956        {
957            int index = list.IndexOf(item);
958            if (index < 0)
959                return false;
960
961            RemoveAt(index);
962            return true;
963        }
964        #endregion
965
966        #region IList<ErasureTarget> Members
967        public int IndexOf(ErasureTarget item)
968        {
969            return list.IndexOf(item);
970        }
971
972        public void Insert(int index, ErasureTarget item)
973        {
974            item.Task = owner;
975            list.Insert(index, item);
976        }
977
978        public void RemoveAt(int index)
979        {
980            list.RemoveAt(index);
981        }
982
983        public ErasureTarget this[int index]
984        {
985            get
986            {
987                return list[index];
988            }
989            set
990            {
991                list[index] = value;
992            }
993        }
994        #endregion
995
996        /// <summary>
997        /// The owner of this list of targets.
998        /// </summary>
999        public Task Owner
1000        {
1001            get
1002            {
1003                return owner;
1004            }
1005            internal set
1006            {
1007                owner = value;
1008                foreach (ErasureTarget target in list)
1009                    target.Task = owner;
1010            }
1011        }
1012
1013        /// <summary>
1014        /// The owner of this list of targets. All targets added to this list
1015        /// will have the owner set to this object.
1016        /// </summary>
1017        private Task owner;
1018
1019        /// <summary>
1020        /// The list bring the data store behind this object.
1021        /// </summary>
1022        private List<ErasureTarget> list;
1023    }
1024
1025    /// <summary>
1026    /// A base event class for all event arguments involving a task.
1027    /// </summary>
1028    public class TaskEventArgs : EventArgs
1029    {
1030        /// <summary>
1031        /// Constructor.
1032        /// </summary>
1033        /// <param name="task">The task being referred to by this event.</param>
1034        public TaskEventArgs(Task task)
1035        {
1036            Task = task;
1037        }
1038
1039        /// <summary>
1040        /// The executing task.
1041        /// </summary>
1042        public Task Task { get; private set; }
1043    }
1044
1045    /// <summary>
1046    /// Stores extra information in the <see cref="ProgressChangedEventArgs"/>
1047    /// structure that is not conveyed in the ProgressManagerBase classes.
1048    /// </summary>
1049    public class TaskProgressChangedEventArgs
1050    {
1051        /// <summary>
1052        /// Constructor.
1053        /// </summary>
1054        /// <param name="itemName">The item whose erasure progress is being erased.</param>
1055        /// <param name="itemPass">The current pass number for this item.</param>
1056        /// <param name="itemTotalPasses">The total number of passes to complete erasure
1057        /// of this item.</param>
1058        public TaskProgressChangedEventArgs(string itemName, int itemPass,
1059            int itemTotalPasses)
1060        {
1061            ItemName = itemName;
1062            ItemPass = itemPass;
1063            ItemTotalPasses = itemTotalPasses;
1064        }
1065
1066        /// <summary>
1067        /// The file name of the item being erased.
1068        /// </summary>
1069        public string ItemName { get; private set; }
1070
1071        /// <summary>
1072        /// The pass number of a multi-pass erasure method.
1073        /// </summary>
1074        public int ItemPass { get; private set; }
1075
1076        /// <summary>
1077        /// The total number of passes to complete before this erasure method is
1078        /// completed.
1079        /// </summary>
1080        public int ItemTotalPasses { get; private set; }
1081    }
1082}
Note: See TracBrowser for help on using the repository browser.