I’ve seen some related questions but failed to find the exact solution for my problem…
Anyway, I have an invalid symlink made like this:
mklink link path/to/dir
Meaning I’m linking to a directory without the /D flag.
However, when I try to open the target file using the WinApi CreateFile
it fails. Do I need to open the symlink as a file or as a directory?
CreateFile(path_to_link,
0,
0,
NULL,
OPEN_EXISTING,
[*],
NULL)
When I specify a directory at [*] the function fails (Access Denied by GetLastError(). I believe that’s because the path itself configured as a file, since I have valid permission to all relevant files).
What do I need to put at [*] to handle path/to/dir
?
Notes:
- I must handle this kind of invalid use of mklink
- My final goal is to get the absolute path of
path/to/dir
. If there is another way withoutCreateFile
I’d love to hear about it:)
CodePudding user response:
As explained in the comment, it behaves like a Shell Link. Here is one way to resolve the target path, it uses the IShellItem2 COM interface and the System.Link.TargetParsingPath property.
C version:
#include <windows.h>
#include <stdio.h>
#include <shobjidl_core.h>
#include <Propkey.h>
int main()
{
CoInitialize(NULL);
{
IShellItem2* item;
if (SUCCEEDED(SHCreateItemFromParsingName(L"c:\\mypath\\link", NULL, IID_PPV_ARGS(&item))))
{
LPWSTR path = NULL;
if (SUCCEEDED(item->GetString(PKEY_Link_TargetParsingPath, &path)))
{
wprintf(L"Target: %s\n", path); // x:\path\to\dir
CoTaskMemFree(name);
}
item->Release();
}
}
CoUninitialize();
return 0;
}
C version:
#include <windows.h>
#include <stdio.h>
#include <shobjidl_core.h>
#include <Propkey.h>
int main()
{
CoInitialize(NULL);
{
IShellItem2* item;
if (SUCCEEDED(SHCreateItemFromParsingName(L"c:\\mypath\\link", NULL, &IID_IShellItem2, &item)))
{
LPWSTR path = NULL;
if (SUCCEEDED(item->lpVtbl->GetString(item, &PKEY_Link_TargetParsingPath, &path)))
{
wprintf(L"Target: %s\n", path); // x:\path\to\dir
CoTaskMemFree(path);
}
item->lpVtbl->Release(item);
}
}
CoUninitialize();
return 0;
}
CodePudding user response:
By default, mklink creates a file symbolic link. And according to Symbolic Link Effects on File Systems Functions, for CreateFile and CreateFileTransacted,
If FILE_FLAG_OPEN_REPARSE_POINT is specified and:
- If an existing file is opened and it is a symbolic link, the handle returned is a handle to the symbolic link.
- If CREATE_ALWAYS, TRUNCATE_EXISTING, or FILE_FLAG_DELETE_ON_CLOSE are specified, the file affected is a symbolic link.
If FILE_FLAG_OPEN_REPARSE_POINT is not specified and:
- If an existing file is opened and it is a symbolic link, the handle returned is a handle to the target.
- If CREATE_ALWAYS, TRUNCATE_EXISTING, or FILE_FLAG_DELETE_ON_CLOSE are specified, the file affected is the target.
The following code which reads a directory symbolic link works for me.
HANDLE h =CreateFile(L"C:\\Users\\SymbolicLink\\To\\MyFolder", GENERIC_READ, FILE_SHARE_READ,NULL, OPEN_ALWAYS, FILE_FLAG_BACKUP_SEMANTICS,NULL);