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.
 
 

239 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.Globalization;
  23. using System.IO;
  24. using System.Runtime.InteropServices;
  25. using System.Security;
  26. namespace Alphaleonis.Win32.Filesystem
  27. {
  28. public static partial class File
  29. {
  30. #region Delete
  31. /// <summary>Deletes the specified file.</summary>
  32. /// <remarks>If the file to be deleted does not exist, no exception is thrown.</remarks>
  33. /// <param name="path">
  34. /// The name of the file to be deleted. Wildcard characters are not supported.
  35. /// </param>
  36. /// <exception cref="ArgumentException"/>
  37. /// <exception cref="NotSupportedException"/>
  38. /// <exception cref="UnauthorizedAccessException"/>
  39. /// <exception cref="FileReadOnlyException"/>
  40. [SecurityCritical]
  41. public static void Delete(string path)
  42. {
  43. DeleteFileCore(null, path, false, PathFormat.RelativePath);
  44. }
  45. /// <summary>[AlphaFS] Deletes the specified file.</summary>
  46. /// <remarks>If the file to be deleted does not exist, no exception is thrown.</remarks>
  47. /// <param name="path">
  48. /// The name of the file to be deleted. Wildcard characters are not supported.
  49. /// </param>
  50. /// <param name="ignoreReadOnly">
  51. /// <see langword="true"/> overrides the read only <see cref="FileAttributes"/> of the file.
  52. /// </param>
  53. /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
  54. /// <exception cref="ArgumentException"/>
  55. /// <exception cref="NotSupportedException"/>
  56. /// <exception cref="UnauthorizedAccessException"/>
  57. /// <exception cref="FileReadOnlyException"/>
  58. [SecurityCritical]
  59. public static void Delete(string path, bool ignoreReadOnly, PathFormat pathFormat)
  60. {
  61. DeleteFileCore(null, path, ignoreReadOnly, pathFormat);
  62. }
  63. /// <summary>[AlphaFS] Deletes the specified file.</summary>
  64. /// <remarks>If the file to be deleted does not exist, no exception is thrown.</remarks>
  65. /// <param name="path">
  66. /// The name of the file to be deleted. Wildcard characters are not supported.
  67. /// </param>
  68. /// <param name="ignoreReadOnly">
  69. /// <see langword="true"/> overrides the read only <see cref="FileAttributes"/> of the file.
  70. /// </param>
  71. /// <exception cref="ArgumentException"/>
  72. /// <exception cref="NotSupportedException"/>
  73. /// <exception cref="UnauthorizedAccessException"/>
  74. /// <exception cref="FileReadOnlyException"/>
  75. [SecurityCritical]
  76. public static void Delete(string path, bool ignoreReadOnly)
  77. {
  78. DeleteFileCore(null, path, ignoreReadOnly, PathFormat.RelativePath);
  79. }
  80. #region Transactional
  81. /// <summary>[AlphaFS] Deletes the specified file.</summary>
  82. /// <remarks>If the file to be deleted does not exist, no exception is thrown.</remarks>
  83. /// <param name="transaction">The transaction.</param>
  84. /// <param name="path">
  85. /// The name of the file to be deleted. Wildcard characters are not supported.
  86. /// </param>
  87. /// <exception cref="ArgumentException"/>
  88. /// <exception cref="NotSupportedException"/>
  89. /// <exception cref="UnauthorizedAccessException"/>
  90. /// <exception cref="FileReadOnlyException"/>
  91. [SecurityCritical]
  92. public static void DeleteTransacted(KernelTransaction transaction, string path)
  93. {
  94. DeleteFileCore(transaction, path, false, PathFormat.RelativePath);
  95. }
  96. /// <summary>[AlphaFS] Deletes the specified file.</summary>
  97. /// <param name="transaction">The transaction.</param>
  98. /// <param name="path">The name of the file to be deleted. Wildcard characters are not supported.</param>
  99. /// <param name="ignoreReadOnly"><see langword="true"/> overrides the read only <see cref="FileAttributes"/> of the file.</param>
  100. /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
  101. /// <remarks>If the file to be deleted does not exist, no exception is thrown.</remarks>
  102. /// <exception cref="ArgumentException"/>
  103. /// <exception cref="NotSupportedException"/>
  104. /// <exception cref="UnauthorizedAccessException"/>
  105. /// <exception cref="FileReadOnlyException"/>
  106. [SecurityCritical]
  107. public static void DeleteTransacted(KernelTransaction transaction, string path, bool ignoreReadOnly, PathFormat pathFormat)
  108. {
  109. DeleteFileCore(transaction, path, ignoreReadOnly, pathFormat);
  110. }
  111. /// <summary>[AlphaFS] Deletes the specified file.</summary>
  112. /// <param name="transaction">The transaction.</param>
  113. /// <param name="path">The name of the file to be deleted. Wildcard characters are not supported.</param>
  114. /// <param name="ignoreReadOnly"><see langword="true"/> overrides the read only <see cref="FileAttributes"/> of the file.</param>
  115. /// <remarks>If the file to be deleted does not exist, no exception is thrown.</remarks>
  116. /// <exception cref="ArgumentException"/>
  117. /// <exception cref="NotSupportedException"/>
  118. /// <exception cref="UnauthorizedAccessException"/>
  119. /// <exception cref="FileReadOnlyException"/>
  120. [SecurityCritical]
  121. public static void DeleteTransacted(KernelTransaction transaction, string path, bool ignoreReadOnly)
  122. {
  123. DeleteFileCore(transaction, path, ignoreReadOnly, PathFormat.RelativePath);
  124. }
  125. #endregion // Transacted
  126. #endregion // Delete
  127. #region Internal Methods
  128. /// <summary>Deletes a Non-/Transacted file.</summary>
  129. /// <remarks>If the file to be deleted does not exist, no exception is thrown.</remarks>
  130. /// <exception cref="ArgumentException"/>
  131. /// <exception cref="NotSupportedException"/>
  132. /// <exception cref="UnauthorizedAccessException"/>
  133. /// <exception cref="FileReadOnlyException"/>
  134. /// <param name="transaction">The transaction.</param>
  135. /// <param name="path">The name of the file to be deleted.</param>
  136. /// <param name="ignoreReadOnly"><see langword="true"/> overrides the read only <see cref="FileAttributes"/> of the file.</param>
  137. /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
  138. [SecurityCritical]
  139. internal static void DeleteFileCore(KernelTransaction transaction, string path, bool ignoreReadOnly, PathFormat pathFormat)
  140. {
  141. #region Setup
  142. if (pathFormat == PathFormat.RelativePath)
  143. Path.CheckSupportedPathFormat(path, true, true);
  144. string pathLp = Path.GetExtendedLengthPathCore(transaction, path, pathFormat, GetFullPathOptions.TrimEnd | GetFullPathOptions.RemoveTrailingDirectorySeparator);
  145. // If the path points to a symbolic link, the symbolic link is deleted, not the target.
  146. #endregion // Setup
  147. startDeleteFile:
  148. if (!(transaction == null || !NativeMethods.IsAtLeastWindowsVista
  149. // DeleteFile() / DeleteFileTransacted()
  150. // In the ANSI version of this function, the name is limited to MAX_PATH characters.
  151. // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path.
  152. // 2013-01-13: MSDN confirms LongPath usage.
  153. ? NativeMethods.DeleteFile(pathLp)
  154. : NativeMethods.DeleteFileTransacted(pathLp, transaction.SafeHandle)))
  155. {
  156. int lastError = Marshal.GetLastWin32Error();
  157. switch ((uint)lastError)
  158. {
  159. case Win32Errors.ERROR_FILE_NOT_FOUND:
  160. // MSDN: .NET 3.5+: If the file to be deleted does not exist, no exception is thrown.
  161. return;
  162. case Win32Errors.ERROR_PATH_NOT_FOUND:
  163. // MSDN: .NET 3.5+: DirectoryNotFoundException: The specified path is invalid (for example, it is on an unmapped drive).
  164. NativeError.ThrowException(lastError, pathLp);
  165. return;
  166. case Win32Errors.ERROR_SHARING_VIOLATION:
  167. // MSDN: .NET 3.5+: IOException: The specified file is in use or there is an open handle on the file.
  168. NativeError.ThrowException(lastError, pathLp);
  169. break;
  170. case Win32Errors.ERROR_ACCESS_DENIED:
  171. var data = new NativeMethods.WIN32_FILE_ATTRIBUTE_DATA();
  172. int dataInitialised = FillAttributeInfoCore(transaction, pathLp, ref data, false, true);
  173. if (data.dwFileAttributes != (FileAttributes)(-1))
  174. {
  175. if ((data.dwFileAttributes & FileAttributes.Directory) != 0)
  176. // MSDN: .NET 3.5+: UnauthorizedAccessException: Path is a directory.
  177. throw new UnauthorizedAccessException(string.Format(CultureInfo.CurrentCulture, "({0}) {1}",
  178. Win32Errors.ERROR_INVALID_PARAMETER, string.Format(CultureInfo.CurrentCulture, Resources.Target_File_Is_A_Directory, pathLp)));
  179. if ((data.dwFileAttributes & FileAttributes.ReadOnly) != 0)
  180. {
  181. if (ignoreReadOnly)
  182. {
  183. // Reset file attributes.
  184. SetAttributesCore(false, transaction, pathLp, FileAttributes.Normal, PathFormat.LongFullPath);
  185. goto startDeleteFile;
  186. }
  187. // MSDN: .NET 3.5+: UnauthorizedAccessException: Path specified a read-only file.
  188. throw new FileReadOnlyException(pathLp);
  189. }
  190. }
  191. if (dataInitialised == Win32Errors.ERROR_SUCCESS)
  192. // MSDN: .NET 3.5+: UnauthorizedAccessException: The caller does not have the required permission.
  193. NativeError.ThrowException(lastError, pathLp);
  194. break;
  195. }
  196. // MSDN: .NET 3.5+: IOException:
  197. // The specified file is in use.
  198. // There is an open handle on the file, and the operating system is Windows XP or earlier.
  199. NativeError.ThrowException(lastError, pathLp);
  200. }
  201. }
  202. #endregion // Internal Methods
  203. }
  204. }