Programming Considerations for Transactional NTFS
For a description of various programming considerations for Transactional NTFS, see the following sections:
- Which File Changes Are Transacted
- Compression
- Creating a File or Directory
- Deleting a File
- Deleting a Directory
- Directory Locking Issues
- Directory Enumeration
- Memory-Mapped Files
- Named Streams
- Renaming a File or Directory
- Reparse Points
- Error Codes
- Encrypted File System
- File I/O Functions and Transactional NTFS
Which File Changes Are Transacted
Most file changes, such as changes to file contents, streams, reparse points, attributes, and the file system namespace, are transacted. When one of these changes is made on a transacted file handle, the change is isolated from other transactions, and the change is undone if the transaction is rolled back.
Changes that do not affect file contents, metadata, or the file system namespace, such as changes to compression or defragmentation, are not transacted. These changes are not isolated from other transactions, and they are not undone if the transaction is rolled back.
Compression
The compression state of a file opened in a transaction cannot be changed.
Creating a File or Directory
A file or directory that is created in a transaction is not visible to anything outside the current transaction. Outside this transaction, any attempt to create a file with the same name fails with the error ERROR_TRANSACTIONAL_CONFLICT, effectively reserving the file name for when the transaction commits or is rolled back.
Deleting a File
A file or directory that is deleted by calling the DeleteFileTransacted function remains visible to all outside readers.
Note
All transacted handles to the file must be closed before the end of the transaction. If the handles are not properly closed, the delete does not occur. All open handles to the file must be closed before performing the commit for the delete operation to be considered part of the transaction. This is because the system does not actually delete a file until the last handle to it is closed, even when the operation is not transacted, as part of the Windows file I/O subsystem.
Deleting a Directory
A directory that is deleted by calling the RemoveDirectoryTransacted function remains visible to all outside readers.
Note
The same constraints exist for open handles on transacted directory operations as on files. For more information, see Deleting a File.
Directory Locking Issues
If a file is modified in a transaction, all directory components of the path to the file are referred to as pinned against rename until the transaction ends. That is, the system prevents you from renaming them until the transaction is committed or rolled back. An attempt to rename a directory that is an ancestor to a file that has been modified in an ongoing transaction will fail with the error ERROR_CANT_BREAK_TRANSACTIONAL_DEPENDENCY.
Directory Enumeration
The contents of a directory can be changed while an enumeration is in progress as a result of using APIs that enumerate, for example the FindFirstFileTransacted and FindNextFile functions.
Changes to a directory outside a transaction are not isolated from the transaction and are immediately visible within the transaction. For example, if a non-transacted writer adds a file to a directory, the new file is immediately visible inside the transaction such that calling the FindFirstFileTransacted or FindNextFile function will return the new file.
Changes made to a directory inside a transaction are isolated until the transaction commits. For example, a file created in the directory as part of the transaction. A non-transacted reader calling the FindFirstFile or FindNextFile function will not see the newly created file until the transaction commits.
Memory-Mapped Files
The client must call the FlushViewOfFile function, close the file-mapping object, and close the file handle before committing the associated transaction on a memory-mapped file.
Named Streams
Named streams are fully transactional, but locking is done at the file level, not the stream level. Writers from outside a transaction that attempt to modify any stream within a locked file receive the error ERROR_SHARING_VIOLATION.
You cannot rename a secondary stream in a transaction.
Renaming a File or Directory
To rename a file as a transacted operation, call MoveFileTransacted to move the file.
Reparse Points
Changes to reparse points are transacted, which means that if a new reparse point gets assigned to a file in a transaction, it is not visible to the other transactions. Similarly, changes or removal of an existing reparse point are not visible until commit.
Error Codes
The Kernel Transaction Manager (KTM) uses the system error codes in the range from 6700 through 6799. Transactional NTFS (TxF) uses Windows error codes in the range from 6800 through 6899. For more information, see WinError.h and System Error Codes (6000-8199).
Encrypted File System
TxF does not support operations on EFS files. You cannot open an EFS-encrypted file for transactions. Calling the CreateFileTransacted function on an EFS file will fail with the error ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION. Similarly, calling the EncryptFile function on a file in a transaction will fail with the error ERROR_EFS_NOT_ALLOWED_IN_TRANSACTION.
File I/O Functions and Transactional NTFS
TxF provides new transacted functions that take a file name, and changes the behavior of existing file I/O API functions that take a file handle.
Transacted Functions
If you do not call one of the following transacted functions in place of its non-transacted version, the operation will not be transacted:
- CopyFileTransacted
- CreateDirectoryTransacted
- CreateFileTransacted
- CreateHardLinkTransacted
- CreateSymbolicLinkTransacted
- DeleteFileTransacted
- FindFirstFileNameTransactedW
- FindFirstFileTransacted
- FindFirstStreamTransactedW
- GetCompressedFileSizeTransacted
- GetFileAttributesTransacted
- GetFullPathNameTransacted
- GetLongPathNameTransacted
- MoveFileTransacted
- RemoveDirectoryTransacted
- SetFileAttributesTransacted
For example, the CreateFile function now has a transacted version: CreateFileTransacted.
File I/O Functions Changed By TxF
The following table lists the functions whose behavior is affected by Transactional NTFS. For example, the behavior of the ReadFile function will vary depending on whether the hFile parameter was created by the CreateFile function or the CreateFileTransacted function.
Function | Description |
---|---|
CloseHandle |
Applications should close all handles bound to a transaction before the transaction is committed. An application must close a transacted handle opened with FILE_FLAG_DELETE_ON_CLOSE before committing the transaction in order for the delete operation to occur. |
CreateFileMapping |
If there is a transaction associated with hFile, then the file-mapping object that this function creates will be associated with the same transaction. Modifications made through views of this file-mapping object are transacted. Applications must call FlushViewOfFile, unmap all views, and close all handles to the file-mapping object before committing transacted changes. |
FindNextFile |
If there is a transaction bound to the file enumeration handle, then the files that are returned are subject to transaction isolation rules. |
FSCTL_SET_COMPRESSION |
You cannot change the compression state of a file opened by CreateFileTransacted. |
GetFileInformationByHandle and GetFileInformationByHandleEx |
If there is a transaction bound to the file handle, then the function returns information for the isolated file view. |
GetFileSize and GetFileSizeEx |
If there is a transaction bound to the file handle, then the function returns information for the isolated file view. |
GetVolumeInformation |
If the volume supports file system transactions, the function returns FILE_SUPPORTS_TRANSACTIONS in lpFileSystemFlags. |
MapViewOfFile and MapViewOfFileEx |
If there is a transaction associated with the file handle used to create the file-mapping object that is being mapped, then the associated view is transacted. If the view is used to make transacted changes to a file, then the user must call FlushViewOfFile, close the file-mapping object, and close the file handle before committing the associated transaction. |
ReadDirectoryChangesW |
If there is a transaction bound to the directory handle, then the notifications reflect the isolated view of the directory. Changes to files outside the transacted view of the directory are not included in the notifications. |
ReadFile, ReadFileEx, and ReadFileScatter |
If there is a transaction bound to the file handle, then the function returns data from the transacted view of the file. A transacted read handle is guaranteed to show the same view of a file for the duration of the handle. |
SetEndOfFile |
If there is a transaction bound to the handle, then the change in the end-of-file position is transacted. |
SetFileInformationByHandle |
If there is a transaction bound to the handle, then the changes made will be transacted for the information classes FileBasicInfo, FileRenameInfo, FileAllocationInfo, FileEndOfFileInfo, and FileDispositionInfo. |
SetFileShortName |
If there is a transaction bound to the handle, then the change in the file's short name is transacted. |
SetFileTime |
If there is a transaction bound to the handle, then the change in file time is transacted. |
WriteFile, WriteFileEx, and WriteFileGather |
If there is a transaction bound to the file handle, then the file write is transacted. |