source: branches/eraser6/Util/StreamInfo.cs @ 1033

Revision 1033, 10.4 KB checked in by lowjoel, 5 years ago (diff)

Allow date Created, date Accessed and date Modified values to be set on streams.

  • Property svn:keywords set to Id
Line 
1/*
2 * $Id$
3 * Copyright 2008 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    public class StreamInfo
34    {
35        /// <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;
53            }
54        }
55
56        /// <summary>
57        /// Gets an instance of the parent directory.
58        /// </summary>
59        public DirectoryInfo Directory
60        {
61            get
62            {
63                return new DirectoryInfo(DirectoryName);
64            }
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.
102        /// </summary>
103        public FileInfo File
104        {
105            get
106            {
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 System.IO.File.GetAttributes(fileName); }
119            set { System.IO.File.SetAttributes(fileName, 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 = fileHandle)
130                    return !(Marshal.GetLastWin32Error() == 2 /*ERROR_FILE_NOT_FOUND*/ &&
131                        handle.IsInvalid);
132            }
133        }
134
135        /// <summary>
136        /// Gets or sets a value that determines if the current file is read only.
137        /// </summary>
138        public bool IsReadOnly
139        {
140            get
141            {
142                return (Attributes & FileAttributes.ReadOnly) != 0;
143            }
144
145            set
146            {
147                if (value)
148                    Attributes |= FileAttributes.ReadOnly;
149                else
150                    Attributes &= ~FileAttributes.ReadOnly;
151            }
152        }
153
154        /// <summary>
155        /// Gets the size of the current stream.
156        /// </summary>
157        public long Length
158        {
159            get
160            {
161                long fileSize;
162                using (SafeFileHandle handle = fileHandle)
163                    if (KernelApi.NativeMethods.GetFileSizeEx(handle, out fileSize))
164                        return fileSize;
165
166                return 0;
167            }
168        }
169
170        public DateTime LastAccessTime
171        {
172            get
173            {
174                DateTime creationTime, lastAccess, lastWrite;
175                using (SafeFileHandle handle = fileHandle)
176                    KernelApi.GetFileTime(handle, out creationTime, out lastAccess,
177                        out lastWrite);
178                return lastAccess;
179            }
180            set
181            {
182                using (SafeFileHandle handle = fileHandle)
183                    KernelApi.SetFileTime(handle, DateTime.MinValue, value, DateTime.MinValue);
184            }
185        }
186
187        public DateTime LastWriteTime
188        {
189            get
190            {
191                DateTime creationTime, lastAccess, lastWrite;
192                using (SafeFileHandle handle = fileHandle)
193                    KernelApi.GetFileTime(handle, out creationTime, out lastAccess,
194                        out lastWrite);
195                return lastWrite;
196            }
197            set
198            {
199                using (SafeFileHandle handle = fileHandle)
200                    KernelApi.SetFileTime(handle, DateTime.MinValue, DateTime.MinValue, value);
201            }
202        }
203
204        public DateTime CreationTime
205        {
206            get
207            {
208                DateTime creationTime, lastAccess, lastWrite;
209                using (SafeFileHandle handle = fileHandle)
210                    KernelApi.GetFileTime(handle, out creationTime, out lastAccess,
211                        out lastWrite);
212                return creationTime;
213            }
214            set
215            {
216                using (SafeFileHandle handle = fileHandle)
217                    KernelApi.SetFileTime(handle, value, DateTime.MinValue, DateTime.MinValue);
218            }
219        }
220
221        /// <summary>
222        /// Permanently deletes a file.
223        /// </summary>
224        public void Delete()
225        {
226            if (streamName == null)
227                File.Delete();
228            else
229                throw new InvalidOperationException("Deleting streams are not implemented");
230        }
231
232        /// <summary>
233        /// Opens a file in the specified mode.
234        /// </summary>
235        /// <param name="mode">A System.IO.FileMode constant specifying the mode
236        /// (for example, Open or Append) in which to open the file.</param>
237        /// <returns>A file opened in the specified mode, with read/write access,
238        /// unshared, and no special file options.</returns>
239        public FileStream Open(FileMode mode)
240        {
241            return Open(mode, FileAccess.ReadWrite, FileShare.None, FileOptions.None);
242        }
243
244        /// <summary>
245        /// Opens a file in the specified mode with read, write, or read/write access.
246        /// </summary>
247        /// <param name="mode">A System.IO.FileMode constant specifying the mode
248        /// (for example, Open or Append) in which to open the file.</param>
249        /// <param name="access">A System.IO.FileAccess constant specifying whether
250        /// to open the file with Read, Write, or ReadWrite file access.</param>
251        /// <returns>A System.IO.FileStream object opened in the specified mode
252        /// and access, unshared, and no special file options.</returns>
253        public FileStream Open(FileMode mode, FileAccess access)
254        {
255            return Open(mode, access, FileShare.None, FileOptions.None);
256        }
257
258        /// <summary>
259        /// Opens a file in the specified mode with read, write, or read/write access
260        /// and the specified sharing option.
261        /// </summary>
262        /// <param name="mode">A System.IO.FileMode constant specifying the mode
263        /// (for example, Open or Append) in which to open the file.</param>
264        /// <param name="access">A System.IO.FileAccess constant specifying whether
265        /// to open the file with Read, Write, or ReadWrite file access.</param>
266        /// <param name="share">A System.IO.FileShare constant specifying the type
267        /// of access other FileStream objects have to this file.</param>
268        /// <returns>A System.IO.FileStream object opened with the specified mode,
269        /// access, sharing options, and no special file options.</returns>
270        public FileStream Open(FileMode mode, FileAccess access, FileShare share)
271        {
272            return Open(mode, access, share, FileOptions.None);
273        }
274
275        /// <summary>
276        /// Opens a file in the specified mode with read, write, or read/write access,
277        /// the specified sharing option, and other advanced options.
278        /// </summary>
279        /// <param name="mode">A System.IO.FileMode constant specifying the mode
280        /// (for example, Open or Append) in which to open the file.</param>
281        /// <param name="access">A System.IO.FileAccess constant specifying whether
282        /// to open the file with Read, Write, or ReadWrite file access.</param>
283        /// <param name="share">A System.IO.FileShare constant specifying the type
284        /// of access other FileStream objects have to this file.</param>
285        /// <param name="options">The System.IO.FileOptions constant specifying
286        /// the advanced file options to use when opening the file.</param>
287        /// <returns>A System.IO.FileStream object opened with the specified mode,
288        /// access, sharing options, and special file options.</returns>
289        public FileStream Open(FileMode mode, FileAccess access, FileShare share,
290            FileOptions options)
291        {
292            SafeFileHandle handle = OpenHandle(mode, access, share, options);
293
294            //Check that the handle is valid
295            if (handle.IsInvalid)
296                throw Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error());
297
298            //Return the FileStream
299            return new FileStream(handle, access);
300        }
301
302        private SafeFileHandle OpenHandle(FileMode mode, FileAccess access, FileShare share,
303            FileOptions options)
304        {
305            //Access mode
306            uint iAccess = 0;
307            switch (access)
308            {
309                case FileAccess.Read:
310                    iAccess = KernelApi.NativeMethods.GENERIC_READ;
311                    break;
312                case FileAccess.ReadWrite:
313                    iAccess = KernelApi.NativeMethods.GENERIC_READ |
314                        KernelApi.NativeMethods.GENERIC_WRITE;
315                    break;
316                case FileAccess.Write:
317                    iAccess = KernelApi.NativeMethods.GENERIC_WRITE;
318                    break;
319            }
320
321            //Sharing mode
322            if ((share & FileShare.Inheritable) != 0)
323                throw new NotSupportedException("Inheritable handles are not supported.");
324
325            //Advanced options
326            if ((options & FileOptions.Asynchronous) != 0)
327                throw new NotSupportedException("Asynchronous handles are not implemented.");
328           
329            //Create the handle
330            SafeFileHandle result = KernelApi.NativeMethods.CreateFile(FullName, iAccess,
331                (uint)share, IntPtr.Zero, (uint)mode, (uint)options, IntPtr.Zero);
332            if (result.IsInvalid)
333                throw new Win32Exception(Marshal.GetLastWin32Error());
334            return result;
335        }
336
337        /// <summary>
338        /// Returns the path as a string.
339        /// </summary>
340        /// <returns>A string representing the path.</returns>
341        public override string ToString()
342        {
343            return FullName;
344        }
345
346        /// <summary>
347        /// Retrieves a file handle with read access and with all sharing enabled.
348        /// </summary>
349        private SafeFileHandle fileHandle
350        {
351            get
352            {
353                return OpenHandle(FileMode.Open, FileAccess.Read, FileShare.ReadWrite |
354                    FileShare.Delete, FileOptions.None);
355            }
356        }
357
358        private string fileName;
359        private string streamName;
360    }
361}
Note: See TracBrowser for help on using the repository browser.