I use FindFirstFile() and co-functions to browse the contents of C:\example\dir
. I know that a file read can be a symbolic link, a junction, etc by checking whether d.dwAttributes & FILE_ATTRIBUTE_REPARSE_POINT != 0
. However, I haven't found a way to follow the link and see the location it is pointing to. Is that even possible?
Asked
Active
Viewed 2,213 times
4

neoaggelos
- 632
- 1
- 4
- 18
1 Answers
4
To find the target of a symbolic link, you have to open the symbolic link. The object manager dereferences the link and returns a handle to the target location. Calling GetFinalPathNameByHandle on that handle returns the pathname of the target.
The following implementation returns the target location, given a symbolic link:
std::wstring GetLinkTarget( const std::wstring& a_Link ) {
// Define smart pointer type for automatic HANDLE cleanup.
typedef std::unique_ptr<std::remove_pointer<HANDLE>::type,
decltype( &::CloseHandle )> FileHandle;
// Open file for querying only (no read/write access).
FileHandle h( ::CreateFileW( a_Link.c_str(), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr ),
&::CloseHandle );
if ( h.get() == INVALID_HANDLE_VALUE ) {
h.release();
throw std::runtime_error( "CreateFileW() failed." );
}
const size_t requiredSize = ::GetFinalPathNameByHandleW( h.get(), nullptr, 0,
FILE_NAME_NORMALIZED );
if ( requiredSize == 0 ) {
throw std::runtime_error( "GetFinalPathNameByHandleW() failed." );
}
std::vector<wchar_t> buffer( requiredSize );
::GetFinalPathNameByHandleW( h.get(), buffer.data(),
static_cast<DWORD>( buffer.size() ),
FILE_NAME_NORMALIZED );
return std::wstring( buffer.begin(), buffer.end() - 1 );
}
Note: For details about the RAII wrapper based on std::unique_ptr see std::unique_ptr, deleters and the Win32 API.

Community
- 1
- 1

IInspectable
- 46,945
- 8
- 85
- 181
-
There is a bug in the code: the file handle isn't closed at the end of the function. It is only closed if GetFinalPathNameByHandleW() returned 0. – Andy Sep 11 '15 at 15:45
-
@Andy: That's true. There's also another bug, that's less visible: If the `std::vector` throws an exception, the file handle isn't closed either. This can be solved by using a library that implements RAII over a `HANDLE`. I'll add appropriate comments. – IInspectable Sep 11 '15 at 15:55
-
@IInspectable: In C++11, you can use `std::unique_ptr` or `std::shared_ptr` (or the boost equivalents) as the RAII wrapper, they both support custom deleters, and `CloseHandle()` can be used for the deleter. – Remy Lebeau Sep 12 '15 at 06:59
-
thank you for this. don't worry about the possible leak, i can take care of this – neoaggelos Sep 12 '15 at 09:20
-
@RemyLebeau: I keep forgetting, that C++ is a new language now. Thanks for the suggestion on implementing exception-safe resource management. – IInspectable Sep 12 '15 at 13:19