Skip to content

Commit 9009984

Browse files
committed
Replace fs::equivalent with native implementation
std::filesystem::equivalent can fail with ERROR_INVALID_PARAMETER with valid and working paths
1 parent 0e61f4f commit 9009984

File tree

2 files changed

+13
-85
lines changed

2 files changed

+13
-85
lines changed

Client/loader/CInstallManager.cpp

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1155,31 +1155,6 @@ SString CInstallManager::_PrepareLaunchLocation()
11551155
const fs::path mtaDir = GetMTARootDirectory() / "MTA";
11561156
const fs::path launchDir = GetGameLaunchDirectory();
11571157

1158-
#if 0
1159-
// NOTE(botder): We are not using this solution because creating directory junctions requires administrator privileges.
1160-
// Create GTA subdirectory junctions to our launch directory.
1161-
for (const char* directoryName : {"anim", "audio", "data", "models", "text"})
1162-
{
1163-
// Delete shortcuts that may be confusing to the eye.
1164-
const fs::path shortcutPath = (launchDir / directoryName).replace_extension(".lnk");
1165-
1166-
if (std::error_code ec; fs::exists(shortcutPath, ec))
1167-
{
1168-
if (!fs::remove(shortcutPath, ec))
1169-
{
1170-
OutputDebugLine(*SString("Failed to remove shortcut for %s (%d, %s)", directoryName, ec.value(), ec.message().c_str()));
1171-
}
1172-
}
1173-
1174-
if (std::error_code ec; !SetDirectoryJunction(gtaDir / directoryName, launchDir / directoryName, ec))
1175-
{
1176-
OutputDebugLine(*SString("Failed to create junction for %s (%d, %s)", directoryName, ec.value(), ec.message().c_str()));
1177-
m_strAdminReason = _("Create GTA:SA junctions");
1178-
return "fail";
1179-
}
1180-
}
1181-
#endif
1182-
11831158
// Copy GTA dependencies to our launch directory.
11841159
for (const char* fileName : {"eax.dll", "ogg.dll", "vorbis.dll", "vorbisFile.dll"})
11851160
{

Client/loader/FileSystem.cpp

Lines changed: 13 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -316,12 +316,6 @@ bool AreFilesEqual(const fs::path& base, const fs::path& other, std::error_code&
316316
{
317317
ec.clear();
318318

319-
if (fs::equivalent(base, other, ec))
320-
return true;
321-
322-
if (ec)
323-
return false;
324-
325319
HandleScope baseHandle{CreateFileW(
326320
/* FileName */ base.wstring().c_str(),
327321
/* DesiredAccess */ GENERIC_READ,
@@ -354,23 +348,31 @@ bool AreFilesEqual(const fs::path& base, const fs::path& other, std::error_code&
354348
return false;
355349
}
356350

357-
LARGE_INTEGER baseSize{};
358-
LARGE_INTEGER otherSize{};
351+
BY_HANDLE_FILE_INFORMATION baseInfo{};
352+
BY_HANDLE_FILE_INFORMATION otherInfo{};
359353

360-
if (!GetFileSizeEx(baseHandle.get(), &baseSize) || !GetFileSizeEx(otherHandle.get(), &otherSize))
354+
if (!GetFileInformationByHandle(baseHandle.get(), &baseInfo) || !GetFileInformationByHandle(otherHandle.get(), &otherInfo))
361355
{
362356
ApplyLastSystemError(ec);
363357
return false;
364358
}
365359

366-
if (baseSize.QuadPart != otherSize.QuadPart)
360+
// Check if the handles represent the same file in the file system.
361+
if (baseInfo.dwVolumeSerialNumber == otherInfo.dwVolumeSerialNumber && baseInfo.nFileIndexHigh == otherInfo.nFileIndexHigh &&
362+
baseInfo.nFileIndexLow == otherInfo.nFileIndexLow)
363+
{
364+
return true;
365+
}
366+
367+
// Check if the file sizes differ.
368+
if (!(baseInfo.nFileSizeHigh == otherInfo.nFileSizeHigh && baseInfo.nFileSizeLow == otherInfo.nFileSizeLow))
367369
return false;
368370

369371
std::array<unsigned char, 4096> baseBuffer{};
370372
std::array<unsigned char, 4096> otherBuffer{};
371373

372374
const auto bytesToRead = static_cast<DWORD>(baseBuffer.size());
373-
LONGLONG remainingSize = baseSize.QuadPart;
375+
LONGLONG remainingSize = (static_cast<LONGLONG>(baseInfo.nFileSizeHigh) << 32) | baseInfo.nFileSizeLow;
374376

375377
while (remainingSize)
376378
{
@@ -479,52 +481,3 @@ auto GetFileBufferHash(const std::vector<unsigned char>& buffer) -> FileHash
479481
sha256_final(&ctx, hash.data());
480482
return hash;
481483
}
482-
483-
bool SetDirectoryJunction(const fs::path& from, const fs::path& to, std::error_code& ec)
484-
{
485-
ec.clear();
486-
487-
// The source directory must exist.
488-
if (!fs::is_directory(from, ec))
489-
return false;
490-
491-
// Check if the target directory is already pointing to the source directory.
492-
if (fs::is_symlink(to, ec))
493-
{
494-
if (fs::equivalent(from, to, ec))
495-
return true;
496-
497-
if (ec)
498-
return false;
499-
}
500-
501-
// Remove the target file to replace it.
502-
if (fs::exists(to, ec))
503-
{
504-
fs::remove_all(to, ec);
505-
}
506-
507-
if (ec)
508-
return false;
509-
510-
// Create the parent directory for the symlink.
511-
const fs::path toParentDirectory = to.parent_path();
512-
513-
if (!fs::exists(toParentDirectory, ec))
514-
{
515-
if (ec || !fs::create_directories(toParentDirectory, ec))
516-
return false;
517-
518-
if (!fs::is_directory(toParentDirectory, ec))
519-
return false;
520-
}
521-
522-
// Use the native function to create the symlink due to flag usage.
523-
if (!CreateSymbolicLinkW(to.wstring().c_str(), from.wstring().c_str(), SYMBOLIC_LINK_FLAG_DIRECTORY | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE))
524-
{
525-
ApplyLastSystemError(ec);
526-
return false;
527-
}
528-
529-
return true;
530-
}

0 commit comments

Comments
 (0)