Changeset 2189


Ignore:
Timestamp:
6/18/2010 2:36:03 PM (4 years ago)
Author:
lowjoel
Message:
  • Define a VolumeStream? class which is a FileStream? customised for raw volume access. This results in the VolumeLock? class being merged into the VolumeStream? class, automatically handling locking and unlocking of volumes.
  • Change all internal OpenHandle? functions to private, since they should not be callable from outside the class.
  • Perform error checking in OpenHandle? so that even callers of OpenHandle? gets error checking.
Location:
trunk/eraser
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/eraser/Eraser.DefaultPlugins/FileSystems/Fat.cs

    r2157 r2189  
    8989                try 
    9090                { 
    91                     using (VolumeLock volumeLock = info.LockVolume(stream)) 
     91                    while (eraseQueue.Count != 0) 
    9292                    { 
    93                         while (eraseQueue.Count != 0) 
    94                         { 
    95                             if (callback != null) 
    96                                 callback(directoriesCleaned, directoriesCleaned + eraseQueue.Count); 
     93                        if (callback != null) 
     94                            callback(directoriesCleaned, directoriesCleaned + eraseQueue.Count); 
    9795 
    98                             FatDirectoryBase currentDir = api.LoadDirectory(eraseQueue[0].FullName); 
    99                             eraseQueue.RemoveAt(0); 
     96                        FatDirectoryBase currentDir = api.LoadDirectory(eraseQueue[0].FullName); 
     97                        eraseQueue.RemoveAt(0); 
    10098 
    101                             //Queue the subfolders in this directory 
    102                             foreach (KeyValuePair<string, FatDirectoryEntry> entry in currentDir.Items) 
    103                                 if (entry.Value.EntryType == FatDirectoryEntryType.Directory) 
    104                                 { 
    105                                     //Check that we don't have the same cluster queued twice (e.g. for 
    106                                     //long/8.3 file names) 
    107                                     if (eraseQueueClusters.Contains(entry.Value.Cluster)) 
    108                                         continue; 
     99                        //Queue the subfolders in this directory 
     100                        foreach (KeyValuePair<string, FatDirectoryEntry> entry in currentDir.Items) 
     101                            if (entry.Value.EntryType == FatDirectoryEntryType.Directory) 
     102                            { 
     103                                //Check that we don't have the same cluster queued twice (e.g. for 
     104                                //long/8.3 file names) 
     105                                if (eraseQueueClusters.Contains(entry.Value.Cluster)) 
     106                                    continue; 
    109107 
    110                                     eraseQueueClusters.Add(entry.Value.Cluster); 
    111                                     eraseQueue.Add(entry.Value); 
    112                                 } 
     108                                eraseQueueClusters.Add(entry.Value.Cluster); 
     109                                eraseQueue.Add(entry.Value); 
     110                            } 
    113111 
    114                             currentDir.ClearDeletedEntries(); 
    115                             ++directoriesCleaned; 
    116                         } 
     112                        currentDir.ClearDeletedEntries(); 
     113                        ++directoriesCleaned; 
    117114                    } 
    118115                } 
  • trunk/eraser/Eraser.Util/NtfsApi.cs

    r1873 r2189  
    6969        internal static NativeMethods.NTFS_VOLUME_DATA_BUFFER? GetNtfsVolumeData(VolumeInfo volume) 
    7070        { 
    71             using (SafeFileHandle volumeHandle = volume.OpenHandle( 
    72                 FileAccess.Read, FileShare.ReadWrite, FileOptions.None)) 
     71            using (FileStream stream = volume.Open(FileAccess.Read, FileShare.ReadWrite, 
     72                FileOptions.None)) 
     73            using (SafeFileHandle handle = stream.SafeFileHandle) 
    7374            { 
    74                 if (volumeHandle.IsInvalid) 
    75                     return null; 
    76  
    7775                uint resultSize = 0; 
    7876                NativeMethods.NTFS_VOLUME_DATA_BUFFER volumeData = 
    7977                    new NativeMethods.NTFS_VOLUME_DATA_BUFFER(); 
    80                 if (NativeMethods.DeviceIoControl(volumeHandle, 
     78                if (NativeMethods.DeviceIoControl(handle, 
    8179                    NativeMethods.FSCTL_GET_NTFS_VOLUME_DATA, IntPtr.Zero, 0, out volumeData, 
    8280                    (uint)Marshal.SizeOf(volumeData), out resultSize, IntPtr.Zero)) 
  • trunk/eraser/Eraser.Util/VolumeInfo.cs

    r2187 r2189  
    635635        public FileStream Open(FileAccess access, FileShare share, FileOptions options) 
    636636        { 
    637             SafeFileHandle handle = OpenHandle(access, share, options); 
    638  
    639             //Check that the handle is valid 
    640             if (handle.IsInvalid) 
    641             { 
    642                 int errorCode = Marshal.GetLastWin32Error(); 
    643                 handle.Close(); 
    644                 throw Win32ErrorCode.GetExceptionForWin32Error(errorCode); 
    645             } 
    646  
    647             //Return the FileStream 
    648             return new FileStream(handle, access); 
    649         } 
    650  
    651         internal SafeFileHandle OpenHandle(FileAccess access, FileShare share, FileOptions options) 
     637            return new VolumeStream(this, OpenHandle(access, share, options), access); 
     638        } 
     639 
     640        private SafeFileHandle OpenHandle(FileAccess access, FileShare share, FileOptions options) 
    652641        { 
    653642            //Access mode 
     
    669658        } 
    670659 
    671         internal SafeFileHandle OpenHandle(uint access, FileShare share, FileOptions options) 
     660        private SafeFileHandle OpenHandle(uint access, FileShare share, FileOptions options) 
    672661        { 
    673662            //Sharing mode 
     
    683672            if (openPath.Length > 0 && openPath[openPath.Length - 1] == '\\') 
    684673                openPath = openPath.Remove(openPath.Length - 1); 
    685             return NativeMethods.CreateFile(openPath, access, (uint)share, IntPtr.Zero, 
    686                 (uint)FileMode.Open, (uint)options, IntPtr.Zero); 
     674 
     675            SafeFileHandle result = NativeMethods.CreateFile(openPath, access, (uint)share, 
     676                IntPtr.Zero, (uint)FileMode.Open, (uint)options, IntPtr.Zero); 
     677 
     678            //Check that the handle is valid 
     679            if (result.IsInvalid) 
     680            { 
     681                int errorCode = Marshal.GetLastWin32Error(); 
     682                result.Close(); 
     683                throw Win32ErrorCode.GetExceptionForWin32Error(errorCode); 
     684            } 
     685 
     686            return result; 
    687687        } 
    688688 
     
    739739            return VolumeId.GetHashCode(); 
    740740        } 
    741  
    742         public VolumeLock LockVolume(FileStream stream) 
    743         { 
    744             return new VolumeLock(stream); 
    745         } 
    746741    } 
    747742 
    748     public sealed class VolumeLock : IDisposable 
     743    public class VolumeStream : FileStream 
    749744    { 
    750         internal VolumeLock(FileStream stream) 
    751         { 
     745        internal VolumeStream(VolumeInfo volume, SafeFileHandle handle, FileAccess access) 
     746            : base(handle, access) 
     747        { 
     748            Volume = volume; 
     749            Access = access; 
     750 
     751            if (Access == FileAccess.Write || Access == FileAccess.ReadWrite) 
     752                LockVolume(); 
     753        } 
     754 
     755        protected override void Dispose(bool disposing) 
     756        { 
     757            if (Access == FileAccess.Write || Access == FileAccess.ReadWrite) 
     758                UnlockVolume(); 
     759            base.Dispose(disposing); 
     760        } 
     761 
     762        public override void SetLength(long value) 
     763        { 
     764            throw new InvalidOperationException(); 
     765        } 
     766 
     767        public override long Length 
     768        { 
     769            get 
     770            { 
     771                if (IsLocked) 
     772                    return LengthCache; 
     773                return Volume.TotalSize; 
     774            } 
     775        } 
     776 
     777        /// <summary> 
     778        /// Temporarily stores the length of the disk while the disk is locked. 
     779        /// </summary> 
     780        private long LengthCache; 
     781 
     782        private void LockVolume() 
     783        { 
     784            LengthCache = Length; 
    752785            uint result = 0; 
    753             for (int i = 0; !NativeMethods.DeviceIoControl(stream.SafeFileHandle, 
     786            for (int i = 0; !NativeMethods.DeviceIoControl(SafeFileHandle, 
    754787                    NativeMethods.FSCTL_LOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 
    755788                    0, out result, IntPtr.Zero); ++i) 
     
    760793            } 
    761794 
    762             Stream = stream; 
    763         } 
    764  
    765         ~VolumeLock() 
    766         { 
    767             Dispose(false); 
    768         } 
    769  
    770         public void Dispose() 
    771         { 
    772             Dispose(true); 
    773             GC.SuppressFinalize(this); 
    774         } 
    775  
    776         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "disposing")] 
    777         private void Dispose(bool disposing) 
    778         { 
    779             if (Stream == null) 
    780                 return; 
    781  
     795            IsLocked = true; 
     796        } 
     797 
     798        private void UnlockVolume() 
     799        { 
    782800            //Flush the contents of the buffer to disk since after we unlock the volume 
    783801            //we can no longer write to the volume. 
    784             Stream.Flush(); 
     802            Flush(); 
    785803 
    786804            uint result = 0; 
    787             if (!NativeMethods.DeviceIoControl(Stream.SafeFileHandle, 
    788                 NativeMethods.FSCTL_UNLOCK_VOLUME, IntPtr.Zero, 0, IntPtr.Zero, 
    789                 0, out result, IntPtr.Zero)) 
     805            if (!NativeMethods.DeviceIoControl(SafeFileHandle, NativeMethods.FSCTL_UNLOCK_VOLUME, 
     806                IntPtr.Zero, 0, IntPtr.Zero, 0, out result, IntPtr.Zero)) 
    790807            { 
    791808                throw new IOException("Could not unlock volume."); 
    792809            } 
    793810 
    794             //Set the stream to null so that we won't run this function again. 
    795             Stream = null; 
    796         } 
    797  
    798         private FileStream Stream; 
     811            LengthCache = 0; 
     812            IsLocked = false; 
     813        } 
     814 
     815        /// <summary> 
     816        /// Reflects whether the current handle has exclusive access to the volume. 
     817        /// </summary> 
     818        private bool IsLocked; 
     819 
     820        /// <summary> 
     821        /// The <see cref="VolumeInfo"/> object this stream is encapsulating. 
     822        /// </summary> 
     823        private VolumeInfo Volume; 
     824 
     825        /// <summary> 
     826        /// The access parameter for this stream. 
     827        /// </summary> 
     828        private FileAccess Access; 
    799829    } 
    800830 
Note: See TracChangeset for help on using the changeset viewer.