From: Beman Dawes on
POSIX has readlink() - read the contents of a symbolic link. In other
words, if "foo" is a symlink to "baz/bar", the result is the string
"baz/bar"

What is the Win32 (Vista and later) equivalent? Presumably there is
one, since from the command line, dir displays the desired information
for symbolic links.

TIA,

--Beman
From: Kerem Gümrükcü on

Hi Bernan,

[Symbolic Link Effects on File Systems Functions]
http://msdn.microsoft.com/en-us/library/aa365682(VS.85).aspx

[Symbolic Links]
http://msdn.microsoft.com/en-us/library/aa365680(VS.85).aspx

Read about "Hard Links", "Junktions",...also have a look at IOCTL's
like FSCTL_GET_REPARSE_POINT and familiar for more information.
You should also pass the symbolic link handle opened with CreateFile(...)
to GetFinalPathNameByHandle(...) to get the target file, that works Vista
and
upper only. AFAIK this also works for UNC Paths (local only!),...

Good Luck!

Regards

Kerem

--
-----------------------
Beste Gr�sse / Best regards / Votre bien devoue
Kerem G�mr�kc�
Latest Project: http://www.pro-it-education.de/software/deviceremover
Latest Open-Source Projects: http://entwicklung.junetz.de
-----------------------

"Beman Dawes" <beman.dawes(a)gmail.com> schrieb im Newsbeitrag
news:d87675af-86d1-4977-b3c2-174dad1f021a(a)z41g2000yqz.googlegroups.com...
> POSIX has readlink() - read the contents of a symbolic link. In other
> words, if "foo" is a symlink to "baz/bar", the result is the string
> "baz/bar"
>
> What is the Win32 (Vista and later) equivalent? Presumably there is
> one, since from the command line, dir displays the desired information
> for symbolic links.
>
> TIA,
>
> --Beman

From: Beman Dawes on
On Dec 9, 9:33 pm, Kerem Gümrükcü <kareem...(a)hotmail.com> wrote:

> [Symbolic Link Effects on File Systems Functions]http://msdn.microsoft.com/en-us/library/aa365682(VS.85).aspx
>
> [Symbolic Links]http://msdn.microsoft.com/en-us/library/aa365680(VS.85).aspx
>
> Read about "Hard Links", "Junktions",...also have a look at IOCTL's
> like FSCTL_GET_REPARSE_POINT and familiar for more information.

Ah! I'd missed that. Works well. See sample program below.

> You should also pass the symbolic link handle opened with CreateFile(...)
> to GetFinalPathNameByHandle(...) to get the target file, that works Vista
> and
> upper only. AFAIK this also works for UNC Paths (local only!),...

The reported hangs with GetFinalPathNameByHandle(...) scared me off
from that approach.

See http://www.codeproject.com/Articles/35202/GetFinalPathNameByHandle-API-Hangs.aspx

Thanks for the sugestions! Very helpful!

--Beman

------------

#include <windows.h>
#include <string>
#include <iostream>

// REPARSE_DATA_BUFFER related definitions are found in ntifs.h,
// which is part of the Device Driver Kit rather than the SDK.
// See http://msdn.microsoft.com/en-us/library/ms791514.aspx

#define SYMLINK_FLAG_RELATIVE 1

typedef struct _REPARSE_DATA_BUFFER {
ULONG ReparseTag;
USHORT ReparseDataLength;
USHORT Reserved;
union {
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
ULONG Flags;
WCHAR PathBuffer[1];
/* Example of distinction between substitute and print names:
mklink /d ldrive c:\
SubstituteName: c:\\??\
PrintName: c:\
*/
} SymbolicLinkReparseBuffer;
struct {
USHORT SubstituteNameOffset;
USHORT SubstituteNameLength;
USHORT PrintNameOffset;
USHORT PrintNameLength;
WCHAR PathBuffer[1];
} MountPointReparseBuffer;
struct {
UCHAR DataBuffer[1];
} GenericReparseBuffer;
};
} REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;

#define REPARSE_DATA_BUFFER_HEADER_SIZE \
FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)

#define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )

