Reduce number of ShareMutex classes
[TortoiseGit.git] / src / Git / gitindex.h
blob66b39a832e351390aeb663ba31b1695330777661
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2014 - TortoiseGit
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "GitHash.h"
21 #include "gitdll.h"
22 #include "GitStatus.h"
23 #include "UnicodeUtils.h"
24 #include "ReaderWriterLock.h"
26 class CGitIndex
28 public:
29 CString m_FileName;
30 __time64_t m_ModifyTime;
31 unsigned short m_Flags;
32 CGitHash m_IndexHash;
34 int Print();
37 class CGitIndexList:public std::vector<CGitIndex>
39 protected:
41 public:
42 __time64_t m_LastModifyTime;
44 CGitIndexList();
45 ~CGitIndexList();
47 int ReadIndex(CString file);
48 int GetStatus(const CString &gitdir, const CString &path, git_wc_status_kind * status, BOOL IsFull = false, BOOL IsRecursive = false, FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr, CGitHash *pHash = nullptr, bool * assumeValid = nullptr, bool * skipWorktree = nullptr);
49 protected:
50 bool m_bCheckContent;
51 CComCriticalSection m_critRepoSec;
52 CAutoRepository repository;
53 int GetFileStatus(const CString &gitdir, const CString &path, git_wc_status_kind * status, __int64 time, FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr, CGitHash *pHash = nullptr, bool * assumeValid = nullptr, bool * skipWorktree = nullptr);
54 int GetDirStatus(const CString &gitdir, const CString &path, git_wc_status_kind * status,__int64 time, FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr,CGitHash *pHash = nullptr);
57 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
58 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
60 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
62 public:
63 CComCriticalSection m_critIndexSec;
65 CGitIndexFileMap() { m_critIndexSec.Init(); }
66 ~CGitIndexFileMap() { m_critIndexSec.Term(); }
68 SHARED_INDEX_PTR SafeGet(const CString &path)
70 CString thePath = path;
71 thePath.MakeLower();
72 CAutoLocker lock(m_critIndexSec);
73 if(this->find(thePath) == end())
74 return SHARED_INDEX_PTR();
75 else
76 return (*this)[thePath];
79 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
81 CString thePath = path;
82 thePath.MakeLower();
83 CAutoLocker lock(m_critIndexSec);
84 (*this)[thePath] = ptr;
87 bool SafeClear(const CString &path)
89 CString thePath = path;
90 thePath.MakeLower();
91 CAutoLocker lock(m_critIndexSec);
92 if (this->find(thePath) == end())
93 return false;
94 (*this)[thePath] = nullptr;
95 return true;
98 bool SafeClearRecursively(const CString &rootpath)
100 CString thePath = rootpath;
101 thePath.MakeLower();
102 CAutoLocker lock(m_critIndexSec);
103 for (auto it = this->begin(); it != this->end(); ++it)
105 if ((*it).first.Find(thePath) == 0)
106 (*this)[(*it).first] = nullptr;
108 return true;
111 int Check(const CString &gitdir, bool *isChanged);
112 int LoadIndex(const CString &gitdir);
114 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
116 bool isChanged=false;
117 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
118 return false;
120 if(isChanged && isLoadUpdatedIndex)
122 LoadIndex(gitdir);
123 return true;
126 return false;
128 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
129 BOOL IsFull=false, BOOL IsRecursive=false,
130 FILL_STATUS_CALLBACK callback = nullptr,
131 void *pData=NULL,CGitHash *pHash=NULL,
132 bool isLoadUpdatedIndex = true, bool * assumeValid = NULL, bool * skipWorktree = NULL);
134 int IsUnderVersionControl(const CString &gitdir,
135 const CString &path,
136 bool isDir,
137 bool *isVersion,
138 bool isLoadUpdateIndex=true);
142 class CGitTreeItem
144 public:
145 CString m_FileName;
146 CGitHash m_Hash;
147 int m_Flags;
150 /* After object create, never change field agains
151 * that needn't lock to get field
153 class CGitHeadFileList:public std::vector<CGitTreeItem>
155 private:
156 int GetPackRef(const CString &gitdir);
157 CReaderWriterLock m_SharedMutex;
159 __time64_t m_LastModifyTimeHead;
160 __time64_t m_LastModifyTimeRef;
161 __time64_t m_LastModifyTimePackRef;
163 CString m_HeadRefFile;
164 CGitHash m_Head;
165 CString m_HeadFile;
166 CString m_Gitdir;
167 CString m_PackRefFile;
169 CGitHash m_TreeHash; /* buffered tree hash value */
171 std::map<CString,CGitHash> m_PackRefMap;
173 public:
174 CGitHeadFileList()
176 m_LastModifyTimeHead=0;
177 m_LastModifyTimeRef=0;
178 m_LastModifyTimePackRef = 0;
181 int ReadTree();
182 int ReadHeadHash(CString gitdir);
183 bool CheckHeadUpdate();
184 bool HeadHashEqualsTreeHash();
185 bool HeadFileIsEmpty();
186 bool HeadIsEmpty();
187 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
190 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
191 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
193 public:
195 CComCriticalSection m_critTreeSec;
197 CGitHeadFileMap() { m_critTreeSec.Init(); }
198 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
200 SHARED_TREE_PTR SafeGet(const CString &path)
202 CString thePath = path;
203 thePath.MakeLower();
204 CAutoLocker lock(m_critTreeSec);
205 if(this->find(thePath) == end())
206 return SHARED_TREE_PTR();
207 else
208 return (*this)[thePath];
211 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
213 CString thePath = path;
214 thePath.MakeLower();
215 CAutoLocker lock(m_critTreeSec);
216 (*this)[thePath] = ptr;
219 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
220 FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr,
221 bool isLoaded=false);
222 bool CheckHeadAndUpdate(const CString &gitdir, bool readTree = true);
223 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
226 class CGitFileName
228 public:
229 CString m_FileName;
230 CString m_CaseFileName;
233 class CGitIgnoreItem
235 public:
236 CReaderWriterLock m_SharedMutex;
238 CGitIgnoreItem()
240 m_LastModifyTime =0;
241 m_pExcludeList =NULL;
242 m_buffer = NULL;
244 ~CGitIgnoreItem()
246 if(m_pExcludeList)
247 git_free_exclude_list(m_pExcludeList);
248 if (m_buffer)
249 free(m_buffer);
250 m_pExcludeList=NULL;
251 m_buffer = NULL;
253 __time64_t m_LastModifyTime;
254 CStringA m_BaseDir;
255 BYTE *m_buffer;
256 EXCLUDE_LIST m_pExcludeList;
258 int FetchIgnoreList(const CString &projectroot, const CString &file, bool isGlobal);
261 class CGitIgnoreList
263 private:
264 bool CheckFileChanged(const CString &path);
265 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore, bool isGlobal);
267 int CheckIgnore(const CString &path, const CString &root, bool isDir);
268 int CheckFileAgainstIgnoreList(const CString &ignorefile, const CStringA &patha, const char * base, int &type);
270 // core.excludesfile stuff
271 std::map<CString, CString> m_CoreExcludesfiles;
272 CString m_sMsysGitBinPath;
273 DWORD m_dMsysGitBinPathLastChecked;
274 CReaderWriterLock m_coreExcludefilesSharedMutex;
275 // checks if the msysgit path has changed and return true/false
276 // if the path changed, the cache is update
277 // force is only ised in constructor
278 bool CheckAndUpdateMsysGitBinpath(bool force = true);
279 bool CheckAndUpdateCoreExcludefile(const CString &adminDir);
280 const CString GetWindowsHome();
282 public:
283 CReaderWriterLock m_SharedMutex;
285 CGitIgnoreList(){ CheckAndUpdateMsysGitBinpath(true); }
287 std::map<CString, CGitIgnoreItem> m_Map;
289 bool CheckIgnoreChanged(const CString &gitdir,const CString &path, bool isDir);
290 int LoadAllIgnoreFile(const CString &gitdir, const CString &path, bool isDir);
291 bool IsIgnore(const CString &path, const CString &root, bool isDir);
294 template<class T>
295 int GetRangeInSortVector(const T &vector, LPCTSTR pstr, int len, int *start, int *end, int pos)
297 if( pos < 0)
299 return -1;
301 if(start == 0 || end == NULL)
302 return -1;
304 *start=*end=-1;
306 if (vector.empty())
307 return -1;
309 if (pos >= (int)vector.size())
310 return -1;
312 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
314 for (int i = 0; i < (int)vector.size(); ++i)
316 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
318 if(*start<0)
319 *start =i;
320 *end =i;
323 return -1;
325 else
327 *start =0;
328 *end = (int)vector.size();
330 for (int i = pos; i < (int)vector.size(); ++i)
332 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
334 *end=i;
336 else
338 break;
341 for(int i=pos;i>=0;i--)
343 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
345 *start=i;
347 else
349 break;
353 return 0;
356 template<class T>
357 int SearchInSortVector(const T &vector, LPCTSTR pstr, int len)
359 int end = (int)vector.size() - 1;
360 int start = 0;
361 int mid = (start+end)/2;
363 if (vector.empty())
364 return -1;
366 while(!( start == end && start==mid))
368 int cmp;
369 if(len < 0)
370 cmp = _tcscmp(vector[mid].m_FileName,pstr);
371 else
372 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
374 if (cmp == 0)
375 return mid;
376 else if (cmp < 0)
377 start = mid + 1;
378 else // (cmp > 0)
379 end = mid;
381 mid=(start +end ) /2;
384 if(len <0)
386 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
387 return mid;
389 else
391 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
392 return mid;
394 return -1;
397 class CGitAdminDirMap:public std::map<CString, CString>
399 public:
400 CComCriticalSection m_critIndexSec;
401 std::map<CString, CString> m_reverseLookup;
403 CGitAdminDirMap() { m_critIndexSec.Init(); }
404 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
406 CString GetAdminDir(const CString &path)
408 CString thePath = path;
409 thePath.MakeLower();
410 CAutoLocker lock(m_critIndexSec);
411 if(this->find(thePath) == end())
413 if (PathIsDirectory(path + _T("\\.git")))
415 (*this)[thePath] = path + _T("\\.git\\");
416 m_reverseLookup[thePath + _T("\\.git")] = path;
417 return (*this)[thePath];
419 else
421 FILE * pFile = _tfsopen(path + _T("\\.git"), _T("r"), SH_DENYWR);
422 if (pFile)
424 int size = 65536;
425 std::unique_ptr<char[]> buffer(new char[size]);
426 int length = 0;
427 if ((length = (int)fread(buffer.get(), sizeof(char), size, pFile)) >= 8)
429 fclose(pFile);
430 CStringA strA(buffer.get(), length);
431 if (strA.Left(8) == "gitdir: ")
433 CString str = CUnicodeUtils::GetUnicode(strA.Trim().Mid(8)); // 8 = len("gitdir: ")
434 str.Replace(_T("/"), _T("\\"));
435 str.TrimRight(_T("\\"));
436 if (str.GetLength() > 0 && str[0] == _T('.'))
438 str = path + _T("\\") + str;
439 CString newPath;
440 PathCanonicalize(newPath.GetBuffer(MAX_PATH), str.GetBuffer());
441 newPath.ReleaseBuffer();
442 str.ReleaseBuffer();
443 str = newPath;
445 (*this)[thePath] = str + _T("\\");
446 m_reverseLookup[str.MakeLower()] = path;
447 return (*this)[thePath];
450 else
451 fclose(pFile);
453 return path + _T("\\.git\\"); // in case of an error stick to old behavior
456 else
457 return (*this)[thePath];
460 CString GetWorkingCopy(const CString &gitDir)
462 CString path = gitDir;
463 path.MakeLower();
464 CAutoLocker lock(m_critIndexSec);
465 if (m_reverseLookup.find(path) == m_reverseLookup.end())
466 return gitDir;
467 else
468 return m_reverseLookup[path];