Add more options to version.txt
[TortoiseGit.git] / src / Git / gitindex.h
blob3ef68fe39c9772e04c4eb4dd216d8d89276c5978
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;
33 __int64 m_Size;
35 int Print();
38 class CGitIndexList:public std::vector<CGitIndex>
40 protected:
42 public:
43 __time64_t m_LastModifyTime;
45 CGitIndexList();
46 ~CGitIndexList();
48 int ReadIndex(CString file);
49 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);
50 protected:
51 bool m_bCheckContent;
52 __int64 m_iMaxCheckSize;
53 CComCriticalSection m_critRepoSec;
54 CAutoRepository repository;
55 int GetFileStatus(const CString &gitdir, const CString &path, git_wc_status_kind * status, __int64 time, __int64 filesize, FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr, CGitHash *pHash = nullptr, bool * assumeValid = nullptr, bool * skipWorktree = nullptr);
56 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);
59 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
60 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
62 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
64 public:
65 CComCriticalSection m_critIndexSec;
67 CGitIndexFileMap() { m_critIndexSec.Init(); }
68 ~CGitIndexFileMap() { m_critIndexSec.Term(); }
70 SHARED_INDEX_PTR SafeGet(const CString &path)
72 CString thePath = path;
73 thePath.MakeLower();
74 CAutoLocker lock(m_critIndexSec);
75 if(this->find(thePath) == end())
76 return SHARED_INDEX_PTR();
77 else
78 return (*this)[thePath];
81 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
83 CString thePath = path;
84 thePath.MakeLower();
85 CAutoLocker lock(m_critIndexSec);
86 (*this)[thePath] = ptr;
89 bool SafeClear(const CString &path)
91 CString thePath = path;
92 thePath.MakeLower();
93 CAutoLocker lock(m_critIndexSec);
94 if (this->find(thePath) == end())
95 return false;
96 (*this)[thePath] = nullptr;
97 return true;
100 bool SafeClearRecursively(const CString &rootpath)
102 CString thePath = rootpath;
103 thePath.MakeLower();
104 CAutoLocker lock(m_critIndexSec);
105 for (auto it = this->begin(); it != this->end(); ++it)
107 if ((*it).first.Find(thePath) == 0)
108 (*this)[(*it).first] = nullptr;
110 return true;
113 int Check(const CString &gitdir, bool *isChanged);
114 int LoadIndex(const CString &gitdir);
116 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
118 bool isChanged=false;
119 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
120 return false;
122 if(isChanged && isLoadUpdatedIndex)
124 LoadIndex(gitdir);
125 return true;
128 return false;
130 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
131 BOOL IsFull=false, BOOL IsRecursive=false,
132 FILL_STATUS_CALLBACK callback = nullptr,
133 void *pData=NULL,CGitHash *pHash=NULL,
134 bool isLoadUpdatedIndex = true, bool * assumeValid = NULL, bool * skipWorktree = NULL);
136 int IsUnderVersionControl(const CString &gitdir,
137 const CString &path,
138 bool isDir,
139 bool *isVersion,
140 bool isLoadUpdateIndex=true);
144 class CGitTreeItem
146 public:
147 CString m_FileName;
148 CGitHash m_Hash;
149 int m_Flags;
152 /* After object create, never change field agains
153 * that needn't lock to get field
155 class CGitHeadFileList:public std::vector<CGitTreeItem>
157 private:
158 int GetPackRef(const CString &gitdir);
159 CReaderWriterLock m_SharedMutex;
161 __time64_t m_LastModifyTimeHead;
162 __time64_t m_LastModifyTimeRef;
163 __time64_t m_LastModifyTimePackRef;
165 CString m_HeadRefFile;
166 CGitHash m_Head;
167 CString m_HeadFile;
168 CString m_Gitdir;
169 CString m_PackRefFile;
171 CGitHash m_TreeHash; /* buffered tree hash value */
173 std::map<CString,CGitHash> m_PackRefMap;
175 public:
176 CGitHeadFileList()
178 m_LastModifyTimeHead=0;
179 m_LastModifyTimeRef=0;
180 m_LastModifyTimePackRef = 0;
183 int ReadTree();
184 int ReadHeadHash(CString gitdir);
185 bool CheckHeadUpdate();
186 bool HeadHashEqualsTreeHash();
187 bool HeadFileIsEmpty();
188 bool HeadIsEmpty();
189 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
192 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
193 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
195 public:
197 CComCriticalSection m_critTreeSec;
199 CGitHeadFileMap() { m_critTreeSec.Init(); }
200 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
202 SHARED_TREE_PTR SafeGet(const CString &path)
204 CString thePath = path;
205 thePath.MakeLower();
206 CAutoLocker lock(m_critTreeSec);
207 if(this->find(thePath) == end())
208 return SHARED_TREE_PTR();
209 else
210 return (*this)[thePath];
213 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
215 CString thePath = path;
216 thePath.MakeLower();
217 CAutoLocker lock(m_critTreeSec);
218 (*this)[thePath] = ptr;
221 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
222 FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr,
223 bool isLoaded=false);
224 bool CheckHeadAndUpdate(const CString &gitdir, bool readTree = true);
225 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
228 class CGitFileName
230 public:
231 CString m_FileName;
232 CString m_CaseFileName;
235 class CGitIgnoreItem
237 public:
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 free(m_buffer);
249 m_pExcludeList=NULL;
250 m_buffer = NULL;
252 __time64_t m_LastModifyTime;
253 CStringA m_BaseDir;
254 BYTE *m_buffer;
255 EXCLUDE_LIST m_pExcludeList;
257 int FetchIgnoreList(const CString &projectroot, const CString &file, bool isGlobal);
260 class CGitIgnoreList
262 private:
263 bool CheckFileChanged(const CString &path);
264 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore, bool isGlobal);
266 int CheckIgnore(const CString &path, const CString &root, bool isDir);
267 int CheckFileAgainstIgnoreList(const CString &ignorefile, const CStringA &patha, const char * base, int &type);
269 // core.excludesfile stuff
270 std::map<CString, CString> m_CoreExcludesfiles;
271 CString m_sMsysGitBinPath;
272 DWORD m_dMsysGitBinPathLastChecked;
273 CReaderWriterLock m_coreExcludefilesSharedMutex;
274 // checks if the msysgit path has changed and return true/false
275 // if the path changed, the cache is update
276 // force is only ised in constructor
277 bool CheckAndUpdateMsysGitBinpath(bool force = true);
278 bool CheckAndUpdateCoreExcludefile(const CString &adminDir);
279 const CString GetWindowsHome();
281 public:
282 CReaderWriterLock m_SharedMutex;
284 CGitIgnoreList(){ CheckAndUpdateMsysGitBinpath(true); }
286 std::map<CString, CGitIgnoreItem> m_Map;
288 bool CheckIgnoreChanged(const CString &gitdir,const CString &path, bool isDir);
289 int LoadAllIgnoreFile(const CString &gitdir, const CString &path, bool isDir);
290 bool IsIgnore(const CString &path, const CString &root, bool isDir);
293 template<class T>
294 int GetRangeInSortVector(const T &vector, LPCTSTR pstr, int len, int *start, int *end, int pos)
296 if( pos < 0)
298 return -1;
300 if(start == 0 || end == NULL)
301 return -1;
303 *start=*end=-1;
305 if (vector.empty())
306 return -1;
308 if (pos >= (int)vector.size())
309 return -1;
311 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
313 for (int i = 0; i < (int)vector.size(); ++i)
315 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
317 if(*start<0)
318 *start =i;
319 *end =i;
322 return -1;
324 else
326 *start =0;
327 *end = (int)vector.size();
329 for (int i = pos; i < (int)vector.size(); ++i)
331 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
333 *end=i;
335 else
337 break;
340 for(int i=pos;i>=0;i--)
342 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
344 *start=i;
346 else
348 break;
352 return 0;
355 template<class T>
356 int SearchInSortVector(const T &vector, LPCTSTR pstr, int len)
358 int end = (int)vector.size() - 1;
359 int start = 0;
360 int mid = (start+end)/2;
362 if (vector.empty())
363 return -1;
365 while(!( start == end && start==mid))
367 int cmp;
368 if(len < 0)
369 cmp = _tcscmp(vector[mid].m_FileName,pstr);
370 else
371 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
373 if (cmp == 0)
374 return mid;
375 else if (cmp < 0)
376 start = mid + 1;
377 else // (cmp > 0)
378 end = mid;
380 mid=(start +end ) /2;
383 if(len <0)
385 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
386 return mid;
388 else
390 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
391 return mid;
393 return -1;
396 class CGitAdminDirMap:public std::map<CString, CString>
398 public:
399 CComCriticalSection m_critIndexSec;
400 std::map<CString, CString> m_reverseLookup;
402 CGitAdminDirMap() { m_critIndexSec.Init(); }
403 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
405 CString GetAdminDir(const CString &path)
407 CString thePath = path;
408 thePath.MakeLower();
409 CAutoLocker lock(m_critIndexSec);
410 if(this->find(thePath) == end())
412 if (PathIsDirectory(path + _T("\\.git")))
414 (*this)[thePath] = path + _T("\\.git\\");
415 m_reverseLookup[thePath + _T("\\.git")] = path;
416 return (*this)[thePath];
418 else
420 FILE * pFile = _tfsopen(path + _T("\\.git"), _T("r"), SH_DENYWR);
421 if (pFile)
423 int size = 65536;
424 std::unique_ptr<char[]> buffer(new char[size]);
425 int length = 0;
426 if ((length = (int)fread(buffer.get(), sizeof(char), size, pFile)) >= 8)
428 fclose(pFile);
429 CStringA strA(buffer.get(), length);
430 if (strA.Left(8) == "gitdir: ")
432 CString str = CUnicodeUtils::GetUnicode(strA.Trim().Mid(8)); // 8 = len("gitdir: ")
433 str.Replace(_T("/"), _T("\\"));
434 str.TrimRight(_T("\\"));
435 if (str.GetLength() > 0 && str[0] == _T('.'))
437 str = path + _T("\\") + str;
438 CString newPath;
439 PathCanonicalize(newPath.GetBuffer(MAX_PATH), str.GetBuffer());
440 newPath.ReleaseBuffer();
441 str.ReleaseBuffer();
442 str = newPath;
444 (*this)[thePath] = str + _T("\\");
445 m_reverseLookup[str.MakeLower()] = path;
446 return (*this)[thePath];
449 else
450 fclose(pFile);
452 return path + _T("\\.git\\"); // in case of an error stick to old behavior
455 else
456 return (*this)[thePath];
459 CString GetWorkingCopy(const CString &gitDir)
461 CString path = gitDir;
462 path.MakeLower();
463 CAutoLocker lock(m_critIndexSec);
464 if (m_reverseLookup.find(path) == m_reverseLookup.end())
465 return gitDir;
466 else
467 return m_reverseLookup[path];