to check if a file has a hard link, using GetFileInformationByHandle
typedef struct _BY_HANDLE_FILE_INFORMATION {
DWORD dwFileAttributes;
FILETIME ftCreationTime;
FILETIME ftLastAccessTime;
FILETIME ftLastWriteTime;
DWORD dwVolumeSerialNumber;
DWORD nFileSizeHigh;
DWORD nFileSizeLow;
DWORD nNumberOfLinks; <--- if this value is more than 1, then we have hard links
DWORD nFileIndexHigh;
DWORD nFileIndexLow;
} BY_HANDLE_FILE_INFORMATION, *PBY_HANDLE_FILE_INFORMATION, *LPBY_HANDLE_FILE_INFORMATION;
then for vista or later, using FindFirstFileName/FindNextFileName to get target.
for earlier system version, traverse the whole volume and comparing nFileIndexHigh and nFileIndexLow, once found,
--nNumberOfLinks, print the target name, until nNumberofLinks==1, then quit.
this is the way I found in FindLinks.exe by reversing the binary.
if ( _wcsicmp(dword_422154, lpFileName) )
{
sub_402580(v4, (DWORD *)&v8, (int)&fileindexlow, (int)&v11);
if ( fileindexlow == a3 && fileindexhigh == a4 )
{
wprintf(L"\r \r%s\n", v4);
if ( --*v5 == 1 ) //numoflinks
exit(0);
}
}
char __usercall sub_402580@<al>(LPCWSTR lpFileName@<ecx>, DWORD *a2@<edx>, int a3, int a4)
{
DWORD *v4; // edi
DWORD v5; // eax
HANDLE v6; // esi
DWORD v7; // ecx
const WCHAR *lpFileNamea; // [esp+Ch] [ebp-40h]
struct _BY_HANDLE_FILE_INFORMATION FileInformation; // [esp+14h] [ebp-38h]
v4 = a2;
lpFileNamea = lpFileName;
v5 = GetFileAttributesW(lpFileName);
if ( v5 == -1 )
return 0;
*v4 = 0;
v4[1] = 0;
*(_DWORD *)a3 = 0;
*(_DWORD *)(a3 + 4) = 0;
*(_DWORD *)a4 = 0;
v6 = CreateFileW(lpFileNamea, 0x80u, 7u, 0, 3u, (v5 & 0x10) << 21, 0);
if ( v6 == (HANDLE)-1 )
return 0;
if ( GetFileInformationByHandle(v6, &FileInformation) )
{
*(_DWORD *)a4 = FileInformation.nNumberOfLinks;
v7 = FileInformation.nFileSizeHigh;
*v4 = FileInformation.nFileSizeLow;
v4[1] = v7;
LOWORD(v7) = FileInformation.nFileIndexHigh;
*(_DWORD *)a3 = FileInformation.nFileIndexLow;
*(_DWORD *)(a3 + 4) = (unsigned __int16)v7;
}
CloseHandle(v6);
return 1;
}