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.
 
 

183 line
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.Runtime.InteropServices;
  24. using System.Security;
  25. using System.Security.AccessControl;
  26. namespace Alphaleonis.Win32.Filesystem
  27. {
  28. public static partial class File
  29. {
  30. #region Replace
  31. /// <summary>
  32. /// Replaces the contents of a specified file with the contents of another file, deleting the original file, and creating a backup of
  33. /// the replaced file.
  34. /// </summary>
  35. /// <remarks>
  36. /// The Replace method replaces the contents of a specified file with the contents of another file. It also creates a backup of the
  37. /// file that was replaced.
  38. /// </remarks>
  39. /// <remarks>
  40. /// If the <paramref name="sourceFileName"/> and <paramref name="destinationFileName"/> are on different volumes, this method will
  41. /// raise an exception. If the <paramref name="destinationBackupFileName"/> is on a different volume from the source file, the backup
  42. /// file will be deleted.
  43. /// </remarks>
  44. /// <remarks>
  45. /// Pass null to the <paramref name="destinationBackupFileName"/> parameter if you do not want to create a backup of the file being
  46. /// replaced.
  47. /// </remarks>
  48. /// <param name="sourceFileName">The name of a file that replaces the file specified by <paramref name="destinationFileName"/>.</param>
  49. /// <param name="destinationFileName">The name of the file being replaced.</param>
  50. /// <param name="destinationBackupFileName">The name of the backup file.</param>
  51. [SecurityCritical]
  52. public static void Replace(string sourceFileName, string destinationFileName, string destinationBackupFileName)
  53. {
  54. ReplaceCore(sourceFileName, destinationFileName, destinationBackupFileName, false, PathFormat.RelativePath);
  55. }
  56. /// <summary>
  57. /// Replaces the contents of a specified file with the contents of another file, deleting the original file, and creating a backup of
  58. /// the replaced file and optionally ignores merge errors.
  59. /// </summary>
  60. /// <remarks>
  61. /// The Replace method replaces the contents of a specified file with the contents of another file. It also creates a backup of the
  62. /// file that was replaced.
  63. /// </remarks>
  64. /// <remarks>
  65. /// If the <paramref name="sourceFileName"/> and <paramref name="destinationFileName"/> are on different volumes, this method will
  66. /// raise an exception. If the <paramref name="destinationBackupFileName"/> is on a different volume from the source file, the backup
  67. /// file will be deleted.
  68. /// </remarks>
  69. /// <remarks>
  70. /// Pass null to the <paramref name="destinationBackupFileName"/> parameter if you do not want to create a backup of the file being
  71. /// replaced.
  72. /// </remarks>
  73. /// <param name="sourceFileName">The name of a file that replaces the file specified by <paramref name="destinationFileName"/>.</param>
  74. /// <param name="destinationFileName">The name of the file being replaced.</param>
  75. /// <param name="destinationBackupFileName">The name of the backup file.</param>
  76. /// <param name="ignoreMetadataErrors">
  77. /// <see langword="true"/> to ignore merge errors (such as attributes and access control lists (ACLs)) from the replaced file to the
  78. /// replacement file; otherwise, <see langword="false"/>.
  79. /// </param>
  80. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
  81. [SecurityCritical]
  82. public static void Replace(string sourceFileName, string destinationFileName, string destinationBackupFileName, bool ignoreMetadataErrors)
  83. {
  84. ReplaceCore(sourceFileName, destinationFileName, destinationBackupFileName, ignoreMetadataErrors, PathFormat.RelativePath);
  85. }
  86. /// <summary>
  87. /// [AlphaFS] Replaces the contents of a specified file with the contents of another file, deleting the original file, and creating a
  88. /// backup of the replaced file and optionally ignores merge errors.
  89. /// </summary>
  90. /// <remarks>
  91. /// The Replace method replaces the contents of a specified file with the contents of another file. It also creates a backup of the
  92. /// file that was replaced.
  93. /// </remarks>
  94. /// <remarks>
  95. /// If the <paramref name="sourceFileName"/> and <paramref name="destinationFileName"/> are on different volumes, this method will
  96. /// raise an exception. If the <paramref name="destinationBackupFileName"/> is on a different volume from the source file, the backup
  97. /// file will be deleted.
  98. /// </remarks>
  99. /// <remarks>
  100. /// Pass null to the <paramref name="destinationBackupFileName"/> parameter if you do not want to create a backup of the file being
  101. /// replaced.
  102. /// </remarks>
  103. /// <param name="sourceFileName">The name of a file that replaces the file specified by <paramref name="destinationFileName"/>.</param>
  104. /// <param name="destinationFileName">The name of the file being replaced.</param>
  105. /// <param name="destinationBackupFileName">The name of the backup file.</param>
  106. /// <param name="ignoreMetadataErrors">
  107. /// <see langword="true"/> to ignore merge errors (such as attributes and access control lists (ACLs)) from the replaced file to the
  108. /// replacement file; otherwise, <see langword="false"/>.
  109. /// </param>
  110. /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
  111. [SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "dest")]
  112. [SecurityCritical]
  113. public static void Replace(string sourceFileName, string destinationFileName, string destinationBackupFileName, bool ignoreMetadataErrors, PathFormat pathFormat)
  114. {
  115. ReplaceCore(sourceFileName, destinationFileName, destinationBackupFileName, ignoreMetadataErrors, pathFormat);
  116. }
  117. #endregion // Replace
  118. #region ReplaceCore
  119. /// <summary>Replaces the contents of a specified file with the contents of another file, deleting
  120. /// the original file, and creating a backup of the replaced file and optionally ignores merge errors.
  121. /// </summary>
  122. /// <remarks>
  123. /// The Replace method replaces the contents of a specified file with the contents of another file. It also creates a backup of the
  124. /// file that was replaced.
  125. /// </remarks>
  126. /// <remarks>
  127. /// If the <paramref name="sourceFileName"/> and <paramref name="destinationFileName"/> are on different volumes, this method will
  128. /// raise an exception. If the <paramref name="destinationBackupFileName"/> is on a different volume from the source file, the backup
  129. /// file will be deleted.
  130. /// </remarks>
  131. /// <remarks>
  132. /// Pass null to the <paramref name="destinationBackupFileName"/> parameter if you do not want to create a backup of the file being
  133. /// replaced.
  134. /// </remarks>
  135. /// <param name="sourceFileName">The name of a file that replaces the file specified by <paramref name="destinationFileName"/>.</param>
  136. /// <param name="destinationFileName">The name of the file being replaced.</param>
  137. /// <param name="destinationBackupFileName">The name of the backup file.</param>
  138. /// <param name="ignoreMetadataErrors">
  139. /// <see langword="true"/> to ignore merge errors (such as attributes and access control lists (ACLs)) from the replaced file to the
  140. /// replacement file; otherwise, <see langword="false"/>.
  141. /// </param>
  142. /// <param name="pathFormat">Indicates the format of the path parameter(s).</param>
  143. [SecurityCritical]
  144. internal static void ReplaceCore(string sourceFileName, string destinationFileName, string destinationBackupFileName, bool ignoreMetadataErrors, PathFormat pathFormat)
  145. {
  146. var options = GetFullPathOptions.RemoveTrailingDirectorySeparator | GetFullPathOptions.FullCheck;
  147. string sourceFileNameLp = Path.GetExtendedLengthPathCore(null, sourceFileName, pathFormat, options);
  148. string destinationFileNameLp = Path.GetExtendedLengthPathCore(null, destinationFileName, pathFormat, options);
  149. // Pass null to the destinationBackupFileName parameter if you do not want to create a backup of the file being replaced.
  150. string destinationBackupFileNameLp = destinationBackupFileName == null
  151. ? null
  152. : Path.GetExtendedLengthPathCore(null, destinationBackupFileName, pathFormat, options);
  153. const int replacefileWriteThrough = 1;
  154. const int replacefileIgnoreMergeErrors = 2;
  155. FileSystemRights dwReplaceFlags = (FileSystemRights) replacefileWriteThrough;
  156. if (ignoreMetadataErrors)
  157. dwReplaceFlags |= (FileSystemRights) replacefileIgnoreMergeErrors;
  158. // ReplaceFile()
  159. // In the ANSI version of this function, the name is limited to MAX_PATH characters.
  160. // To extend this limit to 32,767 wide characters, call the Unicode version of the function and prepend "\\?\" to the path.
  161. // 2013-01-13: MSDN does not confirm LongPath usage but a Unicode version of this function exists.
  162. if (!NativeMethods.ReplaceFile(destinationFileNameLp, sourceFileNameLp, destinationBackupFileNameLp, dwReplaceFlags, IntPtr.Zero, IntPtr.Zero))
  163. NativeError.ThrowException(Marshal.GetLastWin32Error(), sourceFileNameLp, destinationFileNameLp);
  164. }
  165. #endregion // ReplaceCore
  166. }
  167. }