Home > OS >  Opening target symbolic link for mismatched file
Opening target symbolic link for mismatched file

Time:10-24

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 without CreateFile 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.

And A hard link is the file system representation of a file by which more than one path references a single file in the same volume.

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);
  • Related