wsutil: On Windows handle hard links in files identical

Use GetFileInformationByHandleEx to retrieve the Windows-specific
volume and 128-bit file information ID, and use that to see if
files are identical instead of using _fullpath. This has the advantage
of working in the unlikely case of hard links.

GetFileInformationByHandleEx (vs just GetFileInformationByHandle)
isn't available on Windows 7 and earlier, but we don't support even
Windows 8 now.
This commit is contained in:
John Thacker 2024-03-09 07:28:43 -05:00
parent b8f2baa8ba
commit 7013af8367

View File

@ -2386,37 +2386,48 @@ bool config_file_exists_with_entries(const char *fname, char comment_char)
bool
files_identical(const char *fname1, const char *fname2)
{
/* Two different implementations, because:
*
* - _fullpath is not available on UN*X, so we can't get full
* paths and compare them (which wouldn't work with hard links
* in any case);
*
* - st_ino isn't filled in with a meaningful value on Windows.
/* Two different implementations, because st_ino isn't filled in with
* a meaningful value on Windows. Use the Windows API and FILE_ID_INFO
* instead.
*/
#ifdef _WIN32
char full1[MAX_PATH], full2[MAX_PATH];
FILE_ID_INFO filestat1, filestat2;
/*
* Get the absolute full paths of the file and compare them.
* That won't work if you have hard links, but those aren't
* much used on Windows, even though NTFS supports them.
*
* XXX - will _fullpath work with UNC?
* Compare VolumeSerialNumber and FileId.
*/
if( _fullpath( full1, fname1, MAX_PATH ) == NULL ) {
HANDLE h1 = CreateFile(utf_8to16(fname1), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, 0, NULL);
if (h1 == INVALID_HANDLE_VALUE) {
return false;
}
if( _fullpath( full2, fname2, MAX_PATH ) == NULL ) {
if (!GetFileInformationByHandleEx(h1, FileIdInfo, &filestat1, sizeof(FILE_ID_INFO))) {
CloseHandle(h1);
return false;
}
CloseHandle(h1);
HANDLE h2 = CreateFile(utf_8to16(fname2), 0,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
NULL, OPEN_EXISTING, 0, NULL);
if (h2 == INVALID_HANDLE_VALUE) {
return false;
}
if(strcmp(full1, full2) == 0) {
return true;
} else {
if (!GetFileInformationByHandleEx(h2, FileIdInfo, &filestat2, sizeof(FILE_ID_INFO))) {
CloseHandle(h2);
return false;
}
CloseHandle(h2);
return ((memcmp(&filestat1.FileId, &filestat2.FileId, sizeof(FILE_ID_128)) == 0) &&
filestat1.VolumeSerialNumber == filestat2.VolumeSerialNumber);
#else
ws_statb64 filestat1, filestat2;