Add an option to the TortoiseGitMerge settings dialog to specify the number of contex...
[TortoiseGit.git] / src / Git / gitindex.h
blobb79ce1a99e7c84bea797cee15994e1f16524276d
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 "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 = 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 SharedMutex 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;
179 m_SharedMutex.Init();
182 ~CGitHeadFileList()
184 m_SharedMutex.Release();
187 int ReadTree();
188 int ReadHeadHash(CString gitdir);
189 bool CheckHeadUpdate();
190 bool HeadHashEqualsTreeHash();
191 bool HeadFileIsEmpty();
192 bool HeadIsEmpty();
193 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
196 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
197 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
199 public:
201 CComCriticalSection m_critTreeSec;
203 CGitHeadFileMap() { m_critTreeSec.Init(); }
204 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
206 SHARED_TREE_PTR SafeGet(const CString &path)
208 CString thePath = path;
209 thePath.MakeLower();
210 CAutoLocker lock(m_critTreeSec);
211 if(this->find(thePath) == end())
212 return SHARED_TREE_PTR();
213 else
214 return (*this)[thePath];
217 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
219 CString thePath = path;
220 thePath.MakeLower();
221 CAutoLocker lock(m_critTreeSec);
222 (*this)[thePath] = ptr;
225 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
226 FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr,
227 bool isLoaded=false);
228 bool CheckHeadAndUpdate(const CString &gitdir, bool readTree = true);
229 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
232 class CGitFileName
234 public:
235 CString m_FileName;
236 CString m_CaseFileName;
239 class CGitIgnoreItem
241 public:
242 SharedMutex m_SharedMutex;
244 CGitIgnoreItem()
246 m_LastModifyTime =0;
247 m_pExcludeList =NULL;
248 m_buffer = NULL;
250 ~CGitIgnoreItem()
252 if(m_pExcludeList)
253 git_free_exclude_list(m_pExcludeList);
254 if (m_buffer)
255 free(m_buffer);
256 m_pExcludeList=NULL;
257 m_buffer = NULL;
259 __time64_t m_LastModifyTime;
260 CStringA m_BaseDir;
261 BYTE *m_buffer;
262 EXCLUDE_LIST m_pExcludeList;
264 int FetchIgnoreList(const CString &projectroot, const CString &file, bool isGlobal);
267 class CGitIgnoreList
269 private:
270 bool CheckFileChanged(const CString &path);
271 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore, bool isGlobal);
273 int CheckIgnore(const CString &path, const CString &root, bool isDir);
274 int CheckFileAgainstIgnoreList(const CString &ignorefile, const CStringA &patha, const char * base, int &type);
276 // core.excludesfile stuff
277 std::map<CString, CString> m_CoreExcludesfiles;
278 CString m_sMsysGitBinPath;
279 DWORD m_dMsysGitBinPathLastChecked;
280 SharedMutex m_coreExcludefilesSharedMutex;
281 // checks if the msysgit path has changed and return true/false
282 // if the path changed, the cache is update
283 // force is only ised in constructor
284 bool CheckAndUpdateMsysGitBinpath(bool force = true);
285 bool CheckAndUpdateCoreExcludefile(const CString &adminDir);
286 const CString GetWindowsHome();
288 public:
289 SharedMutex m_SharedMutex;
291 CGitIgnoreList(){ m_SharedMutex.Init(); m_coreExcludefilesSharedMutex.Init(); CheckAndUpdateMsysGitBinpath(true); }
292 ~CGitIgnoreList() { m_SharedMutex.Release(); m_coreExcludefilesSharedMutex.Release(); }
294 std::map<CString, CGitIgnoreItem> m_Map;
296 bool CheckIgnoreChanged(const CString &gitdir,const CString &path, bool isDir);
297 int LoadAllIgnoreFile(const CString &gitdir, const CString &path, bool isDir);
298 bool IsIgnore(const CString &path, const CString &root, bool isDir);
301 template<class T>
302 int GetRangeInSortVector(const T &vector, LPCTSTR pstr, int len, int *start, int *end, int pos)
304 if( pos < 0)
306 return -1;
308 if(start == 0 || end == NULL)
309 return -1;
311 *start=*end=-1;
313 if (vector.empty())
314 return -1;
316 if (pos >= (int)vector.size())
317 return -1;
319 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
321 for (int i = 0; i < (int)vector.size(); ++i)
323 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
325 if(*start<0)
326 *start =i;
327 *end =i;
330 return -1;
332 else
334 *start =0;
335 *end = (int)vector.size();
337 for (int i = pos; i < (int)vector.size(); ++i)
339 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
341 *end=i;
343 else
345 break;
348 for(int i=pos;i>=0;i--)
350 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
352 *start=i;
354 else
356 break;
360 return 0;
363 template<class T>
364 int SearchInSortVector(const T &vector, LPCTSTR pstr, int len)
366 int end = (int)vector.size() - 1;
367 int start = 0;
368 int mid = (start+end)/2;
370 if (vector.empty())
371 return -1;
373 while(!( start == end && start==mid))
375 int cmp;
376 if(len < 0)
377 cmp = _tcscmp(vector[mid].m_FileName,pstr);
378 else
379 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
381 if (cmp == 0)
382 return mid;
383 else if (cmp < 0)
384 start = mid + 1;
385 else // (cmp > 0)
386 end = mid;
388 mid=(start +end ) /2;
391 if(len <0)
393 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
394 return mid;
396 else
398 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
399 return mid;
401 return -1;
404 class CGitAdminDirMap:public std::map<CString, CString>
406 public:
407 CComCriticalSection m_critIndexSec;
408 std::map<CString, CString> m_reverseLookup;
410 CGitAdminDirMap() { m_critIndexSec.Init(); }
411 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
413 CString GetAdminDir(const CString &path)
415 CString thePath = path;
416 thePath.MakeLower();
417 CAutoLocker lock(m_critIndexSec);
418 if(this->find(thePath) == end())
420 if (PathIsDirectory(path + _T("\\.git")))
422 (*this)[thePath] = path + _T("\\.git\\");
423 m_reverseLookup[thePath + _T("\\.git")] = path;
424 return (*this)[thePath];
426 else
428 FILE * pFile = _tfsopen(path + _T("\\.git"), _T("r"), SH_DENYWR);
429 if (pFile)
431 int size = 65536;
432 std::unique_ptr<char[]> buffer(new char[size]);
433 int length = 0;
434 if ((length = (int)fread(buffer.get(), sizeof(char), size, pFile)) >= 8)
436 fclose(pFile);
437 CStringA strA(buffer.get(), length);
438 if (strA.Left(8) == "gitdir: ")
440 CString str = CUnicodeUtils::GetUnicode(strA.Trim().Mid(8)); // 8 = len("gitdir: ")
441 str.Replace(_T("/"), _T("\\"));
442 str.TrimRight(_T("\\"));
443 if (str.GetLength() > 0 && str[0] == _T('.'))
445 str = path + _T("\\") + str;
446 CString newPath;
447 PathCanonicalize(newPath.GetBuffer(MAX_PATH), str.GetBuffer());
448 newPath.ReleaseBuffer();
449 str.ReleaseBuffer();
450 str = newPath;
452 (*this)[thePath] = str + _T("\\");
453 m_reverseLookup[str.MakeLower()] = path;
454 return (*this)[thePath];
457 else
458 fclose(pFile);
460 return path + _T("\\.git\\"); // in case of an error stick to old behavior
463 else
464 return (*this)[thePath];
467 CString GetWorkingCopy(const CString &gitDir)
469 CString path = gitDir;
470 path.MakeLower();
471 CAutoLocker lock(m_critIndexSec);
472 if (m_reverseLookup.find(path) == m_reverseLookup.end())
473 return gitDir;
474 else
475 return m_reverseLookup[path];