Changeset 1708


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

Drop-in replacement of the StreamInfo? class with a rewritten one which uses FileSystemInfo? as a base. This makes our code more concise and also behave more like a FileInfo? class.

Location:
branches/eraser6/CodeReview/Eraser.Util
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • branches/eraser6/CodeReview/Eraser.Util/NativeMethods/Kernel.cs

    r1593 r1708  
    4848        [DllImport("Kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)] 
    4949        [return: MarshalAs(UnmanagedType.Bool)] 
    50         [Obsolete] 
    5150        public static extern bool DeleteFile(string lpFileName); 
    5251 
  • branches/eraser6/CodeReview/Eraser.Util/StreamInfo.cs

    r1705 r1708  
    3131namespace Eraser.Util 
    3232{ 
    33     public class StreamInfo 
     33    /// <summary> 
     34    /// Provides methods for the deletion, and opening of file alternate data streams, 
     35    /// and aids in the creation of <see cref="System.IO.FileStream"/> objects. 
     36    /// </summary> 
     37    public class StreamInfo : FileSystemInfo 
    3438    { 
    3539        /// <summary> 
    36         /// Initializes a new instance of the Eraser.Util.StreamInfo class, which 
    37         /// acts as a wrapper for a file path. 
    38         /// </summary> 
    39         /// <param name="path">The fully qualified name (with :ADSName for ADSes) 
    40         /// of the new file, or the relative file name.</param> 
    41         public StreamInfo(string path) 
    42         { 
    43             //Separate the path into the ADS and the file. 
    44             if (path.IndexOf(':') != path.LastIndexOf(':')) 
    45             { 
    46                 int streamNameColon = path.IndexOf(':', path.IndexOf(':') + 1); 
    47                 fileName = path.Substring(0, streamNameColon); 
    48                 streamName = path.Substring(streamNameColon + 1); 
    49             } 
    50             else 
    51             { 
    52                 fileName = path; 
     40        /// Constructor. 
     41        /// <param name="filename">The fully qualified name of the new file, or 
     42        /// the relative file name.</param> 
     43        public StreamInfo(string filename) 
     44            : this(filename, null) 
     45        { 
     46        } 
     47 
     48        /// <summary> 
     49        /// Constructor. 
     50        /// </summary> 
     51        /// <param name="filename">The path to the file.</param> 
     52        /// <param name="streamName">The name of the alternate data stream, or null 
     53        /// to refer to the unnamed stream.</param> 
     54        public StreamInfo(string filename, string streamName) 
     55        { 
     56            OriginalPath = filename; 
     57            FullPath = Path.GetFullPath(filename); 
     58            FileName = FullPath; 
     59            StreamName = streamName; 
     60 
     61            if (!string.IsNullOrEmpty(streamName)) 
     62            { 
     63                OriginalPath += ":" + streamName; 
     64                FullPath += ":" + streamName; 
     65            } 
     66 
     67            Refresh(); 
     68        } 
     69 
     70        /// <summary> 
     71        /// The full name of the stream, including the stream name if provided. 
     72        /// </summary> 
     73        public override string FullName 
     74        { 
     75            get 
     76            { 
     77                return FullPath; 
     78            } 
     79        } 
     80 
     81        /// <summary> 
     82        /// Gets a value indicating whether a file exists. 
     83        /// </summary> 
     84        public override bool Exists 
     85        { 
     86            get 
     87            { 
     88                bool result = System.IO.File.Exists(FullName); 
     89                return result && 
     90                    (string.IsNullOrEmpty(StreamName) || true/*verify the ADS exists*/); 
     91            } 
     92        } 
     93 
     94        /// <summary> 
     95        /// Gets a string representing the directory's full path. 
     96        /// </summary> 
     97        public String DirectoryName 
     98        { 
     99            get 
     100            { 
     101                return Path.GetDirectoryName(FullPath); 
    53102            } 
    54103        } 
     
    63112                return new DirectoryInfo(DirectoryName); 
    64113            } 
    65         } 
    66  
    67         /// <summary> 
    68         /// Gets a string representing the containing directory's full path. 
    69         /// </summary> 
    70         public string DirectoryName 
    71         { 
    72             get 
    73             { 
    74                 return fileName.Substring(0, fileName.LastIndexOf(Path.DirectorySeparatorChar) + 1); 
    75             } 
    76         } 
    77  
    78         /// <summary> 
    79         /// Gets the full name of the file, including the stream name. 
    80         /// </summary> 
    81         public string FullName 
    82         { 
    83             get 
    84             { 
    85                 if (streamName != null) 
    86                     return fileName + ':' + streamName; 
    87                 return fileName; 
    88             } 
    89         } 
    90  
    91         /// <summary> 
    92         /// Gets the name of the file. 
    93         /// </summary> 
    94         public string Name 
    95         { 
    96             get { return fileName; } 
    97         } 
    98  
    99         /// <summary> 
    100         /// Gets an instance of the main file. If this object refers to an ADS, the 
    101         /// result is null. 
     114        }  
     115 
     116        /// <summary> 
     117        /// Gets the file which contains this stream. 
    102118        /// </summary> 
    103119        public FileInfo File 
     
    105121            get 
    106122            { 
    107                 if (streamName == null) 
    108                     return new FileInfo(fileName); 
    109                 return null; 
    110             } 
    111         } 
    112  
    113         /// <summary> 
    114         /// Gets or sets the file attributes on this stream. 
    115         /// </summary> 
    116         public FileAttributes Attributes 
    117         { 
    118             get { return (FileAttributes)NativeMethods.GetFileAttributes(FullName); } 
    119             set { NativeMethods.SetFileAttributes(FullName, (uint)value); } 
    120         } 
    121          
    122         /// <summary> 
    123         /// Gets a value indicating whether the stream exists. 
    124         /// </summary> 
    125         public bool Exists 
    126         { 
    127             get 
    128             { 
    129                 using (SafeFileHandle handle = NativeMethods.CreateFile( 
    130                     FullName, NativeMethods.GENERIC_READ, NativeMethods.FILE_SHARE_READ, 
    131                     IntPtr.Zero, NativeMethods.OPEN_EXISTING, 0, IntPtr.Zero)) 
     123                return new FileInfo(FileName); 
     124            } 
     125        } 
     126 
     127        /// <summary> 
     128        /// The full path to the file we are encapsulating. 
     129        /// </summary> 
     130        public string FileName 
     131        { 
     132            get; 
     133            private set; 
     134        } 
     135 
     136        /// <summary> 
     137        /// Gets the name of the stream. 
     138        /// </summary> 
     139        public override string Name 
     140        { 
     141            get { return StreamName; } 
     142        } 
     143 
     144        /// <summary> 
     145        /// Gets or sets a value that determines if the current file is read only. 
     146        /// </summary> 
     147        public bool IsReadOnly 
     148        { 
     149            get { return (Attributes & FileAttributes.ReadOnly) != 0; } 
     150            set 
     151            { 
     152                Attributes = value ? 
     153                    (Attributes | FileAttributes.ReadOnly) : 
     154                    (Attributes & ~FileAttributes.ReadOnly); 
     155            } 
     156        } 
     157 
     158        /// <summary> 
     159        /// Gets the size, in bytes, of the current stream. 
     160        /// </summary> 
     161        public long Length 
     162        { 
     163            get 
     164            { 
     165                long fileSize; 
     166                using (SafeFileHandle handle = OpenHandle( 
     167                    FileMode.Open, FileAccess.Read, FileShare.ReadWrite, FileOptions.None)) 
    132168                { 
    133                     if (!handle.IsInvalid) 
    134                         return true; 
    135  
    136                     int errorCode = Marshal.GetLastWin32Error(); 
    137                     switch (errorCode) 
    138                     { 
    139                         case Win32ErrorCode.FileNotFound: 
    140                         case Win32ErrorCode.PathNotFound: 
    141                             return false; 
    142                         case Win32ErrorCode.AccessDenied: 
    143                         case Win32ErrorCode.SharingViolation: 
    144                             return true; 
    145                         default: 
    146                             throw Win32ErrorCode.GetExceptionForWin32Error(errorCode); 
    147                     } 
    148                 } 
    149             } 
    150         } 
    151  
    152         /// <summary> 
    153         /// Gets or sets a value that determines if the current file is read only. 
    154         /// </summary> 
    155         public bool IsReadOnly 
    156         { 
    157             get 
    158             { 
    159                 return (Attributes & FileAttributes.ReadOnly) != 0; 
    160             } 
    161  
    162             set 
    163             { 
    164                 if (value) 
    165                     Attributes |= FileAttributes.ReadOnly; 
    166                 else 
    167                     Attributes &= ~FileAttributes.ReadOnly; 
    168             } 
    169         } 
    170  
    171         /// <summary> 
    172         /// Gets the size of the current stream. 
    173         /// </summary> 
    174         public long Length 
    175         { 
    176             get 
    177             { 
    178                 long fileSize; 
    179                 using (SafeFileHandle handle = fileHandle) 
    180169                    if (NativeMethods.GetFileSizeEx(handle, out fileSize)) 
    181170                        return fileSize; 
     171                } 
    182172 
    183173                return 0; 
     
    185175        } 
    186176 
    187         public DateTime LastAccessTime 
    188         { 
    189             get 
    190             { 
    191                 DateTime creationTime, lastAccess, lastWrite; 
    192                 GetFileTime(out creationTime, out lastAccess, out lastWrite); 
    193                 return lastAccess; 
    194             } 
    195             set 
    196             { 
    197                 SetFileTime(DateTime.MinValue, value, DateTime.MinValue); 
    198             } 
    199         } 
    200  
    201         public DateTime LastWriteTime 
    202         { 
    203             get 
    204             { 
    205                 DateTime creationTime, lastAccess, lastWrite; 
    206                 GetFileTime(out creationTime, out lastAccess, out lastWrite); 
    207                 return lastWrite; 
    208             } 
    209             set 
    210             { 
    211                 SetFileTime(DateTime.MinValue, DateTime.MinValue, value); 
    212             } 
    213         } 
    214  
    215         public DateTime CreationTime 
    216         { 
    217             get 
    218             { 
    219                 DateTime creationTime, lastAccess, lastWrite; 
    220                 GetFileTime(out creationTime, out lastAccess, out lastWrite); 
    221                 return creationTime; 
    222             } 
    223             set 
    224             { 
    225                 SetFileTime(value, DateTime.MinValue, DateTime.MinValue); 
    226             } 
    227         } 
    228  
    229         private void GetFileTime(out DateTime creationTime, out DateTime lastAccess, 
    230             out DateTime lastWrite) 
    231         { 
    232             SafeFileHandle handle = exclusiveHandle; 
    233             bool ownsHandle = false; 
    234             try 
    235             { 
    236                 if (handle == null || handle.IsClosed || handle.IsInvalid) 
     177        /// <summary> 
     178        /// Creates the file if it already does not exist, then creates the alternate 
     179        /// data stream. 
     180        /// </summary> 
     181        public FileStream Create() 
     182        { 
     183            return Open(FileMode.Create, FileAccess.ReadWrite, FileShare.None, FileOptions.None); 
     184        } 
     185 
     186        /// <summary> 
     187        /// Permanently deletes the stream. If this refers to the unnamed stream, all 
     188        /// alternate data streams are also deleted. 
     189        /// </summary> 
     190        public override void Delete() 
     191        { 
     192            if (!NativeMethods.DeleteFile(FullName)) 
     193            { 
     194                int errorCode = Marshal.GetLastWin32Error(); 
     195                switch (errorCode) 
    237196                { 
    238                     handle = fileHandle; 
    239                     ownsHandle = true; 
     197                    case Win32ErrorCode.PathNotFound: 
     198                        break; 
     199                    default: 
     200                        throw Win32ErrorCode.GetExceptionForWin32Error(errorCode); 
    240201                } 
    241202            } 
    242             catch (ObjectDisposedException) 
    243             { 
    244                 handle = fileHandle; 
    245                 ownsHandle = true; 
    246             } 
    247  
    248             try 
    249             { 
    250                 Util.File.GetFileTime(handle, out creationTime, out lastAccess, out lastWrite); 
    251             } 
    252             finally 
    253             { 
    254                 if (ownsHandle) 
    255                     handle.Close(); 
    256             } 
    257         } 
    258  
    259         private void SetFileTime(DateTime creationTime, DateTime lastAccess, DateTime lastWrite) 
    260         { 
    261             SafeFileHandle handle = exclusiveHandle; 
    262             bool ownsHandle = false; 
    263             try 
    264             { 
    265                 if (handle == null || handle.IsClosed || handle.IsInvalid) 
    266                 { 
    267                     handle = fileHandle; 
    268                     ownsHandle = true; 
    269                 } 
    270             } 
    271             catch (ObjectDisposedException) 
    272             { 
    273                 handle = fileHandle; 
    274                 ownsHandle = true; 
    275             } 
    276  
    277             try 
    278             { 
    279                 Util.File.SetFileTime(handle, creationTime, lastAccess, lastWrite); 
    280             } 
    281             finally 
    282             { 
    283                 if (ownsHandle) 
    284                     handle.Close(); 
    285             } 
    286         } 
    287  
    288         /// <summary> 
    289         /// Permanently deletes a file. 
    290         /// </summary> 
    291         public void Delete() 
    292         { 
    293             if (streamName == null) 
    294                 File.Delete(); 
    295             else 
    296                 if (!NativeMethods.DeleteFile(FullName)) 
    297                     throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error()); 
    298203        } 
    299204 
     
    368273        } 
    369274 
     275        /// <summary> 
     276        /// Creates a read-only System.IO.FileStream. 
     277        /// </summary> 
     278        /// <returns>A new read-only System.IO.FileStream object.</returns> 
     279        public FileStream OpenRead() 
     280        { 
     281            return Open(FileMode.Open, FileAccess.Read, FileShare.Read, FileOptions.None); 
     282        } 
     283 
     284        /// <summary> 
     285        /// Creates a write-only System.IO.FileStream. 
     286        /// </summary> 
     287        /// <returns>A new write-only unshared System.IO.FileStream object.</returns> 
     288        public FileStream OpenWrite() 
     289        { 
     290            return Open(FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, FileOptions.None); 
     291        } 
     292 
    370293        private SafeFileHandle OpenHandle(FileMode mode, FileAccess access, FileShare share, 
    371294            FileOptions options) 
     
    393316            if ((options & FileOptions.Asynchronous) != 0) 
    394317                throw new NotSupportedException("Asynchronous handles are not implemented."); 
    395              
     318 
    396319            //Create the handle 
    397320            SafeFileHandle result = NativeMethods.CreateFile(FullName, iAccess, 
     
    404327            } 
    405328 
    406             //Cache the handle if we have an exclusive handle - this is used for things like 
    407             //file times. 
    408             if (share == FileShare.None) 
    409                 exclusiveHandle = result; 
    410329            return result; 
    411330        } 
     
    414333        /// Returns the path as a string. 
    415334        /// </summary> 
    416         /// <returns>A string representing the path.</returns> 
     335        /// <returns>A string containing the path given to the constructor.</returns> 
    417336        public override string ToString() 
    418337        { 
    419             return FullName; 
    420         } 
    421  
    422         /// <summary> 
    423         /// Retrieves a file handle with read access and with all sharing enabled. 
    424         /// </summary> 
    425         private SafeFileHandle fileHandle 
    426         { 
    427             get 
    428             { 
    429                 return OpenHandle(FileMode.Open, FileAccess.Read, FileShare.ReadWrite | 
    430                     FileShare.Delete, FileOptions.None); 
    431             } 
    432         } 
    433          
    434         /// <summary> 
    435         /// Cached exclusive file handle. This is used for setting file access times 
    436         /// </summary> 
    437         private SafeFileHandle exclusiveHandle; 
    438         private string fileName; 
    439         private string streamName; 
     338            return OriginalPath; 
     339        } 
     340 
     341        /// <summary> 
     342        /// The name of the stream we are encapsulating. 
     343        /// </summary> 
     344        private string StreamName; 
    440345    } 
    441346} 
Note: See TracChangeset for help on using the changeset viewer.