22
22
#include < boost/algorithm/string/predicate.hpp>
23
23
namespace fs = boost::filesystem;
24
24
#else
25
- namespace fs = std::tr2:: sys;
25
+ namespace fs = std::sys;
26
26
#include <filesystem>
27
27
#endif
28
28
@@ -194,7 +194,7 @@ static inline WCHAR pathNameDriveLetter(LPCWSTR path)
194
194
}
195
195
196
196
// 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)
198
198
{
199
199
WCHAR drive1 = pathNameDriveLetter (path1);
200
200
WCHAR drive2 = pathNameDriveLetter (path2);
@@ -485,29 +485,39 @@ class RerouteW
485
485
const auto & lookupPath = canonizePath (absolutePath (inPath));
486
486
result.m_RealPath = lookupPath.wstring ();
487
487
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);
491
498
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 ()))
500
501
{
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 ;
502
511
}
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 ];
504
517
std::wstring::iterator outIt = result.m_Buffer .end () - 1 ;
505
518
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);
509
520
std::replace (result.m_Buffer .begin (), result.m_Buffer .end (), L' /' , L' \\ ' );
510
- result.m_Rerouted = true ;
511
521
}
512
522
else
513
523
result.m_Buffer = inPath;
@@ -556,16 +566,22 @@ class RerouteW
556
566
557
567
if (found)
558
568
{
559
- if (createPath)
569
+ if (createPath) {
560
570
try {
561
571
usvfs::FunctionGroupLock lock (usvfs::MutExHookGroup::ALL_GROUPS);
562
572
result.m_PathCreated =
563
573
createFakePath (fs::path (result.m_Buffer ).parent_path (), securityAttributes);
564
- } catch (const std::exception &e) {
574
+ }
575
+ catch (const std::exception &e) {
565
576
spdlog::get (" hooks" )->error (" failed to create {}: {}" ,
566
577
ush::string_cast<std::string>(result.m_Buffer ), e.what ());
567
578
}
579
+ }
568
580
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);
569
585
std::replace (result.m_Buffer .begin (), result.m_Buffer .end (), L' /' , L' \\ ' );
570
586
result.m_Rerouted = true ;
571
587
result.m_NewReroute = true ;
@@ -575,11 +591,6 @@ class RerouteW
575
591
}
576
592
else if (inPath)
577
593
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);
583
594
584
595
if (inPath)
585
596
result.m_FileName = result.m_Buffer .c_str ();
@@ -859,15 +870,14 @@ HANDLE WINAPI usvfs::hook_CreateFileA(
859
870
namespace usvfs {
860
871
class CreateRerouter {
861
872
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,
863
874
LPCWSTR lpFileName, DWORD& dwCreationDisposition, DWORD dwDesiredAccess, LPSECURITY_ATTRIBUTES lpSecurityAttributes)
864
875
{
865
876
enum class Open { existing, create, empty };
866
877
Open open = Open::existing;
867
878
868
879
// Notice since we are calling our patched GetFileAttributesW here this will also check virtualized paths
869
880
DWORD virtAttr = GetFileAttributesW (lpFileName);
870
- m_directlyAvailable = virtAttr == INVALID_FILE_ATTRIBUTES && (GetLastError () == ERROR_FILE_NOT_FOUND || GetLastError () == ERROR_PATH_NOT_FOUND);
871
881
bool isFile = virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY) == 0 ;
872
882
m_isDir = virtAttr != INVALID_FILE_ATTRIBUTES && (virtAttr & FILE_ATTRIBUTE_DIRECTORY);
873
883
@@ -911,11 +921,11 @@ namespace usvfs {
911
921
m_reroute = RerouteW::create (context, callContext, lpFileName);
912
922
913
923
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);
915
925
916
926
if (!m_isDir && !isFile && !m_reroute.wasRerouted () && (open == Open::create || open == Open::empty))
917
927
{
918
- m_reroute = RerouteW::createNew (context, callContext, lpFileName, m_directlyAvailable , lpSecurityAttributes);
928
+ m_reroute = RerouteW::createNew (context, callContext, lpFileName, true , lpSecurityAttributes);
919
929
920
930
bool newFile = !m_reroute.wasRerouted () && pathDirectlyAvailable (m_reroute.fileName ());
921
931
if (newFile && open == Open::empty)
@@ -930,7 +940,7 @@ namespace usvfs {
930
940
bool rerouteNew (const usvfs::HookContext::ConstPtr &context, usvfs::HookCallContext &callContext, LPCWSTR lpFileName, bool replaceExisting, const char * hookName)
931
941
{
932
942
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 )) {
934
944
spdlog::get (" hooks" )->info (
935
945
" {} guaranteed failure, skipping original call: {}, replaceExisting={}, error={}" ,
936
946
hookName, ush::string_cast<std::string>(lpFileName, ush::CodePage::UTF8), replaceExisting ? " true" : " false" , error ());
@@ -996,7 +1006,7 @@ HANDLE WINAPI usvfs::hook_CreateFileW(
996
1006
997
1007
DWORD originalDisposition = dwCreationDisposition;
998
1008
CreateRerouter rerouter;
999
- if (rerouter.rereouteCreate (READ_CONTEXT (), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess, lpSecurityAttributes))
1009
+ if (rerouter.rerouteCreate (READ_CONTEXT (), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess, lpSecurityAttributes))
1000
1010
{
1001
1011
PRE_REALCALL
1002
1012
res = ::CreateFileW (rerouter.fileName (), dwDesiredAccess, dwShareMode,
@@ -1062,7 +1072,7 @@ HANDLE WINAPI usvfs::hook_CreateFile2(LPCWSTR lpFileName, DWORD dwDesiredAccess,
1062
1072
1063
1073
DWORD originalDisposition = dwCreationDisposition;
1064
1074
CreateRerouter rerouter;
1065
- if (rerouter.rereouteCreate (READ_CONTEXT (), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess,
1075
+ if (rerouter.rerouteCreate (READ_CONTEXT (), callContext, lpFileName, dwCreationDisposition, dwDesiredAccess,
1066
1076
pCreateExParams ? pCreateExParams->lpSecurityAttributes : nullptr ))
1067
1077
{
1068
1078
PRE_REALCALL
@@ -1290,11 +1300,11 @@ BOOL WINAPI usvfs::hook_DeleteFileW(LPCWSTR lpFileName)
1290
1300
}
1291
1301
1292
1302
BOOL rewriteChangedDrives (LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName,
1293
- const RerouteW& readReroute, const usvfs::CreateRerouter& writeReroute, DWORD newFlags )
1303
+ const RerouteW& readReroute, const usvfs::CreateRerouter& writeReroute)
1294
1304
{
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));
1298
1308
}
1299
1309
1300
1310
BOOL WINAPI usvfs::hook_MoveFileA (LPCSTR lpExistingFileName,
@@ -1350,13 +1360,13 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName,
1350
1360
1351
1361
if (callOriginal)
1352
1362
{
1353
- bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags );
1363
+ bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute);
1354
1364
if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;
1355
1365
1356
1366
bool isDirectory = pathIsDirectory (readReroute.fileName ());
1357
1367
1358
1368
PRE_REALCALL
1359
- if (isDirectory && movedDrives && newFlags ) {
1369
+ if (isDirectory && movedDrives) {
1360
1370
SHFILEOPSTRUCTW sf = { 0 };
1361
1371
sf.wFunc = FO_MOVE;
1362
1372
sf.hwnd = 0 ;
@@ -1390,12 +1400,13 @@ BOOL WINAPI usvfs::hook_MoveFileW(LPCWSTR lpExistingFileName,
1390
1400
writeReroute.updateResult (callContext, res);
1391
1401
1392
1402
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
1394
1404
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 ());
1399
1410
}
1400
1411
}
1401
1412
@@ -1468,13 +1479,12 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName,
1468
1479
1469
1480
if (callOriginal)
1470
1481
{
1471
- bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags);
1472
- if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;
1482
+ bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute);
1473
1483
1474
1484
bool isDirectory = pathIsDirectory (readReroute.fileName ());
1475
1485
1476
1486
PRE_REALCALL
1477
- if (isDirectory && movedDrives && newFlags & MOVEFILE_COPY_ALLOWED ) {
1487
+ if (isDirectory && movedDrives) {
1478
1488
SHFILEOPSTRUCTW sf = { 0 };
1479
1489
sf.wFunc = FO_MOVE;
1480
1490
sf.hwnd = 0 ;
@@ -1506,12 +1516,13 @@ BOOL WINAPI usvfs::hook_MoveFileExW(LPCWSTR lpExistingFileName,
1506
1516
writeReroute.updateResult (callContext, res);
1507
1517
1508
1518
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
1510
1520
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 ());
1515
1526
}
1516
1527
}
1517
1528
@@ -1583,13 +1594,13 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST
1583
1594
1584
1595
if (callOriginal)
1585
1596
{
1586
- bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute, newFlags );
1597
+ bool movedDrives = rewriteChangedDrives (lpExistingFileName, lpNewFileName, readReroute, writeReroute);
1587
1598
if (movedDrives) newFlags |= MOVEFILE_COPY_ALLOWED;
1588
1599
1589
1600
bool isDirectory = pathIsDirectory (readReroute.fileName ());
1590
1601
1591
1602
PRE_REALCALL
1592
- if (isDirectory && movedDrives && newFlags & MOVEFILE_COPY_ALLOWED ) {
1603
+ if (isDirectory && movedDrives) {
1593
1604
SHFILEOPSTRUCTW sf = { 0 };
1594
1605
sf.wFunc = FO_MOVE;
1595
1606
sf.hwnd = 0 ;
@@ -1621,12 +1632,13 @@ BOOL WINAPI usvfs::hook_MoveFileWithProgressW(LPCWSTR lpExistingFileName, LPCWST
1621
1632
writeReroute.updateResult (callContext, res);
1622
1633
1623
1634
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
1625
1636
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 ());
1630
1642
}
1631
1643
}
1632
1644
@@ -1967,27 +1979,34 @@ DWORD WINAPI usvfs::hook_GetModuleFileNameW(HMODULE hModule,
1967
1979
res = ::GetModuleFileNameW (hModule, lpFilename, nSize);
1968
1980
POST_REALCALL
1969
1981
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
+
1970
1996
RerouteW reroute
1971
- = RerouteW::create (READ_CONTEXT (), callContext, lpFilename, true );
1997
+ = RerouteW::create (READ_CONTEXT (), callContext, buf. empty () ? lpFilename : buf. data () , true );
1972
1998
if (reroute.wasRerouted ()) {
1973
- DWORD reroutedSize = static_cast <DWORD>(reroute.buffer (). size ( ));
1999
+ DWORD reroutedSize = static_cast <DWORD>(wcslen ( reroute.fileName () ));
1974
2000
if (reroutedSize >= nSize) {
1975
- callContext.updateLastError (ERROR_INSUFFICIENT_BUFFER);
1976
2001
reroutedSize = nSize - 1 ;
2002
+ callContext.updateLastError (ERROR_INSUFFICIENT_BUFFER);
2003
+ res = nSize;
1977
2004
}
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 ;
1989
2009
1990
- if (reroute.wasRerouted ()) {
1991
2010
LOG_CALL ()
1992
2011
.PARAM (hModule)
1993
2012
.addParam (" lpFilename" , usvfs::log::Wrap<LPCWSTR>(
0 commit comments