Search code examples
c++winapireparsepoint

Getting target path of junction always seems to end in "Error 5 Access Denied"


I have a project where I have to get the target of a junction. This is some code I came up with:

#include "stdafx.h"
#include <iostream>
#include <Windows.h>

#define BUFSIZE MAX_PATH

using namespace std;


int main()
{
TCHAR Path[BUFSIZE];
DWORD dwRet;
HANDLE hFile;

hFile = CreateFile(L"C:\\Users\\Test\\Documents\\My Videos",
    GENERIC_READ,
    FILE_SHARE_READ,
    0,
    OPEN_EXISTING,
    FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
    0);

if (hFile == INVALID_HANDLE_VALUE)
{
    printf("Could not open file (error %d)\n", GetLastError());
    return 0;
}
dwRet = GetFinalPathNameByHandle(hFile, Path, BUFSIZE, VOLUME_NAME_DOS);
if (dwRet < BUFSIZE)
{
    _tprintf(TEXT("\nThe final path is: %s\n"), Path);
}


CloseHandle(hFile);

//wcout << Path;

return 0;
}

Now, the weird thing is that the code returns nicely the GetFinalPathNameByHandle for every directory EXCEPT the junction / reparse point Documents\My Videos. For the junctions it throws an "error 5" with the GetLastError(). Has anyone an idea what can cause this?


Solution

  • I got to the bottom of it. You first have to do takeown /f "C:\users\test\Documents\My Videos" /r /d y before any C++ API can open a handle on the filesystem object.

    EDIT 2:

    For anyone who reads this in the future. The above code can work, but only when you use the takeown command on the juncture. Before the takeown usage there is a Everyone:(DENY)(S,RD) policy on the standards Windows junctions which denies all users read access. After takeown that policy is gone and the junction is also usable in Windows Explorer.

    EDIT: This is the working solution in C++ without using the takeown command:

    #define BUFSIZE MAX_PATH
    
    using namespace std;
    
    int main()
    {
    TCHAR Path[BUFSIZE];
    DWORD dwRet;
    HANDLE hFile;
    
    hFile = CreateFile(L"C:\\Users\\Test\\Documents\\My Music",
        0,
        0,
        0,
        OPEN_EXISTING,
        FILE_FLAG_BACKUP_SEMANTICS,
        0);
    
    if (hFile == INVALID_HANDLE_VALUE)
    {
        printf("Could not open file (error %d)\n", GetLastError());
        return 0;
    }
    dwRet = GetFinalPathNameByHandle(hFile, Path, BUFSIZE, VOLUME_NAME_DOS);
    if (dwRet < BUFSIZE)
    {
        _tprintf(TEXT("\nThe final path is: %s\n"), Path);
    }
    
    CloseHandle(hFile);
    
    return 0;
    }
    

    The product of this code is the target path of C:\users\test\Documents\My Music