1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2012-2017 - 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 getlocktop
= CRegStdDWORD(L
"Software\\TortoiseGit\\GetLockTop", TRUE
, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
45 excludedasnormal
= CRegStdDWORD(L
"Software\\TortoiseGit\\ShowExcludedAsNormal", TRUE
, 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
);
61 langid
= CRegStdDWORD(L
"Software\\TortoiseGit\\LanguageID", 1033, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
62 blockstatus
= CRegStdDWORD(L
"Software\\TortoiseGit\\BlockStatus", 0, false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
63 std::fill_n(drivetypecache
, 27, (UINT
)-1);
64 if (DWORD(drivefloppy
) == 0)
66 // A: and B: are floppy disks
67 drivetypecache
[0] = DRIVE_REMOVABLE
;
68 drivetypecache
[1] = DRIVE_REMOVABLE
;
70 drivetypepathcache
[0] = L
'\0';
71 nocontextpaths
= CRegStdString(L
"Software\\TortoiseGit\\NoContextPaths", L
"", false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
);
73 // Use RegNotifyChangeKeyValue() to get a notification event whenever a registry value
74 // below HKCU\Software\TortoiseGit is changed. If a value has changed, re-read all
75 // the registry variables to ensure we use the latest ones
76 RegOpenKeyEx(HKEY_CURRENT_USER
, L
"Software\\TortoiseGit", 0, KEY_NOTIFY
| KEY_WOW64_64KEY
, &m_hNotifyRegKey
);
77 m_registryChangeEvent
= CreateEvent(nullptr, true, false, nullptr);
78 if (RegNotifyChangeKeyValue(m_hNotifyRegKey
, false, REG_NOTIFY_CHANGE_LAST_SET
, m_registryChangeEvent
, TRUE
) != ERROR_SUCCESS
)
80 if (m_registryChangeEvent
)
81 CloseHandle(m_registryChangeEvent
);
82 m_registryChangeEvent
= nullptr;
83 RegCloseKey(m_hNotifyRegKey
);
84 m_hNotifyRegKey
= nullptr;
87 // find out if we're elevated
89 HANDLE hToken
= nullptr;
90 if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY
, &hToken
))
92 TOKEN_ELEVATION te
= { 0 };
93 DWORD dwReturnLength
= 0;
94 if (::GetTokenInformation(hToken
, TokenElevation
, &te
, sizeof(te
), &dwReturnLength
))
95 isElevated
= (te
.TokenIsElevated
!= 0);
96 ::CloseHandle(hToken
);
100 ShellCache::~ShellCache()
102 if (m_registryChangeEvent
)
103 CloseHandle(m_registryChangeEvent
);
104 m_registryChangeEvent
= nullptr;
106 RegCloseKey(m_hNotifyRegKey
);
107 m_hNotifyRegKey
= nullptr;
110 bool ShellCache::RefreshIfNeeded()
112 // don't wait for the registry change event but only test if such an event
113 // has occurred since the last time we got here.
114 // if the event has occurred, re-read all registry variables and of course
115 // re-set the notification event to get further notifications of registry changes.
116 bool signalled
= WaitForSingleObjectEx(m_registryChangeEvent
, 0, true) != WAIT_TIMEOUT
;
120 if (RegNotifyChangeKeyValue(m_hNotifyRegKey
, false, REG_NOTIFY_CHANGE_LAST_SET
, m_registryChangeEvent
, TRUE
) != ERROR_SUCCESS
)
122 CloseHandle(m_registryChangeEvent
);
123 m_registryChangeEvent
= nullptr;
124 RegCloseKey(m_hNotifyRegKey
);
125 m_hNotifyRegKey
= nullptr;
129 onlynonelevated
.read();
130 showrecursive
.read();
131 folderoverlay
.read();
139 simplecontext
.read();
140 shellmenuaccelerators
.read();
141 unversionedasmodified
.read();
142 recursesubmodules
.read();
143 showunversionedoverlay
.read();
144 showignoredoverlay
.read();
145 excludedasnormal
.read();
146 hidemenusforunversioneditems
.read();
147 menulayoutlow
.read();
148 menulayouthigh
.read();
152 menumasklow_lm
.read();
153 menumaskhigh_lm
.read();
154 menumasklow_cu
.read();
155 menumaskhigh_cu
.read();
156 nocontextpaths
.read();
158 Locker
lock(m_critSec
);
159 pathFilter
.Refresh();
164 ShellCache::CacheType
ShellCache::GetCacheType()
167 return CacheType(DWORD((cachetype
)));
170 DWORD
ShellCache::BlockStatus()
173 return (blockstatus
);
176 unsigned __int64
ShellCache::GetMenuLayout()
179 unsigned __int64 temp
= unsigned __int64(DWORD(menulayouthigh
)) << 32;
180 temp
|= unsigned __int64(DWORD(menulayoutlow
));
184 unsigned __int64
ShellCache::GetMenuExt()
187 unsigned __int64 temp
= unsigned __int64(DWORD(menuexthigh
)) << 32;
188 temp
|= unsigned __int64(DWORD(menuextlow
));
192 unsigned __int64
ShellCache::GetMenuMask()
194 auto ticks
= GetTickCount64();
195 if ((ticks
- menumaskticker
) > ADMINDIRTIMEOUT
)
197 menumaskticker
= ticks
;
198 menumasklow_lm
.read();
199 menumaskhigh_lm
.read();
201 DWORD low
= (DWORD
)menumasklow_lm
| (DWORD
)menumasklow_cu
;
202 DWORD high
= (DWORD
)menumaskhigh_lm
| (DWORD
)menumaskhigh_cu
;
203 unsigned __int64 temp
= unsigned __int64(high
) << 32;
204 temp
|= unsigned __int64(low
);
208 bool ShellCache::IsProcessElevated()
213 BOOL
ShellCache::IsOnlyNonElevated()
216 return (onlynonelevated
);
219 BOOL
ShellCache::IsRecursive()
222 return (showrecursive
);
225 BOOL
ShellCache::IsFolderOverlay()
228 return (folderoverlay
);
231 BOOL
ShellCache::IsSimpleContext()
234 return (simplecontext
!= 0);
237 BOOL
ShellCache::HasShellMenuAccelerators()
240 return (shellmenuaccelerators
!= 0);
243 BOOL
ShellCache::IsUnversionedAsModified()
246 return (unversionedasmodified
);
249 BOOL
ShellCache::IsRecurseSubmodules()
252 return (recursesubmodules
);
255 BOOL
ShellCache::ShowUnversionedOverlay()
258 return (showunversionedoverlay
);
261 BOOL
ShellCache::ShowIgnoredOverlay()
264 return (showignoredoverlay
);
267 BOOL
ShellCache::IsGetLockTop()
273 BOOL
ShellCache::ShowExcludedAsNormal()
276 return (excludedasnormal
);
279 BOOL
ShellCache::HideMenusForUnversionedItems()
282 return (hidemenusforunversioneditems
);
285 BOOL
ShellCache::IsRemote()
288 return (driveremote
);
291 BOOL
ShellCache::IsFixed()
297 BOOL
ShellCache::IsCDRom()
303 BOOL
ShellCache::IsRemovable()
306 return (driveremove
);
309 BOOL
ShellCache::IsRAM()
315 BOOL
ShellCache::IsUnknown()
318 return (driveunknown
);
321 BOOL
ShellCache::IsContextPathAllowed(LPCTSTR path
)
323 Locker
lock(m_critSec
);
324 ExcludeContextValid();
325 for (const auto& exPath
: excontextvector
)
329 if (exPath
[exPath
.size() - 1] == '*')
331 tstring str
= exPath
.substr(0, exPath
.size() - 1);
332 if (_wcsnicmp(str
.c_str(), path
, str
.size()) == 0)
335 else if (_wcsicmp(exPath
.c_str(), path
) == 0)
341 BOOL
ShellCache::IsPathAllowed(LPCTSTR path
)
344 Locker
lock(m_critSec
);
345 tristate_t allowed
= pathFilter
.IsPathAllowed(path
);
346 if (allowed
!= tristate_unknown
)
347 return allowed
== tristate_true
? TRUE
: FALSE
;
350 int drivenumber
= PathGetDriveNumber(path
);
351 if ((drivenumber
>= 0) && (drivenumber
< 25))
353 drivetype
= drivetypecache
[drivenumber
];
354 if ((drivetype
== -1) || ((GetTickCount64() - drivetypeticker
) > DRIVETYPETIMEOUT
))
356 if ((DWORD(drivefloppy
) == 0) && ((drivenumber
== 0) || (drivenumber
== 1)))
357 drivetypecache
[drivenumber
] = DRIVE_REMOVABLE
;
360 drivetypeticker
= GetTickCount64();
361 TCHAR pathbuf
[MAX_PATH
+ 4] = { 0 }; // MAX_PATH ok here. PathStripToRoot works with partial paths too.
362 wcsncpy_s(pathbuf
, path
, _countof(pathbuf
) - 1);
363 PathStripToRoot(pathbuf
);
364 PathAddBackslash(pathbuf
);
365 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
": GetDriveType for %s, Drive %d\n", pathbuf
, drivenumber
);
366 drivetype
= GetDriveType(pathbuf
);
367 drivetypecache
[drivenumber
] = drivetype
;
373 TCHAR pathbuf
[MAX_PATH
+ 4] = { 0 }; // MAX_PATH ok here. PathIsUNCServer works with partial paths too.
374 wcsncpy_s(pathbuf
, path
, _countof(pathbuf
) - 1);
375 if (PathIsUNCServer(pathbuf
))
376 drivetype
= DRIVE_REMOTE
;
379 PathStripToRoot(pathbuf
);
380 PathAddBackslash(pathbuf
);
381 if (wcsncmp(pathbuf
, drivetypepathcache
, MAX_PATH
- 1) == 0) // MAX_PATH ok.
382 drivetype
= drivetypecache
[26];
385 CTraceToOutputDebugString::Instance()(_T(__FUNCTION__
) L
"GetDriveType for %s\n", pathbuf
);
386 drivetype
= GetDriveType(pathbuf
);
387 drivetypecache
[26] = drivetype
;
388 wcsncpy_s(drivetypepathcache
, pathbuf
, MAX_PATH
- 1); // MAX_PATH ok.
392 if ((drivetype
== DRIVE_REMOVABLE
) && (!IsRemovable()))
394 if ((drivetype
== DRIVE_FIXED
) && (!IsFixed()))
396 if (((drivetype
== DRIVE_REMOTE
) || (drivetype
== DRIVE_NO_ROOT_DIR
)) && (!IsRemote()))
398 if ((drivetype
== DRIVE_CDROM
) && (!IsCDRom()))
400 if ((drivetype
== DRIVE_RAMDISK
) && (!IsRAM()))
402 if ((drivetype
== DRIVE_UNKNOWN
) && (IsUnknown()))
408 DWORD
ShellCache::GetLangID()
414 BOOL
ShellCache::HasGITAdminDir(LPCTSTR path
, BOOL bIsDir
, CString
* ProjectTopDir
/*= nullptr*/)
416 tstring
folder(path
);
419 size_t pos
= folder
.rfind(L
'\\');
420 if (pos
!= tstring::npos
)
423 std::map
<tstring
, AdminDir_s
>::const_iterator iter
;
424 if ((iter
= admindircache
.find(folder
)) != admindircache
.cend())
426 Locker
lock(m_critSec
);
427 if ((GetTickCount64() - iter
->second
.timeout
) < ADMINDIRTIMEOUT
)
429 if (ProjectTopDir
&& iter
->second
.bHasAdminDir
)
430 *ProjectTopDir
= iter
->second
.sProjectRoot
.c_str();
431 return iter
->second
.bHasAdminDir
;
435 CString sProjectRoot
;
436 BOOL hasAdminDir
= GitAdminDir::HasAdminDir(folder
.c_str(), true, &sProjectRoot
);
438 Locker
lock(m_critSec
);
439 AdminDir_s
& ad
= admindircache
[folder
];
440 ad
.bHasAdminDir
= hasAdminDir
;
441 ad
.timeout
= GetTickCount64();
444 ad
.sProjectRoot
.assign(sProjectRoot
);
446 *ProjectTopDir
= sProjectRoot
;
452 void ShellCache::ExcludeContextValid()
454 if (RefreshIfNeeded())
456 Locker
lock(m_critSec
);
457 if (excludecontextstr
.compare((tstring
)nocontextpaths
) == 0)
459 excludecontextstr
= (tstring
)nocontextpaths
;
460 excontextvector
.clear();
461 size_t pos
= 0, pos_ant
= 0;
462 pos
= excludecontextstr
.find(L
'\n', pos_ant
);
463 while (pos
!= tstring::npos
)
465 tstring token
= excludecontextstr
.substr(pos_ant
, pos
- pos_ant
);
466 excontextvector
.push_back(token
);
468 pos
= excludecontextstr
.find(L
'\n', pos_ant
);
470 if (!excludecontextstr
.empty())
471 excontextvector
.push_back(excludecontextstr
.substr(pos_ant
, excludecontextstr
.size() - 1));
472 excludecontextstr
= (tstring
)nocontextpaths
;
476 // construct \ref data content
477 void ShellCache::CPathFilter::AddEntry(const tstring
& s
, bool include
)
479 static wchar_t pathbuf
[MAX_PATH
* 4] = { 0 };
483 TCHAR lastChar
= *s
.rbegin();
486 entry
.hasSubFolderEntries
= false;
487 entry
.recursive
= lastChar
!= L
'?';
488 entry
.included
= include
? tristate_true
: tristate_false
;
489 entry
.subPathIncluded
= include
== entry
.recursive
? tristate_true
: tristate_false
;
492 if ((lastChar
== L
'?') || (lastChar
== L
'*'))
493 entry
.path
.erase(s
.length() - 1);
494 if (!entry
.path
.empty() && (*entry
.path
.rbegin() == L
'\\'))
495 entry
.path
.erase(entry
.path
.length() - 1);
497 auto ret
= ExpandEnvironmentStrings(entry
.path
.c_str(), pathbuf
, _countof(pathbuf
));
498 if ((ret
> 0) && (ret
< _countof(pathbuf
)))
499 entry
.path
= pathbuf
;
501 data
.push_back(entry
);
504 void ShellCache::CPathFilter::AddEntries(const tstring
& s
, bool include
)
506 size_t pos
= 0, pos_ant
= 0;
507 pos
= s
.find(L
'\n', pos_ant
);
508 while (pos
!= tstring::npos
)
510 AddEntry(s
.substr(pos_ant
, pos
- pos_ant
), include
);
512 pos
= s
.find(L
'\n', pos_ant
);
516 AddEntry(s
.substr(pos_ant
, s
.size() - 1), include
);
519 // for all paths, have at least one entry in data
520 void ShellCache::CPathFilter::PostProcessData()
525 std::sort(data
.begin(), data
.end());
527 // update subPathIncluded props and remove duplicate entries
528 auto begin
= data
.begin();
529 auto end
= data
.end();
531 for (auto source
= begin
; source
!= end
; ++source
)
533 if (_wcsicmp(source
->path
.c_str(), dest
->path
.c_str()) == 0)
535 // multiple entries for the same path -> merge them
537 // update subPathIncluded
538 // (all relevant parent info has already been normalized)
539 if (!source
->recursive
)
540 source
->subPathIncluded
= IsPathAllowed(source
->path
.c_str(), begin
, dest
);
542 // multiple specs for the same path
543 // -> merge them into the existing entry @ dest
544 if (!source
->recursive
&& dest
->recursive
)
546 // reset the marker for the this case
547 dest
->recursive
= false;
548 dest
->included
= source
->included
;
552 // include beats exclude
553 if (source
->included
== tristate_true
)
554 dest
->included
= tristate_true
;
555 if (source
->recursive
&& source
->subPathIncluded
== tristate_true
)
556 dest
->subPathIncluded
= tristate_true
;
561 // new path -> don't merge this entry
562 size_t destSize
= dest
->path
.size();
563 dest
->hasSubFolderEntries
= (source
->path
.size() > destSize
) && (source
->path
[destSize
] == L
'\\') && (_wcsnicmp(source
->path
.substr(0, destSize
).c_str(), dest
->path
.c_str(), destSize
) == 0);
567 // update subPathIncluded
568 // (all relevant parent info has already been normalized)
569 if (!dest
->recursive
)
570 dest
->subPathIncluded
= IsPathAllowed(source
->path
.c_str(), begin
, dest
);
574 // remove duplicate info
576 data
.erase(++dest
, end
);
579 // lookup. default result is "unknown".
580 // We must look for *every* parent path because of situations like:
581 // excluded: C:, C:\some\deep\path
583 // lookup for C:\some\deeper\path
584 tristate_t
ShellCache::CPathFilter::IsPathAllowed(LPCTSTR path
, TData::const_iterator begin
, TData::const_iterator end
) const
586 tristate_t result
= tristate_unknown
;
588 // handle special cases
592 size_t maxLength
= wcslen(path
);
596 // look for the most specific entry, start at the root
600 LPCTSTR backslash
= wcschr(path
+ pos
+ 1,L
'\\');
601 pos
= backslash
== nullptr ? maxLength
: backslash
- path
;
603 std::pair
<LPCTSTR
, size_t> toFind(path
, pos
);
604 TData::const_iterator iter
= std::lower_bound(begin
, end
, toFind
);
606 // found a relevant entry?
607 if ((iter
!= end
) && (iter
->path
.length() == pos
) && (_wcsnicmp(iter
->path
.c_str(), path
, pos
) == 0))
610 if (pos
== maxLength
)
611 return iter
->included
;
614 result
= iter
->subPathIncluded
;
617 if (iter
->hasSubFolderEntries
)
624 // set a (potentially) closer lower limit
629 // set a (potentially) closer upper limit
630 end
= std::upper_bound(begin
, end
, toFind
);
631 } while ((pos
< maxLength
) && (begin
!= end
));
633 // nothing more specific found
639 ShellCache::CPathFilter::CPathFilter()
640 : excludelist(L
"Software\\TortoiseGit\\OverlayExcludeList", L
"", false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
)
641 , includelist(L
"Software\\TortoiseGit\\OverlayIncludeList", L
"", false, HKEY_CURRENT_USER
, KEY_WOW64_64KEY
)
646 // notify of (potential) registry settings
648 void ShellCache::CPathFilter::Refresh()
653 if ((excludeliststr
.compare((tstring
)excludelist
) == 0) && (includeliststr
.compare((tstring
)includelist
) == 0))
656 excludeliststr
= (tstring
)excludelist
;
657 includeliststr
= (tstring
)includelist
;
659 AddEntries(excludeliststr
, false);
660 AddEntries(includeliststr
, true);
666 tristate_t
ShellCache::CPathFilter::IsPathAllowed(LPCTSTR path
) const
669 return tristate_unknown
;
670 // always ignore the recycle bin
671 PTSTR pFound
= StrStrI(path
, L
":\\RECYCLER");
674 if ((*(pFound
+ 10) == L
'\0') || (*(pFound
+ 10) == L
'\\'))
675 return tristate_false
;
677 pFound
= StrStrI(path
, L
":\\$Recycle.Bin");
680 if ((*(pFound
+ 14) == '\0') || (*(pFound
+ 14) == L
'\\'))
681 return tristate_false
;
683 return IsPathAllowed(path
, data
.begin(), data
.end());