You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

251 lines
11 KiB

  1. /* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. using System;
  22. using System.Diagnostics.CodeAnalysis;
  23. using System.Globalization;
  24. using System.IO;
  25. using System.Security;
  26. namespace Alphaleonis.Win32.Filesystem
  27. {
  28. /// <summary>Provides properties and instance methods for the creation, copying, deletion, moving, and opening of files, and aids in the creation of <see cref="FileStream"/> objects. This class cannot be inherited.</summary>
  29. [SerializableAttribute]
  30. public sealed partial class FileInfo : FileSystemInfo
  31. {
  32. #region Constructors
  33. #region .NET
  34. /// <summary>Initializes a new instance of the <see cref="Alphaleonis.Win32.Filesystem.FileInfo"/> class, which acts as a wrapper for a file path.</summary>
  35. /// <param name="fileName">The fully qualified name of the new file, or the relative file name. Do not end the path with the directory separator character.</param>
  36. /// <remarks>This constructor does not check if a file exists. This constructor is a placeholder for a string that is used to access the file in subsequent operations.</remarks>
  37. public FileInfo(string fileName) : this(null, fileName, PathFormat.RelativePath)
  38. {
  39. }
  40. #endregion // .NET
  41. #region AlphaFS
  42. #region Non-Transactional
  43. /// <summary>[AlphaFS] Initializes a new instance of the <see cref="Alphaleonis.Win32.Filesystem.FileInfo"/> class, which acts as a wrapper for a file path.</summary>
  44. /// <param name="fileName">The fully qualified name of the new file, or the relative file name. Do not end the path with the directory separator character.</param>
  45. /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
  46. /// <remarks>This constructor does not check if a file exists. This constructor is a placeholder for a string that is used to access the file in subsequent operations.</remarks>
  47. public FileInfo(string fileName, PathFormat pathFormat) : this(null, fileName, pathFormat)
  48. {
  49. }
  50. #endregion // Non-Transactional
  51. #region Transactional
  52. /// <summary>[AlphaFS] Initializes a new instance of the <see cref="Alphaleonis.Win32.Filesystem.FileInfo"/> class, which acts as a wrapper for a file path.</summary>
  53. /// <param name="transaction">The transaction.</param>
  54. /// <param name="fileName">The fully qualified name of the new file, or the relative file name. Do not end the path with the directory separator character.</param>
  55. /// <remarks>This constructor does not check if a file exists. This constructor is a placeholder for a string that is used to access the file in subsequent operations.</remarks>
  56. public FileInfo(KernelTransaction transaction, string fileName) : this(transaction, fileName, PathFormat.RelativePath)
  57. {
  58. }
  59. /// <summary>[AlphaFS] Initializes a new instance of the <see cref="Alphaleonis.Win32.Filesystem.FileInfo"/> class, which acts as a wrapper for a file path.</summary>
  60. /// <param name="transaction">The transaction.</param>
  61. /// <param name="fileName">The fully qualified name of the new file, or the relative file name. Do not end the path with the directory separator character.</param>
  62. /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
  63. /// <remarks>This constructor does not check if a file exists. This constructor is a placeholder for a string that is used to access the file in subsequent operations.</remarks>
  64. public FileInfo(KernelTransaction transaction, string fileName, PathFormat pathFormat)
  65. {
  66. InitializeCore(false, transaction, fileName, pathFormat);
  67. _name = Path.GetFileName(Path.RemoveTrailingDirectorySeparator(fileName, false), pathFormat != PathFormat.LongFullPath);
  68. }
  69. #endregion // Transacted
  70. #endregion // AlphaFS
  71. #endregion // Constructors
  72. #region Properties
  73. #region .NET
  74. #region Directory
  75. /// <summary>Gets an instance of the parent directory.</summary>
  76. /// <value>A <see cref="DirectoryInfo"/> object representing the parent directory of this file.</value>
  77. /// <remarks>To get the parent directory as a string, use the DirectoryName property.</remarks>
  78. /// <exception cref="DirectoryNotFoundException"/>
  79. public DirectoryInfo Directory
  80. {
  81. get
  82. {
  83. string dirName = DirectoryName;
  84. return dirName == null ? null : new DirectoryInfo(Transaction, dirName, PathFormat.FullPath);
  85. }
  86. }
  87. #endregion // Directory
  88. #region DirectoryName
  89. /// <summary>Gets a string representing the directory's full path.</summary>
  90. /// <value>A string representing the directory's full path.</value>
  91. /// <remarks>
  92. /// <para>To get the parent directory as a DirectoryInfo object, use the Directory property.</para>
  93. /// <para>When first called, FileInfo calls Refresh and caches information about the file.</para>
  94. /// <para>On subsequent calls, you must call Refresh to get the latest copy of the information.</para>
  95. /// </remarks>
  96. /// <exception cref="ArgumentNullException"/>
  97. public string DirectoryName
  98. {
  99. [SecurityCritical] get { return Path.GetDirectoryName(FullPath, false); }
  100. }
  101. #endregion // DirectoryName
  102. #region Exists
  103. /// <summary>Gets a value indicating whether the file exists.</summary>
  104. /// <value><see langword="true"/> if the file exists; otherwise, <see langword="false"/>.</value>
  105. /// <remarks>
  106. /// <para>The <see cref="Exists"/> property returns <see langword="false"/> if any error occurs while trying to determine if the specified file exists.</para>
  107. /// <para>This can occur in situations that raise exceptions such as passing a file name with invalid characters or too many characters,</para>
  108. /// <para>a failing or missing disk, or if the caller does not have permission to read the file.</para>
  109. /// </remarks>
  110. [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes")]
  111. public override bool Exists
  112. {
  113. [SecurityCritical]
  114. get
  115. {
  116. try
  117. {
  118. if (DataInitialised == -1)
  119. Refresh();
  120. FileAttributes attrs = Win32AttributeData.dwFileAttributes;
  121. return DataInitialised == 0 && attrs != (FileAttributes) (-1) && (attrs & FileAttributes.Directory) == 0;
  122. }
  123. catch
  124. {
  125. return false;
  126. }
  127. }
  128. }
  129. #endregion // Exists
  130. #region IsReadOnly
  131. /// <summary>Gets or sets a value that determines if the current file is read only.</summary>
  132. /// <value><see langword="true"/> if the current file is read only; otherwise, <see langword="false"/>.</value>
  133. /// <remarks>
  134. /// <para>Use the IsReadOnly property to quickly determine or change whether the current file is read only.</para>
  135. /// <para>When first called, FileInfo calls Refresh and caches information about the file.</para>
  136. /// <para>On subsequent calls, you must call Refresh to get the latest copy of the information.</para>
  137. /// </remarks>
  138. /// <exception cref="FileNotFoundException"/>
  139. /// <exception cref="IOException"/>
  140. public bool IsReadOnly
  141. {
  142. get { return EntryInfo == null || EntryInfo.IsReadOnly; }
  143. set
  144. {
  145. if (value)
  146. Attributes |= FileAttributes.ReadOnly;
  147. else
  148. Attributes &= ~FileAttributes.ReadOnly;
  149. }
  150. }
  151. #endregion // IsReadOnly
  152. #region Length
  153. /// <summary>Gets the size, in bytes, of the current file.</summary>
  154. /// <value>The size of the current file in bytes.</value>
  155. /// <remarks>
  156. /// <para>The value of the Length property is pre-cached</para>
  157. /// <para>To get the latest value, call the Refresh method.</para>
  158. /// </remarks>
  159. /// <exception cref="FileNotFoundException"/>
  160. /// <exception cref="IOException"/>
  161. [SuppressMessage("Microsoft.Design", "CA1065:DoNotRaiseExceptionsInUnexpectedLocations")]
  162. public long Length
  163. {
  164. [SecurityCritical]
  165. get
  166. {
  167. if (DataInitialised == -1)
  168. {
  169. Win32AttributeData = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA();
  170. Refresh();
  171. }
  172. // MSDN: .NET 3.5+: IOException: Refresh cannot initialize the data.
  173. if (DataInitialised != 0)
  174. NativeError.ThrowException(DataInitialised, LongFullName);
  175. FileAttributes attrs = Win32AttributeData.dwFileAttributes;
  176. // MSDN: .NET 3.5+: FileNotFoundException: The file does not exist or the Length property is called for a directory.
  177. if (attrs == (FileAttributes) (-1))
  178. NativeError.ThrowException(Win32Errors.ERROR_FILE_NOT_FOUND, LongFullName);
  179. // MSDN: .NET 3.5+: FileNotFoundException: The file does not exist or the Length property is called for a directory.
  180. if ((attrs & FileAttributes.Directory) == FileAttributes.Directory)
  181. NativeError.ThrowException(Win32Errors.ERROR_FILE_NOT_FOUND, string.Format(CultureInfo.CurrentCulture, Resources.Target_File_Is_A_Directory, LongFullName));
  182. return Win32AttributeData.FileSize;
  183. }
  184. }
  185. #endregion // Length
  186. #region Name
  187. private string _name;
  188. /// <summary>Gets the name of the file.</summary>
  189. /// <value>The name of the file.</value>
  190. /// <remarks>
  191. /// <para>The name of the file includes the file extension.</para>
  192. /// <para>When first called, <see cref="FileInfo"/> calls Refresh and caches information about the file.</para>
  193. /// <para>On subsequent calls, you must call Refresh to get the latest copy of the information.</para>
  194. /// <para>The name of the file includes the file extension.</para>
  195. /// </remarks>
  196. public override string Name
  197. {
  198. get { return _name; }
  199. }
  200. #endregion // Name
  201. #endregion // .NET
  202. #endregion // Properties
  203. }
  204. }