int main(int argc, char * argv[])
{
union info_t
{
char buf[REPARSE_DATA_BUFFER_HEADER_SIZE
+MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
REPARSE_DATA_BUFFER rdb;
} info;

HANDLE h = ::CreateFile(argv[1], GENERIC_READ, 0, 0,
OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS
| FILE_FLAG_OPEN_REPARSE_POINT, 0);

if (h == INVALID_HANDLE_VALUE)
{
std::cout << "INVALID_HANDLE_VALUE\n";
return 1;
}

DWORD sz;

if (::DeviceIoControl(
h, // file or directory handle
FSCTL_GET_REPARSE_POINT, // dwIoControlCode
0, // lpInBuffer
0, // nInBufferSize
info.buf, // output buffer
sizeof(info), // size of output buffer
&sz, // number of bytes returned
0 // OVERLAPPED structure
) == 0)
{
std::cout << "Error: " << ::GetLastError() << "\n";
if (::GetLastError() == 4390L) std::cout <<
"ERROR_NOT_A_REPARSE_POINT\n";
return 1;
}

std::cout
<< "REPARSE_DATA_BUFFER_HEADER_SIZE: "
<< REPARSE_DATA_BUFFER_HEADER_SIZE << '\n'
<< "info.rdb.ReparseDataLength: "
<< info.rdb.ReparseDataLength << '\n'
<< "info.rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset: "
<< info.rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset << '\n'
<< "info.rdb.SymbolicLinkReparseBuffer.SubstituteNameLength: "
<< info.rdb.SymbolicLinkReparseBuffer.SubstituteNameLength << '\n'
<< "info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset: "
<< info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset << '\n'
<< "info.rdb.SymbolicLinkReparseBuffer.PrintNameLength: "
<< info.rdb.SymbolicLinkReparseBuffer.PrintNameLength << '\n'
<< "info.rdb.SymbolicLinkReparseBuffer.Flags: "
<< info.rdb.SymbolicLinkReparseBuffer.Flags << std::endl;

std::wstring subname(
(wchar_t*)info.rdb.SymbolicLinkReparseBuffer.PathBuffer
+ info.rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof
(wchar_t),
(wchar_t*)info.rdb.SymbolicLinkReparseBuffer.PathBuffer
+ info.rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof
(wchar_t)
+ info.rdb.SymbolicLinkReparseBuffer.SubstituteNameLength/sizeof
(wchar_t));
std::wstring prtname(
(wchar_t*)info.rdb.SymbolicLinkReparseBuffer.PathBuffer
+ info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof
(wchar_t),
(wchar_t*)info.rdb.SymbolicLinkReparseBuffer.PathBuffer
+ info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof
(wchar_t)
+ info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof
(wchar_t));

std::wcout
<< L"SubstituteName: " << subname
<< L", PrintName: " << prtname << std::endl;

return 0;
}
From: Kerem Gümrükcü on
Hi,

you are welcome Bernan and thanks for posting the
sample here, always good if someone needs one!

Regards

Kerem

--
-----------------------
Beste Gr�sse / Best regards / Votre bien devoue
Kerem G�mr�kc�
Latest Project: http://www.pro-it-education.de/software/deviceremover
Latest Open-Source Projects: http://entwicklung.junetz.de
-----------------------

"Beman Dawes" <beman.dawes(a)gmail.com> schrieb im Newsbeitrag
news:9cb182b8-4fff-49e4-8f57-7608666bc69b(a)m25g2000yqc.googlegroups.com...
> On Dec 9, 9:33 pm, Kerem G�mr�kc� <kareem...(a)hotmail.com> wrote:
>
>> [Symbolic Link Effects on File Systems
>> Functions]http://msdn.microsoft.com/en-us/library/aa365682(VS.85).aspx
>>
>> [Symbolic
>> Links]http://msdn.microsoft.com/en-us/library/aa365680(VS.85).aspx
>>
>> Read about "Hard Links", "Junktions",...also have a look at IOCTL's
>> like FSCTL_GET_REPARSE_POINT and familiar for more information.
>
> Ah! I'd missed that. Works well. See sample program below.
>
>> You should also pass the symbolic link handle opened with CreateFile(...)
>> to GetFinalPathNameByHandle(...) to get the target file, that works Vista
>> and
>> upper only. AFAIK this also works for UNC Paths (local only!),...
>
> The reported hangs with GetFinalPathNameByHandle(...) scared me off
> from that approach.
>
> See
> http://www.codeproject.com/Articles/35202/GetFinalPathNameByHandle-API-Hangs.aspx
>
> Thanks for the sugestions! Very helpful!
>
> --Beman
>
> ------------
>
> #include <windows.h>
> #include <string>
> #include <iostream>
>
> // REPARSE_DATA_BUFFER related definitions are found in ntifs.h,
> // which is part of the Device Driver Kit rather than the SDK.
> // See http://msdn.microsoft.com/en-us/library/ms791514.aspx
>
> #define SYMLINK_FLAG_RELATIVE 1
>
> typedef struct _REPARSE_DATA_BUFFER {
> ULONG ReparseTag;
> USHORT ReparseDataLength;
> USHORT Reserved;
> union {
> struct {
> USHORT SubstituteNameOffset;
> USHORT SubstituteNameLength;
> USHORT PrintNameOffset;
> USHORT PrintNameLength;
> ULONG Flags;
> WCHAR PathBuffer[1];
> /* Example of distinction between substitute and print names:
> mklink /d ldrive c:\
> SubstituteName: c:\\??\
> PrintName: c:\
> */
> } SymbolicLinkReparseBuffer;
> struct {
> USHORT SubstituteNameOffset;
> USHORT SubstituteNameLength;
> USHORT PrintNameOffset;
> USHORT PrintNameLength;
> WCHAR PathBuffer[1];
> } MountPointReparseBuffer;
> struct {
> UCHAR DataBuffer[1];
> } GenericReparseBuffer;
> };
> } REPARSE_DATA_BUFFER, *PREPARSE_DATA_BUFFER;
>
> #define REPARSE_DATA_BUFFER_HEADER_SIZE \
> FIELD_OFFSET(REPARSE_DATA_BUFFER, GenericReparseBuffer)
>
> #define MAXIMUM_REPARSE_DATA_BUFFER_SIZE ( 16 * 1024 )
>
> int main(int argc, char * argv[])
> {
> union info_t
> {
> char buf[REPARSE_DATA_BUFFER_HEADER_SIZE
> +MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
> REPARSE_DATA_BUFFER rdb;
> } info;
>
> HANDLE h = ::CreateFile(argv[1], GENERIC_READ, 0, 0,
> OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS
> | FILE_FLAG_OPEN_REPARSE_POINT, 0);
>
> if (h == INVALID_HANDLE_VALUE)
> {
> std::cout << "INVALID_HANDLE_VALUE\n";
> return 1;
> }
>
> DWORD sz;
>
> if (::DeviceIoControl(
> h, // file or directory handle
> FSCTL_GET_REPARSE_POINT, // dwIoControlCode
> 0, // lpInBuffer
> 0, // nInBufferSize
> info.buf, // output buffer
> sizeof(info), // size of output buffer
> &sz, // number of bytes returned
> 0 // OVERLAPPED structure
> ) == 0)
> {
> std::cout << "Error: " << ::GetLastError() << "\n";
> if (::GetLastError() == 4390L) std::cout <<
> "ERROR_NOT_A_REPARSE_POINT\n";
> return 1;
> }
>
> std::cout
> << "REPARSE_DATA_BUFFER_HEADER_SIZE: "
> << REPARSE_DATA_BUFFER_HEADER_SIZE << '\n'
> << "info.rdb.ReparseDataLength: "
> << info.rdb.ReparseDataLength << '\n'
> << "info.rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset: "
> << info.rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset << '\n'
> << "info.rdb.SymbolicLinkReparseBuffer.SubstituteNameLength: "
> << info.rdb.SymbolicLinkReparseBuffer.SubstituteNameLength << '\n'
> << "info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset: "
> << info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset << '\n'
> << "info.rdb.SymbolicLinkReparseBuffer.PrintNameLength: "
> << info.rdb.SymbolicLinkReparseBuffer.PrintNameLength << '\n'
> << "info.rdb.SymbolicLinkReparseBuffer.Flags: "
> << info.rdb.SymbolicLinkReparseBuffer.Flags << std::endl;
>
> std::wstring subname(
> (wchar_t*)info.rdb.SymbolicLinkReparseBuffer.PathBuffer
> + info.rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof
> (wchar_t),
> (wchar_t*)info.rdb.SymbolicLinkReparseBuffer.PathBuffer
> + info.rdb.SymbolicLinkReparseBuffer.SubstituteNameOffset/sizeof
> (wchar_t)
> + info.rdb.SymbolicLinkReparseBuffer.SubstituteNameLength/sizeof
> (wchar_t));
> std::wstring prtname(
> (wchar_t*)info.rdb.SymbolicLinkReparseBuffer.PathBuffer
> + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof
> (wchar_t),
> (wchar_t*)info.rdb.SymbolicLinkReparseBuffer.PathBuffer
> + info.rdb.SymbolicLinkReparseBuffer.PrintNameOffset/sizeof
> (wchar_t)
> + info.rdb.SymbolicLinkReparseBuffer.PrintNameLength/sizeof
> (wchar_t));
>
> std::wcout
> << L"SubstituteName: " << subname
> << L", PrintName: " << prtname << std::endl;
>
> return 0;
> }