Changeset 2038


Ignore:
Timestamp:
5/4/2010 1:28:39 AM (4 years ago)
Author:
lowjoel
Message:

Split the huge File.cs into its constituent classes in separate files.

Location:
trunk/eraser/Eraser.DefaultPlugins
Files:
4 added
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/eraser/Eraser.DefaultPlugins/Eraser.DefaultPlugins.csproj

    r2036 r2038  
    8484    <Compile Include="ErasureMethods\RCMP_TSSIT_OPS_II.cs" /> 
    8585    <Compile Include="ErasureTargets\File.cs" /> 
     86    <Compile Include="ErasureTargets\FileSystemObject.cs" /> 
    8687    <Compile Include="ErasureTargets\FileErasureTargetSettings.cs"> 
    8788      <SubType>UserControl</SubType> 
     
    9091      <DependentUpon>FileErasureTargetSettings.cs</DependentUpon> 
    9192    </Compile> 
     93    <Compile Include="ErasureTargets\Folder.cs" /> 
    9294    <Compile Include="ErasureTargets\FolderErasureTargetSettings.cs"> 
    9395      <SubType>UserControl</SubType> 
     
    9698      <DependentUpon>FolderErasureTargetSettings.cs</DependentUpon> 
    9799    </Compile> 
     100    <Compile Include="ErasureTargets\RecycleBin.cs" /> 
     101    <Compile Include="ErasureTargets\UnusedSpace.cs" /> 
    98102    <Compile Include="ErasureTargets\UnusedSpaceErasureTargetSettings.cs"> 
    99103      <SubType>UserControl</SubType> 
  • trunk/eraser/Eraser.DefaultPlugins/ErasureTargets/File.cs

    r2037 r2038  
    2525using System.Text; 
    2626 
    27 using System.Text.RegularExpressions; 
    2827using System.Runtime.Serialization; 
    2928using System.Runtime.InteropServices; 
    30 using System.Security.Permissions; 
    3129using System.IO; 
    32  
    33 using Eraser.Manager; 
    34 using Eraser.Util; 
    35 using Eraser.Util.ExtensionMethods; 
    3630 
    3731namespace Eraser.DefaultPlugins 
    3832{ 
    39     /// <summary> 
    40     /// Class representing a tangible object (file/folder) to be erased. 
    41     /// </summary> 
    42     [Serializable] 
    43     public abstract class FileSystemObjectTarget : ErasureTarget 
    44     { 
    45         #region Serialization code 
    46         protected FileSystemObjectTarget(SerializationInfo info, StreamingContext context) 
    47             : base(info, context) 
    48         { 
    49             Path = (string)info.GetValue("Path", typeof(string)); 
    50         } 
    51  
    52         [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] 
    53         public override void GetObjectData(SerializationInfo info, StreamingContext context) 
    54         { 
    55             base.GetObjectData(info, context); 
    56             info.AddValue("Path", Path); 
    57         } 
    58         #endregion 
    59  
    60         /// <summary> 
    61         /// Constructor. 
    62         /// </summary> 
    63         protected FileSystemObjectTarget() 
    64             : base() 
    65         { 
    66         } 
    67  
    68         protected new SteppedProgressManager Progress 
    69         { 
    70             get 
    71             { 
    72                 return (SteppedProgressManager)base.Progress; 
    73             } 
    74             set 
    75             { 
    76                 base.Progress = value; 
    77             } 
    78         } 
    79  
    80         /// <summary> 
    81         /// Retrieves the list of files/folders to erase as a list. 
    82         /// </summary> 
    83         /// <param name="totalSize">Returns the total size in bytes of the 
    84         /// items.</param> 
    85         /// <returns>A list containing the paths to all the files to be erased.</returns> 
    86         internal abstract List<string> GetPaths(out long totalSize); 
    87  
    88         /// <summary> 
    89         /// Adds ADSes of the given file to the list. 
    90         /// </summary> 
    91         /// <param name="list">The list to add the ADS paths to.</param> 
    92         /// <param name="file">The file to look for ADSes</param> 
    93         protected void GetPathADSes(ICollection<string> list, out long totalSize, string file) 
    94         { 
    95             totalSize = 0; 
    96  
    97             try 
    98             { 
    99                 //Get the ADS names 
    100                 IList<string> adses = new FileInfo(file).GetADSes(); 
    101  
    102                 //Then prepend the path. 
    103                 foreach (string adsName in adses) 
    104                 { 
    105                     string adsPath = file + ':' + adsName; 
    106                     list.Add(adsPath); 
    107                     StreamInfo info = new StreamInfo(adsPath); 
    108                     totalSize += info.Length; 
    109                 } 
    110             } 
    111             catch (FileNotFoundException) 
    112             { 
    113             } 
    114             catch (SharingViolationException) 
    115             { 
    116                 //The system cannot open the file, try to force the file handle to close. 
    117                 if (!ManagerLibrary.Settings.ForceUnlockLockedFiles) 
    118                     throw; 
    119  
    120                 StringBuilder processStr = new StringBuilder(); 
    121                 foreach (OpenHandle handle in OpenHandle.Close(file)) 
    122                 { 
    123                     try 
    124                     { 
    125                         processStr.AppendFormat( 
    126                             System.Globalization.CultureInfo.InvariantCulture, 
    127                             "{0}, ", (System.Diagnostics.Process.GetProcessById(handle.ProcessId)).MainModule.FileName); 
    128                     } 
    129                     catch (System.ComponentModel.Win32Exception) 
    130                     { 
    131                         processStr.AppendFormat( 
    132                             System.Globalization.CultureInfo.InvariantCulture, 
    133                             "Process ID {0}, ", handle.ProcessId); 
    134                     } 
    135                 } 
    136  
    137                 if (processStr.Length == 0) 
    138                 { 
    139                     GetPathADSes(list, out totalSize, file); 
    140                     return; 
    141                 } 
    142                 else 
    143                     throw; 
    144             } 
    145             catch (UnauthorizedAccessException e) 
    146             { 
    147                 //The system cannot read the file, assume no ADSes for lack of 
    148                 //more information. 
    149                 Logger.Log(e.Message, LogLevel.Error); 
    150             } 
    151         } 
    152  
    153         /// <summary> 
    154         /// The path to the file or folder referred to by this object. 
    155         /// </summary> 
    156         public string Path { get; set; } 
    157  
    158         public sealed override ErasureMethod EffectiveMethod 
    159         { 
    160             get 
    161             { 
    162                 if (Method != ErasureMethodRegistrar.Default) 
    163                     return base.EffectiveMethod; 
    164  
    165                 return ManagerLibrary.Instance.ErasureMethodRegistrar[ 
    166                     ManagerLibrary.Settings.DefaultFileErasureMethod]; 
    167             } 
    168         } 
    169  
    170         public override string UIText 
    171         { 
    172             get 
    173             { 
    174                 string fileName = System.IO.Path.GetFileName(Path); 
    175                 string directoryName = System.IO.Path.GetDirectoryName(Path); 
    176                 return string.IsNullOrEmpty(fileName) ? 
    177                         (string.IsNullOrEmpty(directoryName) ? Path : directoryName) 
    178                     : fileName; 
    179             } 
    180         } 
    181  
    182         public override void Execute() 
    183         { 
    184             //Retrieve the list of files to erase. 
    185             long dataTotal = 0; 
    186             List<string> paths = GetPaths(out dataTotal); 
    187  
    188             //Get the erasure method if the user specified he wants the default. 
    189             ErasureMethod method = EffectiveMethod; 
    190             dataTotal = method.CalculateEraseDataSize(paths, dataTotal); 
    191  
    192             //Set the event's current target status. 
    193             SteppedProgressManager progress = new SteppedProgressManager(); 
    194             Progress = progress; 
    195             Task.Progress.Steps.Add(new SteppedProgressManagerStep(progress, 1.0f / Task.Targets.Count)); 
    196  
    197             //Iterate over every path, and erase the path. 
    198             for (int i = 0; i < paths.Count; ++i) 
    199             { 
    200                 //Check that the file exists - we do not want to bother erasing nonexistant files 
    201                 StreamInfo info = new StreamInfo(paths[i]); 
    202                 if (!info.Exists) 
    203                 { 
    204                     Logger.Log(S._("The file {0} was not erased as the file does not exist.", 
    205                         paths[i]), LogLevel.Notice); 
    206                     continue; 
    207                 } 
    208  
    209                 //Get the filesystem provider to handle the secure file erasures 
    210                 FileSystem fsManager = ManagerLibrary.Instance.FileSystemRegistrar[ 
    211                     VolumeInfo.FromMountPoint(info.DirectoryName)]; 
    212  
    213                 bool isReadOnly = false; 
    214  
    215                 try 
    216                 { 
    217                     //Update the task progress 
    218                     ProgressManager step = new ProgressManager(); 
    219                     progress.Steps.Add(new SteppedProgressManagerStep(step, 
    220                         info.Length / (float)dataTotal, S._("Erasing files..."))); 
    221                     OnProgressChanged(this, new ProgressChangedEventArgs(step, 
    222                         new TaskProgressChangedEventArgs(paths[i], 0, method.Passes))); 
    223  
    224                     //Remove the read-only flag, if it is set. 
    225                     if (isReadOnly = info.IsReadOnly) 
    226                         info.IsReadOnly = false; 
    227  
    228                     //Make sure the file does not have any attributes which may affect 
    229                     //the erasure process 
    230                     if ((info.Attributes & FileAttributes.Compressed) != 0 || 
    231                         (info.Attributes & FileAttributes.Encrypted) != 0 || 
    232                         (info.Attributes & FileAttributes.SparseFile) != 0) 
    233                     { 
    234                         //Log the error 
    235                         Logger.Log(S._("The file {0} could not be erased because the file was " + 
    236                             "either compressed, encrypted or a sparse file.", info.FullName), 
    237                             LogLevel.Error); 
    238                         continue; 
    239                     } 
    240  
    241                     fsManager.EraseFileSystemObject(info, method, 
    242                         delegate(long lastWritten, long totalData, int currentPass) 
    243                         { 
    244                             if (Task.Canceled) 
    245                                 throw new OperationCanceledException(S._("The task was cancelled.")); 
    246  
    247                             step.Total = totalData; 
    248                             step.Completed += lastWritten; 
    249                             OnProgressChanged(this, new ProgressChangedEventArgs(step, 
    250                                 new TaskProgressChangedEventArgs(info.FullName, currentPass, method.Passes))); 
    251                         }); 
    252  
    253                     //Remove the file. 
    254                     FileInfo fileInfo = info.File; 
    255                     if (fileInfo != null) 
    256                         fsManager.DeleteFile(fileInfo); 
    257                     step.MarkComplete(); 
    258                 } 
    259                 catch (UnauthorizedAccessException) 
    260                 { 
    261                     Logger.Log(S._("The file {0} could not be erased because the file's " + 
    262                         "permissions prevent access to the file.", info.FullName), LogLevel.Error); 
    263                 } 
    264                 catch (SharingViolationException) 
    265                 { 
    266                     if (!ManagerLibrary.Settings.ForceUnlockLockedFiles) 
    267                         throw; 
    268  
    269                     StringBuilder processStr = new StringBuilder(); 
    270                     foreach (OpenHandle handle in OpenHandle.Close(info.FullName)) 
    271                     { 
    272                         try 
    273                         { 
    274                             processStr.AppendFormat( 
    275                                 System.Globalization.CultureInfo.InvariantCulture, 
    276                                 "{0}, ", System.Diagnostics.Process.GetProcessById(handle.ProcessId).MainModule.FileName); 
    277                         } 
    278                         catch (System.ComponentModel.Win32Exception) 
    279                         { 
    280                             processStr.AppendFormat( 
    281                                 System.Globalization.CultureInfo.InvariantCulture, 
    282                                 "Process ID {0}, ", handle.ProcessId); 
    283                         } 
    284                     } 
    285  
    286                     if (processStr.Length != 0) 
    287                         Logger.Log(S._("Could not force closure of file \"{0}\" {1}", 
    288                                 paths[i], S._("(locked by {0})", 
    289                                     processStr.ToString().Remove(processStr.Length - 2)).Trim()), 
    290                             LogLevel.Error); 
    291                 } 
    292                 finally 
    293                 { 
    294                     //Re-set the read-only flag if the file exists (i.e. there was an error) 
    295                     if (isReadOnly && info.Exists && !info.IsReadOnly) 
    296                         info.IsReadOnly = isReadOnly; 
    297                 } 
    298             } 
    299  
    300             Progress = null; 
    301         } 
    302     } 
    303  
    304     /// <summary> 
    305     /// Class representing a unused space erase. 
    306     /// </summary> 
    307     [Serializable] 
    308     [Guid("A627BEC4-CAFC-46ce-92AD-209157C3177A")] 
    309     public class UnusedSpaceTarget : ErasureTarget 
    310     { 
    311         #region Serialization code 
    312         protected UnusedSpaceTarget(SerializationInfo info, StreamingContext context) 
    313             : base(info, context) 
    314         { 
    315             Drive = (string)info.GetValue("Drive", typeof(string)); 
    316             EraseClusterTips = (bool)info.GetValue("EraseClusterTips", typeof(bool)); 
    317         } 
    318  
    319         [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] 
    320         public override void GetObjectData(SerializationInfo info, StreamingContext context) 
    321         { 
    322             base.GetObjectData(info, context); 
    323             info.AddValue("Drive", Drive); 
    324             info.AddValue("EraseClusterTips", EraseClusterTips); 
    325         } 
    326         #endregion 
    327  
    328         /// <summary> 
    329         /// Constructor. 
    330         /// </summary> 
    331         public UnusedSpaceTarget() 
    332             : base() 
    333         { 
    334         } 
    335  
    336         public override Guid Guid 
    337         { 
    338             get { return GetType().GUID; } 
    339         } 
    340  
    341         public sealed override ErasureMethod EffectiveMethod 
    342         { 
    343             get 
    344             { 
    345                 if (Method == ErasureMethodRegistrar.Default) 
    346                     return base.EffectiveMethod; 
    347  
    348                 return ManagerLibrary.Instance.ErasureMethodRegistrar[ 
    349                     ManagerLibrary.Settings.DefaultUnusedSpaceErasureMethod]; 
    350             } 
    351         } 
    352  
    353         public override bool SupportsMethod(ErasureMethod method) 
    354         { 
    355             return method == ErasureMethodRegistrar.Default || 
    356                 method is UnusedSpaceErasureMethod; 
    357         } 
    358  
    359         /// <summary> 
    360         /// Override the base class property so that we won't need to keep casting 
    361         /// </summary> 
    362         protected new SteppedProgressManager Progress 
    363         { 
    364             get 
    365             { 
    366                 return (SteppedProgressManager)base.Progress; 
    367             } 
    368             set 
    369             { 
    370                 base.Progress = value; 
    371             } 
    372         } 
    373  
    374         public override string UIText 
    375         { 
    376             get { return S._("Unused disk space ({0})", Drive); } 
    377         } 
    378  
    379         public override IErasureTargetConfigurer Configurer 
    380         { 
    381             get { return new UnusedSpaceErasureTargetSettings(); } 
    382         } 
    383  
    384         /// <summary> 
    385         /// The drive to erase 
    386         /// </summary> 
    387         public string Drive { get; set; } 
    388  
    389         /// <summary> 
    390         /// Whether cluster tips should be erased. 
    391         /// </summary> 
    392         public bool EraseClusterTips { get; set; } 
    393  
    394         public override void Execute() 
    395         { 
    396             //Check for sufficient privileges to run the unused space erasure. 
    397             if (!Security.IsAdministrator()) 
    398             { 
    399                 if (Environment.OSVersion.Platform == PlatformID.Win32NT && 
    400                     Environment.OSVersion.Version >= new Version(6, 0)) 
    401                 { 
    402                     Logger.Log(S._("The program does not have the required permissions to erase " + 
    403                         "the unused space on disk. Run the program as an administrator and retry " + 
    404                         "the operation."), LogLevel.Error); 
    405                 } 
    406                 else 
    407                 { 
    408                     Logger.Log(S._("The program does not have the required permissions to erase " + 
    409                         "the unused space on disk."), LogLevel.Error); 
    410                 } 
    411  
    412                 return; 
    413             } 
    414  
    415             //Check whether System Restore has any available checkpoints. 
    416             if (SystemRestore.GetInstances().Count != 0) 
    417             { 
    418                 Logger.Log(S._("This computer has had System Restore or Volume Shadow Copies " + 
    419                     "enabled. This may allow copies of files stored on the disk to be recovered " + 
    420                     "and pose a security concern.", Drive), LogLevel.Warning); 
    421             } 
    422  
    423             //If the user is under disk quotas, log a warning message 
    424             if (VolumeInfo.FromMountPoint(Drive).HasQuota) 
    425                 Logger.Log(S._("The drive {0} has disk quotas active. This will prevent the " + 
    426                     "complete erasure of unused space and may pose a security concern.", 
    427                     Drive), LogLevel.Warning); 
    428  
    429             //Get the erasure method if the user specified he wants the default. 
    430             ErasureMethod method = EffectiveMethod; 
    431  
    432             //Make a folder to dump our temporary files in 
    433             DirectoryInfo info = new DirectoryInfo(Drive); 
    434             VolumeInfo volInfo = VolumeInfo.FromMountPoint(Drive); 
    435             FileSystem fsManager = ManagerLibrary.Instance.FileSystemRegistrar[volInfo]; 
    436  
    437             //Start sampling the speed of the task. 
    438             Progress = new SteppedProgressManager(); 
    439             Task.Progress.Steps.Add(new SteppedProgressManagerStep( 
    440                 Progress, 1.0f / Task.Targets.Count)); 
    441  
    442             //Erase the cluster tips of every file on the drive. 
    443             if (EraseClusterTips) 
    444             { 
    445                 //Define the callback handlers 
    446                 ProgressManager tipSearch = new ProgressManager(); 
    447                 Progress.Steps.Add(new SteppedProgressManagerStep(tipSearch, 
    448                     0.0f, S._("Searching for files' cluster tips..."))); 
    449                 tipSearch.Total = 1; 
    450                 ClusterTipsSearchProgress searchProgress = delegate(string path) 
    451                 { 
    452                     if (Task.Canceled) 
    453                         throw new OperationCanceledException(S._("The task was cancelled.")); 
    454  
    455                     OnProgressChanged(this, new ProgressChangedEventArgs(tipSearch, 
    456                         new TaskProgressChangedEventArgs(path, 0, 0))); 
    457                 }; 
    458  
    459                 ProgressManager tipProgress = new ProgressManager(); 
    460                 Progress.Steps.Add(new SteppedProgressManagerStep(tipProgress, 0.1f, 
    461                     S._("Erasing cluster tips..."))); 
    462                 ClusterTipsEraseProgress eraseProgress = 
    463                     delegate(int currentFile, int totalFiles, string currentFilePath) 
    464                     { 
    465                         tipSearch.MarkComplete(); 
    466                         tipProgress.Total = totalFiles; 
    467                         tipProgress.Completed = currentFile; 
    468                         OnProgressChanged(this, new ProgressChangedEventArgs(tipProgress, 
    469                             new TaskProgressChangedEventArgs(currentFilePath, 0, 0))); 
    470  
    471                         if (Task.Canceled) 
    472                             throw new OperationCanceledException(S._("The task was cancelled.")); 
    473                     }; 
    474  
    475                 //Start counting statistics 
    476                 fsManager.EraseClusterTips(VolumeInfo.FromMountPoint(Drive), 
    477                     method, searchProgress, eraseProgress); 
    478                 tipProgress.MarkComplete(); 
    479             } 
    480  
    481             bool lowDiskSpaceNotifications = Shell.LowDiskSpaceNotificationsEnabled; 
    482             info = info.CreateSubdirectory(Path.GetFileName( 
    483                 FileSystem.GenerateRandomFileName(info, 18))); 
    484             try 
    485             { 
    486                 //Set the folder's compression flag off since we want to use as much 
    487                 //space as possible 
    488                 if (info.IsCompressed()) 
    489                     info.Uncompress(); 
    490  
    491                 //Disable the low disk space notifications 
    492                 Shell.LowDiskSpaceNotificationsEnabled = false; 
    493  
    494                 ProgressManager mainProgress = new ProgressManager(); 
    495                 Progress.Steps.Add(new SteppedProgressManagerStep(mainProgress, 
    496                     EraseClusterTips ? 0.8f : 0.9f, S._("Erasing unused space..."))); 
    497  
    498                 //Continue creating files while there is free space. 
    499                 while (volInfo.AvailableFreeSpace > 0) 
    500                 { 
    501                     //Generate a non-existant file name 
    502                     string currFile = FileSystem.GenerateRandomFileName(info, 18); 
    503  
    504                     //Create the stream 
    505                     using (FileStream stream = new FileStream(currFile, FileMode.CreateNew, 
    506                         FileAccess.Write, FileShare.None, 8, FileOptions.WriteThrough)) 
    507                     { 
    508                         //Set the length of the file to be the amount of free space left 
    509                         //or the maximum size of one of these dumps. 
    510                         mainProgress.Total = mainProgress.Completed + 
    511                             method.CalculateEraseDataSize(null, volInfo.AvailableFreeSpace); 
    512                         long streamLength = Math.Min(ErasureMethod.FreeSpaceFileUnit, 
    513                             volInfo.AvailableFreeSpace); 
    514  
    515                         //Handle IO exceptions gracefully, because the filesystem 
    516                         //may require more space than demanded by us for file allocation. 
    517                         while (true) 
    518                             try 
    519                             { 
    520                                 stream.SetLength(streamLength); 
    521                                 break; 
    522                             } 
    523                             catch (IOException) 
    524                             { 
    525                                 if (streamLength > volInfo.ClusterSize) 
    526                                     streamLength -= volInfo.ClusterSize; 
    527                                 else 
    528                                     throw; 
    529                             } 
    530  
    531                         //Then run the erase task 
    532                         method.Erase(stream, long.MaxValue, 
    533                             ManagerLibrary.Instance.PrngRegistrar[ManagerLibrary.Settings.ActivePrng], 
    534                             delegate(long lastWritten, long totalData, int currentPass) 
    535                             { 
    536                                 mainProgress.Completed += lastWritten; 
    537                                 OnProgressChanged(this, new ProgressChangedEventArgs(mainProgress, 
    538                                     new TaskProgressChangedEventArgs(Drive, currentPass, method.Passes))); 
    539  
    540                                 if (Task.Canceled) 
    541                                     throw new OperationCanceledException(S._("The task was cancelled.")); 
    542                             } 
    543                         ); 
    544                     } 
    545                 } 
    546  
    547                 //Mark the main bulk of the progress as complete 
    548                 mainProgress.MarkComplete(); 
    549  
    550                 //Erase old resident file system table files 
    551                 ProgressManager residentProgress = new ProgressManager(); 
    552                 Progress.Steps.Add(new SteppedProgressManagerStep(residentProgress, 
    553                     0.05f, S._("Old resident file system table files"))); 
    554                 fsManager.EraseOldFileSystemResidentFiles(volInfo, info, method, 
    555                     delegate(int currentFile, int totalFiles) 
    556                     { 
    557                         residentProgress.Completed = currentFile; 
    558                         residentProgress.Total = totalFiles; 
    559                         OnProgressChanged(this, new ProgressChangedEventArgs(residentProgress, 
    560                             new TaskProgressChangedEventArgs(string.Empty, 0, 0))); 
    561  
    562                         if (Task.Canceled) 
    563                             throw new OperationCanceledException(S._("The task was cancelled.")); 
    564                     } 
    565                 ); 
    566  
    567                 residentProgress.MarkComplete(); 
    568             } 
    569             finally 
    570             { 
    571                 //Remove the folder holding all our temporary files. 
    572                 ProgressManager tempFiles = new ProgressManager(); 
    573                 Progress.Steps.Add(new SteppedProgressManagerStep(tempFiles, 
    574                     0.0f, S._("Removing temporary files..."))); 
    575                 OnProgressChanged(this, new ProgressChangedEventArgs(tempFiles, 
    576                     new TaskProgressChangedEventArgs(string.Empty, 0, 0))); 
    577                 info.Delete(true); 
    578                 tempFiles.Completed = tempFiles.Total; 
    579  
    580                 //Reset the low disk space notifications 
    581                 Shell.LowDiskSpaceNotificationsEnabled = lowDiskSpaceNotifications; 
    582             } 
    583  
    584             //Then clean the old file system entries 
    585             ProgressManager structureProgress = new ProgressManager(); 
    586             Progress.Steps.Add(new SteppedProgressManagerStep(structureProgress, 
    587                 0.05f, S._("Erasing unused directory structures..."))); 
    588             fsManager.EraseDirectoryStructures(volInfo, 
    589                 delegate(int currentFile, int totalFiles) 
    590                 { 
    591                     if (Task.Canceled) 
    592                         throw new OperationCanceledException(S._("The task was cancelled.")); 
    593  
    594                     //Compute the progress 
    595                     structureProgress.Total = totalFiles; 
    596                     structureProgress.Completed = currentFile; 
    597  
    598                     //Set the event parameters, then broadcast the progress event. 
    599                     OnProgressChanged(this, new ProgressChangedEventArgs(structureProgress, 
    600                         new TaskProgressChangedEventArgs(string.Empty, 0, 0))); 
    601                 } 
    602             ); 
    603  
    604             structureProgress.MarkComplete(); 
    605             Progress = null; 
    606         } 
    607     } 
    608  
    60933    /// <summary> 
    61034    /// Class representing a file to be erased. 
     
    65478        } 
    65579    } 
    656  
    657     /// <summary> 
    658     /// Represents a folder and its files which are to be erased. 
    659     /// </summary> 
    660     [Serializable] 
    661     [Guid("F50B0A44-3AB1-4cab-B81E-1713AC3D28C9")] 
    662     public class FolderTarget : FileSystemObjectTarget 
    663     { 
    664         #region Serialization code 
    665         protected FolderTarget(SerializationInfo info, StreamingContext context) 
    666             : base(info, context) 
    667         { 
    668             IncludeMask = (string)info.GetValue("IncludeMask", typeof(string)); 
    669             ExcludeMask = (string)info.GetValue("ExcludeMask", typeof(string)); 
    670             DeleteIfEmpty = (bool)info.GetValue("DeleteIfEmpty", typeof(bool)); 
    671         } 
    672  
    673         [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)] 
    674         public override void GetObjectData(SerializationInfo info, StreamingContext context) 
    675         { 
    676             base.GetObjectData(info, context); 
    677             info.AddValue("IncludeMask", IncludeMask); 
    678             info.AddValue("ExcludeMask", ExcludeMask); 
    679             info.AddValue("DeleteIfEmpty", DeleteIfEmpty); 
    680         } 
    681         #endregion 
    682  
    683         /// <summary> 
    684         /// Constructor. 
    685         /// </summary> 
    686         public FolderTarget() 
    687         { 
    688             IncludeMask = string.Empty; 
    689             ExcludeMask = string.Empty; 
    690             DeleteIfEmpty = true; 
    691         } 
    692  
    693         public override Guid Guid 
    694         { 
    695             get { return GetType().GUID; } 
    696         } 
    697  
    698         public override IErasureTargetConfigurer Configurer 
    699         { 
    700             get { return new FolderErasureTargetSettings(); } 
    701         } 
    702  
    703         internal override List<string> GetPaths(out long totalSize) 
    704         { 
    705             //Get a list to hold all the resulting paths. 
    706             List<string> result = new List<string>(); 
    707  
    708             //Open the root of the search, including every file matching the pattern 
    709             DirectoryInfo dir = new DirectoryInfo(Path); 
    710  
    711             //List recursively all the files which match the include pattern. 
    712             FileInfo[] files = GetFiles(dir); 
    713  
    714             //Then exclude each file and finalize the list and total file size 
    715             totalSize = 0; 
    716             if (ExcludeMask.Length != 0) 
    717             { 
    718                 string regex = Regex.Escape(ExcludeMask).Replace("\\*", ".*"). 
    719                     Replace("\\?", "."); 
    720                 Regex excludePattern = new Regex(regex, RegexOptions.IgnoreCase); 
    721                 foreach (FileInfo file in files) 
    722                     if (file.Exists && 
    723                         (file.Attributes & FileAttributes.ReparsePoint) == 0 && 
    724                         excludePattern.Matches(file.FullName).Count == 0) 
    725                     { 
    726                         totalSize += file.Length; 
    727                         GetPathADSes(result, out totalSize, file.FullName); 
    728                         result.Add(file.FullName); 
    729                     } 
    730             } 
    731             else 
    732                 foreach (FileInfo file in files) 
    733                 { 
    734                     if (!file.Exists || (file.Attributes & FileAttributes.ReparsePoint) != 0) 
    735                         continue; 
    736  
    737                     //Get the size of the file and its ADSes 
    738                     totalSize += file.Length; 
    739                     long adsesSize = 0; 
    740                     GetPathADSes(result, out adsesSize, file.FullName); 
    741                     totalSize += adsesSize; 
    742  
    743                     //Append this file to the list of files to erase. 
    744                     result.Add(file.FullName); 
    745                 } 
    746  
    747             //Return the filtered list. 
    748             return result; 
    749         } 
    750  
    751         /// <summary> 
    752         /// Gets all files in the provided directory. 
    753         /// </summary> 
    754         /// <param name="info">The directory to look files in.</param> 
    755         /// <returns>A list of files found in the directory matching the IncludeMask 
    756         /// property.</returns> 
    757         private FileInfo[] GetFiles(DirectoryInfo info) 
    758         { 
    759             List<FileInfo> result = new List<FileInfo>(); 
    760             if (info.Exists) 
    761             { 
    762                 try 
    763                 { 
    764                     foreach (DirectoryInfo dir in info.GetDirectories()) 
    765                         result.AddRange(GetFiles(dir)); 
    766  
    767                     if (IncludeMask.Length == 0) 
    768                         result.AddRange(info.GetFiles()); 
    769                     else 
    770                         result.AddRange(info.GetFiles(IncludeMask, SearchOption.TopDirectoryOnly)); 
    771                 } 
    772                 catch (UnauthorizedAccessException e) 
    773                 { 
    774                     Logger.Log(S._("Could not erase files and subfolders in {0} because {1}", 
    775                         info.FullName, e.Message), LogLevel.Error); 
    776                 } 
    777             } 
    778  
    779             return result.ToArray(); 
    780         } 
    781  
    782         /// <summary> 
    783         /// A wildcard expression stating the condition for the set of files to include. 
    784         /// The include mask is applied before the exclude mask is applied. If this value 
    785         /// is empty, all files and folders within the folder specified is included. 
    786         /// </summary> 
    787         public string IncludeMask { get; set; } 
    788  
    789         /// <summary> 
    790         /// A wildcard expression stating the condition for removing files from the set 
    791         /// of included files. If this value is omitted, all files and folders extracted 
    792         /// by the inclusion mask is erased. 
    793         /// </summary> 
    794         public string ExcludeMask { get; set; } 
    795  
    796         /// <summary> 
    797         /// Determines if Eraser should delete the folder after the erase process. 
    798         /// </summary> 
    799         public bool DeleteIfEmpty { get; set; } 
    800  
    801         public override void Execute() 
    802         { 
    803              base.Execute(); 
    804  
    805              //If the user requested a folder removal, do it. 
    806              if (Directory.Exists(Path)) 
    807              { 
    808                  ProgressManager step = new ProgressManager(); 
    809                  Progress.Steps.Add(new SteppedProgressManagerStep(step, 
    810                      0.0f, S._("Removing folders..."))); 
    811  
    812                  //Remove all subfolders which are empty. 
    813                  FileSystem fsManager = ManagerLibrary.Instance.FileSystemRegistrar[ 
    814                      VolumeInfo.FromMountPoint(Path)]; 
    815                  Action<DirectoryInfo> eraseEmptySubFolders = null; 
    816                  eraseEmptySubFolders = delegate(DirectoryInfo info) 
    817                  { 
    818                      foreach (DirectoryInfo subDir in info.GetDirectories()) 
    819                          eraseEmptySubFolders(subDir); 
    820                      OnProgressChanged(this, new ProgressChangedEventArgs(step, 
    821                         new TaskProgressChangedEventArgs(info.FullName, 0, 0))); 
    822  
    823                      FileSystemInfo[] files = info.GetFileSystemInfos(); 
    824                      if (files.Length == 0) 
    825                          fsManager.DeleteFolder(info); 
    826                  }; 
    827  
    828                  DirectoryInfo directory = new DirectoryInfo(Path); 
    829                  foreach (DirectoryInfo subDir in directory.GetDirectories()) 
    830                      eraseEmptySubFolders(subDir); 
    831  
    832                  if (DeleteIfEmpty) 
    833                  { 
    834                      //See if this is the root of a volume. 
    835                      bool isVolumeRoot = directory.Parent == null; 
    836                      foreach (VolumeInfo volume in VolumeInfo.Volumes) 
    837                          foreach (string mountPoint in volume.MountPoints) 
    838                              if (directory.FullName == mountPoint) 
    839                                  isVolumeRoot = true; 
    840  
    841                      //If the folder is a mount point, then don't delete it. If it isn't, 
    842                      //search for files under the folder to see if it is empty. 
    843                      if (!isVolumeRoot && directory.Exists && 
    844                          directory.GetFiles("*", SearchOption.AllDirectories).Length == 0) 
    845                      { 
    846                          fsManager.DeleteFolder(directory); 
    847                      } 
    848                  } 
    849              } 
    850         } 
    851     } 
    852  
    853     [Serializable] 
    854     [Guid("A1FA7354-0258-4903-88E9-0D31FC5F8D51")] 
    855     public class RecycleBinTarget : FileSystemObjectTarget 
    856     { 
    857         #region Serialization code 
    858         protected RecycleBinTarget(SerializationInfo info, StreamingContext context) 
    859             : base(info, context) 
    860         { 
    861         } 
    862         #endregion 
    863  
    864         public RecycleBinTarget() 
    865         { 
    866         } 
    867  
    868         public override Guid Guid 
    869         { 
    870             get { return GetType().GUID; } 
    871         } 
    872  
    873         public override IErasureTargetConfigurer Configurer 
    874         { 
    875             get { return null; } 
    876         } 
    877  
    878         internal override List<string> GetPaths(out long totalSize) 
    879         { 
    880             totalSize = 0; 
    881             List<string> result = new List<string>(); 
    882             string[] rootDirectory = new string[] { 
    883                     "$RECYCLE.BIN", 
    884                     "RECYCLER" 
    885                 }; 
    886  
    887             foreach (DriveInfo drive in DriveInfo.GetDrives()) 
    888             { 
    889                 foreach (string rootDir in rootDirectory) 
    890                 { 
    891                     DirectoryInfo dir = new DirectoryInfo( 
    892                         System.IO.Path.Combine( 
    893                             System.IO.Path.Combine(drive.Name, rootDir), 
    894                             System.Security.Principal.WindowsIdentity.GetCurrent(). 
    895                                 User.ToString())); 
    896                     if (!dir.Exists) 
    897                         continue; 
    898  
    899                     GetRecyclerFiles(dir, result, ref totalSize); 
    900                 } 
    901             } 
    902  
    903             return result; 
    904         } 
    905  
    906         /// <summary> 
    907         /// Retrieves all files within this folder, without exclusions. 
    908         /// </summary> 
    909         /// <param name="info">The DirectoryInfo object representing the folder to traverse.</param> 
    910         /// <param name="paths">The list of files to store path information in.</param> 
    911         /// <param name="totalSize">Receives the total size of the files.</param> 
    912         private void GetRecyclerFiles(DirectoryInfo info, List<string> paths, 
    913             ref long totalSize) 
    914         { 
    915             try 
    916             { 
    917                 foreach (FileInfo fileInfo in info.GetFiles()) 
    918                 { 
    919                     if (!fileInfo.Exists || (fileInfo.Attributes & FileAttributes.ReparsePoint) != 0) 
    920                         continue; 
    921  
    922                     long adsSize = 0; 
    923                     GetPathADSes(paths, out adsSize, fileInfo.FullName); 
    924                     totalSize += adsSize; 
    925                     totalSize += fileInfo.Length; 
    926                     paths.Add(fileInfo.FullName); 
    927                 } 
    928  
    929                 foreach (DirectoryInfo directoryInfo in info.GetDirectories()) 
    930                     if ((directoryInfo.Attributes & FileAttributes.ReparsePoint) == 0) 
    931                         GetRecyclerFiles(directoryInfo, paths, ref totalSize); 
    932             } 
    933             catch (UnauthorizedAccessException e) 
    934             { 
    935                 Logger.Log(e.Message, LogLevel.Error); 
    936             } 
    937         } 
    938  
    939         /// <summary> 
    940         /// Retrieves the text to display representing this task. 
    941         /// </summary> 
    942         public override string UIText 
    943         { 
    944             get 
    945             { 
    946                 return S._("Recycle Bin"); 
    947             } 
    948         } 
    949  
    950         public override void Execute() 
    951         { 
    952             base.Execute(); 
    953  
    954             ProgressManager step = new ProgressManager(); 
    955             Progress.Steps.Add(new SteppedProgressManagerStep(step, 
    956                 0.0f, S._("Emptying recycle bin..."))); 
    957             OnProgressChanged(this, new ProgressChangedEventArgs(step, 
    958                 new TaskProgressChangedEventArgs(string.Empty, 0, 0))); 
    959  
    960             RecycleBin.Empty(EmptyRecycleBinOptions.NoConfirmation | 
    961                 EmptyRecycleBinOptions.NoProgressUI | EmptyRecycleBinOptions.NoSound); 
    962         } 
    963     } 
    96480} 
Note: See TracChangeset for help on using the changeset viewer.