Moved #include "git2.h" to stdafx.h
[TortoiseGit.git] / src / Git / gitindex.h
bloba4fa9395891e05eef73edf83bbe7c1c8ad4a0d25
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2013 - 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"
24 #include "UnicodeUtils.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 = NULL, void *pData = NULL,CGitHash *pHash=NULL, bool * assumeValid = NULL, bool * skipWorktree = NULL);
49 protected:
50 bool m_bCheckContent;
51 CComCriticalSection m_critRepoSec;
52 git_repository * repository;
53 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, bool * skipWorktree = NULL);
54 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);
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 int Check(const CString &gitdir, bool *isChanged);
88 int LoadIndex(const CString &gitdir);
90 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
92 bool isChanged=false;
93 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
94 return false;
96 if(isChanged && isLoadUpdatedIndex)
98 LoadIndex(gitdir);
99 return true;
102 return false;
104 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
105 BOOL IsFull=false, BOOL IsRecursive=false,
106 FIll_STATUS_CALLBACK callback=NULL,
107 void *pData=NULL,CGitHash *pHash=NULL,
108 bool isLoadUpdatedIndex = true, bool * assumeValid = NULL, bool * skipWorktree = NULL);
110 int IsUnderVersionControl(const CString &gitdir,
111 const CString &path,
112 bool isDir,
113 bool *isVersion,
114 bool isLoadUpdateIndex=true);
118 class CGitTreeItem
120 public:
121 CString m_FileName;
122 CGitHash m_Hash;
123 int m_Flags;
126 /* After object create, never change field agains
127 * that needn't lock to get field
129 class CGitHeadFileList:public std::vector<CGitTreeItem>
131 private:
132 int GetPackRef(const CString &gitdir);
133 SharedMutex m_SharedMutex;
135 __time64_t m_LastModifyTimeHead;
136 __time64_t m_LastModifyTimeRef;
137 __time64_t m_LastModifyTimePackRef;
139 CString m_HeadRefFile;
140 CGitHash m_Head;
141 CString m_HeadFile;
142 CString m_Gitdir;
143 CString m_PackRefFile;
145 CGitHash m_TreeHash; /* buffered tree hash value */
147 std::map<CString,CGitHash> m_PackRefMap;
149 public:
150 CGitHeadFileList()
152 m_LastModifyTimeHead=0;
153 m_LastModifyTimeRef=0;
154 m_LastModifyTimePackRef = 0;
155 m_SharedMutex.Init();
158 ~CGitHeadFileList()
160 m_SharedMutex.Release();
163 int ReadTree();
164 int ReadHeadHash(CString gitdir);
165 bool CheckHeadUpdate();
166 bool HeadHashEqualsTreeHash();
167 bool HeadFileIsEmpty();
168 bool HeadIsEmpty();
169 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
172 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
173 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
175 public:
177 CComCriticalSection m_critTreeSec;
179 CGitHeadFileMap() { m_critTreeSec.Init(); }
180 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
182 SHARED_TREE_PTR SafeGet(const CString &path)
184 CString thePath = path;
185 thePath.MakeLower();
186 CAutoLocker lock(m_critTreeSec);
187 if(this->find(thePath) == end())
188 return SHARED_TREE_PTR();
189 else
190 return (*this)[thePath];
193 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
195 CString thePath = path;
196 thePath.MakeLower();
197 CAutoLocker lock(m_critTreeSec);
198 (*this)[thePath] = ptr;
201 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
202 FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,
203 bool isLoaded=false);
204 bool CheckHeadAndUpdate(const CString &gitdir, bool readTree = true);
205 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
208 class CGitFileName
210 public:
211 CString m_FileName;
212 CString m_CaseFileName;
215 class CGitIgnoreItem
217 public:
218 SharedMutex m_SharedMutex;
220 CGitIgnoreItem()
222 m_LastModifyTime =0;
223 m_pExcludeList =NULL;
224 m_buffer = NULL;
226 ~CGitIgnoreItem()
228 if(m_pExcludeList)
229 git_free_exclude_list(m_pExcludeList);
230 if (m_buffer)
231 free(m_buffer);
232 m_pExcludeList=NULL;
233 m_buffer = NULL;
235 __time64_t m_LastModifyTime;
236 CStringA m_BaseDir;
237 BYTE *m_buffer;
238 EXCLUDE_LIST m_pExcludeList;
240 int FetchIgnoreList(const CString &projectroot, const CString &file, bool isGlobal);
243 class CGitIgnoreList
245 private:
246 bool CheckFileChanged(const CString &path);
247 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore, bool isGlobal);
249 int CheckIgnore(const CString &path,const CString &root);
250 int CheckFileAgainstIgnoreList(const CString &ignorefile, const CStringA &patha, const char * base, int &type);
252 // core.excludesfile stuff
253 std::map<CString, CString> m_CoreExcludesfiles;
254 CString m_sMsysGitBinPath;
255 DWORD m_dMsysGitBinPathLastChecked;
256 SharedMutex m_coreExcludefilesSharedMutex;
257 // checks if the msysgit path has changed and return true/false
258 // if the path changed, the cache is update
259 // force is only ised in constructor
260 bool CheckAndUpdateMsysGitBinpath(bool force = true);
261 bool CheckAndUpdateCoreExcludefile(const CString &adminDir);
262 const CString GetWindowsHome();
264 public:
265 SharedMutex m_SharedMutex;
267 CGitIgnoreList(){ m_SharedMutex.Init(); m_coreExcludefilesSharedMutex.Init(); CheckAndUpdateMsysGitBinpath(true); }
268 ~CGitIgnoreList() { m_SharedMutex.Release(); m_coreExcludefilesSharedMutex.Release(); }
270 std::map<CString, CGitIgnoreItem> m_Map;
272 bool CheckIgnoreChanged(const CString &gitdir,const CString &path);
273 int LoadAllIgnoreFile(const CString &gitdir,const CString &path);
274 bool IsIgnore(const CString &path,const CString &root);
277 template<class T>
278 int GetRangeInSortVector(T &vector,LPTSTR pstr,int len, int *start, int *end, int pos)
280 if( pos < 0)
282 return -1;
284 if(start == 0 || end == NULL)
285 return -1;
287 *start=*end=-1;
289 if (vector.empty())
290 return -1;
292 if (pos >= (int)vector.size())
293 return -1;
295 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
297 for (int i = 0; i < (int)vector.size(); ++i)
299 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
301 if(*start<0)
302 *start =i;
303 *end =i;
306 return -1;
308 else
310 *start =0;
311 *end = (int)vector.size();
313 for (int i = pos; i < (int)vector.size(); ++i)
315 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
317 *end=i;
319 else
321 break;
324 for(int i=pos;i>=0;i--)
326 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
328 *start=i;
330 else
332 break;
336 return 0;
339 template<class T>
340 int SearchInSortVector(T &vector, LPTSTR pstr, int len)
342 int end = (int)vector.size() - 1;
343 int start = 0;
344 int mid = (start+end)/2;
346 if (vector.empty())
347 return -1;
349 while(!( start == end && start==mid))
351 int cmp;
352 if(len < 0)
353 cmp = _tcscmp(vector[mid].m_FileName,pstr);
354 else
355 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
357 if (cmp == 0)
358 return mid;
359 else if (cmp < 0)
360 start = mid + 1;
361 else // (cmp > 0)
362 end = mid;
364 mid=(start +end ) /2;
367 if(len <0)
369 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
370 return mid;
372 else
374 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
375 return mid;
377 return -1;
380 class CGitAdminDirMap:public std::map<CString, CString>
382 public:
383 CComCriticalSection m_critIndexSec;
384 std::map<CString, CString> m_reverseLookup;
386 CGitAdminDirMap() { m_critIndexSec.Init(); }
387 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
389 CString GetAdminDir(const CString &path)
391 CString thePath = path;
392 thePath.MakeLower();
393 CAutoLocker lock(m_critIndexSec);
394 if(this->find(thePath) == end())
396 if (PathIsDirectory(thePath + _T("\\.git")))
398 (*this)[thePath] = thePath + _T("\\.git\\");
399 m_reverseLookup[thePath + _T("\\.git")] = thePath;
400 return (*this)[thePath];
402 else
404 FILE * pFile = _tfsopen(thePath + _T("\\.git"), _T("r"), SH_DENYWR);
405 if (pFile)
407 int size = 65536;
408 std::unique_ptr<char[]> buffer(new char[size]);
409 SecureZeroMemory(buffer.get(), size);
410 if (fread(buffer.get(), sizeof(char), size, pFile))
412 fclose(pFile);
413 CStringA strA(buffer.get());
414 if (strA.Left(8) == "gitdir: ")
416 CString str = CUnicodeUtils::GetUnicode(strA.Trim().Mid(8)); // 8 = len("gitdir: ")
417 str.Replace(_T("/"), _T("\\"));
418 str.TrimRight(_T("\\"));
419 if (str.GetLength() > 0 && str[0] == _T('.'))
421 str = thePath + _T("\\") + str;
422 CString newPath;
423 PathCanonicalize(newPath.GetBuffer(MAX_PATH), str.GetBuffer());
424 newPath.ReleaseBuffer();
425 str.ReleaseBuffer();
426 str = newPath;
428 (*this)[thePath] = str + _T("\\");
429 m_reverseLookup[str.MakeLower()] = path;
430 return (*this)[thePath];
433 else
434 fclose(pFile);
436 return thePath + _T("\\.git\\"); // in case of an error stick to old behavior
439 else
440 return (*this)[thePath];
443 CString GetWorkingCopy(const CString &gitDir)
445 CString path = gitDir;
446 path.MakeLower();
447 CAutoLocker lock(m_critIndexSec);
448 if (m_reverseLookup.find(path) == m_reverseLookup.end())
449 return gitDir;
450 else
451 return m_reverseLookup[path];