2015 10 31 01 35 [windows] 使用 NtSetInformationFile 來改檔案或目錄名稱

剛開始,遇到的問題是權限不足,
後來才知道開檔案的時候要多加DELETE的權限.
之後就遇到無法Create目錄的Handle.
查MSND才知道要用FILE_FLAG_BACKUP_SEMANTICS去Create目錄的HANDLE.
才再試著改寫成, 不要直接使用CreateFile這個API,
改使用ntdll的NtCreateFile.
於是就有了以下的source codes了.
而使用方式是 XRenameFile(L"\\??\\C:\\old.txt", L"\\??\\C:\\new.txt");
大致上在64bits Win10 user mode下測試是workable的.

BOOLEAN XRenameFile(PWCHAR OldName, PWCHAR NewName)
{
    NTSTATUS                 ntStatus;
    OBJECT_ATTRIBUTES        objectAttributes;
    HANDLE                   fileHandle;
    IO_STATUS_BLOCK          ioStatus;
    PCHAR                    renameInformationBuffer;
    ULONG                    newNameLength;
    PFILE_RENAME_INFORMATION renameInformation;
    UNICODE_STRING           OldNameUS;
    
    if (OldName == NULL || NewName == NULL) {
        return FALSE;
    }
    OldNameUS.Buffer = OldName;
    OldNameUS.Length = wcslen(OldName) * 2;
    OldNameUS.MaximumLength = OldNameUS.Length + 2;


    newNameLength = wcslen(NewName) * 2;
    renameInformationBuffer = RtlAllocateHeap(RtlGetProcessHeap(), 0, (sizeof(FILE_RENAME_INFORMATION) + newNameLength));
    if (renameInformationBuffer==NULL) {
        return FALSE;
    }


#if 1

    InitializeObjectAttributes(&objectAttributes,
        &OldNameUS,
        0,
        NULL,
        NULL);

    ntStatus = NtCreateFile(&fileHandle,
        (DELETE | SYNCHRONIZE),
        &objectAttributes,
        &ioStatus,
        NULL,
        0,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        FILE_OPEN,
        FILE_SYNCHRONOUS_IO_NONALERT,
        NULL,
        0);

    if (!NT_SUCCESS(ntStatus)) {
        RtlFreeHeap(RtlGetProcessHeap(), 0, renameInformationBuffer);
        return FALSE;
    }
#else
    fileHandle = CreateFile(OldName,
        ( DELETE | SYNCHRONIZE),
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS,
        NULL);
    if (INVALID_HANDLE_VALUE == fileHandle) {
        return FALSE;
    }
#endif

    renameInformation = (PFILE_RENAME_INFORMATION)renameInformationBuffer;
    renameInformation->ReplaceIfExists = 1;
    renameInformation->RootDirectory = 0;
    renameInformation->FileNameLength = newNameLength;
    wcscpy(renameInformation->FileName, NewName);
    ntStatus = NtSetInformationFile(fileHandle, &ioStatus, renameInformation,
        sizeof(FILE_RENAME_INFORMATION) + newNameLength,
        FileRenameInformation);

    NtClose(fileHandle);
    RtlFreeHeap(RtlGetProcessHeap(), 0, renameInformationBuffer);

    return NT_SUCCESS(ntStatus);
}