bool CDirectoryWatcher::AddPath(const CTGitPath& path, bool bCloseInfoMap) { if (!CGitStatusCache::Instance().IsPathAllowed(path)) return false; if ((!blockedPath.IsEmpty())&&(blockedPath.IsAncestorOf(path))) { if (GetTickCount64() < blockTickCount) { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Path %s prevented from being watched\n"), path.GetWinPath()); return false; } } if (path.GetWinPathString().Find(L":\\RECYCLER\\") >= 0) return false; if (path.GetWinPathString().Find(L":\\$Recycle.Bin\\") >= 0) return false; AutoLocker lock(m_critSec); for (int i=0; i<watchedPaths.GetCount(); ++i) { if (watchedPaths[i].IsAncestorOf(path)) return false; // already watched (recursively) } // now check if with the new path we might have a new root CTGitPath newroot; for (int i=0; i<watchedPaths.GetCount(); ++i) { const CString& watched = watchedPaths[i].GetWinPathString(); const CString& sPath = path.GetWinPathString(); int minlen = min(sPath.GetLength(), watched.GetLength()); int len = 0; for (len = 0; len < minlen; ++len) { if (watched.GetAt(len) != sPath.GetAt(len)) { if ((len > 1)&&(len < minlen)) { if (sPath.GetAt(len)=='\\') { newroot = CTGitPath(sPath.Left(len)); } else if (watched.GetAt(len)=='\\') { newroot = CTGitPath(watched.Left(len)); } } break; } } if (len == minlen) { if (sPath.GetLength() == minlen) { if (watched.GetLength() > minlen) { if (watched.GetAt(len)=='\\') { newroot = path; } else if (sPath.GetLength() == 3 && sPath[1] == ':') { newroot = path; } } } else { if (sPath.GetLength() > minlen) { if (sPath.GetAt(len)=='\\') { newroot = CTGitPath(watched); } else if (watched.GetLength() == 3 && watched[1] == ':') { newroot = CTGitPath(watched); } } } } } if (!newroot.IsEmpty()) { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": add path to watch %s\n"), newroot.GetWinPath()); watchedPaths.AddPath(newroot); watchedPaths.RemoveChildren(); if (bCloseInfoMap) ClearInfoMap(); return true; } CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": add path to watch %s\n"), path.GetWinPath()); watchedPaths.AddPath(path); if (bCloseInfoMap) ClearInfoMap(); return true; }
bool CPathWatcher::AddPath(const CTGitPath& path) { AutoLocker lock(m_critSec); for (int i=0; i<watchedPaths.GetCount(); ++i) { if (watchedPaths[i].IsAncestorOf(path)) return false; // already watched (recursively) } // now check if with the new path we might have a new root CTGitPath newroot; for (int i=0; i<watchedPaths.GetCount(); ++i) { const CString& watched = watchedPaths[i].GetWinPathString(); const CString& sPath = path.GetWinPathString(); int minlen = min(sPath.GetLength(), watched.GetLength()); int len = 0; for (len = 0; len < minlen; ++len) { if (watched.GetAt(len) != sPath.GetAt(len)) { if ((len > 1)&&(len < minlen)) { if (sPath.GetAt(len)=='\\') { newroot = CTGitPath(sPath.Left(len)); } else if (watched.GetAt(len)=='\\') { newroot = CTGitPath(watched.Left(len)); } } break; } } if (len == minlen) { if (sPath.GetLength() == minlen) { if (watched.GetLength() > minlen) { if (watched.GetAt(len)=='\\') { newroot = path; } else if (sPath.GetLength() == 3 && sPath[1] == ':') { newroot = path; } } } else { if (sPath.GetLength() > minlen) { if (sPath.GetAt(len)=='\\') { newroot = CTGitPath(watched); } else if (watched.GetLength() == 3 && watched[1] == ':') { newroot = CTGitPath(watched); } } } } } if (!newroot.IsEmpty()) { ATLTRACE(_T("add path to watch %s\n"), newroot.GetWinPath()); watchedPaths.AddPath(newroot); watchedPaths.RemoveChildren(); m_hCompPort = INVALID_HANDLE_VALUE; return true; } ATLTRACE(_T("add path to watch %s\n"), path.GetWinPath()); watchedPaths.AddPath(path); m_hCompPort = INVALID_HANDLE_VALUE; return true; }
void CShellUpdater::WorkerThread() { HANDLE hWaitHandles[2]; hWaitHandles[0] = m_hTerminationEvent; hWaitHandles[1] = m_hWakeEvent; for(;;) { DWORD waitResult = WaitForMultipleObjects(_countof(hWaitHandles), hWaitHandles, FALSE, INFINITE); // exit event/working loop if the first event (m_hTerminationEvent) // has been signaled or if one of the events has been abandoned // (i.e. ~CShellUpdater() is being executed) if(waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED_0 || waitResult == WAIT_ABANDONED_0+1) { // Termination event break; } // wait some time before we notify the shell Sleep(50); for(;;) { CTGitPath workingPath; if (!m_bRunning) return; Sleep(0); { AutoLocker lock(m_critSec); if(m_pathsToUpdate.empty()) { // Nothing left to do break; } if(m_bItemsAddedSinceLastUpdate) { m_pathsToUpdate.erase(std::unique(m_pathsToUpdate.begin(), m_pathsToUpdate.end(), &CTGitPath::PredLeftEquivalentToRight), m_pathsToUpdate.end()); m_bItemsAddedSinceLastUpdate = false; } workingPath = m_pathsToUpdate.front(); m_pathsToUpdate.pop_front(); } if (workingPath.IsEmpty()) continue; ATLTRACE(_T("Update notifications for: %s\n"), workingPath.GetWinPath()); if (workingPath.IsDirectory()) { // check if the path is monitored by the watcher. If it isn't, then we have to invalidate the cache // for that path and add it to the watcher. if (!CGitStatusCache::Instance().IsPathWatched(workingPath)) { if (workingPath.HasAdminDir()) CGitStatusCache::Instance().AddPathToWatch(workingPath); } // first send a notification about a sub folder change, so explorer doesn't discard // the folder notification. Since we only know for sure that the subversion admin // dir is present, we send a notification for that folder. CString admindir = workingPath.GetWinPathString() + _T("\\") + g_GitAdminDir.GetAdminDirName(); if(::PathFileExists(admindir)) SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, (LPCTSTR)admindir, NULL); SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL); // Sending an UPDATEDIR notification somehow overwrites/deletes the UPDATEITEM message. And without // that message, the folder overlays in the current view don't get updated without hitting F5. // Drawback is, without UPDATEDIR, the left tree view isn't always updated... SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL); } else SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL); } } _endthread(); }
BOOL ProjectProperties::ReadProps(CTGitPath path) { CString sPropVal; GetStringProps(this->sLabel,BUGTRAQPROPNAME_LABEL); GetStringProps(this->sMessage,BUGTRAQPROPNAME_MESSAGE); GetStringProps(this->sUrl,BUGTRAQPROPNAME_URL); GetBOOLProps(this->bWarnIfNoIssue,BUGTRAQPROPNAME_WARNIFNOISSUE); GetBOOLProps(this->bNumber,BUGTRAQPROPNAME_NUMBER); GetBOOLProps(this->bAppend,BUGTRAQPROPNAME_APPEND); GetStringProps(sPropVal,BUGTRAQPROPNAME_LOGREGEX,false); sCheckRe = sPropVal; if (sCheckRe.Find('\n')>=0) { sBugIDRe = sCheckRe.Mid(sCheckRe.Find('\n')).Trim(); sCheckRe = sCheckRe.Left(sCheckRe.Find('\n')).Trim(); } if (!sCheckRe.IsEmpty()) { sCheckRe = sCheckRe.Trim(); } return TRUE; #if 0 BOOL bFoundBugtraqLabel = FALSE; BOOL bFoundBugtraqMessage = FALSE; BOOL bFoundBugtraqNumber = FALSE; BOOL bFoundBugtraqLogRe = FALSE; BOOL bFoundBugtraqURL = FALSE; BOOL bFoundBugtraqWarnIssue = FALSE; BOOL bFoundBugtraqAppend = FALSE; BOOL bFoundLogWidth = FALSE; BOOL bFoundLogTemplate = FALSE; BOOL bFoundMinLogSize = FALSE; BOOL bFoundMinLockMsgSize = FALSE; BOOL bFoundFileListEnglish = FALSE; BOOL bFoundProjectLanguage = FALSE; BOOL bFoundUserFileProps = FALSE; BOOL bFoundUserDirProps = FALSE; BOOL bFoundWebViewRev = FALSE; BOOL bFoundWebViewPathRev = FALSE; BOOL bFoundAutoProps = FALSE; BOOL bFoundLogSummary = FALSE; if (!path.IsDirectory()) path = path.GetContainingDirectory(); for (;;) { GitProperties props(path, GitRev::REV_WC, false); for (int i=0; i<props.GetCount(); ++i) { CString sPropName = props.GetItemName(i).c_str(); CString sPropVal = CUnicodeUtils::GetUnicode(((char *)props.GetItemValue(i).c_str())); if ((!bFoundBugtraqLabel)&&(sPropName.Compare(BUGTRAQPROPNAME_LABEL)==0)) { sLabel = sPropVal; bFoundBugtraqLabel = TRUE; } if ((!bFoundBugtraqMessage)&&(sPropName.Compare(BUGTRAQPROPNAME_MESSAGE)==0)) { sMessage = sPropVal; bFoundBugtraqMessage = TRUE; } if ((!bFoundBugtraqNumber)&&(sPropName.Compare(BUGTRAQPROPNAME_NUMBER)==0)) { CString val; val = sPropVal; val = val.Trim(_T(" \n\r\t")); if ((val.CompareNoCase(_T("false"))==0)||(val.CompareNoCase(_T("no"))==0)) bNumber = FALSE; else bNumber = TRUE; bFoundBugtraqNumber = TRUE; } if ((!bFoundBugtraqLogRe)&&(sPropName.Compare(BUGTRAQPROPNAME_LOGREGEX)==0)) { sCheckRe = sPropVal; if (sCheckRe.Find('\n')>=0) { sBugIDRe = sCheckRe.Mid(sCheckRe.Find('\n')).Trim(); sCheckRe = sCheckRe.Left(sCheckRe.Find('\n')).Trim(); } if (!sCheckRe.IsEmpty()) { sCheckRe = sCheckRe.Trim(); } bFoundBugtraqLogRe = TRUE; } if ((!bFoundBugtraqURL)&&(sPropName.Compare(BUGTRAQPROPNAME_URL)==0)) { sUrl = sPropVal; bFoundBugtraqURL = TRUE; } if ((!bFoundBugtraqWarnIssue)&&(sPropName.Compare(BUGTRAQPROPNAME_WARNIFNOISSUE)==0)) { CString val; val = sPropVal; val = val.Trim(_T(" \n\r\t")); if ((val.CompareNoCase(_T("true"))==0)||(val.CompareNoCase(_T("yes"))==0)) bWarnIfNoIssue = TRUE; else bWarnIfNoIssue = FALSE; bFoundBugtraqWarnIssue = TRUE; } if ((!bFoundBugtraqAppend)&&(sPropName.Compare(BUGTRAQPROPNAME_APPEND)==0)) { CString val; val = sPropVal; val = val.Trim(_T(" \n\r\t")); if ((val.CompareNoCase(_T("true"))==0)||(val.CompareNoCase(_T("yes"))==0)) bAppend = TRUE; else bAppend = FALSE; bFoundBugtraqAppend = TRUE; } if ((!bFoundLogWidth)&&(sPropName.Compare(PROJECTPROPNAME_LOGWIDTHLINE)==0)) { CString val; val = sPropVal; if (!val.IsEmpty()) { nLogWidthMarker = _ttoi(val); } bFoundLogWidth = TRUE; } if ((!bFoundLogTemplate)&&(sPropName.Compare(PROJECTPROPNAME_LOGTEMPLATE)==0)) { sLogTemplate = sPropVal; sLogTemplate.Remove('\r'); sLogTemplate.Replace(_T("\n"), _T("\r\n")); bFoundLogTemplate = TRUE; } if ((!bFoundMinLogSize)&&(sPropName.Compare(PROJECTPROPNAME_LOGMINSIZE)==0)) { CString val; val = sPropVal; if (!val.IsEmpty()) { nMinLogSize = _ttoi(val); } bFoundMinLogSize = TRUE; } if ((!bFoundMinLockMsgSize)&&(sPropName.Compare(PROJECTPROPNAME_LOCKMSGMINSIZE)==0)) { CString val; val = sPropVal; if (!val.IsEmpty()) { nMinLockMsgSize = _ttoi(val); } bFoundMinLockMsgSize = TRUE; } if ((!bFoundFileListEnglish)&&(sPropName.Compare(PROJECTPROPNAME_LOGFILELISTLANG)==0)) { CString val; val = sPropVal; val = val.Trim(_T(" \n\r\t")); if ((val.CompareNoCase(_T("false"))==0)||(val.CompareNoCase(_T("no"))==0)) bFileListInEnglish = TRUE; else bFileListInEnglish = FALSE; bFoundFileListEnglish = TRUE; } if ((!bFoundProjectLanguage)&&(sPropName.Compare(PROJECTPROPNAME_PROJECTLANGUAGE)==0)) { CString val; val = sPropVal; if (!val.IsEmpty()) { LPTSTR strEnd; lProjectLanguage = _tcstol(val, &strEnd, 0); } bFoundProjectLanguage = TRUE; } if ((!bFoundUserFileProps)&&(sPropName.Compare(PROJECTPROPNAME_USERFILEPROPERTY)==0)) { sFPPath = sPropVal; sFPPath.Replace(_T("\r\n"), _T("\n")); bFoundUserFileProps = TRUE; } if ((!bFoundUserDirProps)&&(sPropName.Compare(PROJECTPROPNAME_USERDIRPROPERTY)==0)) { sDPPath = sPropVal; sDPPath.Replace(_T("\r\n"), _T("\n")); bFoundUserDirProps = TRUE; } if ((!bFoundAutoProps)&&(sPropName.Compare(PROJECTPROPNAME_AUTOPROPS)==0)) { sAutoProps = sPropVal; sAutoProps.Replace(_T("\r\n"), _T("\n")); bFoundAutoProps = TRUE; } if ((!bFoundWebViewRev)&&(sPropName.Compare(PROJECTPROPNAME_WEBVIEWER_REV)==0)) { sWebViewerRev = sPropVal; bFoundWebViewRev = TRUE; } if ((!bFoundWebViewPathRev)&&(sPropName.Compare(PROJECTPROPNAME_WEBVIEWER_PATHREV)==0)) { sWebViewerPathRev = sPropVal; bFoundWebViewPathRev = TRUE; } if ((!bFoundLogSummary)&&(sPropName.Compare(PROJECTPROPNAME_LOGSUMMARY)==0)) { sLogSummaryRe = sPropVal; bFoundLogSummary = TRUE; } } if (PathIsRoot(path.GetWinPath())) return FALSE; propsPath = path; path = path.GetContainingDirectory(); if ((!path.HasAdminDir())||(path.IsEmpty())) { if (bFoundBugtraqLabel | bFoundBugtraqMessage | bFoundBugtraqNumber | bFoundBugtraqURL | bFoundBugtraqWarnIssue | bFoundLogWidth | bFoundLogTemplate | bFoundBugtraqLogRe | bFoundMinLockMsgSize | bFoundUserFileProps | bFoundUserDirProps | bFoundAutoProps | bFoundWebViewRev | bFoundWebViewPathRev | bFoundLogSummary) { return TRUE; } propsPath.Reset(); return FALSE; } } #endif return FALSE; //never reached }
/* Fetch is false, means fetch status from cache */ CStatusCacheEntry CGitStatusCache::GetStatusForPath(const CTGitPath& path, DWORD flags, bool bFetch /* = true */) { bool bRecursive = !!(flags & TGITCACHE_FLAGS_RECUSIVE_STATUS); // Check a very short-lived 'mini-cache' of the last thing we were asked for. long now = (long)GetTickCount(); if(now-m_mostRecentExpiresAt < 0) { if(path.IsEquivalentToWithoutCase(m_mostRecentPath)) { return m_mostRecentStatus; } } { AutoLocker lock(m_critSec); m_mostRecentPath = path; m_mostRecentExpiresAt = now + 1000; } if (IsPathGood(path)) { // Stop the crawler starting on a new folder while we're doing this much more important task... // Please note, that this may be a second "lock" used concurrently to the one in RemoveCacheForPath(). CCrawlInhibitor crawlInhibit(&m_folderCrawler); CTGitPath dirpath = path.GetContainingDirectory(); if ((dirpath.IsEmpty()) || (!m_shellCache.IsPathAllowed(dirpath.GetWinPath()))) dirpath = path.GetDirectory(); CCachedDirectory * cachedDir = GetDirectoryCacheEntry(dirpath); if (cachedDir != NULL) { //CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": GetStatusForMember %d\n"), bFetch); CStatusCacheEntry entry = cachedDir->GetStatusForMember(path, bRecursive, bFetch); { AutoLocker lock(m_critSec); m_mostRecentStatus = entry; return m_mostRecentStatus; } } } else { // path is blocked for some reason: return the cached status if we have one // we do here only a cache search, absolutely no disk access is allowed! CCachedDirectory::ItDir itMap = m_directoryCache.find(path.GetDirectory()); if ((itMap != m_directoryCache.end())&&(itMap->second)) { if (path.IsDirectory()) { CStatusCacheEntry entry = itMap->second->GetOwnStatus(false); AutoLocker lock(m_critSec); m_mostRecentStatus = entry; return m_mostRecentStatus; } else { // We've found this directory in the cache CCachedDirectory * cachedDir = itMap->second; CStatusCacheEntry entry = cachedDir->GetCacheStatusForMember(path); { AutoLocker lock(m_critSec); m_mostRecentStatus = entry; return m_mostRecentStatus; } } } } AutoLocker lock(m_critSec); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": ignored no good path %s\n"), path.GetWinPath()); m_mostRecentStatus = CStatusCacheEntry(); if (m_shellCache.ShowExcludedAsNormal() && path.IsDirectory() && m_shellCache.HasGITAdminDir(path.GetWinPath(), true)) { CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": force status %s\n"), path.GetWinPath()); m_mostRecentStatus.ForceStatus(git_wc_status_normal); } return m_mostRecentStatus; }