Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to programmatically check if the current process is long path aware on Windows?

Tags:

In Windows 10 version 1607, processes can now opt in to long path awareness using a manifest attribute (https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247.aspx#maxpath)

How can I programmatically check if the calling process is long path aware? Note that checking the OS version or the value of the registry key alone is insufficient due to the case where the Windows version is >= 1607, long paths are disabled system wide, and the process is not manifested for long paths.

like image 660
Jake Petroules Avatar asked Dec 04 '16 20:12

Jake Petroules


People also ask

What is long file path?

A file path is the total file name that consists of the local disk name, root folder name, names of folders/subfolders, file name, and file extension. A long path is the one that exceeds 260 characters.


1 Answers

ntdll (in win10 1607) export next API BOOLEAN NTAPI RtlAreLongPathsEnabled(); - so you can call this. it return TRUE if LongPaths Enabled

here code spinet - if RtlAreLongPathsEnabled returned false - STATUS_NAME_TOO_LONG (c0000106) is returned

enter image description here

system need convert Win32 path to NT path before use it in any file functions, which call kernel. this is done by calling RtlDosPathNameTo*NtPathName* . this functions, if see that path exceeds MAX_PATH (~) - called RtlAreLongPathsEnabled() and continue work only if function return TRUE. in case false - STATUS_NAME_TOO_LONG returned.

code of RtlAreLongPathsEnabled is simply - when first time called - it check registry (and only registry) and save result. not looking for manifest at all. here exactly code of function:

BOOLEAN RtlAreLongPathsEnabled()
{
    static BOOLEAN init;
    static BOOLEAN elp;
    if (!init)
    {
        init = true;
        HANDLE hKey;
        KEY_VALUE_PARTIAL_INFORMATION kvpi;
        STATIC_OBJECT_ATTRIBUTES(FileSystemRegKeyName, "\\registry\\MACHINE\\SYSTEM\\CurrentControlSet\\Control\\FileSystem");
        if (0 <= ZwOpenKey(&hKey, KEY_READ, &FileSystemRegKeyName))
        {
            STATIC_UNICODE_STRING(LongPathRegKeyValue, "LongPathsEnabled");
            if (0 <= ZwQueryValueKey(hKey, &LongPathRegKeyValue, KeyValuePartialInformation, &kvpi, sizeof(kvpi), &kvpi.TitleIndex) &&
                kvpi.Type == REG_DWORD && kvpi.DataLength == sizeof(DWORD))
            {
                elp = *(DWORD*)kvpi.Data != 0;
            }
            ZwClose(hKey);
        }
    }
    return elp;
}

so my conclusion - in current build long path behavior dependent only from registry settings and absolute not depended from application manifest, despite MSDN.

for down votes - for me simply interesting - are somebody from you build test app (with and without manifest) and test this yourself , or you can only read documentation ?

for those who find it difficult, or too lazy to write the code yourself. you can test with this code:

BOOL CreateFolder(LPCWSTR lpPathName)
{
    return CreateDirectoryW(lpPathName, 0) || GetLastError() == ERROR_ALREADY_EXISTS;
}

void LPT()
{
    WCHAR name[128], path[0x8000], *c;

    if (!SHGetFolderPath(0, CSIDL_PROFILE , 0, 0, path))
    {
        *name = '\\';
        __stosw((PUSHORT)name + 1, '3', RTL_NUMBER_OF(name) - 2);
        name[RTL_NUMBER_OF(name) - 1] = 0;

        c = path + wcslen(path);

        int n = 4;
        do 
        {
            memcpy(c, name, sizeof(name));
            c += RTL_NUMBER_OF(name) - 1;

            if (!CreateFolder(path))
            {
                break;
            }

        } while (--n);

        if (!n)
        {
            wcscpy(c, L"\\1.txt");

            HANDLE hFile = CreateFileW(path, FILE_GENERIC_WRITE, FILE_SHARE_VALID_FLAGS, 0, OPEN_ALWAYS, 0, 0);

            if (hFile != INVALID_HANDLE_VALUE)
            {
                CloseHandle(hFile);
                return ;
            }
        }
    }

    GetLastError();
}

and test it with <ws2:longPathAware>true</ws2:longPathAware> in manifest and LongPathsEnabled==0 in registry. it fail ? and then test it without manifest but with LongPathsEnabled==1 in registry. worked ?

if so i test on windows 10. version 1607. build 14393.0


on win10 1709 implementation changed: now RtlAreLongPathsEnabled is very simply:

enter image description here

BOOLEAN RtlAreLongPathsEnabled()
{
    return NtCurrentTeb()->ProcessEnvironmentBlock->IsLongPathAwareProcess;
}

in previous build was:

enter image description here

like image 50
RbMm Avatar answered Sep 23 '22 16:09

RbMm