Changeset 2335


Ignore:
Timestamp:
10/30/2011 1:56:23 AM (3 years ago)
Author:
lowjoel
Message:

Allow file unlocking to be done in the actual erasure as well, in addition to when finding stream ADSes. This allows a greater number of files to be unlocked. Addresses #394

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/eraser/Eraser.DefaultPlugins/ErasureTargets/FileSystemObjectErasureTarget.cs

    r2274 r2335  
    255255                    info.IsReadOnly = false; 
    256256 
    257                 //Make sure the file does not have any attributes which may affect 
    258                 //the erasure process 
    259                 if ((info.Attributes & FileAttributes.Compressed) != 0 || 
    260                     (info.Attributes & FileAttributes.Encrypted) != 0 || 
    261                     (info.Attributes & FileAttributes.SparseFile) != 0) 
    262                 { 
    263                     //Log the error 
    264                     Logger.Log(S._("The file {0} could not be erased because the file was " + 
    265                         "either compressed, encrypted or a sparse file.", info.FullName), 
    266                         LogLevel.Error); 
    267                     return; 
    268                 } 
    269  
    270                 //Do not erase reparse points, as they will cause other references to the file 
    271                 //to be to garbage. 
    272                 if ((info.Attributes & FileAttributes.ReparsePoint) == 0) 
    273                     fsManager.EraseFileSystemObject(info, method, 
    274                         delegate(long lastWritten, long totalData, int currentPass) 
    275                         { 
    276                             if (Task.Canceled) 
    277                                 throw new OperationCanceledException(S._("The task was cancelled.")); 
    278  
    279                             progress.Total = totalData; 
    280                             progress.Completed += lastWritten; 
    281                             OnProgressChanged(this, new ProgressChangedEventArgs(progress, 
    282                                 new TaskProgressChangedEventArgs(info.FullName, currentPass, method.Passes))); 
    283                         }); 
    284                 else 
    285                     Logger.Log(S._("The file {0} is a hard link or a symbolic link thus the " + 
    286                         "contents of the file was not erased.", LogLevel.Notice)); 
    287  
    288                 //Remove the file. 
    289                 FileInfo fileInfo = info.File; 
    290                 if (fileInfo != null) 
    291                     fsManager.DeleteFile(fileInfo); 
     257                //Define the callback function for progress reporting. 
     258                ErasureMethodProgressFunction callback = 
     259                    delegate(long lastWritten, long totalData, int currentPass) 
     260                    { 
     261                        if (Task.Canceled) 
     262                            throw new OperationCanceledException(S._("The task was cancelled.")); 
     263 
     264                        progress.Total = totalData; 
     265                        progress.Completed += lastWritten; 
     266                        OnProgressChanged(this, new ProgressChangedEventArgs(progress, 
     267                            new TaskProgressChangedEventArgs(info.FullName, currentPass, method.Passes))); 
     268                    }; 
     269 
     270                TryEraseStream(fsManager, method, info, callback); 
    292271                progress.MarkComplete(); 
    293272            } 
     
    296275                Logger.Log(S._("The file {0} could not be erased because the file's " + 
    297276                    "permissions prevent access to the file.", info.FullName), LogLevel.Error); 
    298             } 
    299             catch (SharingViolationException) 
    300             { 
    301                 if (!ManagerLibrary.Settings.ForceUnlockLockedFiles) 
    302                     throw; 
    303  
    304                 StringBuilder processStr = new StringBuilder(); 
    305                 foreach (OpenHandle handle in OpenHandle.Close(info.FullName)) 
    306                 { 
    307                     try 
    308                     { 
    309                         processStr.AppendFormat( 
    310                             System.Globalization.CultureInfo.InvariantCulture, 
    311                             "{0}, ", handle.Process.MainModule.FileName); 
    312                     } 
    313                     catch (System.ComponentModel.Win32Exception) 
    314                     { 
    315                         processStr.AppendFormat( 
    316                             System.Globalization.CultureInfo.InvariantCulture, 
    317                             "Process ID {0}, ", handle.Process.Id); 
    318                     } 
    319                 } 
    320  
    321                 if (processStr.Length != 0) 
    322                     Logger.Log(S._("Could not force closure of file \"{0}\" {1}", 
    323                             info.FileName, S._("(locked by {0})", 
    324                                 processStr.ToString().Remove(processStr.Length - 2)).Trim()), 
    325                         LogLevel.Error); 
    326277            } 
    327278            finally 
     
    332283            } 
    333284        } 
     285 
     286        /// <summary> 
     287        /// Attempts to erase a stream, trying to close all open handles if a process has 
     288        /// a lock on the file. 
     289        /// </summary> 
     290        /// <param name="fsManager">The file system provider used to erase the stream.</param> 
     291        /// <param name="method">The erasure method to use to erase the stream.</param> 
     292        /// <param name="info">The stream to erase.</param> 
     293        /// <param name="callback">The erasure progress callback.</param> 
     294        private void TryEraseStream(FileSystem fsManager, ErasureMethod method, StreamInfo info, 
     295            ErasureMethodProgressFunction callback) 
     296        { 
     297            for (int i = 0; ; ++i) 
     298            { 
     299                try 
     300                { 
     301                    //Make sure the file does not have any attributes which may affect 
     302                    //the erasure process 
     303                    if ((info.Attributes & FileAttributes.Compressed) != 0 || 
     304                        (info.Attributes & FileAttributes.Encrypted) != 0 || 
     305                        (info.Attributes & FileAttributes.SparseFile) != 0) 
     306                    { 
     307                        //Log the error 
     308                        Logger.Log(S._("The file {0} could not be erased because the file was " + 
     309                            "either compressed, encrypted or a sparse file.", info.FullName), 
     310                            LogLevel.Error); 
     311                        return; 
     312                    } 
     313 
     314                    //Do not erase reparse points, as they will cause other references to the file 
     315                    //to be to garbage. 
     316                    if ((info.Attributes & FileAttributes.ReparsePoint) == 0) 
     317                        fsManager.EraseFileSystemObject(info, method, callback); 
     318                    else 
     319                        Logger.Log(S._("The file {0} is a hard link or a symbolic link thus the " + 
     320                            "contents of the file was not erased.", LogLevel.Notice)); 
     321 
     322                    //Remove the file. 
     323                    FileInfo fileInfo = info.File; 
     324                    if (fileInfo != null) 
     325                        fsManager.DeleteFile(fileInfo); 
     326                    return; 
     327                } 
     328                catch (SharingViolationException) 
     329                { 
     330                    if (!ManagerLibrary.Settings.ForceUnlockLockedFiles) 
     331                        throw; 
     332 
     333                    //Try closing all open handles. If it succeeds, we can run the erase again. 
     334                    //To prevent Eraser from deadlocking, we will only attempt this once. Some 
     335                    //programs may be aggressive and keep a handle open in a tight loop. 
     336                    List<OpenHandle> remainingHandles = OpenHandle.Close(info.FullName); 
     337                    if (i == 0 && remainingHandles.Count == 0) 
     338                        continue; 
     339 
     340                    //Either we could not close all instances, or we already tried twice. Report 
     341                    //the error. 
     342                    StringBuilder processStr = new StringBuilder(); 
     343                    foreach (OpenHandle handle in remainingHandles) 
     344                    { 
     345                        try 
     346                        { 
     347                            processStr.AppendFormat( 
     348                                System.Globalization.CultureInfo.InvariantCulture, 
     349                                "{0}, ", handle.Process.MainModule.FileName); 
     350                        } 
     351                        catch (System.ComponentModel.Win32Exception) 
     352                        { 
     353                            processStr.AppendFormat( 
     354                                System.Globalization.CultureInfo.InvariantCulture, 
     355                                "Process ID {0}, ", handle.Process.Id); 
     356                        } 
     357                    } 
     358 
     359                    if (processStr.Length != 0) 
     360                        Logger.Log(S._("Could not force closure of file \"{0}\" {1}", 
     361                                info.FileName, S._("(locked by {0})", 
     362                                    processStr.ToString().Remove(processStr.Length - 2)).Trim()), 
     363                            LogLevel.Error); 
     364                } 
     365            } 
     366        } 
    334367    } 
    335368} 
Note: See TracChangeset for help on using the changeset viewer.