NS_IMETHODIMP nsDOMOfflineResourceList::MozRemove(const nsAString& aURI) { nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); if (!nsContentUtils::OfflineAppAllowed(mDocumentURI)) { return NS_ERROR_DOM_SECURITY_ERR; } nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } nsCAutoString key; rv = GetCacheKey(aURI, key); NS_ENSURE_SUCCESS(rv, rv); ClearCachedKeys(); // XXX: This is a race condition. remove() is specced to remove // from the currently associated application cache, but if this // happens during an update (or after an update, if we haven't // swapped yet), that remove() will be lost when the next update is // finished. Need to bring this issue up. rv = appCache->UnmarkEntry(key, nsIApplicationCache::ITEM_DYNAMIC); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
std::vector<std::shared_ptr<Procedure>> ProcedureController::GetProceduresFromQuery(QSqlQuery &query, bool isTypeProcedure) { std::vector<std::shared_ptr<Procedure>> result; if(!query.exec()) { return result; } while(query.next()) { auto newProc = std::unique_ptr<Procedure>(new Procedure()); newProc->SetTemplateProcedure(!(query.value("ProjectTypeId").isNull())); newProc->SetPureTemplateProcedure(isTypeProcedure); newProc->SetProjectId(query.value("ProjectId").toInt()); newProc->SetProcedureId(query.value("ProcedureId").toInt()); newProc->SetProjectProcedureId(query.value("ProjectProcedureId").toInt()); newProc->SetDescription(query.value("Description").toString()); newProc->SetDoneState(query.value("IsDone").toInt() != 0); ProcedureCacheKey key = GetCacheKey(*newProc); std::shared_ptr<Procedure> sharedPtr = m_cache.Lookup(key); if(!sharedPtr) { sharedPtr = std::shared_ptr<Procedure>(std::move(newProc)); AddProcedure(key, sharedPtr); } result.push_back(sharedPtr); } return result; }
NS_IMETHODIMP nsDOMOfflineResourceList::MozHasItem(const nsAString& aURI, PRBool* aExists) { nsresult rv = Init(); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIApplicationCache> appCache = GetDocumentAppCache(); if (!appCache) { return NS_ERROR_DOM_INVALID_STATE_ERR; } nsCAutoString key; rv = GetCacheKey(aURI, key); NS_ENSURE_SUCCESS(rv, rv); PRUint32 types; rv = appCache->GetTypes(key, &types); if (rv == NS_ERROR_CACHE_KEY_NOT_FOUND) { *aExists = PR_FALSE; return NS_OK; } NS_ENSURE_SUCCESS(rv, rv); *aExists = ((types & nsIApplicationCache::ITEM_DYNAMIC) != 0); return NS_OK; }
void nsPreflightCache::RemoveEntries(nsIURI* aURI, nsIPrincipal* aPrincipal) { CacheEntry* entry; nsCString key; if (GetCacheKey(aURI, aPrincipal, PR_TRUE, key) && mTable.Get(key, &entry)) { PR_REMOVE_LINK(entry); mTable.Remove(key); } if (GetCacheKey(aURI, aPrincipal, PR_FALSE, key) && mTable.Get(key, &entry)) { PR_REMOVE_LINK(entry); mTable.Remove(key); } }
nsresult nsDOMOfflineResourceList::GetCacheKey(const nsAString &aURI, nsCString &aKey) { nsCOMPtr<nsIURI> requestedURI; nsresult rv = NS_NewURI(getter_AddRefs(requestedURI), aURI); NS_ENSURE_SUCCESS(rv, rv); return GetCacheKey(requestedURI, aKey); }
CStatusCacheEntry CCachedDirectory::GetCacheStatusForMember(const CTGitPath& path) { // no disk access! AutoLocker lock(m_critSec); CacheEntryMap::iterator itMap = m_entryCache.find(GetCacheKey(path)); if(itMap != m_entryCache.end()) return itMap->second; return CStatusCacheEntry(); }
CStatusCacheEntry CCachedDirectory::GetCacheStatusForMember( const CTSVNPath& path ) { AutoLocker lock(m_critSec); CStringA strCacheKey = GetCacheKey(path); CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey); if(itMap != m_entryCache.end()) { return itMap->second; } return CStatusCacheEntry(); }
void CCachedDirectory::AddEntry(const CTSVNPath& path, const svn_client_status_t* pSVNStatus, bool needsLock, bool forceNormal) { svn_wc_status_kind nodestatus = forceNormal ? svn_wc_status_normal : (pSVNStatus ? pSVNStatus->node_status : svn_wc_status_none); if(path.IsDirectory()) { // no lock here: // AutoLocker lock(m_critSec); // because GetDirectoryCacheEntry() can try to obtain a write lock CCachedDirectory * childDir = CSVNStatusCache::Instance().GetDirectoryCacheEntry(path); if (childDir) { if ((childDir->GetCurrentFullStatus() != svn_wc_status_ignored)||(pSVNStatus==NULL)||(nodestatus != svn_wc_status_unversioned)) childDir->m_ownStatus.SetStatus(pSVNStatus, needsLock, forceNormal); childDir->m_ownStatus.SetKind(svn_node_dir); } } else { AutoLocker lock(m_critSec); CStringA cachekey = GetCacheKey(path); CacheEntryMap::iterator entry_it = m_entryCache.lower_bound(cachekey); if (entry_it != m_entryCache.end() && entry_it->first == cachekey) { if (pSVNStatus) { if (entry_it->second.GetEffectiveStatus() > svn_wc_status_none && entry_it->second.GetEffectiveStatus() != nodestatus) { CSVNStatusCache::Instance().UpdateShell(path); CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": shell update for %s\n"), path.GetWinPath()); } } } else { entry_it = m_entryCache.insert(entry_it, std::make_pair(cachekey, CStatusCacheEntry())); } entry_it->second = CStatusCacheEntry(pSVNStatus, needsLock, path.GetLastWriteTime(), forceNormal); } }
bool ProcedureController::RemoveProcedure(const Procedure &procedure) { if(!procedure.IsTemplateProcedure()) { QSqlQuery procedureProjectDelete = GetDb().CreateQuery(); procedureProjectDelete.prepare("DELETE FROM \"ProjectProcedure\" " "WHERE \"ProjectProcedureId\"=:projectProcedureId;"); procedureProjectDelete.bindValue(":projectProcedureId", procedure.GetProjectProcedureId()); if(!procedureProjectDelete.exec()) { return false; } } QSqlQuery procedureDelete = GetDb().CreateQuery(); procedureDelete.prepare("DELETE FROM \"Procedure\" " "WHERE \"ProcedureId\"=:procedureId;"); procedureDelete.bindValue(":procedureId", procedure.GetProcedureId()); if(!procedureDelete.exec()) { return false; } ProcedureCacheKey key = GetCacheKey(procedure); auto removedProcedure = m_cache.Lookup(key); if(removedProcedure) { m_cache.Remove(key); emit sigProcedureRemoved(*removedProcedure); if(procedure.IsPureTemplateProcedure()) { RemoveProjectProceduresOfTemplate(procedure.GetProcedureId()); } return true; } return false; }
void CCachedDirectory::AddEntry(const CTGitPath& path, const git_wc_status2_t* pGitStatus, DWORD validuntil /* = 0*/) { AutoLocker lock(m_critSec); if(path.IsDirectory()) { CCachedDirectory * childDir = CGitStatusCache::Instance().GetDirectoryCacheEntry(path); if (childDir) { if ((childDir->GetCurrentFullStatus() != git_wc_status_missing)||(pGitStatus==NULL)||(pGitStatus->text_status != git_wc_status_unversioned)) { if(pGitStatus) { if(childDir->GetCurrentFullStatus() != GitStatus::GetMoreImportant(pGitStatus->prop_status, pGitStatus->text_status)) { CGitStatusCache::Instance().UpdateShell(path); //CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": shell update for %s\n"), path.GetWinPath()); childDir->m_ownStatus.SetKind(git_node_dir); childDir->m_ownStatus.SetStatus(pGitStatus); } } } childDir->m_ownStatus.SetKind(git_node_dir); } } else { CCachedDirectory * childDir = CGitStatusCache::Instance().GetDirectoryCacheEntry(path.GetContainingDirectory()); bool bNotified = false; if(!childDir) return ; AutoLocker lock2(childDir->m_critSec); CString cachekey = GetCacheKey(path); CacheEntryMap::iterator entry_it = childDir->m_entryCache.lower_bound(cachekey); if (entry_it != childDir->m_entryCache.end() && entry_it->first == cachekey) { if (pGitStatus) { if (entry_it->second.GetEffectiveStatus() > git_wc_status_none && entry_it->second.GetEffectiveStatus() != GitStatus::GetMoreImportant(pGitStatus->prop_status, pGitStatus->text_status) ) { bNotified =true; } } } else { entry_it = childDir->m_entryCache.insert(entry_it, std::make_pair(cachekey, CStatusCacheEntry())); bNotified = true; } entry_it->second = CStatusCacheEntry(pGitStatus, path.GetLastWriteTime(), path.IsReadOnly(), validuntil); // TEMP(?): git status doesn't not have "entry" that contains node type, so manually set as file entry_it->second.SetKind(git_node_file); childDir->m_entryCache_tmp[cachekey] = entry_it->second; if(bNotified) { CGitStatusCache::Instance().UpdateShell(path); //CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": shell update for %s\n"), path.GetWinPath()); } //CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Path Entry Add %s %s %s %d\n"), path.GetWinPath(), cachekey, m_directoryPath.GetWinPath(), pGitStatus->text_status); } }
CStatusCacheEntry CCachedDirectory::GetStatusFromGit(const CTGitPath &path, CString sProjectRoot) { CString subpaths = path.GetGitPathString(); if(subpaths.GetLength() >= sProjectRoot.GetLength()) { if(subpaths[sProjectRoot.GetLength()] == _T('/')) subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()-1); else subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()); } GitStatus *pGitStatus = &CGitStatusCache::Instance().m_GitStatus; UNREFERENCED_PARAMETER(pGitStatus); bool isVersion =true; pGitStatus->IsUnderVersionControl(sProjectRoot, subpaths, path.IsDirectory(), &isVersion); if(!isVersion) { //untracked file bool isDir = path.IsDirectory(); bool isIgnoreFileChanged = pGitStatus->HasIgnoreFilesChanged(sProjectRoot, subpaths, isDir); if( isIgnoreFileChanged) { pGitStatus->LoadIgnoreFile(sProjectRoot, subpaths, isDir); } if (isDir) { CCachedDirectory * dirEntry = CGitStatusCache::Instance().GetDirectoryCacheEntry(path, false); /* we needn't watch untracked directory*/ if(dirEntry) { AutoLocker lock(dirEntry->m_critSec); git_wc_status_kind dirstatus = dirEntry->GetCurrentFullStatus() ; if (CGitStatusCache::Instance().IsUnversionedAsModified() || dirstatus == git_wc_status_none || dirstatus >= git_wc_status_normal || isIgnoreFileChanged) {/* status have not initialized*/ bool isignore = false; pGitStatus->IsIgnore(sProjectRoot, subpaths, &isignore, isDir); if (!isignore && CGitStatusCache::Instance().IsUnversionedAsModified()) { dirEntry->EnumFiles(path, TRUE); dirEntry->UpdateCurrentStatus(); return CStatusCacheEntry(dirEntry->GetCurrentFullStatus()); } git_wc_status2_t status2; status2.text_status = status2.prop_status = (isignore? git_wc_status_ignored:git_wc_status_unversioned); // we do not know anything about files here, all we know is that there are not versioned files in this dir dirEntry->m_mostImportantFileStatus = git_wc_status_none; dirEntry->m_ownStatus.SetKind(git_node_dir); dirEntry->m_ownStatus.SetStatus(&status2); dirEntry->m_currentFullStatus = status2.text_status; } return dirEntry->m_ownStatus; } } else /* path is file */ { AutoLocker lock(m_critSec); CString strCacheKey = GetCacheKey(path); if (strCacheKey.IsEmpty()) return CStatusCacheEntry(); CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey); if(itMap == m_entryCache.end() || isIgnoreFileChanged) { git_wc_status2_t status2; bool isignore = false; pGitStatus->IsIgnore(sProjectRoot, subpaths, &isignore, isDir); status2.text_status = status2.prop_status = (isignore? git_wc_status_ignored:git_wc_status_unversioned); AddEntry(path, &status2); return m_entryCache[strCacheKey]; } else { return itMap->second; } } return CStatusCacheEntry(); } else { EnumFiles(path, TRUE); UpdateCurrentStatus(); if (!path.IsDirectory()) return GetCacheStatusForMember(path); return CStatusCacheEntry(m_ownStatus); } }
CStatusCacheEntry CCachedDirectory::GetStatusFromCache(const CTGitPath& path, bool bRecursive) { if(path.IsDirectory()) { // We don't have directory status in our cache // Ask the directory if it knows its own status CCachedDirectory * dirEntry = CGitStatusCache::Instance().GetDirectoryCacheEntry(path); if( dirEntry) { if (dirEntry->IsOwnStatusValid()) return dirEntry->GetOwnStatus(bRecursive); else { /* cache have outof date, need crawl again*/ /*AutoLocker lock(dirEntry->m_critSec); ChildDirStatus::const_iterator it; for(it = dirEntry->m_childDirectories.begin(); it != dirEntry->m_childDirectories.end(); ++it) { CGitStatusCache::Instance().AddFolderForCrawling(it->first); }*/ CGitStatusCache::Instance().AddFolderForCrawling(path); /*Return old status during crawling*/ return dirEntry->GetOwnStatus(bRecursive); } } else { CGitStatusCache::Instance().AddFolderForCrawling(path); } return CStatusCacheEntry(); } else { //All file ignored if under ignore directory if (m_ownStatus.GetEffectiveStatus() == git_wc_status_ignored) return CStatusCacheEntry(git_wc_status_ignored); if (m_ownStatus.GetEffectiveStatus() == git_wc_status_unversioned) return CStatusCacheEntry(git_wc_status_unversioned); // Look up a file in our own cache AutoLocker lock(m_critSec); CString strCacheKey = GetCacheKey(path); CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey); if(itMap != m_entryCache.end()) { // We've hit the cache - check for timeout if(!itMap->second.HasExpired((long)GetTickCount())) { if(itMap->second.DoesFileTimeMatch(path.GetLastWriteTime())) { if ((itMap->second.GetEffectiveStatus()!=git_wc_status_missing)||(!PathFileExists(path.GetWinPath()))) { // Note: the filetime matches after a modified has been committed too. // So in that case, we would return a wrong status (e.g. 'modified' instead // of 'normal') here. return itMap->second; } } } } CGitStatusCache::Instance().AddFolderForCrawling(path.GetContainingDirectory()); return CStatusCacheEntry(); } }
nsPreflightCache::CacheEntry* nsPreflightCache::GetEntry(nsIURI* aURI, nsIPrincipal* aPrincipal, PRBool aWithCredentials, PRBool aCreate) { nsCString key; if (!GetCacheKey(aURI, aPrincipal, aWithCredentials, key)) { NS_WARNING("Invalid cache key!"); return nsnull; } CacheEntry* entry; if (mTable.Get(key, &entry)) { // Entry already existed so just return it. Also update the LRU list. // Move to the head of the list. PR_REMOVE_LINK(entry); PR_INSERT_LINK(entry, &mList); return entry; } if (!aCreate) { return nsnull; } // This is a new entry, allocate and insert into the table now so that any // failures don't cause items to be removed from a full cache. entry = new CacheEntry(key); if (!entry) { NS_WARNING("Failed to allocate new cache entry!"); return nsnull; } NS_ASSERTION(mTable.Count() <= PREFLIGHT_CACHE_SIZE, "Something is borked, too many entries in the cache!"); // Now enforce the max count. if (mTable.Count() == PREFLIGHT_CACHE_SIZE) { // Try to kick out all the expired entries. PRTime now = PR_Now(); mTable.Enumerate(RemoveExpiredEntries, &now); // If that didn't remove anything then kick out the least recently used // entry. if (mTable.Count() == PREFLIGHT_CACHE_SIZE) { CacheEntry* lruEntry = static_cast<CacheEntry*>(PR_LIST_TAIL(&mList)); PR_REMOVE_LINK(lruEntry); // This will delete 'lruEntry'. mTable.Remove(lruEntry->mKey); NS_ASSERTION(mTable.Count() == PREFLIGHT_CACHE_SIZE - 1, "Somehow tried to remove an entry that was never added!"); } } if (!mTable.Put(key, entry)) { // Failed, clean up the new entry. delete entry; NS_WARNING("Failed to add entry to the CORS preflight cache!"); return nsnull; } PR_INSERT_LINK(entry, &mList); return entry; }
CStatusCacheEntry CCachedDirectory::GetStatusForMember(const CTSVNPath& path, bool bRecursive, bool bFetch /* = true */) { CStringA strCacheKey; bool bThisDirectoryIsUnversioned = false; bool bRequestForSelf = false; if(path.IsEquivalentToWithoutCase(m_directoryPath)) { bRequestForSelf = true; } // In all most circumstances, we ask for the status of a member of this directory. ATLASSERT(m_directoryPath.IsEquivalentToWithoutCase(path.GetContainingDirectory()) || bRequestForSelf); long long dbFileTime = CSVNStatusCache::Instance().WCRoots()->GetDBFileTime(m_directoryPath); bool wcDbFileTimeChanged = (m_wcDbFileTime != dbFileTime); if ( !wcDbFileTimeChanged ) { if(m_wcDbFileTime == 0) { // We are a folder which is not in a working copy bThisDirectoryIsUnversioned = true; m_ownStatus.SetStatus(NULL, false, false); // If a user removes the .svn directory, we get here with m_entryCache // not being empty, but still us being unversioned if (!m_entryCache.empty()) { m_entryCache.clear(); } ATLASSERT(m_entryCache.empty()); // However, a member *DIRECTORY* might be the top of WC // so we need to ask them to get their own status if(!path.IsDirectory()) { if ((PathFileExists(path.GetWinPath()))||(bRequestForSelf)) return CStatusCacheEntry(); // the entry doesn't exist anymore! // but we can't remove it from the cache here: // the GetStatusForMember() method is called only with a read // lock and not a write lock! // So mark it for crawling, and let the crawler remove it // later CSVNStatusCache::Instance().AddFolderForCrawling(path.GetContainingDirectory()); return CStatusCacheEntry(); } else { // If we're in the special case of a directory being asked for its own status // and this directory is unversioned, then we should just return that here if(bRequestForSelf) { return CStatusCacheEntry(); } } } if (CSVNStatusCache::Instance().GetDirectoryCacheEntryNoCreate(path) != NULL) { // We don't have directory status in our cache // Ask the directory if it knows its own status CCachedDirectory * dirEntry = CSVNStatusCache::Instance().GetDirectoryCacheEntry(path); if ((dirEntry)&&(dirEntry->IsOwnStatusValid())) { // To keep recursive status up to date, we'll request that children are all crawled again // We have to do this because the directory watcher isn't very reliable (especially under heavy load) // and also has problems with SUBSTed drives. // If nothing has changed in those directories, this crawling is fast and only // accesses two files for each directory. if (bRecursive) { AutoLocker lock(dirEntry->m_critSec); ChildDirStatus::const_iterator it; for(it = dirEntry->m_childDirectories.begin(); it != dirEntry->m_childDirectories.end(); ++it) { CTSVNPath newpath; CString winPath = CUnicodeUtils::GetUnicode (it->first); newpath.SetFromWin(winPath, true); CSVNStatusCache::Instance().AddFolderForCrawling(newpath); } } return dirEntry->GetOwnStatus(bRecursive); } } else { { // if we currently are fetching the status of the directory // we want the status for, we just return an empty entry here // and don't wait for that fetching to finish. // That's because fetching the status can take a *really* long // time (e.g. if a commit is also in progress on that same // directory), and we don't want to make the explorer appear // to hang. if ((!bFetch)&&(m_FetchingStatus)) { if (m_directoryPath.IsAncestorOf(path)) { m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; return GetCacheStatusForMember(path); } } } // Look up a file in our own cache AutoLocker lock(m_critSec); strCacheKey = GetCacheKey(path); CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey); if(itMap != m_entryCache.end()) { // We've hit the cache - check for timeout if(!itMap->second.HasExpired((long)GetTickCount())) { if(itMap->second.DoesFileTimeMatch(path.GetLastWriteTime())) { if ((itMap->second.GetEffectiveStatus()!=svn_wc_status_missing)||(!PathFileExists(path.GetWinPath()))) { // Note: the filetime matches after a modified has been committed too. // So in that case, we would return a wrong status (e.g. 'modified' instead // of 'normal') here. return itMap->second; } } } } } } else { if ((!bFetch)&&(m_FetchingStatus)) { if (m_directoryPath.IsAncestorOf(path)) { // returning empty status (status fetch in progress) // also set the status to 'none' to have the status change and // the shell updater invoked in the crawler m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; CSVNStatusCache::Instance().AddFolderForCrawling(m_directoryPath.GetDirectory()); return GetCacheStatusForMember(path); } } // if we're fetching the status for the explorer, // we don't refresh the status but use the one // we already have (to save time and make the explorer // more responsive in stress conditions). // We leave the refreshing to the crawler. if ((!bFetch)&&(m_wcDbFileTime)) { CSVNStatusCache::Instance().AddFolderForCrawling(m_directoryPath.GetDirectory()); return GetCacheStatusForMember(path); } AutoLocker lock(m_critSec); m_entryCache.clear(); strCacheKey = GetCacheKey(path); } // We've not got this item in the cache - let's add it // We never bother asking SVN for the status of just one file, always for its containing directory if (g_SVNAdminDir.IsAdminDirPath(path.GetWinPathString())) { // We're being asked for the status of an .SVN directory // It's not worth asking for this return CStatusCacheEntry(); } { if ((!bFetch)&&(m_FetchingStatus)) { if (m_directoryPath.IsAncestorOf(path)) { m_currentFullStatus = m_mostImportantFileStatus = svn_wc_status_none; return GetCacheStatusForMember(path); } } } { AutoLocker lock(m_critSec); m_mostImportantFileStatus = svn_wc_status_none; m_childDirectories.clear(); m_entryCache.clear(); m_ownStatus.SetStatus(NULL, false, false); } if(!bThisDirectoryIsUnversioned) { if (!SvnUpdateMembersStatus()) { m_wcDbFileTime = 0; return CStatusCacheEntry(); } } // Now that we've refreshed our SVN status, we can see if it's // changed the 'most important' status value for this directory. // If it has, then we should tell our parent UpdateCurrentStatus(); m_wcDbFileTime = dbFileTime; if (path.IsDirectory()) { CCachedDirectory * dirEntry = CSVNStatusCache::Instance().GetDirectoryCacheEntry(path); if ((dirEntry)&&(dirEntry->IsOwnStatusValid())) { //CSVNStatusCache::Instance().AddFolderForCrawling(path); return dirEntry->GetOwnStatus(bRecursive); } // If the status *still* isn't valid here, it means that // the current directory is unversioned, and we shall need to ask its children for info about themselves if ((dirEntry)&&(dirEntry != this)) return dirEntry->GetStatusForMember(path,bRecursive); // add the path for crawling: if it's really unversioned, the crawler will // only check for the admin dir and do nothing more. But if it is // versioned (could happen in a nested layout) the crawler will update its // status correctly CSVNStatusCache::Instance().AddFolderForCrawling(path); return CStatusCacheEntry(); } else { CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey); if(itMap != m_entryCache.end()) { return itMap->second; } } AddEntry(path, NULL, false, false); return CStatusCacheEntry(); }
CStatusCacheEntry CCachedDirectory::GetStatusFromGit(const CTGitPath &path, CString sProjectRoot) { CString subpaths = path.GetGitPathString(); if(subpaths.GetLength() >= sProjectRoot.GetLength()) { if(subpaths[sProjectRoot.GetLength()] == _T('/')) subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()-1); else subpaths=subpaths.Right(subpaths.GetLength() - sProjectRoot.GetLength()); } GitStatus *pGitStatus = &CGitStatusCache::Instance().m_GitStatus; CGitHash head; pGitStatus->GetHeadHash(sProjectRoot,head); bool isVersion =true; pGitStatus->IsUnderVersionControl(sProjectRoot, subpaths, path.IsDirectory(), &isVersion); if(!isVersion) { //untracked file bool isIgnoreFileChanged=false; isIgnoreFileChanged = pGitStatus->IsGitReposChanged(sProjectRoot, subpaths, GIT_MODE_IGNORE); if( isIgnoreFileChanged) { pGitStatus->LoadIgnoreFile(sProjectRoot, subpaths); } if(path.IsDirectory()) { CCachedDirectory * dirEntry = CGitStatusCache::Instance().GetDirectoryCacheEntry(path, false); /* we needn't watch untracked directory*/ if(dirEntry) { AutoLocker lock(dirEntry->m_critSec); git_wc_status_kind dirstatus = dirEntry->GetCurrentFullStatus() ; if( dirstatus == git_wc_status_none || dirstatus >= git_wc_status_normal || isIgnoreFileChanged ) {/* status have not initialized*/ git_wc_status2_t status2; bool isignore = false; pGitStatus->IsIgnore(sProjectRoot,subpaths,&isignore); status2.text_status = status2.prop_status = (isignore? git_wc_status_ignored:git_wc_status_unversioned); dirEntry->m_ownStatus.SetStatus(&status2); dirEntry->m_ownStatus.SetKind(git_node_dir); } return dirEntry->m_ownStatus; } } else /* path is file */ { AutoLocker lock(m_critSec); CString strCacheKey = GetCacheKey(path); CacheEntryMap::iterator itMap = m_entryCache.find(strCacheKey); if(itMap == m_entryCache.end() || isIgnoreFileChanged) { git_wc_status2_t status2; bool isignore = false; pGitStatus->IsIgnore(sProjectRoot,subpaths,&isignore); status2.text_status = status2.prop_status = (isignore? git_wc_status_ignored:git_wc_status_unversioned); AddEntry(path, &status2); return m_entryCache[strCacheKey]; } else { return itMap->second; } } return CStatusCacheEntry(); } else { EnumFiles((CTGitPath*)&path, TRUE); UpdateCurrentStatus(); return CStatusCacheEntry(m_ownStatus); } }