TGitCache: Switched to a new locking mechanism
[TortoiseGit.git] / src / Git / gitindex.h
blobf76b76efd1426ceec2f51f2865ee8408573cea19
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2012 - 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 "SharedMutex.h"
25 class CGitIndex
27 public:
28 CString m_FileName;
29 __time64_t m_ModifyTime;
30 unsigned short m_Flags;
31 CGitHash m_IndexHash;
33 int Print();
36 class CGitIndexList:public std::vector<CGitIndex>
38 protected:
40 public:
41 __time64_t m_LastModifyTime;
43 CGitIndexList();
45 int ReadIndex(CString file);
46 int GetStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,CGitHash *pHash=NULL, bool * assumeValid = NULL);
47 protected:
48 int GetFileStatus(const CString &gitdir,const CString &path, git_wc_status_kind * status,__int64 time,FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,CGitHash *pHash=NULL, bool * assumeValid = NULL);
49 int GetDirStatus(const CString &gitdir,const CString &path, git_wc_status_kind * status,__int64 time,FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,CGitHash *pHash=NULL);
52 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
53 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
55 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
57 public:
58 CComCriticalSection m_critIndexSec;
60 CGitIndexFileMap() { m_critIndexSec.Init(); }
61 ~CGitIndexFileMap() { m_critIndexSec.Term(); }
63 SHARED_INDEX_PTR SafeGet(const CString &path)
65 CString thePath = path;
66 thePath.MakeLower();
67 CAutoLocker lock(m_critIndexSec);
68 if(this->find(thePath) == end())
69 return SHARED_INDEX_PTR();
70 else
71 return (*this)[thePath];
74 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
76 CString thePath = path;
77 thePath.MakeLower();
78 CAutoLocker lock(m_critIndexSec);
79 (*this)[thePath] = ptr;
82 int Check(const CString &gitdir, bool *isChanged);
83 int LoadIndex(const CString &gitdir);
85 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
87 bool isChanged=false;
88 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
89 return false;
91 if(isChanged && isLoadUpdatedIndex)
93 LoadIndex(gitdir);
94 return true;
97 return false;
99 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
100 BOOL IsFull=false, BOOL IsRecursive=false,
101 FIll_STATUS_CALLBACK callback=NULL,
102 void *pData=NULL,CGitHash *pHash=NULL,
103 bool isLoadUpdatedIndex=true, bool * assumeValid = NULL);
105 int IsUnderVersionControl(const CString &gitdir,
106 const CString &path,
107 bool isDir,
108 bool *isVersion,
109 bool isLoadUpdateIndex=true);
113 class CGitTreeItem
115 public:
116 CString m_FileName;
117 CGitHash m_Hash;
118 int m_Flags;
121 /* After object create, never change field agains
122 * that needn't lock to get field
124 class CGitHeadFileList:public std::vector<CGitTreeItem>
126 private:
128 int GetPackRef(const CString &gitdir);
129 SharedMutex m_SharedMutex;
131 public:
132 __time64_t m_LastModifyTimeHead;
133 __time64_t m_LastModifyTimeRef;
134 __time64_t m_LastModifyTimePackRef;
136 CString m_HeadRefFile;
137 CGitHash m_Head;
138 CString m_HeadFile;
139 CString m_Gitdir;
140 CString m_PackRefFile;
142 CGitHash m_TreeHash; /* buffered tree hash value */
144 std::map<CString,CGitHash> m_PackRefMap;
146 CGitHeadFileList()
148 m_LastModifyTimeHead=0;
149 m_LastModifyTimeRef=0;
150 m_LastModifyTimePackRef = 0;
151 m_SharedMutex.Init();
154 ~CGitHeadFileList()
156 m_SharedMutex.Release();
159 int ReadTree();
160 int ReadHeadHash(CString gitdir);
161 bool CheckHeadUpdate();
162 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
163 //int ReadTree();
166 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
167 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
169 public:
171 CComCriticalSection m_critTreeSec;
173 CGitHeadFileMap() { m_critTreeSec.Init(); }
174 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
176 SHARED_TREE_PTR SafeGet(const CString &path)
178 CString thePath = path;
179 thePath.MakeLower();
180 CAutoLocker lock(m_critTreeSec);
181 if(this->find(thePath) == end())
182 return SHARED_TREE_PTR();
183 else
184 return (*this)[thePath];
187 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
189 CString thePath = path;
190 thePath.MakeLower();
191 CAutoLocker lock(m_critTreeSec);
192 (*this)[thePath] = ptr;
195 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
196 FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,
197 bool isLoaded=false);
198 bool CheckHeadUpdate(const CString &gitdir);
199 int GetHeadHash(const CString &gitdir, CGitHash &hash);
200 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
203 bool IsHashChanged(const CString &gitdir)
205 SHARED_TREE_PTR ptr = SafeGet(gitdir);
207 if( ptr.get() == NULL)
208 return false;
210 return ptr->m_Head != ptr->m_TreeHash;
215 class CGitFileName
217 public:
218 CString m_FileName;
219 CString m_CaseFileName;
222 class CGitIgnoreItem
224 public:
225 SharedMutex m_SharedMutex;
227 CGitIgnoreItem()
229 m_LastModifyTime =0;
230 m_pExcludeList =NULL;
232 ~CGitIgnoreItem()
234 if(m_pExcludeList)
235 git_free_exclude_list(m_pExcludeList);
236 m_pExcludeList=NULL;
238 __time64_t m_LastModifyTime;
239 CStringA m_BaseDir;
240 EXCLUDE_LIST m_pExcludeList;
241 int FetchIgnoreList(const CString &projectroot, const CString &file, bool isGlobal);
244 class CGitIgnoreList
246 private:
247 bool CheckFileChanged(const CString &path);
248 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore, bool isGlobal);
250 int CheckIgnore(const CString &path,const CString &root);
251 int CheckFileAgainstIgnoreList(const CString &ignorefile, const CStringA &patha, const char * base, int &type);
253 // core.excludesfile stuff
254 std::map<CString, CString> m_CoreExcludesfiles;
255 CString m_sMsysGitBinPath;
256 DWORD m_dMsysGitBinPathLastChecked;
257 SharedMutex m_coreExcludefilesSharedMutex;
258 // checks if the msysgit path has changed and return true/false
259 // if the path changed, the cache is update
260 // force is only ised in constructor
261 bool CheckAndUpdateMsysGitBinpath(bool force = true);
262 bool CheckAndUpdateCoreExcludefile(const CString &adminDir);
263 const CString GetWindowsHome();
265 public:
266 SharedMutex m_SharedMutex;
268 CGitIgnoreList(){ m_SharedMutex.Init(); m_coreExcludefilesSharedMutex.Init(); CheckAndUpdateMsysGitBinpath(true); }
269 ~CGitIgnoreList() { m_SharedMutex.Release(); m_coreExcludefilesSharedMutex.Release(); }
271 std::map<CString, CGitIgnoreItem> m_Map;
273 bool CheckIgnoreChanged(const CString &gitdir,const CString &path);
274 int LoadAllIgnoreFile(const CString &gitdir,const CString &path);
275 bool IsIgnore(const CString &path,const CString &root);
278 template<class T>
279 int GetRangeInSortVector(T &vector,LPTSTR pstr,int len, int *start, int *end, int pos)
281 if( pos < 0)
283 return -1;
285 if(start == 0 || end == NULL)
286 return -1;
288 *start=*end=-1;
290 if(vector.size() ==0)
291 return -1;
293 if(pos >= vector.size())
294 return -1;
296 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
298 for(int i=0;i< vector.size();i++)
300 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
302 if(*start<0)
303 *start =i;
304 *end =i;
307 return -1;
309 else
311 *start =0;
312 *end = vector.size();
314 for(int i=pos;i<vector.size();i++)
316 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
318 *end=i;
320 else
322 break;
325 for(int i=pos;i>=0;i--)
327 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
329 *start=i;
331 else
333 break;
337 return 0;
340 template<class T>
341 int SearchInSortVector(T &vector, LPTSTR pstr, int len)
343 int end=vector.size()-1;
344 int start = 0;
345 int mid = (start+end)/2;
347 if(vector.size() == 0)
348 return -1;
350 while(!( start == end && start==mid))
352 int cmp;
353 if(len < 0)
354 cmp = _tcscmp(vector[mid].m_FileName,pstr);
355 else
356 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
358 if(cmp ==0)
359 return mid;
361 if(cmp < 0)
363 start = mid+1;
366 if(cmp > 0)
368 end=mid;
370 mid=(start +end ) /2;
373 if(len <0)
375 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
376 return mid;
378 else
380 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
381 return mid;
383 return -1;
385 #if 0
387 class CGitStatus
389 protected:
390 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL);
391 public:
392 CGitIgnoreList m_IgnoreList;
393 CGitHeadFileMap m_HeadFilesMap;
394 CGitIndexFileMap m_IndexFilesMap;
396 int GetStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL);
399 #endif
401 class CGitAdminDirMap:public std::map<CString, CString>
403 public:
404 CComCriticalSection m_critIndexSec;
405 std::map<CString, CString> m_reverseLookup;
407 CGitAdminDirMap() { m_critIndexSec.Init(); }
408 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
410 CString GetAdminDir(const CString &path)
412 CString thePath = path;
413 thePath.MakeLower();
414 CAutoLocker lock(m_critIndexSec);
415 if(this->find(thePath) == end())
417 if (PathIsDirectory(thePath + _T("\\.git")))
419 (*this)[thePath] = thePath + _T("\\.git\\");
420 m_reverseLookup[thePath + _T("\\.git")] = thePath;
421 return (*this)[thePath];
423 else
425 FILE * pFile = _tfsopen(thePath + _T("\\.git"), _T("r"), SH_DENYWR);
426 if (pFile)
428 int size = 65536;
429 auto_buffer<char> buffer(size);
430 if (fread(buffer, sizeof(char), size, pFile))
432 fclose(pFile);
433 CString str = CString(buffer);
434 if (str.Left(8) == _T("gitdir: "))
436 str = str.TrimRight().Mid(8);
437 str.Replace(_T("/"), _T("\\"));
438 str.TrimRight(_T("\\"));
439 if (str.GetLength() > 0 && str[0] == _T('.'))
441 str = thePath + _T("\\") + str;
442 CString newPath;
443 PathCanonicalize(newPath.GetBuffer(MAX_PATH), str.GetBuffer());
444 newPath.ReleaseBuffer();
445 str.ReleaseBuffer();
446 str = newPath;
448 (*this)[thePath] = str + _T("\\");
449 m_reverseLookup[str.MakeLower()] = path;
450 return (*this)[thePath];
453 fclose(pFile);
455 return thePath + _T("\\.git\\"); // in case of an error stick to old behavior
458 else
459 return (*this)[thePath];
462 CString GetWorkingCopy(const CString &gitDir)
464 CString path = gitDir;
465 path.MakeLower();
466 CAutoLocker lock(m_critIndexSec);
467 if (m_reverseLookup.find(path) == m_reverseLookup.end())
468 return gitDir;
469 else
470 return m_reverseLookup[path];