int CGitIndexFileMap::Check(const CString &gitdir, bool *isChanged) { __int64 time; CString IndexFile = g_AdminDirMap.GetAdminDirConcat(gitdir, _T("index")); if (CGit::GetFileModifyTime(IndexFile, &time)) return -1; SHARED_INDEX_PTR pIndex; pIndex = this->SafeGet(gitdir); if (!pIndex) { if(isChanged) *isChanged = true; return 0; } if (pIndex->m_LastModifyTime == time) { if (isChanged) *isChanged = false; } else { if (isChanged) *isChanged = true; } return 0; }
bool GitStatus::IsExistIndexLockFile(const CString &gitdir) { CString sDirName= gitdir; if (!PathIsDirectory(sDirName)) { int x = sDirName.ReverseFind(_T('\\')); if (x < 2) return false; sDirName = sDirName.Left(x); } for (;;) { if(PathFileExists(sDirName + _T("\\.git"))) { if(PathFileExists(g_AdminDirMap.GetAdminDir(sDirName) + _T("index.lock"))) return true; else return false; } int x = sDirName.ReverseFind(_T('\\')); if (x < 2) return false; sDirName = sDirName.Left(x); } }
int CGitIndexFileMap::Check(const CString &gitdir, bool *isChanged) { __int64 time; int result; CString IndexFile = g_AdminDirMap.GetAdminDir(gitdir) + _T("index"); /* Get data associated with "crt_stat.c": */ result = g_Git.GetFileModifyTime(IndexFile, &time); if (result) return result; SHARED_INDEX_PTR pIndex; pIndex = this->SafeGet(gitdir); if (pIndex.get() == NULL) { if(isChanged) *isChanged = true; return 0; } if (pIndex->m_LastModifyTime == time) { if (isChanged) *isChanged = false; } else { if (isChanged) *isChanged = true; } return 0; }
bool CGitIgnoreList::CheckIgnoreChanged(const CString &gitdir, const CString &path, bool isDir) { CString temp; temp = gitdir; temp += _T("\\"); temp += path; temp.Replace(_T('/'), _T('\\')); if (!isDir) { int x = temp.ReverseFind(_T('\\')); if (x >= 2) temp = temp.Left(x); } while(!temp.IsEmpty()) { CString tempOrig = temp; temp += _T("\\.git"); if (CGit::GitPathFileExists(temp)) { CString gitignore=temp; gitignore += _T("ignore"); if (CheckFileChanged(gitignore)) return true; CString adminDir = g_AdminDirMap.GetAdminDir(tempOrig); CString wcglobalgitignore = adminDir + _T("info\\exclude"); if (CheckFileChanged(wcglobalgitignore)) return true; if (CheckAndUpdateCoreExcludefile(adminDir)) return true; return false; } else { temp += _T("ignore"); if (CheckFileChanged(temp)) return true; } int found=0; int i; for (i = temp.GetLength() - 1; i >= 0; i--) { if(temp[i] == _T('\\')) ++found; if(found == 2) break; } temp = temp.Left(i); } return true; }
bool GitStatus::IsExistIndexLockFile(CString sDirName) { if (!PathIsDirectory(sDirName)) { int x = sDirName.ReverseFind(_T('\\')); if (x < 2) return false; sDirName = sDirName.Left(x); } for (;;) { if (PathFileExists(CombinePath(sDirName, _T(".git")))) { if (PathFileExists(g_AdminDirMap.GetAdminDirConcat(sDirName, _T("index.lock")))) return true; return false; } int x = sDirName.ReverseFind(_T('\\')); if (x < 2) return false; sDirName = sDirName.Left(x); } }
int CGitIndexFileMap::LoadIndex(const CString &gitdir) { SHARED_INDEX_PTR pIndex(new CGitIndexList); if (pIndex->ReadIndex(g_AdminDirMap.GetAdminDir(gitdir))) return -1; this->SafeSet(gitdir, pIndex); return 0; }
int CGitIgnoreList::LoadAllIgnoreFile(const CString &gitdir, const CString &path, bool isDir) { CString temp(gitdir); temp += _T('\\'); temp += path; temp.Replace(_T('/'), _T('\\')); if (!isDir) { int x = temp.ReverseFind(_T('\\')); if (x >= 2) temp.Truncate(x); } while (!temp.IsEmpty()) { CString tempOrig = temp; temp += _T("\\.git"); if (CGit::GitPathFileExists(temp)) { CString gitignore = temp; gitignore += _T("ignore"); if (CheckFileChanged(gitignore)) FetchIgnoreFile(gitdir, gitignore, false); CString adminDir = g_AdminDirMap.GetAdminDir(tempOrig); CString wcglobalgitignore = adminDir; wcglobalgitignore += _T("info\\exclude"); if (CheckFileChanged(wcglobalgitignore)) { FetchIgnoreFile(gitdir, wcglobalgitignore, true); } if (CheckAndUpdateCoreExcludefile(adminDir)) { CString excludesFile; { CAutoReadLock lock(m_SharedMutex); excludesFile = m_CoreExcludesfiles[adminDir]; } if (!excludesFile.IsEmpty()) FetchIgnoreFile(gitdir, excludesFile, true); } return 0; } temp += _T("ignore"); if (CheckFileChanged(temp)) FetchIgnoreFile(gitdir, temp, false); int found = 0; int i; for (i = temp.GetLength() - 1; i >= 0; --i) { if(temp[i] == _T('\\')) ++found; if(found == 2) break; } temp.Truncate(i); } return 0; }
int CGitHeadFileList::ReadHeadHash(const CString& gitdir) { CAutoWriteLock lock(m_SharedMutex); m_Gitdir = g_AdminDirMap.GetAdminDir(gitdir); m_HeadFile = m_Gitdir; m_HeadFile += _T("HEAD"); if( CGit::GetFileModifyTime(m_HeadFile, &m_LastModifyTimeHead)) return -1; CAutoFile hfile = CreateFile(m_HeadFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (!hfile) return -1; DWORD size = 0; unsigned char buffer[40]; ReadFile(hfile, buffer, 4, &size, nullptr); if (size != 4) return -1; buffer[4] = 0; if (strcmp((const char*)buffer, "ref:") == 0) { m_HeadRefFile.Empty(); DWORD filesize = GetFileSize(hfile, nullptr); if (filesize < 5) return -1; unsigned char *p = (unsigned char*)malloc(filesize - 4); if (!p) return -1; ReadFile(hfile, p, filesize - 4, &size, nullptr); CGit::StringAppend(&m_HeadRefFile, p, CP_UTF8, filesize - 4); free(p); CString ref = m_HeadRefFile.Trim(); int start = 0; ref = ref.Tokenize(_T("\n"), start); m_HeadRefFile = m_Gitdir + m_HeadRefFile; m_HeadRefFile.Replace(_T('/'), _T('\\')); __int64 time; if (CGit::GetFileModifyTime(m_HeadRefFile, &time, nullptr)) { m_HeadRefFile.Empty(); if (GetPackRef(gitdir)) return -1; if (m_PackRefMap.find(ref) == m_PackRefMap.end()) return -1; m_Head = m_PackRefMap[ref]; return 0; } CAutoFile href = CreateFile(m_HeadRefFile, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (!href) { m_HeadRefFile.Empty(); if (GetPackRef(gitdir)) return -1; if (m_PackRefMap.find(ref) == m_PackRefMap.end()) return -1; m_Head = m_PackRefMap[ref]; return 0; } ReadFile(href, buffer, 40, &size, nullptr); if (size != 40) return -1; m_Head.ConvertFromStrA((char*)buffer); m_LastModifyTimeRef = time; return 0; } ReadFile(hfile, buffer + 4, 40 - 4, &size, nullptr); if (size != 36) return -1; m_HeadRefFile.Empty(); m_Head.ConvertFromStrA((char*)buffer); return 0; }
// This method is assumed to be called with m_SharedMutex locked. int CGitHeadFileList::GetPackRef(const CString &gitdir) { CString PackRef = g_AdminDirMap.GetAdminDirConcat(gitdir, _T("packed-refs")); __int64 mtime; if (CGit::GetFileModifyTime(PackRef, &mtime)) { //packed refs is not existed this->m_PackRefFile.Empty(); this->m_PackRefMap.clear(); return 0; } else if(mtime == m_LastModifyTimePackRef) return 0; else { this->m_PackRefFile = PackRef; this->m_LastModifyTimePackRef = mtime; } m_PackRefMap.clear(); CAutoFile hfile = CreateFile(PackRef, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); if (!hfile) return -1; DWORD filesize = GetFileSize(hfile, nullptr); if (filesize == 0) return -1; DWORD size = 0; auto buff = std::make_unique<char[]>(filesize); ReadFile(hfile, buff.get(), filesize, &size, nullptr); if (size != filesize) return -1; for (DWORD i = 0; i < filesize;) { CString hash; CString ref; if (buff[i] == '#' || buff[i] == '^') { while (buff[i] != '\n') { ++i; if (i == filesize) break; } ++i; } if (i >= filesize) break; while (buff[i] != ' ') { hash.AppendChar(buff[i]); ++i; if (i == filesize) break; } ++i; if (i >= filesize) break; while (buff[i] != '\n') { ref.AppendChar(buff[i]); ++i; if (i == filesize) break; } if (!ref.IsEmpty()) m_PackRefMap[ref] = hash; while (buff[i] == '\n') { ++i; if (i == filesize) break; } } return 0; }
int CGitIgnoreList::CheckIgnore(const CString &path, const CString &projectroot, bool isDir) { CString temp = CombinePath(projectroot, path); temp.Replace(_T('/'), _T('\\')); CStringA patha = CUnicodeUtils::GetMulti(path, CP_UTF8); patha.Replace('\\', '/'); int type = 0; if (isDir) { type = DT_DIR; // strip directory name // we do not need to check for a .ignore file inside a directory we might ignore int i = temp.ReverseFind(_T('\\')); if (i >= 0) temp.Truncate(i); } else { type = DT_REG; int x = temp.ReverseFind(_T('\\')); if (x >= 2) temp.Truncate(x); } int pos = patha.ReverseFind('/'); const char * base = (pos >= 0) ? ((const char*)patha + pos + 1) : patha; int ret = -1; CAutoReadLock lock(m_SharedMutex); while (!temp.IsEmpty()) { CString tempOrig = temp; temp += _T("\\.git"); if (CGit::GitPathFileExists(temp)) { CString gitignore = temp; gitignore += _T("ignore"); if ((ret = CheckFileAgainstIgnoreList(gitignore, patha, base, type)) != -1) break; CString adminDir = g_AdminDirMap.GetAdminDir(tempOrig); CString wcglobalgitignore = adminDir; wcglobalgitignore += _T("info\\exclude"); if ((ret = CheckFileAgainstIgnoreList(wcglobalgitignore, patha, base, type)) != -1) break; CString excludesFile = m_CoreExcludesfiles[adminDir]; if (!excludesFile.IsEmpty()) ret = CheckFileAgainstIgnoreList(excludesFile, patha, base, type); break; } temp += _T("ignore"); if ((ret = CheckFileAgainstIgnoreList(temp, patha, base, type)) != -1) break; int found = 0; int i; for (i = temp.GetLength() - 1; i >= 0; i--) { if (temp[i] == _T('\\')) ++found; if (found == 2) break; } temp.Truncate(i); } return ret; }
void CDirectoryWatcher::WorkerThread() { DWORD numBytes; CDirWatchInfo * pdi = NULL; LPOVERLAPPED lpOverlapped; WCHAR buf[READ_DIR_CHANGE_BUFFER_SIZE] = {0}; WCHAR * pFound = NULL; while (m_bRunning) { CleanupWatchInfo(); if (watchedPaths.GetCount()) { // Any incoming notifications? pdi = NULL; numBytes = 0; InterlockedExchange(&m_bCleaned, FALSE); if ((!m_hCompPort) || !GetQueuedCompletionStatus(m_hCompPort, &numBytes, (PULONG_PTR) &pdi, &lpOverlapped, 600000 /*10 minutes*/)) { // No. Still trying? if (!m_bRunning) return; ATLTRACE(_T(": restarting watcher\n")); m_hCompPort.CloseHandle(); // We must sync the whole section because other threads may // receive "AddPath" calls that will delete the completion // port *while* we are adding references to it . AutoLocker lock(m_critSec); // Clear the list of watched objects and recreate that list. // This will also delete the old completion port ClearInfoMap(); CleanupWatchInfo(); for (int i=0; i<watchedPaths.GetCount(); ++i) { CTGitPath watchedPath = watchedPaths[i]; CAutoFile hDir = CreateFile(watchedPath.GetWinPath(), FILE_LIST_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, //security attributes OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | //required privileges: SE_BACKUP_NAME and SE_RESTORE_NAME. FILE_FLAG_OVERLAPPED, NULL); if (!hDir) { // this could happen if a watched folder has been removed/renamed ATLTRACE(_T("CDirectoryWatcher: CreateFile failed. Can't watch directory %s\n"), watchedPaths[i].GetWinPath()); watchedPaths.RemovePath(watchedPath); break; } DEV_BROADCAST_HANDLE NotificationFilter; SecureZeroMemory(&NotificationFilter, sizeof(NotificationFilter)); NotificationFilter.dbch_size = sizeof(DEV_BROADCAST_HANDLE); NotificationFilter.dbch_devicetype = DBT_DEVTYP_HANDLE; NotificationFilter.dbch_handle = hDir; // RegisterDeviceNotification sends a message to the UI thread: // make sure we *can* send it and that the UI thread isn't waiting on a lock int numPaths = watchedPaths.GetCount(); size_t numWatch = watchInfoMap.size(); lock.Unlock(); NotificationFilter.dbch_hdevnotify = RegisterDeviceNotification(hWnd, &NotificationFilter, DEVICE_NOTIFY_WINDOW_HANDLE); lock.Lock(); // since we released the lock to prevent a deadlock with the UI thread, // it could happen that new paths were added to watch, or another thread // could have cleared our info map. // if that happened, we have to restart watching all paths again. if ((numPaths != watchedPaths.GetCount()) || (numWatch != watchInfoMap.size())) { ClearInfoMap(); CleanupWatchInfo(); Sleep(200); break; } CDirWatchInfo * pDirInfo = new CDirWatchInfo(hDir, watchedPath); hDir.Detach(); // the new CDirWatchInfo object owns the handle now pDirInfo->m_hDevNotify = NotificationFilter.dbch_hdevnotify; HANDLE port = CreateIoCompletionPort(pDirInfo->m_hDir, m_hCompPort, (ULONG_PTR)pDirInfo, 0); if (port == NULL) { ATLTRACE(_T("CDirectoryWatcher: CreateIoCompletionPort failed. Can't watch directory %s\n"), watchedPath.GetWinPath()); // we must close the directory handle to allow ClearInfoMap() // to close the completion port properly pDirInfo->CloseDirectoryHandle(); ClearInfoMap(); CleanupWatchInfo(); delete pDirInfo; pDirInfo = NULL; watchedPaths.RemovePath(watchedPath); break; } m_hCompPort = port; if (!ReadDirectoryChangesW(pDirInfo->m_hDir, pDirInfo->m_Buffer, READ_DIR_CHANGE_BUFFER_SIZE, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &numBytes,// not used &pDirInfo->m_Overlapped, NULL)) //no completion routine! { ATLTRACE(_T("CDirectoryWatcher: ReadDirectoryChangesW failed. Can't watch directory %s\n"), watchedPath.GetWinPath()); // we must close the directory handle to allow ClearInfoMap() // to close the completion port properly pDirInfo->CloseDirectoryHandle(); ClearInfoMap(); CleanupWatchInfo(); delete pDirInfo; pDirInfo = NULL; watchedPaths.RemovePath(watchedPath); break; } ATLTRACE(_T("watching path %s\n"), pDirInfo->m_DirName.GetWinPath()); watchInfoMap[pDirInfo->m_hDir] = pDirInfo; } } else { if (!m_bRunning) return; if (watchInfoMap.empty()) continue; // NOTE: the longer this code takes to execute until ReadDirectoryChangesW // is called again, the higher the chance that we miss some // changes in the file system! if (pdi) { BOOL bRet = false; std::list<CTGitPath> notifyPaths; { AutoLocker lock(m_critSec); // in case the CDirectoryWatcher objects have been cleaned, // the m_bCleaned variable will be set to true here. If the // objects haven't been cleared, we can access them here. if (InterlockedExchange(&m_bCleaned, FALSE)) continue; if ( (!pdi->m_hDir) || watchInfoMap.empty() || (watchInfoMap.find(pdi->m_hDir) == watchInfoMap.end())) { continue; } PFILE_NOTIFY_INFORMATION pnotify = (PFILE_NOTIFY_INFORMATION)pdi->m_Buffer; DWORD nOffset = 0; do { pnotify = (PFILE_NOTIFY_INFORMATION)((LPBYTE)pnotify + nOffset); if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; nOffset = pnotify->NextEntryOffset; if (pnotify->FileNameLength >= (READ_DIR_CHANGE_BUFFER_SIZE*sizeof(TCHAR))) continue; SecureZeroMemory(buf, READ_DIR_CHANGE_BUFFER_SIZE*sizeof(TCHAR)); _tcsncpy_s(buf, pdi->m_DirPath, _countof(buf) - 1); errno_t err = _tcsncat_s(buf + pdi->m_DirPath.GetLength(), READ_DIR_CHANGE_BUFFER_SIZE-pdi->m_DirPath.GetLength(), pnotify->FileName, min(READ_DIR_CHANGE_BUFFER_SIZE-pdi->m_DirPath.GetLength(), pnotify->FileNameLength/sizeof(TCHAR))); if (err == STRUNCATE) { continue; } buf[(pnotify->FileNameLength/sizeof(TCHAR))+pdi->m_DirPath.GetLength()] = 0; if (m_FolderCrawler) { if ((pFound = wcsstr(buf, L"\\tmp")) != NULL) { pFound += 4; if (((*pFound)=='\\')||((*pFound)=='\0')) { continue; } } if ((pFound = wcsstr(buf, L":\\RECYCLER\\")) != NULL) { if ((pFound-buf) < 5) { // a notification for the recycle bin - ignore it continue; } } if ((pFound = wcsstr(buf, L":\\$Recycle.Bin\\")) != NULL) { if ((pFound-buf) < 5) { // a notification for the recycle bin - ignore it continue; } } if (wcsstr(buf, L".tmp") != NULL) { // assume files with a .tmp extension are not versioned and interesting, // so ignore them. continue; } CTGitPath path; bool isIndex = false; if ((pFound = wcsstr(buf, L".git")) != NULL) { // omit repository data change except .git/index.lock- or .git/HEAD.lock-files if ((ULONG_PTR)pnotify - (ULONG_PTR)pdi->m_Buffer > READ_DIR_CHANGE_BUFFER_SIZE) break; path = g_AdminDirMap.GetWorkingCopy(CTGitPath(buf).GetContainingDirectory().GetWinPathString()); if ((wcsstr(pFound, L"index.lock") != NULL || wcsstr(pFound, L"HEAD.lock") != NULL) && pnotify->Action == FILE_ACTION_ADDED) { CGitStatusCache::Instance().BlockPath(path); continue; } else if (((wcsstr(pFound, L"index.lock") != NULL || wcsstr(pFound, L"HEAD.lock") != NULL) && pnotify->Action == FILE_ACTION_REMOVED) || (((wcsstr(pFound, L"index") != NULL && wcsstr(pFound, L"index.lock") == NULL) || (wcsstr(pFound, L"HEAD") != NULL && wcsstr(pFound, L"HEAD.lock") != NULL)) && pnotify->Action == FILE_ACTION_MODIFIED) || ((wcsstr(pFound, L"index.lock") == NULL || wcsstr(pFound, L"HEAD.lock") != NULL) && pnotify->Action == FILE_ACTION_RENAMED_NEW_NAME)) { isIndex = true; CGitStatusCache::Instance().BlockPath(path, 1); } else { continue; } } else path.SetFromUnknown(buf); if(!path.HasAdminDir() && !isIndex) continue; ATLTRACE(_T("change notification: %s\n"), buf); notifyPaths.push_back(path); } } while ((nOffset > 0)&&(nOffset < READ_DIR_CHANGE_BUFFER_SIZE)); // setup next notification cycle SecureZeroMemory (pdi->m_Buffer, sizeof(pdi->m_Buffer)); SecureZeroMemory (&pdi->m_Overlapped, sizeof(OVERLAPPED)); bRet = ReadDirectoryChangesW(pdi->m_hDir, pdi->m_Buffer, READ_DIR_CHANGE_BUFFER_SIZE, TRUE, FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE, &numBytes,// not used &pdi->m_Overlapped, NULL); //no completion routine! } if (!notifyPaths.empty()) { for (std::list<CTGitPath>::const_iterator nit = notifyPaths.begin(); nit != notifyPaths.end(); ++nit) { m_FolderCrawler->AddPathForUpdate(*nit); } } // any clean-up to do? CleanupWatchInfo(); if (!bRet) { // Since the call to ReadDirectoryChangesW failed, just // wait a while. We don't want to have this thread // running using 100% CPU if something goes completely // wrong. Sleep(200); } } } }// if (watchedPaths.GetCount()) else Sleep(200); }// while (m_bRunning) }
int CGitHeadFileList::ReadHeadHash(CString gitdir) { int ret = 0; CAutoWriteLock lock(&this->m_SharedMutex); m_Gitdir = g_AdminDirMap.GetAdminDir(gitdir); m_HeadFile = m_Gitdir + _T("HEAD"); if( g_Git.GetFileModifyTime(m_HeadFile, &m_LastModifyTimeHead)) return -1; try { do { CAutoFile hfile = CreateFile(m_HeadFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (!hfile) { ret = -1; break; } DWORD size = 0; unsigned char buffer[40] ; ReadFile(hfile, buffer, 4, &size, NULL); if (size != 4) { ret = -1; break; } buffer[4]=0; if (strcmp((const char*)buffer,"ref:") == 0) { DWORD filesize = GetFileSize(hfile, NULL); if (filesize < 5) { m_HeadRefFile.Empty(); ret = -1; break; } unsigned char *p = (unsigned char*)malloc(filesize -4); ReadFile(hfile, p, filesize - 4, &size, NULL); m_HeadRefFile.Empty(); g_Git.StringAppend(&this->m_HeadRefFile, p, CP_UTF8, filesize - 4); CString ref = this->m_HeadRefFile; ref = ref.Trim(); int start = 0; ref = ref.Tokenize(_T("\n"), start); free(p); m_HeadRefFile = m_Gitdir + m_HeadRefFile.Trim(); m_HeadRefFile.Replace(_T('/'),_T('\\')); __int64 time; if (g_Git.GetFileModifyTime(m_HeadRefFile, &time, NULL)) { m_HeadRefFile.Empty(); if (GetPackRef(gitdir)) { ret = -1; break; } if (this->m_PackRefMap.find(ref) == m_PackRefMap.end()) { ret = -1; break; } this ->m_Head = m_PackRefMap[ref]; ret = 0; break; } CAutoFile href = CreateFile(m_HeadRefFile, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (!href) { m_HeadRefFile.Empty(); if (GetPackRef(gitdir)) { ret = -1; break; } if (this->m_PackRefMap.find(ref) == m_PackRefMap.end()) { ret = -1; break; } this ->m_Head = m_PackRefMap[ref]; ret = 0; break; } ReadFile(href, buffer, 40, &size, NULL); if (size != 40) { ret = -1; break; } this->m_Head.ConvertFromStrA((char*)buffer); this->m_LastModifyTimeRef = time; } else { ReadFile(hfile, buffer + 4, 40 - 4, &size, NULL); if(size != 36) { ret = -1; break; } m_HeadRefFile.Empty(); this->m_Head.ConvertFromStrA((char*)buffer); } } while(0); } catch(...) { ret = -1; } return ret; }
// This method is assumed to be called with m_SharedMutex locked. int CGitHeadFileList::GetPackRef(const CString &gitdir) { CString PackRef = g_AdminDirMap.GetAdminDir(gitdir) + _T("packed-refs"); __int64 mtime; if (g_Git.GetFileModifyTime(PackRef, &mtime)) { //packed refs is not existed this->m_PackRefFile.Empty(); this->m_PackRefMap.clear(); return 0; } else if(mtime == m_LastModifyTimePackRef) { return 0; } else { this->m_PackRefFile = PackRef; this->m_LastModifyTimePackRef = mtime; } int ret = 0; { this->m_PackRefMap.clear(); CAutoFile hfile = CreateFile(PackRef, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); do { if (!hfile) { ret = -1; break; } DWORD filesize = GetFileSize(hfile, NULL); if (filesize == 0) { ret = -1; break; } DWORD size =0; char *buff; buff = new char[filesize]; ReadFile(hfile, buff, filesize, &size, NULL); if (size != filesize) { delete[] buff; ret = -1; break; } CString hash; CString ref; for(DWORD i=0; i<filesize;) { hash.Empty(); ref.Empty(); if (buff[i] == '#' || buff[i] == '^') { while (buff[i] != '\n') { ++i; if (i == filesize) break; } ++i; } if (i >= filesize) break; while (buff[i] != ' ') { hash.AppendChar(buff[i]); ++i; if (i == filesize) break; } ++i; if (i >= filesize) break; while (buff[i] != '\n') { ref.AppendChar(buff[i]); ++i; if (i == filesize) break; } if (!ref.IsEmpty() ) { this->m_PackRefMap[ref] = hash; } while (buff[i] == '\n') { ++i; if (i == filesize) break; } } delete[] buff; } while(0); } return ret; }
int CGitIgnoreList::CheckIgnore(const CString &path,const CString &projectroot) { __int64 time = 0; bool dir = 0; CString temp = projectroot + _T("\\") + path; temp.Replace(_T('/'), _T('\\')); CStringA patha = CUnicodeUtils::GetMulti(path, CP_UTF8); patha.Replace('\\', '/'); if(g_Git.GetFileModifyTime(temp, &time, &dir)) return -1; int type = 0; if (dir) { type = DT_DIR; // strip directory name // we do not need to check for a .ignore file inside a directory we might ignore int i = temp.ReverseFind(_T('\\')); if (i >= 0) temp = temp.Left(i); } else type = DT_REG; char * base = NULL; int pos = patha.ReverseFind('/'); base = pos >= 0 ? patha.GetBuffer() + pos + 1 : patha.GetBuffer(); int ret = -1; CAutoReadLock lock(&this->m_SharedMutex); while (!temp.IsEmpty()) { CString tempOrig = temp; temp += _T("\\.git"); if (CGit::GitPathFileExists(temp)) { CString gitignore = temp; gitignore += _T("ignore"); if ((ret = CheckFileAgainstIgnoreList(gitignore, patha, base, type)) != -1) break; CString adminDir = g_AdminDirMap.GetAdminDir(tempOrig); CString wcglobalgitignore = adminDir + _T("info\\exclude"); if ((ret = CheckFileAgainstIgnoreList(wcglobalgitignore, patha, base, type)) != -1) break; m_SharedMutex.AcquireShared(); CString excludesFile = m_CoreExcludesfiles[adminDir]; m_SharedMutex.ReleaseShared(); if (!excludesFile.IsEmpty()) ret = CheckFileAgainstIgnoreList(excludesFile, patha, base, type); break; } else { temp += _T("ignore"); if ((ret = CheckFileAgainstIgnoreList(temp, patha, base, type)) != -1) break; } int found = 0; int i; for (i = temp.GetLength() - 1; i >= 0; i--) { if (temp[i] == _T('\\')) ++found; if (found == 2) break; } temp = temp.Left(i); } patha.ReleaseBuffer(); return ret; }
int CGitIgnoreList::LoadAllIgnoreFile(const CString &gitdir,const CString &path) { CString temp; temp = gitdir; temp += _T("\\"); temp += path; temp.Replace(_T('/'), _T('\\')); while (!temp.IsEmpty()) { CString tempOrig = temp; temp += _T("\\.git"); if (CGit::GitPathFileExists(temp)) { CString gitignore = temp; gitignore += _T("ignore"); if (CheckFileChanged(gitignore)) { FetchIgnoreFile(gitdir, gitignore, false); } CString adminDir = g_AdminDirMap.GetAdminDir(tempOrig); CString wcglobalgitignore = adminDir + _T("info\\exclude"); if (CheckFileChanged(wcglobalgitignore)) { FetchIgnoreFile(gitdir, wcglobalgitignore, true); } if (CheckAndUpdateCoreExcludefile(adminDir)) { m_SharedMutex.AcquireShared(); CString excludesFile = m_CoreExcludesfiles[adminDir]; m_SharedMutex.ReleaseShared(); if (!excludesFile.IsEmpty()) FetchIgnoreFile(gitdir, excludesFile, true); } return 0; } else { temp += _T("ignore"); if (CheckFileChanged(temp)) { FetchIgnoreFile(gitdir, temp, false); } } int found = 0; int i; for (i = temp.GetLength() - 1; i >= 0; i--) { if(temp[i] == _T('\\')) ++found; if(found == 2) break; } temp = temp.Left(i); } return 0; }