1
// TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2023 - TortoiseGit
4 // Copyright (C) 2003-2017 - TortoiseSVN
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "ShellCache.h"
22 #include "GitAdminDir.h"
24 ShellCache::ShellCache()
26 cachetype
= CRegStdDWORD(L
"Software\\TortoiseGit\\CacheType", GetSystemMetrics(SM_REMOTESESSION
) ? dll
: exe
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
27 onlynonelevated
= CRegStdDWORD(L
"Software\\TortoiseGit\\ShowOverlaysOnlyNonElevated", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
28 showrecursive
= CRegStdDWORD(L
"Software\\TortoiseGit\\RecursiveOverlay", TRUE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
29 folderoverlay
= CRegStdDWORD(L
"Software\\TortoiseGit\\FolderOverlay", TRUE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
30 driveremote
= CRegStdDWORD(L
"Software\\TortoiseGit\\DriveMaskRemote", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
31 drivefixed
= CRegStdDWORD(L
"Software\\TortoiseGit\\DriveMaskFixed", TRUE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
32 drivecdrom
= CRegStdDWORD(L
"Software\\TortoiseGit\\DriveMaskCDROM", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
33 driveremove
= CRegStdDWORD(L
"Software\\TortoiseGit\\DriveMaskRemovable", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
34 drivefloppy
= CRegStdDWORD(L
"Software\\TortoiseGit\\DriveMaskFloppy", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
35 driveram
= CRegStdDWORD(L
"Software\\TortoiseGit\\DriveMaskRAM", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
36 driveunknown
= CRegStdDWORD(L
"Software\\TortoiseGit\\DriveMaskUnknown", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
37 shellmenuaccelerators
= CRegStdDWORD(L
"Software\\TortoiseGit\\ShellMenuAccelerators", TRUE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
38 simplecontext
= CRegStdDWORD(L
"Software\\TortoiseGit\\SimpleContext", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
39 unversionedasmodified
= CRegStdDWORD(L
"Software\\TortoiseGit\\UnversionedAsModified", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
40 recursesubmodules
= CRegStdDWORD(L
"Software\\TortoiseGit\\TGitCacheRecurseSubmodules", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
41 hidemenusforunversioneditems
= CRegStdDWORD(L
"Software\\TortoiseGit\\HideMenusForUnversionedItems", FALSE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
42 showunversionedoverlay
= CRegStdDWORD(L
"Software\\TortoiseGit\\ShowUnversionedOverlay", TRUE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
43 showignoredoverlay
= CRegStdDWORD(L
"Software\\TortoiseGit\\ShowIgnoredOverlay", TRUE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
44 excludedasnormal
= CRegStdDWORD(L
"Software\\TortoiseGit\\ShowExcludedAsNormal", TRUE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
46 menuLayout11
= CRegStdQWORD(L
"Software\\TortoiseGit\\ContextMenu11Entries", DEFAULTWIN11MENUTOPENTRIES
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
48 unsigned __int64 entries
= (DEFAULTMENUTOPENTRIES
);
49 menulayoutlow
= CRegStdDWORD(L
"Software\\TortoiseGit\\ContextMenuEntries", entries
& 0xFFFFFFFF, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
50 menulayouthigh
= CRegStdDWORD(L
"Software\\TortoiseGit\\ContextMenuEntrieshigh", entries
>> 32, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
52 unsigned __int64 ext
= (DEFAULTMENUEXTENTRIES
);
53 menuextlow
= CRegStdDWORD(L
"Software\\TortoiseGit\\ContextMenuExtEntriesLow", ext
& 0xFFFFFFFF, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
54 menuexthigh
= CRegStdDWORD(L
"Software\\TortoiseGit\\ContextMenuExtEntriesHigh", ext
>> 32, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
56 menumasklow_lm
= CRegStdDWORD(L
"Software\\TortoiseGit\\ContextMenuEntriesMaskLow", 0, FALSE
, HKEY_LOCAL_MACHINE
, KEY_WOW64_64KEY
);
57 menumaskhigh_lm
= CRegStdDWORD(L
"Software\\TortoiseGit\\ContextMenuEntriesMaskHigh", 0, FALSE
, HKEY_LOCAL_MACHINE
, KEY_WOW64_64KEY
);
58 menumasklow_cu
= CRegStdDWORD(L
"Software\\TortoiseGit\\ContextMenuEntriesMaskLow", 0, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
59 menumaskhigh_cu
= CRegStdDWORD(L
"Software\\TortoiseGit\\ContextMenuEntriesMaskHigh", 0, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
60 langid
= CRegStdDWORD(L
"Software\\TortoiseGit\\LanguageID", 1033, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
61 blockstatus
= CRegStdDWORD(L
"Software\\TortoiseGit\\BlockStatus", 0, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
62 std::fill_n(drivetypecache
, 27, UINT(-1));
63 if (DWORD(drivefloppy
) == 0)
65 // A: and B: are floppy disks
66 drivetypecache
[0] = DRIVE_REMOVABLE
;
67 drivetypecache
[1] = DRIVE_REMOVABLE
;
69 nocontextpaths
= CRegStdString(L
"Software\\TortoiseGit\\NoContextPaths", L
"", false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
70 // Use RegNotifyChangeKeyValue() to get a notification event whenever a registry value
71 // below HKCU\Software\TortoiseGit is changed. If a value has changed, re-read all
72 // the registry variables to ensure we use the latest ones
73 RegOpenKeyEx(HKEY_CURRENT_USER
, L
"Software\\TortoiseGit", 0, KEY_NOTIFY
| KEY_WOW64_64KEY
, &m_hNotifyRegKey
);
74 m_registryChangeEvent
= CreateEvent(nullptr, true, false, nullptr);
75 if (RegNotifyChangeKeyValue(m_hNotifyRegKey
, false, REG_NOTIFY_CHANGE_LAST_SET
, m_registryChangeEvent
, TRUE
) != ERROR_SUCCESS
)
77 if (m_registryChangeEvent
)
78 CloseHandle(m_registryChangeEvent
);
79 m_registryChangeEvent
= nullptr;
80 RegCloseKey(m_hNotifyRegKey
);
81 m_hNotifyRegKey
= nullptr;
84 // find out if we're elevated
85 HANDLE hToken
= nullptr;
86 if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
88 TOKEN_ELEVATION te
= { 0 };
89 DWORD dwReturnLength
= 0;
90 if (::GetTokenInformation(hToken
, TokenElevation
, &te
, sizeof(te
), &dwReturnLength
))
91 isElevated
= (te
.TokenIsElevated
!= 0);
92 ::CloseHandle(hToken
);
96 ShellCache::~ShellCache()
98 if (m_registryChangeEvent
)
99 CloseHandle(m_registryChangeEvent
);
100 m_registryChangeEvent
= nullptr;
102 RegCloseKey(m_hNotifyRegKey
);
103 m_hNotifyRegKey
= nullptr;
106 bool ShellCache::RefreshIfNeeded()
108 // don't wait for the registry change event but only test if such an event
109 // has occurred since the last time we got here.
110 // if the event has occurred, re-read all registry variables and of course
111 // re-set the notification event to get further notifications of registry changes.
112 const bool signalled
= WaitForSingleObjectEx(m_registryChangeEvent
, 0, true) != WAIT_TIMEOUT
;
116 if (RegNotifyChangeKeyValue(m_hNotifyRegKey
, false, REG_NOTIFY_CHANGE_LAST_SET
, m_registryChangeEvent
, TRUE
) != ERROR_SUCCESS
)
118 CloseHandle(m_registryChangeEvent
);
119 m_registryChangeEvent
= nullptr;
120 RegCloseKey(m_hNotifyRegKey
);
121 m_hNotifyRegKey
= nullptr;
125 onlynonelevated
.read();
126 showrecursive
.read();
127 folderoverlay
.read();
135 simplecontext
.read();
136 shellmenuaccelerators
.read();
137 unversionedasmodified
.read();
138 recursesubmodules
.read();
139 showunversionedoverlay
.read();
140 showignoredoverlay
.read();
141 excludedasnormal
.read();
142 hidemenusforunversioneditems
.read();
144 menulayoutlow
.read();
145 menulayouthigh
.read();
148 menumasklow_lm
.read();
149 menumaskhigh_lm
.read();
150 menumasklow_cu
.read();
151 menumaskhigh_cu
.read();
154 nocontextpaths
.read();
156 if (DWORD(drivefloppy
) == 0)
158 // A: and B: are floppy disks
159 drivetypecache
[0] = DRIVE_REMOVABLE
;
160 drivetypecache
[1] = DRIVE_REMOVABLE
;
164 // reset floppy drive cache
165 drivetypecache
[0] = UINT(-1);
166 drivetypecache
[1] = UINT(-1);
169 Locker
lock(m_critSec
);
170 pathFilter
.Refresh();
175 ShellCache::CacheType
ShellCache::GetCacheType()
178 return CacheType(static_cast<DWORD
>(cachetype
));
181 DWORD
ShellCache::BlockStatus()
184 return (blockstatus
);
187 unsigned __int64
ShellCache::GetMenuLayout11()
193 unsigned __int64
ShellCache::GetMenuLayout()
197 temp
.HighPart
= menulayouthigh
;
198 temp
.LowPart
= menulayoutlow
;
199 return temp
.QuadPart
;
202 unsigned __int64
ShellCache::GetMenuExt()
206 temp
.HighPart
= menuexthigh
;
207 temp
.LowPart
= menuextlow
;
208 return temp
.QuadPart
;
211 unsigned __int64
ShellCache::GetMenuMask()
213 auto ticks
= GetTickCount64();
214 if ((ticks
- menumaskticker
) > ADMINDIRTIMEOUT
)
216 menumaskticker
= ticks
;
217 menumasklow_lm
.read();
218 menumaskhigh_lm
.read();
222 temp
.LowPart
= menumasklow_lm
| menumasklow_cu
;
223 temp
.HighPart
= menumaskhigh_lm
| menumaskhigh_cu
;
224 return temp
.QuadPart
;
227 bool ShellCache::IsProcessElevated()
232 BOOL
ShellCache::IsOnlyNonElevated()
235 return (onlynonelevated
);
238 BOOL
ShellCache::IsRecursive()
241 return (showrecursive
);
244 BOOL
ShellCache::IsFolderOverlay()
247 return (folderoverlay
);
250 BOOL
ShellCache::IsSimpleContext()
253 return (simplecontext
!= 0);
256 BOOL
ShellCache::HasShellMenuAccelerators()
259 return (shellmenuaccelerators
!= 0);
262 BOOL
ShellCache::IsUnversionedAsModified()
265 return (unversionedasmodified
);
268 BOOL
ShellCache::IsRecurseSubmodules()
271 return (recursesubmodules
);
274 BOOL
ShellCache::ShowUnversionedOverlay()
277 return (showunversionedoverlay
);
280 BOOL
ShellCache::ShowIgnoredOverlay()
283 return (showignoredoverlay
);
286 BOOL
ShellCache::ShowExcludedAsNormal()
289 return (excludedasnormal
);
292 BOOL
ShellCache::HideMenusForUnversionedItems()
295 return (hidemenusforunversioneditems
);
298 BOOL
ShellCache::IsRemote()
301 return (driveremote
);
304 BOOL
ShellCache::IsFixed()
310 BOOL
ShellCache::IsCDRom()
316 BOOL
ShellCache::IsRemovable()
319 return (driveremove
);
322 BOOL
ShellCache::IsRAM()
328 BOOL
ShellCache::IsUnknown()
331 return (driveunknown
);
334 BOOL
ShellCache::IsContextPathAllowed(LPCWSTR path
)
336 Locker
lock(m_critSec
);
337 ExcludeContextValid();
338 for (const auto& exPath
: excontextvector
)
342 if (exPath
[exPath
.size() - 1] == '*')
344 std::wstring str
= exPath
.substr(0, exPath
.size() - 1);
345 if (_wcsnicmp(str
.c_str(), path
, str
.size()) == 0)
348 else if (_wcsicmp(exPath
.c_str(), path
) == 0)
354 BOOL
ShellCache::IsPathAllowed(LPCWSTR path
)
357 Locker
lock(m_critSec
);
358 const Tristate allowed
= pathFilter
.IsPathAllowed(path
);
359 if (allowed
!= Tristate::Unknown
)
360 return allowed
== Tristate::True
? TRUE
: FALSE
;
363 const int drivenumber
= PathGetDriveNumber(path
);
364 if ((drivenumber
>= 0) && (drivenumber
<= 25))
366 drivetype
= drivetypecache
[drivenumber
];
367 if ((drivetype
== -1) || ((GetTickCount64() - drivetypeticker
) > DRIVETYPETIMEOUT
))
369 if ((DWORD(drivefloppy
) == 0) && ((drivenumber
== 0) || (drivenumber
== 1)))
370 drivetype
= DRIVE_REMOVABLE
;
371 else if (PathIsNetworkPath(path
))
372 drivetype
= DRIVE_REMOTE
;
375 wchar_t pathbuf
[MAX_PATH
+ 4] = { 0 }; // MAX_PATH ok here. PathStripToRoot works with partial paths too.
376 wcsncpy_s(pathbuf
, path
, _countof(pathbuf
) - 1);
377 PathStripToRoot(pathbuf
);
378 PathAddBackslash(pathbuf
);
379 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": GetDriveType for %s, Drive %d\n", pathbuf
, drivenumber
);
380 drivetype
= GetDriveType(pathbuf
);
382 drivetypecache
[drivenumber
] = drivetype
;
383 drivetypeticker
= GetTickCount64();
388 if (PathIsNetworkPath(path
))
389 drivetype
= DRIVE_REMOTE
;
392 wchar_t pathbuf
[MAX_PATH
+ 4] = { 0 }; // MAX_PATH ok here. PathStripToRoot works with partial paths too.
393 wcsncpy_s(pathbuf
, path
, _countof(pathbuf
) - 1);
394 PathStripToRoot(pathbuf
);
395 PathAddBackslash(pathbuf
);
396 if (wcsncmp(pathbuf
, drivetypepathcache
, MAX_PATH
- 1) == 0) // MAX_PATH ok.
397 drivetype
= drivetypecache
[26];
400 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
"GetDriveType for %s\n", pathbuf
);
401 drivetype
= GetDriveType(pathbuf
);
402 drivetypecache
[26] = drivetype
;
403 wcsncpy_s(drivetypepathcache
, pathbuf
, MAX_PATH
- 1); // MAX_PATH ok.
407 if ((drivetype
== DRIVE_REMOVABLE
) && (!IsRemovable()))
409 if ((drivetype
== DRIVE_FIXED
) && (!IsFixed()))
411 if (((drivetype
== DRIVE_REMOTE
) || (drivetype
== DRIVE_NO_ROOT_DIR
)) && (!IsRemote()))
413 if ((drivetype
== DRIVE_CDROM
) && (!IsCDRom()))
415 if ((drivetype
== DRIVE_RAMDISK
) && (!IsRAM()))
417 if ((drivetype
== DRIVE_UNKNOWN
) && (IsUnknown()))
423 DWORD
ShellCache::GetLangID()
429 BOOL
ShellCache::HasGITAdminDir(LPCWSTR path
, BOOL bIsDir
, CString
* ProjectTopDir
/*= nullptr*/)
431 std::wstring
folder(path
);
434 size_t pos
= folder
.rfind(L
'\\');
435 if (pos
!= std::wstring::npos
)
438 std::map
<std::wstring
, AdminDir_s
>::const_iterator iter
;
439 if ((iter
= admindircache
.find(folder
)) != admindircache
.cend())
441 Locker
lock(m_critSec
);
442 if ((GetTickCount64() - iter
->second
.timeout
) < ADMINDIRTIMEOUT
)
444 if (ProjectTopDir
&& iter
->second
.bHasAdminDir
)
445 *ProjectTopDir
= iter
->second
.sProjectRoot
.c_str();
446 return iter
->second
.bHasAdminDir
;
450 CString sProjectRoot
;
451 const BOOL hasAdminDir
= GitAdminDir::HasAdminDir(folder
.c_str(), true, &sProjectRoot
);
453 Locker
lock(m_critSec
);
454 AdminDir_s
& ad
= admindircache
[folder
];
455 ad
.bHasAdminDir
= hasAdminDir
;
456 ad
.timeout
= GetTickCount64();
459 ad
.sProjectRoot
.assign(sProjectRoot
);
461 *ProjectTopDir
= sProjectRoot
;
467 void ShellCache::ExcludeContextValid()
469 // Lock must be taken by caller, which is done by IsContextPathAllowed()
471 if (excludecontextstr
.compare(nocontextpaths
) == 0)
474 excludecontextstr
= nocontextpaths
;
475 excontextvector
.clear();
476 size_t pos
= 0, pos_ant
= 0;
477 pos
= excludecontextstr
.find(L
'\n', pos_ant
);
478 while (pos
!= std::wstring::npos
)
480 std::wstring token
= excludecontextstr
.substr(pos_ant
, pos
- pos_ant
);
482 excontextvector
.push_back(token
);
484 pos
= excludecontextstr
.find(L
'\n', pos_ant
);
486 if (!excludecontextstr
.empty())
488 std::wstring token
= excludecontextstr
.substr(pos_ant
, excludecontextstr
.size() - 1);
490 excontextvector
.push_back(token
);
494 // construct \ref data content
495 void ShellCache::CPathFilter::AddEntry(const std::wstring
& s
, bool include
)
497 static wchar_t pathbuf
[MAX_PATH
* 4] = { 0 };
501 wchar_t lastChar
= *s
.rbegin();
504 entry
.hasSubFolderEntries
= false;
505 entry
.recursive
= lastChar
!= L
'?';
506 entry
.included
= include
? Tristate::True
: Tristate::False
;
507 entry
.subPathIncluded
= include
== entry
.recursive
? Tristate::True
: Tristate::False
;
510 if ((lastChar
== L
'?') || (lastChar
== L
'*'))
511 entry
.path
.erase(s
.length() - 1);
512 if (!entry
.path
.empty() && (*entry
.path
.rbegin() == L
'\\'))
513 entry
.path
.erase(entry
.path
.length() - 1);
515 if (auto ret
= ExpandEnvironmentStrings(entry
.path
.c_str(), pathbuf
, _countof(pathbuf
)); ret
> 0 && ret
< _countof(pathbuf
))
516 entry
.path
= pathbuf
;
518 data
.push_back(entry
);
521 void ShellCache::CPathFilter::AddEntries(const std::wstring
& s
, bool include
)
523 size_t pos
= 0, pos_ant
= 0;
524 pos
= s
.find(L
'\n', pos_ant
);
525 while (pos
!= std::wstring::npos
)
527 AddEntry(s
.substr(pos_ant
, pos
- pos_ant
), include
);
529 pos
= s
.find(L
'\n', pos_ant
);
533 AddEntry(s
.substr(pos_ant
, s
.size() - 1), include
);
536 // for all paths, have at least one entry in data
537 void ShellCache::CPathFilter::PostProcessData()
542 std::sort(data
.begin(), data
.end());
544 // update subPathIncluded props and remove duplicate entries
545 auto begin
= data
.begin();
546 auto end
= data
.end();
548 for (auto source
= begin
; source
!= end
; ++source
)
550 if (_wcsicmp(source
->path
.c_str(), dest
->path
.c_str()) == 0)
552 // multiple entries for the same path -> merge them
554 // update subPathIncluded
555 // (all relevant parent info has already been normalized)
556 if (!source
->recursive
)
557 source
->subPathIncluded
= IsPathAllowed(source
->path
.c_str(), begin
, dest
);
559 // multiple specs for the same path
560 // -> merge them into the existing entry @ dest
561 if (!source
->recursive
&& dest
->recursive
)
563 // reset the marker for the this case
564 dest
->recursive
= false;
565 dest
->included
= source
->included
;
569 // include beats exclude
570 if (source
->included
== Tristate::True
)
571 dest
->included
= Tristate::True
;
572 if (source
->recursive
&& source
->subPathIncluded
== Tristate::True
)
573 dest
->subPathIncluded
= Tristate::True
;
578 // new path -> don't merge this entry
579 size_t destSize
= dest
->path
.size();
580 dest
->hasSubFolderEntries
= (source
->path
.size() > destSize
) && (source
->path
[destSize
] == L
'\\') && (_wcsnicmp(source
->path
.substr(0, destSize
).c_str(), dest
->path
.c_str(), destSize
) == 0);
584 // update subPathIncluded
585 // (all relevant parent info has already been normalized)
586 if (!dest
->recursive
)
587 dest
->subPathIncluded
= IsPathAllowed(source
->path
.c_str(), begin
, dest
);
591 // remove duplicate info
593 data
.erase(++dest
, end
);
596 // lookup. default result is "unknown".
597 // We must look for *every* parent path because of situations like:
598 // excluded: C:, C:\some\deep\path
600 // lookup for C:\some\deeper\path
601 Tristate
ShellCache::CPathFilter::IsPathAllowed(LPCWSTR path
, TData::const_iterator begin
, TData::const_iterator end
) const
603 Tristate result
= Tristate::Unknown
;
605 // handle special cases
609 size_t maxLength
= wcslen(path
);
613 // look for the most specific entry, start at the root
617 LPCWSTR backslash
= wcschr(path
+ pos
+ 1,L
'\\');
618 pos
= backslash
== nullptr ? maxLength
: backslash
- path
;
620 std::pair
<LPCWSTR
, size_t> toFind(path
, pos
);
621 TData::const_iterator iter
= std::lower_bound(begin
, end
, toFind
);
623 // found a relevant entry?
624 if ((iter
!= end
) && (iter
->path
.length() == pos
) && (_wcsnicmp(iter
->path
.c_str(), path
, pos
) == 0))
627 if (pos
== maxLength
)
628 return iter
->included
;
631 result
= iter
->subPathIncluded
;
634 if (iter
->hasSubFolderEntries
)
641 // set a (potentially) closer lower limit
646 // set a (potentially) closer upper limit
647 end
= std::upper_bound(begin
, end
, toFind
);
648 } while ((pos
< maxLength
) && (begin
!= end
));
650 // nothing more specific found
656 ShellCache::CPathFilter::CPathFilter()
657 : excludelist(L
"Software\\TortoiseGit\\OverlayExcludeList", L
"", false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
)
658 , includelist(L
"Software\\TortoiseGit\\OverlayIncludeList", L
"", false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
)
663 // notify of (potential) registry settings
665 void ShellCache::CPathFilter::Refresh()
670 if (excludeliststr
.compare(excludelist
) == 0 && includeliststr
.compare(includelist
) == 0)
673 excludeliststr
= excludelist
;
674 includeliststr
= includelist
;
676 AddEntries(excludeliststr
, false);
677 AddEntries(includeliststr
, true);
683 Tristate
ShellCache::CPathFilter::IsPathAllowed(LPCWSTR path
) const
686 return Tristate::Unknown
;
687 // always ignore the recycle bin
688 PTSTR pFound
= StrStrI(path
, L
":\\RECYCLER");
691 if ((*(pFound
+ 10) == L
'\0') || (*(pFound
+ 10) == L
'\\'))
692 return Tristate::False
;
694 pFound
= StrStrI(path
, L
":\\$Recycle.Bin");
697 if ((*(pFound
+ 14) == '\0') || (*(pFound
+ 14) == L
'\\'))
698 return Tristate::False
;
700 return IsPathAllowed(path
, data
.begin(), data
.end());