mirror of https://github.com/raandree/NTFSSecurity
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.
159 lines
7.1 KiB
159 lines
7.1 KiB
/* Copyright (C) 2008-2016 Peter Palotas, Jeffrey Jangli, Alexandr Normuradov
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
* of this software and associated documentation files (the "Software"), to deal
|
|
* in the Software without restriction, including without limitation the rights
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
* copies of the Software, and to permit persons to whom the Software is
|
|
* furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
* THE SOFTWARE.
|
|
*/
|
|
|
|
using System;
|
|
using System.ComponentModel;
|
|
using System.Diagnostics.CodeAnalysis;
|
|
using System.Runtime.InteropServices;
|
|
using System.Security;
|
|
using System.Security.AccessControl;
|
|
using System.Security.Permissions;
|
|
using System.Transactions;
|
|
|
|
namespace Alphaleonis.Win32.Filesystem
|
|
{
|
|
[ComImport]
|
|
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
|
|
[Guid("79427A2B-F895-40e0-BE79-B57DC82ED231")]
|
|
[SuppressUnmanagedCodeSecurity]
|
|
internal interface IKernelTransaction
|
|
{
|
|
void GetHandle([Out] out SafeKernelTransactionHandle handle);
|
|
}
|
|
|
|
/// <summary>A KTM transaction object for use with the transacted operations in <see cref="Filesystem"/></summary>
|
|
public sealed class KernelTransaction : MarshalByRefObject, IDisposable
|
|
{
|
|
/// <summary>Initializes a new instance of the <see cref="KernelTransaction"/> class, internally using the specified <see cref="Transaction"/>.
|
|
/// This method allows the usage of methods accepting a <see cref="KernelTransaction"/> with an instance of <see cref="System.Transactions.Transaction"/>.
|
|
/// </summary>
|
|
/// <param name="transaction">The transaction to use for any transactional operations.</param>
|
|
[SuppressMessage("Microsoft.Security", "CA2122:DoNotIndirectlyExposeMethodsWithLinkDemands")]
|
|
[SecurityCritical]
|
|
public KernelTransaction(Transaction transaction)
|
|
{
|
|
((IKernelTransaction) TransactionInterop.GetDtcTransaction(transaction)).GetHandle(out _hTrans);
|
|
}
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="KernelTransaction"/> class with a default security descriptor, infinite timeout and no description.</summary>
|
|
[SecurityCritical]
|
|
public KernelTransaction()
|
|
: this(0, null)
|
|
{
|
|
}
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="KernelTransaction"/> class with a default security descriptor.</summary>
|
|
/// <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>
|
|
/// <param name="description">A user-readable description of the transaction. This parameter may be <see langword="null"/>.</param>
|
|
[SecurityCritical]
|
|
public KernelTransaction(int timeout, string description)
|
|
: this(null, timeout, description)
|
|
{
|
|
}
|
|
|
|
/// <summary>Initializes a new instance of the <see cref="KernelTransaction"/> class.</summary>
|
|
/// <param name="securityDescriptor">The <see cref="ObjectSecurity"/> security descriptor.</param>
|
|
/// <param name="timeout"><para>The time, in milliseconds, when the transaction will be aborted if it has not already reached the prepared state.</para>
|
|
/// <para>Specify 0 to provide an infinite timeout.</para></param>
|
|
/// <param name="description">A user-readable description of the transaction. This parameter may be <see langword="null"/>.</param>
|
|
[SecurityCritical]
|
|
public KernelTransaction(ObjectSecurity securityDescriptor, int timeout, string description)
|
|
{
|
|
if (!NativeMethods.IsAtLeastWindowsVista)
|
|
throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
|
|
|
|
using (var securityAttributes = new Security.NativeMethods.SecurityAttributes(securityDescriptor))
|
|
{
|
|
|
|
_hTrans = NativeMethods.CreateTransaction(securityAttributes, IntPtr.Zero, 0, 0, 0, timeout, description);
|
|
int lastError = Marshal.GetLastWin32Error();
|
|
|
|
NativeMethods.IsValidHandle(_hTrans, lastError);
|
|
}
|
|
}
|
|
|
|
/// <summary>Requests that the specified transaction be committed.</summary>
|
|
/// <exception cref="TransactionAlreadyCommittedException"/>
|
|
/// <exception cref="TransactionAlreadyAbortedException"/>
|
|
/// <exception cref="Win32Exception"/>
|
|
[SecurityCritical]
|
|
public void Commit()
|
|
{
|
|
if (!NativeMethods.IsAtLeastWindowsVista)
|
|
throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
|
|
|
|
if (!NativeMethods.CommitTransaction(_hTrans))
|
|
CheckTransaction();
|
|
}
|
|
|
|
/// <summary>Requests that the specified transaction be rolled back. This function is synchronous.</summary>
|
|
/// <exception cref="TransactionAlreadyCommittedException"/>
|
|
/// <exception cref="Win32Exception"/>
|
|
[SecurityCritical]
|
|
public void Rollback()
|
|
{
|
|
if (!NativeMethods.IsAtLeastWindowsVista)
|
|
throw new PlatformNotSupportedException(Resources.Requires_Windows_Vista_Or_Higher);
|
|
|
|
if (!NativeMethods.RollbackTransaction(_hTrans))
|
|
CheckTransaction();
|
|
}
|
|
|
|
private static void CheckTransaction()
|
|
{
|
|
uint error = (uint) Marshal.GetLastWin32Error();
|
|
int hr = Marshal.GetHRForLastWin32Error();
|
|
|
|
switch (error)
|
|
{
|
|
case Win32Errors.ERROR_TRANSACTION_ALREADY_ABORTED:
|
|
throw new TransactionAlreadyAbortedException("Transaction was already aborted", Marshal.GetExceptionForHR(hr));
|
|
|
|
case Win32Errors.ERROR_TRANSACTION_ALREADY_COMMITTED:
|
|
throw new TransactionAlreadyAbortedException("Transaction was already committed", Marshal.GetExceptionForHR(hr));
|
|
|
|
default:
|
|
Marshal.ThrowExceptionForHR(Marshal.GetHRForLastWin32Error());
|
|
break;
|
|
}
|
|
}
|
|
|
|
/// <summary>Gets the safe handle.</summary>
|
|
/// <value>The safe handle.</value>
|
|
public SafeHandle SafeHandle
|
|
{
|
|
get { return _hTrans; }
|
|
}
|
|
|
|
private readonly SafeKernelTransactionHandle _hTrans;
|
|
|
|
#region IDisposable Members
|
|
|
|
/// <summary>Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.</summary>
|
|
[SecurityPermissionAttribute(SecurityAction.Demand, UnmanagedCode = true)]
|
|
public void Dispose()
|
|
{
|
|
_hTrans.Close();
|
|
}
|
|
|
|
#endregion // IDisposable Members
|
|
}
|
|
}
|
|
|