Search code examples
windowswinapidirectoryntfs-mft

CreateFile on Directory in NTFS fails on ReadFile


Supposedly it is possible to actually open and read directories on NTFS volumes. However, my code to try this wasn't working, so I tried google, which found me this.

The key observation there seems to be that you must use FILE_FLAG_BACKUP_SEMANTICS. So, trimming that down, I basically get:

HANDLE hFile = CreateFile(L"C:\\temp", GENERIC_READ, FILE_SHARE_READ,
    0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0);

DWORD dwFileSize = GetFileSize(hFile, 0);
char* buf = new char[dwFileSize];

DWORD dwBytesRead = 0;
BOOL b = ReadFile(hFile, buf, dwFileSize, &dwBytesRead, 0);

Seems pretty straight-forward. Unfortunately, it doesn't work.

The CreateFile and GetFileSize both work (handle is not INVALID_HANDLE_VALUE, non-zero and plausible file size), but the ReadFile returns FALSE, dwBytesRead is zero, and GetLastError returns 1 ("Incorrect function"). Huh.

While I was typing this question, the 'Similar Questions' prompt showed me this. That business about using AdjustTokenPrivileges made a lot of sense. However, it didn't help. Adding ReadFile (and using c:\temp) to that example gives the same behavior. A closer reading of the CreateFile docs shows that even without the SE_BACKUP_NAME privilege, I should be able to open the file due to admin privileges.

I've tried a number of permutations:

  • Different ways of specifying the directory name (c:\temp, c:\temp\, \\.\c:\temp, \\?\c:\temp\, etc).
  • Different directories
  • Different drives
  • Different share options (0, FILE_SHARE_READ, FILE_SHARE_READ | FILE_SHARE_WRITE)
  • Different access permissions (GENERIC_READ, FILE_LIST_DIRECTORY, FILE_LIST_DIRECTORY + FILE_READ_EA + FILE_READ_ATTRIBUTES, FILE_LIST_DIRECTORY + FILE_READ_EA + FILE_READ_ATTRIBUTES + FILE_TRAVERSE)
  • I can't see any flags that might apply other than FILE_FLAG_BACKUP_SEMANTICS (which I assume is required), but I tried FILE_FLAG_NO_BUFFERING and a 4096 byte aligned buffer. Nope.

I'm (currently) trying 152 permutations, and none of the ReadFiles are working. What am I missing?

Is my original assumption here incorrect? Is it not really possible to 'read' from a directory? Or is there just some trick I'm still missing?

What else should I mention?

  • I'm running as an admin, and can do a CreateFile on the volume.
  • My program is 64bit, built for unicode.
  • Windows 7 x64
  • NTFS 3.1 volume
  • It's cloudy outside (Hey, you never know what might matter...)

Solution

  • It looks like Jonathan Potter has given the correct answer. Despite prompting, he has elected not to post his comments as an answer. So I'm going to create one based on his responses in order to close the question.

    In short: "You can open a handle to a directory to do certain things, but calling ReadFile on it isn't one of them."

    What things? These things. This list includes:

    • BackupRead
    • BackupSeek
    • BackupWrite
    • GetFileInformationByHandle
    • GetFileSize
    • GetFileTime
    • GetFileType
    • ReadDirectoryChangesW
    • SetFileTime

    In summary: While you can "open" directories and "read" certain information about them, you can't actually use ReadFile. If you want to read the DirName::$INDEX_ALLOCATION information, you'll have to use a different approach.