1

I want to modify a single attribute on a file (e.g the read-only attribute). In order to do that, it looks like I have to query the current file attributes with either GetFileAttributes or GetFileInformationByHandle, then set the new attributes with either SetFileAttributes or SetFileInformationByHandle: https://learn.microsoft.com/en-us/windows/win32/fileio/retrieving-and-changing-file-attributes

However that is inherently racy, as the file attributes may change between the query and the update. Is there a method to update file attributes atomically? I would expect there to be an API like ModifyFileAttributes(DWORD addAttributes, DWORD rmAttributes) which would do its best to work atomically. Transactional NTFS is not an option for me because a) it's deprecated b) only works on NTFS.

Thanks!

lb90
  • 828
  • 4
  • 8
  • 1
    "*Is there a method to update file attributes atomically?*" - AFAIK, no. – Remy Lebeau Feb 07 '23 at 15:41
  • 1
    As [SetFileAttributesTransacted](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-setfileattributestransactedw) said, *Many scenarios that TxF was developed for can be achieved through simpler and more readily available techniques. please see [Alternatives to using Transactional NTFS](https://learn.microsoft.com/en-us/windows/desktop/FileIO/deprecation-of-txf).* Like [FILE_SHARE_READ](https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea). – YangXiaoPo-MSFT Feb 08 '23 at 02:40
  • @YangXiaoPo-MSFT ah, true! If I deny write access by not passing FILE_SHARE_WRITE, then attributes cannot be changed. Nice! I thought FILE_SHARE_WRITE wasn't about attributes at all :) – lb90 Feb 08 '23 at 16:40

1 Answers1

1

As mentioned in the comment, FILE_SHARE_READ is a trade-off. The following code is adapted from SetFileInformationByHandle function. SetFileInformationByHandle for hFile2 is ERROR_ACCESS_DENIED.

#include <Windows.h>
#include <Tchar.h>
int main()
{
    //...
    HANDLE hFile1 = CreateFile(TEXT("tempfile"),
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ,
        NULL,
        CREATE_ALWAYS,
        0,
        NULL);

    HANDLE hFile2 = CreateFile(TEXT("tempfile"),
        GENERIC_READ,
        FILE_SHARE_READ| FILE_SHARE_WRITE,
        NULL,
        OPEN_ALWAYS,
        0,
        NULL);

    if (hFile1 != INVALID_HANDLE_VALUE && hFile2 != INVALID_HANDLE_VALUE)
    {
        HANDLE hFile = hFile1;
        //HANDLE hFile = hFile2;
        FILE_BASIC_INFO fdi{};
        fdi.FileAttributes = FILE_ATTRIBUTE_TEMPORARY | FILE_ATTRIBUTE_NORMAL;

        BOOL fResult = SetFileInformationByHandle(hFile,
            FileBasicInfo,
            &fdi,
            sizeof(FILE_BASIC_INFO));

        if (fResult)
        {
            // File will be deleted upon CloseHandle.
            _tprintf(TEXT("SetFileInformationByHandle marked tempfile for deletion\n"));

            // ... 
            // Now use the file for whatever temp data storage you need,
            // it will automatically be deleted upon CloseHandle or 
            // application termination.
            // ...
        }
        else
        {
            _tprintf(TEXT("error %lu:  SetFileInformationByHandle could not mark tempfile for deletion\n"),
                GetLastError());
        }

        CloseHandle(hFile);

        // At this point, the file is closed and deleted by the system.
    }
    else
    {
        _tprintf(TEXT("error %lu:  could not create tempfile\n"),
            GetLastError());
    }
    //...
}
YangXiaoPo-MSFT
  • 1,589
  • 1
  • 4
  • 22