Win32 API トランザクションNTFSを使って、ファイル操作をアトミックにする CreateTransaction

Windows Vistaから搭載されたTransactional NTFSという機能で、ファイル操作に対してトランザクション処理を行えるようになりました。
例えば、[ファイル1 作成]→[ディレクトリ1 作成]→[ファイル2 作成] という複数のファイルシステム上の操作をアトミックに行うことができます。途中に失敗などでコミットすることなくトランザクションを終了した場合(または、明示的にロールバックした場合)、この一連の処理はロールバックされるということになります。


実際のAPI呼び出しの流れは、おおよそ以下のようになります。

No処理内容
1CreateTransactionでトランザクションハンドルを取得し、トランザクション開始
2トランザクションハンドルを使用して、各種ファイル操作を行う
3CommitTransactionでトランザクションをコミット
4CloseTransactionでトランザクション終了


また、ファイル操作に対してトランザクションを適用する際には、従来のファイル操作APIの名前に「Transacted」が付いた、「XxxxTransacted」という名前のファイル操作APIを使用します。
例えば、以下のようなAPIがあります。

CreateFileTransactedCreateDirectoryTransacted
FindFirstFileTransactedDeleteFileTransacted
CopyFileTransactedGetLongPathNameTransacted
MoveFileTransactedCreateSymbolicLinkTransacted
CreateHardLinkTransactedGetFileAttributesTransacted
FindFirstFileNameTransactedWGetFullPathNameTransacted
FindFirstStreamTransactedWGetCompressedFileSizeTransact
SetFileAttributesTransacted







CreateTransactionのプロトタイプ

HANDLE WINAPI CreateTransaction(
  _In_opt_  LPSECURITY_ATTRIBUTES lpTransactionAttributes,
  _In_opt_  LPGUID UOW,
  _In_opt_  DWORD CreateOptions,
  _In_opt_  DWORD IsolationLevel,
  _In_opt_  DWORD IsolationFlags,
  _In_opt_  DWORD Timeout,
  _In_opt_  LPWSTR Description
);

引数説明
lpTransactionAttributesセキュリティ記述子
UOW予約済み。0を指定する
CreateOptionsトランザクション命令のオプション。TRANSACTION_DO_NOT_PROMOTEを指定すると、トランザクションは分散できなくなる。
IsolationLevel予約済み。0を指定する
IsolationFlags予約済み。0を指定する
Timeoutタイムアウト期限(ミリ秒で指定する)。0かINFINITEを指定すると、無期限タイムアウト
Descriptionユーザー可読なトランザクションの説明

戻り値
成功したらトランザクションハンドルを返す。失敗したらINVALID_HANDLE_VALUEを返し、拡張エラー情報を得るには、GetLastErrorを呼び出す。



トランザクション NTFSを使用するサンプルプログラム

ファイル作成とディレクトリ作成をアトミックに行う

#include <windows.h>
#include <KtmW32.h>

#pragma comment(lib, "KtmW32.lib")

int main()
{
    HANDLE hTran;
    HANDLE hFile;
    DWORD dwWrittenBytes;

    char *lpString = "あいうえお";
    TCHAR szFileName[] = TEXT("testfile");
    TCHAR szDirName[] = TEXT("testdir");

    //トランザクション開始
    hTran = CreateTransaction(NULL, 
                              0, 
                              TRANSACTION_DO_NOT_PROMOTE, 
                              0, 
                              0,
                              INFINITE, 
                              L"あいうえお");
    if (hTran == INVALID_HANDLE_VALUE) {
        return 1;
    }

    //ファイル作成
    hFile = CreateFileTransacted(
        szFileName, 
        GENERIC_WRITE, 
        0, 
        NULL, 
        OPEN_ALWAYS, 
        0, 
        NULL,
        hTran,
        NULL,
        NULL);
    if (hFile == INVALID_HANDLE_VALUE) {
        return 1;
    }
    WriteFile(hFile, lpString, strlen(lpString), &dwWrittenBytes, NULL);

    //ディレクトリ作成
    CreateDirectoryTransacted(NULL, szDirName, NULL, hTran);

    //トランザクションをコミット
    CommitTransaction(hTran);
    
    //トランザクション終了
    CloseHandle(hTran);
    
    return 0;
}






参考
http://msdn.microsoft.com/ja-jp/library/windows/desktop/aa366011(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/windows/desktop/aa363859(v=vs.85).aspx
http://msdn.microsoft.com/ja-jp/library/windows/desktop/aa366001(v=vs.85).aspx
http://ja.wikipedia.org/wiki/%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B6%E3%82%AF%E3%82%B7%E3%83%A7%E3%83%B3NTFS