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.

160 rivejä
7.1 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.ComponentModel;
  23. using System.Diagnostics.CodeAnalysis;
  24. using System.Runtime.InteropServices;
  25. using System.Security;
  26. using System.Security.AccessControl;
  27. using System.Security.Permissions;
  28. using System.Transactions;
  29. namespace Alphaleonis.Win32.Filesystem
  30. {
  31. [ComImport]
  32. [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
  33. [Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")]
  34. [SuppressUnmanagedCodeSecurity]
  35. internal interface IKernelTransaction
  36. {
  37. void GetHandle([Out] out SafeKernelTransactionHandle handle);
  38. }
  39. /// <summary>A KTM transaction object for use with the transacted operations in <see cref="Filesystem"/></summary>
  40. public sealed class KernelTransaction : MarshalByRefObject, IDisposable
  41. {
  42. /// <summary>Initializes a new instance of the <see cref="KernelTransaction"/> class, internally using the specified <see cref="Transaction"/>.
  43. /// This method allows the usage of methods accepting a <see cref="KernelTransaction"/> with an instance of <see cref="System.Transactions.Transaction"/>.
  44. /// </summary>
  45. /// <param name="transaction">The transaction to use for any transactional operations.</param>
  46. [SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
  47. [SecurityCritical]
  48. public KernelTransaction(Transaction transaction)
  49. {
  50. ((IKernelTransaction) TransactionInterop.GetDtcTransaction(transaction)).GetHandle(out _hTrans);
  51. }
  52. /// <summary>Initializes a new instance of the <see cref="KernelTransaction"/> class with a default security descriptor, infinite timeout and no description.</summary>
  53. [SecurityCritical]
  54. public KernelTransaction()
  55. : this(0, null)
  56. {
  57. }
  58. /// <summary>Initializes a new instance of the <see cref="KernelTransaction"/> class with a default security descriptor.</summary>
  59. /// <param name="timeout"><para>The time, in milliseconds, when the transaction will be aborted if it has not already reached the prepared state.</para></param>
  60. /// <param name="description">A user-readable description of the transaction. This parameter may be <see langword="null"/>.</param>
  61. [SecurityCritical]
  62. public KernelTransaction(int timeout, string description)
  63. : this(null, timeout, description)
  64. {
  65. }
  66. /// <summary>Initializes a new instance of the <see cref="KernelTransaction"/> class.</summary>
  67. /// <param name="securityDescriptor">The <see cref="ObjectSecurity"/> security descriptor.</param>
  68. /// <param name="timeout"><para>The time, in milliseconds, when the transaction will be aborted if it has not already reached the prepared state.</para>
  69. /// <para>Specify 0 to provide an infinite timeout.</para></param>
  70. /// <param name="description">A user-readable description of the transaction. This parameter may be <see langword="null"/>.</param>
  71. [SecurityCritical]
  72. public KernelTransaction(ObjectSecurity securityDescriptor, int timeout, string description)
  73. {
  74. if (!NativeMethods.IsAtLeastWindowsVista)
  75. throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
  76. using (var securityAttributes = new Security.NativeMethods.SecurityAttributes(securityDescriptor))
  77. {
  78. _hTrans = NativeMethods.CreateTransaction(securityAttributes, IntPtr.Zero, 0, 0, 0, timeout, description);
  79. int lastError = Marshal.GetLastWin32Error();
  80. NativeMethods.IsValidHandle(_hTrans, lastError);
  81. }
  82. }
  83. /// <summary>Requests that the specified transaction be committed.</summary>
  84. /// <exception cref="TransactionAlreadyCommittedException"/>
  85. /// <exception cref="TransactionAlreadyAbortedException"/>
  86. /// <exception cref="Win32Exception"/>
  87. [SecurityCritical]
  88. public void Commit()
  89. {
  90. if (!NativeMethods.IsAtLeastWindowsVista)
  91. throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
  92. if (!NativeMethods.CommitTransaction(_hTrans))
  93. CheckTransaction();
  94. }
  95. /// <summary>Requests that the specified transaction be rolled back. This function is synchronous.</summary>
  96. /// <exception cref="TransactionAlreadyCommittedException"/>
  97. /// <exception cref="Win32Exception"/>
  98. [SecurityCritical]
  99. public void Rollback()
  100. {
  101. if (!NativeMethods.IsAtLeastWindowsVista)
  102. throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
  103. if (!NativeMethods.RollbackTransaction(_hTrans))
  104. CheckTransaction();
  105. }
  106. private static void CheckTransaction()
  107. {
  108. uint error = (uint) Marshal.GetLastWin32Error();
  109. int hr = Marshal.GetHRForLastWin32Error();
  110. switch (error)
  111. {
  112. case Win32Errors.ERROR_TRANSACTION_ALREADY_ABORTED:
  113. throw new TransactionAlreadyAbortedException("Transaction was already aborted", Marshal.GetExceptionForHR(hr));
  114. case Win32Errors.ERROR_TRANSACTION_ALREADY_COMMITTED:
  115. throw new TransactionAlreadyAbortedException("Transaction was already committed", Marshal.GetExceptionForHR(hr));
  116. default:
  117. Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
  118. break;
  119. }
  120. }
  121. /// <summary>Gets the safe handle.</summary>
  122. /// <value>The safe handle.</value>
  123. public SafeHandle SafeHandle
  124. {
  125. get { return _hTrans; }
  126. }
  127. private readonly SafeKernelTransactionHandle _hTrans;
  128. #region IDisposable Members
  129. /// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
  130. [SecurityPermissionAttribute(SecurityAction.Demand, UnmanagedCode = true)]
  131. public void Dispose()
  132. {
  133. _hTrans.Close();
  134. }
  135. #endregion // IDisposable Members
  136. }
  137. }