2222#include < boost/algorithm/string/predicate.hpp>
2323namespace fs = boost::filesystem;
2424#else
25- namespace fs = std::tr2:: sys;
25+ namespace fs = std::sys;
2626#include <filesystem>
2727 #endif
2828
@@ -194,7 +194,7 @@ static inline WCHAR pathNameDriveLetter(LPCWSTR path)
194194}
195195
196196// returns false also in case we fail to determine the drive letter of the path
197- static inline bool pathesOnDifferentDrives (LPCWSTR path1, LPCWSTR path2)
197+ static inline bool pathsOnDifferentDrives (LPCWSTR path1, LPCWSTR path2)
198198{
199199 WCHAR drive1 = pathNameDriveLetter (path1);
200200 WCHAR drive2 = pathNameDriveLetter (path2);
@@ -485,29 +485,39 @@ class RerouteW
485485 const auto & lookupPath = canonizePath (absolutePath (inPath));
486486 result.m_RealPath = lookupPath.wstring ();
487487
488- const usvfs::RedirectionTreeContainer &table
489- = inverse ? context->inverseTable () : context->redirectionTable ();
490- result.m_FileNode = table->findNode (lookupPath);
488+ result.m_Buffer = k32DeleteTracker.lookup (result.m_RealPath );
489+ bool found = !result.m_Buffer .empty ();
490+ if (found) {
491+ spdlog::get (" hooks" )->info (" Rerouting file open to location of deleted file: {}" ,
492+ ush::string_cast<std::string>(result.m_Buffer ));
493+ result.m_NewReroute = true ;
494+ } else {
495+ const usvfs::RedirectionTreeContainer &table
496+ = inverse ? context->inverseTable () : context->redirectionTable ();
497+ result.m_FileNode = table->findNode (lookupPath);
491498
492- if (result.m_FileNode .get ()
493- && (!result.m_FileNode ->data ().linkTarget .empty () || result.m_FileNode ->isDirectory ()))
494- {
495- if (!result.m_FileNode ->data ().linkTarget .empty ()) {
496- result.m_Buffer = string_cast<std::wstring>(
497- result.m_FileNode ->data ().linkTarget .c_str (), CodePage::UTF8);
498- }
499- else
499+ if (result.m_FileNode .get ()
500+ && (!result.m_FileNode ->data ().linkTarget .empty () || result.m_FileNode ->isDirectory ()))
500501 {
501- result.m_Buffer = result.m_FileNode ->path ().wstring ();
502+ if (!result.m_FileNode ->data ().linkTarget .empty ()) {
503+ result.m_Buffer = string_cast<std::wstring>(
504+ result.m_FileNode ->data ().linkTarget .c_str (), CodePage::UTF8);
505+ }
506+ else
507+ {
508+ result.m_Buffer = result.m_FileNode ->path ().wstring ();
509+ }
510+ found = true ;
502511 }
503- wchar_t inIt = inPath[wcslen (inPath) - 1 ];
512+ }
513+ if (found) {
514+ result.m_Rerouted = true ;
515+
516+ wchar_t inIt = inPath[wcslen (inPath) - 1 ];
504517 std::wstring::iterator outIt = result.m_Buffer .end () - 1 ;
505518 if ((*outIt == L' \\ ' || *outIt == L' /' ) && !(inIt == L' \\ ' || inIt == L' /' ))
506- result.m_Buffer .erase (outIt);
507- if (result.m_Buffer .length () >= MAX_PATH && !ush::startswith (result.m_Buffer .c_str (), LR"( \\?\)" ))
508- result.m_Buffer = LR"( \\?\)" + result.m_Buffer ;
519+ result.m_Buffer .erase (outIt);
509520 std::replace (result.m_Buffer .begin (), result.m_Buffer .end (), L' /' , L' \\ ' );
510- result.m_Rerouted = true ;
511521 }
512522 else
513523 result.m_Buffer = inPath;
@@ -556,16 +566,22 @@ class RerouteW
556566
557567 if (found)
558568 {
559- if (createPath)
569+ if (createPath) {
560570 try {
561571 usvfs::FunctionGroupLock lock (usvfs::MutExHookGroup::ALL_GROUPS);
562572 result.m_PathCreated =
563573 createFakePath (fs::path (result.m_Buffer ).parent_path (), securityAttributes);
564- } catch (const std::exception &e) {
574+ }
575+ catch (const std::exception &e) {
565576 spdlog::get (" hooks" )->error (" failed to create {}: {}" ,
566577 ush::string_cast<std::string>(result.m_Buffer ), e.what ());
567578 }
579+ }
568580
581+ wchar_t inIt = inPath[wcslen (inPath) - 1 ];
582+ std::wstring::iterator outIt = result.m_Buffer .end () - 1 ;
583+ if ((*outIt == L' \\ ' || *outIt == L' /' ) && !(inIt == L' \\ ' || inIt == L' /' ))
584+ result.m_Buffer .erase (outIt);
569585 std::replace (result.m_Buffer .begin (), result.m_Buffer .end (), L' /' , L' \\ ' );
570586 result.m_Rerouted = true ;
571587 result.m_NewReroute = true ;
@@ -575,11 +591,6 @@ class RerouteW
575591 }
576592 else if (inPath)
577593 result.m_Buffer = inPath;
578- std::wstring::iterator it = result.m_Buffer .end () - 1 ;
579- wchar_t inIt = inPath[wcslen (inPath) - 1 ];
580- std::wstring::iterator outIt = result.m_Buffer .end () - 1 ;
581- if ((*outIt == L' \\ ' || *outIt == L' /' ) && !(inIt == L' \\ ' || inIt == L' /' ))
582- result.m_Buffer .erase (outIt);
583594
584595 if (inPath)
585596 result.m_FileName = result.m_Buffer .c_str ();
@@ -859,15 +870,14 @@ HANDLE WINAPI usvfs::hook_CreateFileA(
859870namespace usvfs {
860871 class CreateRerouter {
861872 public:
862- bool rereouteCreate (const usvfs::HookContext::ConstPtr &context, const usvfs::HookCallContext &callContext,
873+ bool rerouteCreate (const usvfs::HookContext::ConstPtr &context, const usvfs::HookCallContext &callContext,
863874 LPCWSTR lpFileName, DWORD& dwCreationDisposition, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
864875 {
865876 enum class Open { existing, create, empty };
866877 Open open = Open::existing;
867878
868879 // Notice since we are calling our patched GetFileAttributesW here this will also check virtualized paths
869880 DWORD virtAttr = GetFileAttributesW (lpFileName);
870- m_directlyAvailable = virtAttr == INVALID_FILE_ATTRIBUTES && (GetLastError () == ERROR_FILE_NOT_FOUND || GetLastError () == ERROR_PATH_NOT_FOUND);
871881 bool isFile = virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 ;
872882 m_isDir = virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY);
873883
@@ -911,11 +921,11 @@ namespace usvfs {
911921 m_reroute = RerouteW::create (context, callContext, lpFileName);
912922
913923 if (m_reroute.wasRerouted () && open == Open::create && pathIsDirectory (m_reroute.fileName ()))
914- m_reroute = RerouteW::createNew (context, callContext, lpFileName, m_directlyAvailable , lpSecurityAttributes);
924+ m_reroute = RerouteW::createNew (context, callContext, lpFileName, true , lpSecurityAttributes);
915925
916926 if (!m_isDir && !isFile && !m_reroute.wasRerouted () && (open == Open::create || open == Open::empty))
917927 {
918- m_reroute = RerouteW::createNew (context, callContext, lpFileName, m_directlyAvailable , lpSecurityAttributes);
928+ m_reroute = RerouteW::createNew (context, callContext, lpFileName, true , lpSecurityAttributes);
919929
920930 bool newFile = !m_reroute.wasRerouted () && pathDirectlyAvailable (m_reroute.fileName ());
921931 if (newFile && open == Open::empty)
@@ -930,7 +940,7 @@ namespace usvfs {
930940 bool rerouteNew (const usvfs::HookContext::ConstPtr &context, usvfs::HookCallContext &callContext, LPCWSTR lpFileName, bool replaceExisting, const char * hookName)
931941 {
932942 DWORD disposition = replaceExisting ? CREATE_ALWAYS : CREATE_NEW;
933- if (!rereouteCreate (context, callContext, lpFileName, disposition, GENERIC_WRITE, nullptr )) {
943+ if (!rerouteCreate (context, callContext, lpFileName, disposition, GENERIC_WRITE, nullptr )) {
934944 spdlog::get (" hooks" )->info (
935945 " {} guaranteed failure, skipping original call: {}, replaceExisting={}, error={}" ,
936946 hookName, ush::string_cast<std::string>(lpFileName, ush::CodePage::UTF8), replaceExisting ? " true" : " false" , error ());
@@ -996,7 +1006,7 @@ HANDLE WINAPI usvfs::hook_CreateFileW(
9961006
9971007 DWORD originalDisposition = dwCreationDisposition;
9981008 CreateRerouter rerouter;
999- if (rerouter.rereouteCreate (READ_CONTEXT (), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess, lpSecurityAttributes))
1009+ if (rerouter.rerouteCreate (READ_CONTEXT (), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess, lpSecurityAttributes))
10001010 {
10011011 PRE_REALCALL
10021012 res = ::CreateFileW (rerouter.fileName (), dwDesiredAccess, dwShareMode,
@@ -1062,7 +1072,7 @@ HANDLE WINAPI usvfs::hook_CreateFile2(LPCWSTR lpFileName, DWORD dwDesiredAccess,
10621072
10631073 DWORD originalDisposition = dwCreationDisposition;
10641074 CreateRerouter rerouter;
1065- if (rerouter.rereouteCreate (READ_CONTEXT (), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess,
1075+ if (rerouter.rerouteCreate (READ_CONTEXT (), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess,
10661076 pCreateExParams ? pCreateExParams->lpSecurityAttributes : nullptr ))
10671077 {
10681078 PRE_REALCALL
@@ -1290,11 +1300,11 @@ BOOL WINAPI usvfs::hook_DeleteFileW(LPCWSTR lpFileName)
12901300}
12911301
12921302BOOL rewriteChangedDrives (LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName,
1293- const RerouteW& readReroute, const usvfs::CreateRerouter& writeReroute, DWORD newFlags )
1303+ const RerouteW& readReroute, const usvfs::CreateRerouter& writeReroute)
12941304{
1295- return ((newFlags & MOVEFILE_COPY_ALLOWED) == 0 && ( readReroute.wasRerouted () || writeReroute.wasRerouted ())
1296- && pathesOnDifferentDrives (readReroute.fileName (), writeReroute.fileName ())
1297- && !pathesOnDifferentDrives (lpExistingFileName, lpNewFileName));
1305+ return ((readReroute.wasRerouted () || writeReroute.wasRerouted ())
1306+ && pathsOnDifferentDrives (readReroute.fileName (), writeReroute.fileName ())
1307+ && !pathsOnDifferentDrives (lpExistingFileName, lpNewFileName));
12981308}
12991309
13001310BOOL WINAPI usvfs::hook_MoveFileA (LPCSTR lpExistingFileName,
@@ -1350,13 +1360,13 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName,
13501360
13511361 if (callOriginal)
13521362 {
1353- bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags );
1363+ bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute);
13541364 if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;
13551365
13561366 bool isDirectory = pathIsDirectory (readReroute.fileName ());
13571367
13581368 PRE_REALCALL
1359- if (isDirectory && movedDrives && newFlags ) {
1369+ if (isDirectory && movedDrives) {
13601370 SHFILEOPSTRUCTW sf = { 0 };
13611371 sf.wFunc = FO_MOVE;
13621372 sf.hwnd = 0 ;
@@ -1390,12 +1400,13 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName,
13901400 writeReroute.updateResult (callContext, res);
13911401
13921402 if (res) {
1393- // readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Leaving a ghost fixes some problems with apps expecting the file to be gone
1403+ readReroute.removeMapping (READ_CONTEXT (), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay
13941404
1395- if (writeReroute.newReroute () && isDirectory) {
1396- RerouteW::addDirectoryMapping (WRITE_CONTEXT (), fs::path (lpNewFileName), fs::path (writeReroute.fileName ()));
1397- } else {
1398- writeReroute.insertMapping (WRITE_CONTEXT ());
1405+ if (writeReroute.newReroute ()) {
1406+ if (isDirectory)
1407+ RerouteW::addDirectoryMapping (WRITE_CONTEXT (), fs::path (lpNewFileName), fs::path (writeReroute.fileName ()));
1408+ else
1409+ writeReroute.insertMapping (WRITE_CONTEXT ());
13991410 }
14001411 }
14011412
@@ -1468,13 +1479,12 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName,
14681479
14691480 if (callOriginal)
14701481 {
1471- bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags);
1472- if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;
1482+ bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute);
14731483
14741484 bool isDirectory = pathIsDirectory (readReroute.fileName ());
14751485
14761486 PRE_REALCALL
1477- if (isDirectory && movedDrives && newFlags & MOVEFILE_COPY_ALLOWED ) {
1487+ if (isDirectory && movedDrives) {
14781488 SHFILEOPSTRUCTW sf = { 0 };
14791489 sf.wFunc = FO_MOVE;
14801490 sf.hwnd = 0 ;
@@ -1506,12 +1516,13 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName,
15061516 writeReroute.updateResult (callContext, res);
15071517
15081518 if (res) {
1509- // readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Leaving a ghost fixes some problems with apps expecting the file to be gone
1519+ readReroute.removeMapping (READ_CONTEXT (), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay
15101520
1511- if (writeReroute.newReroute () && isDirectory) {
1512- RerouteW::addDirectoryMapping (WRITE_CONTEXT (), fs::path (lpNewFileName), fs::path (writeReroute.fileName ()));
1513- } else {
1514- writeReroute.insertMapping (WRITE_CONTEXT ());
1521+ if (writeReroute.newReroute ()) {
1522+ if (isDirectory)
1523+ RerouteW::addDirectoryMapping (WRITE_CONTEXT (), fs::path (lpNewFileName), fs::path (writeReroute.fileName ()));
1524+ else
1525+ writeReroute.insertMapping (WRITE_CONTEXT ());
15151526 }
15161527 }
15171528
@@ -1583,13 +1594,13 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST
15831594
15841595 if (callOriginal)
15851596 {
1586- bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags );
1597+ bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute);
15871598 if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;
15881599
15891600 bool isDirectory = pathIsDirectory (readReroute.fileName ());
15901601
15911602 PRE_REALCALL
1592- if (isDirectory && movedDrives && newFlags & MOVEFILE_COPY_ALLOWED ) {
1603+ if (isDirectory && movedDrives) {
15931604 SHFILEOPSTRUCTW sf = { 0 };
15941605 sf.wFunc = FO_MOVE;
15951606 sf.hwnd = 0 ;
@@ -1621,12 +1632,13 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST
16211632 writeReroute.updateResult (callContext, res);
16221633
16231634 if (res) {
1624- // readReroute.removeMapping(READ_CONTEXT(), isDirectory); // Leaving a ghost fixes some problems with apps expecting the file to be gone
1635+ readReroute.removeMapping (READ_CONTEXT (), isDirectory); // Updating the rerouteCreate to check deleted file entries should make this okay
16251636
1626- if (writeReroute.newReroute () && isDirectory) {
1627- RerouteW::addDirectoryMapping (WRITE_CONTEXT (), fs::path (lpNewFileName), fs::path (writeReroute.fileName ()));
1628- } else {
1629- writeReroute.insertMapping (WRITE_CONTEXT ());
1637+ if (writeReroute.newReroute ()) {
1638+ if (isDirectory)
1639+ RerouteW::addDirectoryMapping (WRITE_CONTEXT (), fs::path (lpNewFileName), fs::path (writeReroute.fileName ()));
1640+ else
1641+ writeReroute.insertMapping (WRITE_CONTEXT ());
16301642 }
16311643 }
16321644
@@ -1967,27 +1979,34 @@ DWORD WINAPI usvfs::hook_GetModuleFileNameW(HMODULE hModule,
19671979 res = ::GetModuleFileNameW (hModule, lpFilename, nSize);
19681980 POST_REALCALL
19691981 if ((res != 0 ) && callContext.active ()) {
1982+ std::vector<WCHAR> buf;
1983+ // If GetModuleFileNameW failed because the buffer is not large enough this complicates matters
1984+ // because we are dealing with incomplete information (consider for example the case that we
1985+ // have a long real path which will be routed to a short virtual so the call should actually
1986+ // succeed in such a case).
1987+ // To solve this we simply use our own buffer to find the complete module path:
1988+ DWORD full_res = res;
1989+ size_t buf_size = nSize;
1990+ while (full_res == buf_size) {
1991+ buf_size = std::max (static_cast <size_t >(MAX_PATH), buf_size * 2 );
1992+ buf.resize (buf_size);
1993+ full_res = ::GetModuleFileNameW (hModule, buf.data (), buf_size);
1994+ }
1995+
19701996 RerouteW reroute
1971- = RerouteW::create (READ_CONTEXT (), callContext, lpFilename, true );
1997+ = RerouteW::create (READ_CONTEXT (), callContext, buf. empty () ? lpFilename : buf. data () , true );
19721998 if (reroute.wasRerouted ()) {
1973- DWORD reroutedSize = static_cast <DWORD>(reroute.buffer (). size ( ));
1999+ DWORD reroutedSize = static_cast <DWORD>(wcslen ( reroute.fileName () ));
19742000 if (reroutedSize >= nSize) {
1975- callContext.updateLastError (ERROR_INSUFFICIENT_BUFFER);
19762001 reroutedSize = nSize - 1 ;
2002+ callContext.updateLastError (ERROR_INSUFFICIENT_BUFFER);
2003+ res = nSize;
19772004 }
1978- // res can't be bigger than nSize-1 at this point
1979- if (reroutedSize > 0 ) {
1980- if (reroutedSize < res) {
1981- // zero out the string windows has previously written to
1982- memset (lpFilename, ' \0 ' , std::min (res, nSize) * sizeof (wchar_t ));
1983- }
1984- // this truncates the string if the buffer is too small
1985- ush::wcsncpy_sz (lpFilename, reroute.fileName (), reroutedSize + 1 );
1986- }
1987- res = reroutedSize;
1988- }
2005+ else
2006+ res = reroutedSize;
2007+ memcpy (lpFilename, reroute.fileName (), reroutedSize * sizeof (lpFilename[0 ]));
2008+ lpFilename[reroutedSize] = 0 ;
19892009
1990- if (reroute.wasRerouted ()) {
19912010 LOG_CALL ()
19922011 .PARAM (hModule)
19932012 .addParam (" lpFilename" , usvfs::log::Wrap<LPCWSTR>(
0 commit comments