Andreas
Andreas

Reputation: 10037

How to check if relative path exists

In this post it is suggested to use GetFileAttributes() to check if a directory exists. But apparently, GetFileAttributes() can succeed even if it is passed an invalid path.

For example, let's assume the current directory is D:/test but doing the following still doesn't return INVALID_FILE_ATTRIBUTES although the path passed to GetFileAttributes() clearly doesn't exist because there are way too many levels of ..:

DWORD attrs = GetFileAttributes("../../../../../../..");

So how can I detect if a path actually exists?

Upvotes: 1

Views: 668

Answers (1)

RbMm
RbMm

Reputation: 33706

But apparently, GetFileAttributes() can succeed even if it is passed an invalid path.

this is wrong. if path really invalid - GetFileAttributes return appropriate error (ERROR_INVALID_NAME or ERROR_FILE_NOT_FOUND usually). not also that need check for ERROR_SHARING_VIOLATION and ERROR_ACCESS_DENIED in case GetFileAttributes return INVALID_FILE_ATTRIBUTES. because win32 convert to ERROR_ACCESS_DENIED not only STATUS_ACCESS_DENIED but many other unrelated status - more correct use NtQueryAttributesFile. also exist undocumented

extern "C" NTSYSAPI BOOLEAN NTAPI RtlDoesFileExists_U( _In_ PWSTR FileName );

which do this job (internal it call NtQueryAttributesFile and check also for STATUS_SHARING_VIOLATION AND STATUS_ACCESS_DENIED)

also after api return - file already can be deleted (or created) - as result returned value can be already wrong. so usual if we need some file/folder - need not try check but create or open it. or get error in this operation


but really your problem not in GetFileAttributes but in win32 to nt path conversion.

you assume that path D:/test../../../../../../.. is wrong. but system think that not. the RtlDosPathNameToNtPathName_U_WithStatus (or related) used by system for convert win32 path to nt. if test this api with your path, this give:

UNICODE_STRING us;
if (0 <= RtlDosPathNameToNtPathName_U_WithStatus(L"D:/test../../../../../../..", &us, 0, 0))
{
    DbgPrint("%wZ\n", &us);
    RtlFreeUnicodeString(&us);
}
if (0 <= RtlDosPathNameToNtPathName_U_WithStatus(L"../../../../../../..", &us, 0, 0))
{
    DbgPrint("%wZ\n", &us);
    RtlFreeUnicodeString(&us);
}

\??\D:\ and \??\<X>:\ so system convert this to root folder on drive. and this folder exist.

Upvotes: 2

Related Questions