I have this code which runs fine if path
points to a regular directory:
#include <windows.h>
#include <stdio.h>
int main()
{
wchar_t path[1024] = L"C:\\MyPath\\MyDir";
auto h = CreateFile(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (h == INVALID_HANDLE_VALUE)
{
printf("CreateFile error: 0x%08X\n", GetLastError());
return 0;
}
FILE_ID_INFO id = {};
if (!GetFileInformationByHandleEx(h, FILE_INFO_BY_HANDLE_CLASS::FileIdInfo, &id, sizeof(id)))
{
printf("FileIdInfo error: 0x%08X\n", GetLastError());
}
unsigned char buffer[4096];
do
{
if (!GetFileInformationByHandleEx(h, FILE_INFO_BY_HANDLE_CLASS::FileIdExtdDirectoryInfo, buffer, ARRAYSIZE(buffer)))
{
auto gle = GetLastError();
if (gle == ERROR_NO_MORE_FILES)
break;
printf("FileIdExtdDirectoryInfo error: 0x%08X\n", gle);
break;
}
auto current = buffer;
do
{
auto info = (FILE_ID_EXTD_DIR_INFO*)current;
wprintf(L"name: %.*s\n", info->FileNameLength / 2, info->FileName);
if (!info->NextEntryOffset)
break;
current += info->NextEntryOffset;
} while (true);
} while (true);
CloseHandle(h);
}
But if the directory points to a junction point, it returns (ERROR_INVALID_PARAMETER
invalid parameter)
FileIdInfo error: 0x00000057
FileIdExtdDirectoryInfo error: 0x00000057
So, I've tried this for CreateFile
auto h = CreateFile(path, FILE_LIST_DIRECTORY, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, NULL);
and now, I have no error, but it only shows "."
and ".."
entries, not all the files in the directory which I can read using cmd.exe
C:\MyPath\MyDir>dir
Volume in drive C has no label.
Volume Serial Number is AEA6-688A
Directory of C:\MyPath\MyDir
20/10/2017 14:08 (157) My Icon.ico
11/04/2018 09:08 321 My File.cpp
30/04/2018 15:14 <DIR> My dossier
19/09/2019 10:40 (41 650) New Rich Text Document.rtf
10/10/2021 11:06 0 New Text Document.txt
4 File(s) 46 224 bytes
1 Dir(s) 544 625 274 880 bytes free
It turns out my code in itself is correct, but it can fail if the file system below doesn't support NTFS object ID, since this is what it's trying to read (using FILE_INFO_BY_HANDLE_CLASS::FileIdInfo and FILE_INFO_BY_HANDLE_CLASS::FileIdExtdDirectoryInfo).
This happens for example if the directory is an NTFS mount point with a substitute name that points to a volume that doesn't have the FILE_SUPPORTS_OBJECT_IDS flag set (seen in virtual drive scenarios).
The error here (ERROR_INVALID_PARAMETER
) is kind of misleading as there's no problem with any parameter (except maybe the FileInformationClass
one), I would have expected some "unsupported" error instead.
As for cmd.exe, well, it just doesn't read/need that information so it works fine.