source: trunk/eraser/Eraser.Util/StreamInfo.cs @ 2194

Revision 2194, 10.5 KB checked in by lowjoel, 4 years ago (diff)

Change all internal OpenHandle? functions to private, since they should not be callable from outside the class.

  • 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;
25
26using Microsoft.Win32.SafeHandles;
27using System.IO;
28using System.ComponentModel;
29using System.Runtime.InteropServices;
30
31namespace Eraser.Util
32{
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
38    {
39        /// <summary>
40        /// Constructor.
41        /// </summary>
42        /// <param name="filename">The fully qualified name of the new file, or
43        /// the relative file name.</param>
44        public StreamInfo(string filename)
45            : this(filename, null)
46        {
47        }
48
49        /// <summary>
50        /// Constructor.
51        /// </summary>
52        /// <param name="filename">The path to the file.</param>
53        /// <param name="streamName">The name of the alternate data stream, or null
54        /// to refer to the unnamed stream.</param>
55        public StreamInfo(string filename, string streamName)
56        {
57            OriginalPath = filename;
58            FullPath = Path.GetFullPath(filename);
59            FileName = FullPath;
60            StreamName = streamName;
61
62            if (!string.IsNullOrEmpty(streamName))
63            {
64                OriginalPath += ":" + streamName;
65                FullPath += ":" + streamName;
66            }
67
68            Refresh();
69        }
70
71        /// <summary>
72        /// The full name of the stream, including the stream name if provided.
73        /// </summary>
74        public override string FullName
75        {
76            get
77            {
78                return FullPath;
79            }
80        }
81
82        /// <summary>
83        /// Gets a value indicating whether a file exists.
84        /// </summary>
85        public override bool Exists
86        {
87            get
88            {
89                bool result = System.IO.File.Exists(FullName);
90                return result &&
91                    (string.IsNullOrEmpty(StreamName) || true/*TODO: verify the ADS exists*/);
92            }
93        }
94
95        /// <summary>
96        /// Gets a string representing the directory's full path.
97        /// </summary>
98        public String DirectoryName
99        {
100            get
101            {
102                return Path.GetDirectoryName(FullPath);
103            }
104        }
105
106        /// <summary>
107        /// Gets an instance of the parent directory.
108        /// </summary>
109        public DirectoryInfo Directory
110        {
111            get
112            {
113                return new DirectoryInfo(DirectoryName);
114            }
115        } 
116
117        /// <summary>
118        /// Gets the file which contains this stream.
119        /// </summary>
120        public FileInfo File
121        {
122            get
123            {
124                return new FileInfo(FileName);
125            }
126        }
127
128        /// <summary>
129        /// The full path to the file we are encapsulating.
130        /// </summary>
131        public string FileName
132        {
133            get;
134            private set;
135        }
136
137        /// <summary>
138        /// Gets the name of the stream.
139        /// </summary>
140        public override string Name
141        {
142            get { return StreamName; }
143        }
144
145        /// <summary>
146        /// Gets or sets a value that determines if the current file is read only.
147        /// </summary>
148        public bool IsReadOnly
149        {
150            get { return (Attributes & FileAttributes.ReadOnly) != 0; }
151            set
152            {
153                Attributes = value ?
154                    (Attributes | FileAttributes.ReadOnly) :
155                    (Attributes & ~FileAttributes.ReadOnly);
156            }
157        }
158
159        /// <summary>
160        /// Gets the size, in bytes, of the current stream.
161        /// </summary>
162        public long Length
163        {
164            get
165            {
166                long fileSize;
167                using (SafeFileHandle handle = OpenHandle(
168                    FileMode.Open, FileAccess.Read, FileShare.ReadWrite, FileOptions.None))
169                {
170                    if (NativeMethods.GetFileSizeEx(handle, out fileSize))
171                        return fileSize;
172                }
173
174                return 0;
175            }
176        }
177
178        /// <summary>
179        /// Creates the file if it already does not exist, then creates the alternate
180        /// data stream.
181        /// </summary>
182        public FileStream Create()
183        {
184            return Open(FileMode.Create, FileAccess.ReadWrite, FileShare.None, FileOptions.None);
185        }
186
187        /// <summary>
188        /// Permanently deletes the stream. If this refers to the unnamed stream, all
189        /// alternate data streams are also deleted.
190        /// </summary>
191        public override void Delete()
192        {
193            if (!NativeMethods.DeleteFile(FullName))
194            {
195                int errorCode = Marshal.GetLastWin32Error();
196                switch (errorCode)
197                {
198                    case Win32ErrorCode.PathNotFound:
199                        break;
200                    default:
201                        throw Win32ErrorCode.GetExceptionForWin32Error(errorCode);
202                }
203            }
204        }
205
206        /// <summary>
207        /// Opens a file in the specified mode.
208        /// </summary>
209        /// <param name="mode">A System.IO.FileMode constant specifying the mode
210        /// (for example, Open or Append) in which to open the file.</param>
211        /// <returns>A file opened in the specified mode, with read/write access,
212        /// unshared, and no special file options.</returns>
213        public FileStream Open(FileMode mode)
214        {
215            return Open(mode, FileAccess.ReadWrite, FileShare.None, FileOptions.None);
216        }
217
218        /// <summary>
219        /// Opens a file in the specified mode with read, write, or read/write access.
220        /// </summary>
221        /// <param name="mode">A System.IO.FileMode constant specifying the mode
222        /// (for example, Open or Append) in which to open the file.</param>
223        /// <param name="access">A System.IO.FileAccess constant specifying whether
224        /// to open the file with Read, Write, or ReadWrite file access.</param>
225        /// <returns>A System.IO.FileStream object opened in the specified mode
226        /// and access, unshared, and no special file options.</returns>
227        public FileStream Open(FileMode mode, FileAccess access)
228        {
229            return Open(mode, access, FileShare.None, FileOptions.None);
230        }
231
232        /// <summary>
233        /// Opens a file in the specified mode with read, write, or read/write access
234        /// and the specified sharing option.
235        /// </summary>
236        /// <param name="mode">A System.IO.FileMode constant specifying the mode
237        /// (for example, Open or Append) in which to open the file.</param>
238        /// <param name="access">A System.IO.FileAccess constant specifying whether
239        /// to open the file with Read, Write, or ReadWrite file access.</param>
240        /// <param name="share">A System.IO.FileShare constant specifying the type
241        /// of access other FileStream objects have to this file.</param>
242        /// <returns>A System.IO.FileStream object opened with the specified mode,
243        /// access, sharing options, and no special file options.</returns>
244        public FileStream Open(FileMode mode, FileAccess access, FileShare share)
245        {
246            return Open(mode, access, share, FileOptions.None);
247        }
248
249        /// <summary>
250        /// Opens a file in the specified mode with read, write, or read/write access,
251        /// the specified sharing option, and other advanced options.
252        /// </summary>
253        /// <param name="mode">A System.IO.FileMode constant specifying the mode
254        /// (for example, Open or Append) in which to open the file.</param>
255        /// <param name="access">A System.IO.FileAccess constant specifying whether
256        /// to open the file with Read, Write, or ReadWrite file access.</param>
257        /// <param name="share">A System.IO.FileShare constant specifying the type
258        /// of access other FileStream objects have to this file.</param>
259        /// <param name="options">The System.IO.FileOptions constant specifying
260        /// the advanced file options to use when opening the file.</param>
261        /// <returns>A System.IO.FileStream object opened with the specified mode,
262        /// access, sharing options, and special file options.</returns>
263        public FileStream Open(FileMode mode, FileAccess access, FileShare share,
264            FileOptions options)
265        {
266            SafeFileHandle handle = OpenHandle(mode, access, share, options);
267
268            //Check that the handle is valid
269            if (handle.IsInvalid)
270                throw Win32ErrorCode.GetExceptionForWin32Error(Marshal.GetLastWin32Error());
271
272            //Return the FileStream
273            return new FileStream(handle, access);
274        }
275
276        /// <summary>
277        /// Creates a read-only System.IO.FileStream.
278        /// </summary>
279        /// <returns>A new read-only System.IO.FileStream object.</returns>
280        public FileStream OpenRead()
281        {
282            return Open(FileMode.Open, FileAccess.Read, FileShare.Read, FileOptions.None);
283        }
284
285        /// <summary>
286        /// Creates a write-only System.IO.FileStream.
287        /// </summary>
288        /// <returns>A new write-only unshared System.IO.FileStream object.</returns>
289        public FileStream OpenWrite()
290        {
291            return Open(FileMode.OpenOrCreate, FileAccess.Write, FileShare.None, FileOptions.None);
292        }
293
294        private SafeFileHandle OpenHandle(FileMode mode, FileAccess access, FileShare share,
295            FileOptions options)
296        {
297            //Access mode
298            uint iAccess = 0;
299            switch (access)
300            {
301                case FileAccess.Read:
302                    iAccess = NativeMethods.GENERIC_READ;
303                    break;
304                case FileAccess.ReadWrite:
305                    iAccess = NativeMethods.GENERIC_READ | NativeMethods.GENERIC_WRITE;
306                    break;
307                case FileAccess.Write:
308                    iAccess = NativeMethods.GENERIC_WRITE;
309                    break;
310            }
311
312            return OpenHandle(mode, iAccess, share, options);
313        }
314
315        private SafeFileHandle OpenHandle(FileMode mode, uint access, FileShare share,
316            FileOptions options)
317        {
318            //Sharing mode
319            if ((share & FileShare.Inheritable) != 0)
320                throw new NotSupportedException("Inheritable handles are not supported.");
321
322            //Advanced options
323            if ((options & FileOptions.Asynchronous) != 0)
324                throw new NotSupportedException("Asynchronous handles are not implemented.");
325
326            //Create the handle
327            SafeFileHandle result = NativeMethods.CreateFile(FullName, access,
328                (uint)share, IntPtr.Zero, (uint)mode, (uint)options, IntPtr.Zero);
329            if (result.IsInvalid)
330            {
331                int errorCode = Marshal.GetLastWin32Error();
332                result.Close();
333                throw Win32ErrorCode.GetExceptionForWin32Error(errorCode);
334            }
335
336            return result;
337        }
338
339        public void SetTimes(DateTime updateTime, DateTime createdTime, DateTime lastModifiedTime,
340            DateTime lastAccessedTime)
341        {
342            using (SafeFileHandle streamHandle = OpenHandle(FileMode.Open,
343                    NativeMethods.FILE_WRITE_ATTRIBUTES, FileShare.ReadWrite,
344                    FileOptions.None))
345            {
346                ExtensionMethods.IO.SetTimes(streamHandle, updateTime, createdTime,
347                    lastModifiedTime, lastAccessedTime);
348            }
349        }
350
351        /// <summary>
352        /// Returns the path as a string.
353        /// </summary>
354        /// <returns>A string containing the path given to the constructor.</returns>
355        public override string ToString()
356        {
357            return OriginalPath;
358        }
359
360        /// <summary>
361        /// The name of the stream we are encapsulating.
362        /// </summary>
363        private string StreamName;
364    }
365}
Note: See TracBrowser for help on using the repository browser.