Replace var++ by ++var and use size_t where necessary
[TortoiseGit.git] / src / Git / gitindex.h
blobcdc4c6596e60b95729cbe4d2de8e705637347eb3
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 "git2.h"
25 #include "UnicodeUtils.h"
27 class CGitIndex
29 public:
30 CString m_FileName;
31 __time64_t m_ModifyTime;
32 unsigned short m_Flags;
33 CGitHash m_IndexHash;
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 = NULL, void *pData = NULL,CGitHash *pHash=NULL, bool * assumeValid = NULL, bool * skipWorktree = NULL);
50 protected:
51 bool m_bCheckContent;
52 CComCriticalSection m_critRepoSec;
53 git_repository * repository;
54 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);
55 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);
58 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
59 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
61 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
63 public:
64 CComCriticalSection m_critIndexSec;
66 CGitIndexFileMap() { m_critIndexSec.Init(); }
67 ~CGitIndexFileMap() { m_critIndexSec.Term(); }
69 SHARED_INDEX_PTR SafeGet(const CString &path)
71 CString thePath = path;
72 thePath.MakeLower();
73 CAutoLocker lock(m_critIndexSec);
74 if(this->find(thePath) == end())
75 return SHARED_INDEX_PTR();
76 else
77 return (*this)[thePath];
80 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
82 CString thePath = path;
83 thePath.MakeLower();
84 CAutoLocker lock(m_critIndexSec);
85 (*this)[thePath] = ptr;
88 int Check(const CString &gitdir, bool *isChanged);
89 int LoadIndex(const CString &gitdir);
91 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
93 bool isChanged=false;
94 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
95 return false;
97 if(isChanged && isLoadUpdatedIndex)
99 LoadIndex(gitdir);
100 return true;
103 return false;
105 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
106 BOOL IsFull=false, BOOL IsRecursive=false,
107 FIll_STATUS_CALLBACK callback=NULL,
108 void *pData=NULL,CGitHash *pHash=NULL,
109 bool isLoadUpdatedIndex = true, bool * assumeValid = NULL, bool * skipWorktree = NULL);
111 int IsUnderVersionControl(const CString &gitdir,
112 const CString &path,
113 bool isDir,
114 bool *isVersion,
115 bool isLoadUpdateIndex=true);
119 class CGitTreeItem
121 public:
122 CString m_FileName;
123 CGitHash m_Hash;
124 int m_Flags;
127 /* After object create, never change field agains
128 * that needn't lock to get field
130 class CGitHeadFileList:public std::vector<CGitTreeItem>
132 private:
133 int GetPackRef(const CString &gitdir);
134 SharedMutex m_SharedMutex;
136 __time64_t m_LastModifyTimeHead;
137 __time64_t m_LastModifyTimeRef;
138 __time64_t m_LastModifyTimePackRef;
140 CString m_HeadRefFile;
141 CGitHash m_Head;
142 CString m_HeadFile;
143 CString m_Gitdir;
144 CString m_PackRefFile;
146 CGitHash m_TreeHash; /* buffered tree hash value */
148 std::map<CString,CGitHash> m_PackRefMap;
150 public:
151 CGitHeadFileList()
153 m_LastModifyTimeHead=0;
154 m_LastModifyTimeRef=0;
155 m_LastModifyTimePackRef = 0;
156 m_SharedMutex.Init();
159 ~CGitHeadFileList()
161 m_SharedMutex.Release();
164 int ReadTree();
165 int ReadHeadHash(CString gitdir);
166 bool CheckHeadUpdate();
167 bool HeadHashEqualsTreeHash();
168 bool HeadFileIsEmpty();
169 bool HeadIsEmpty();
170 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
173 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
174 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
176 public:
178 CComCriticalSection m_critTreeSec;
180 CGitHeadFileMap() { m_critTreeSec.Init(); }
181 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
183 SHARED_TREE_PTR SafeGet(const CString &path)
185 CString thePath = path;
186 thePath.MakeLower();
187 CAutoLocker lock(m_critTreeSec);
188 if(this->find(thePath) == end())
189 return SHARED_TREE_PTR();
190 else
191 return (*this)[thePath];
194 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
196 CString thePath = path;
197 thePath.MakeLower();
198 CAutoLocker lock(m_critTreeSec);
199 (*this)[thePath] = ptr;
202 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
203 FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,
204 bool isLoaded=false);
205 bool CheckHeadAndUpdate(const CString &gitdir, bool readTree = true);
206 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
209 class CGitFileName
211 public:
212 CString m_FileName;
213 CString m_CaseFileName;
216 class CGitIgnoreItem
218 public:
219 SharedMutex m_SharedMutex;
221 CGitIgnoreItem()
223 m_LastModifyTime =0;
224 m_pExcludeList =NULL;
225 m_buffer = NULL;
227 ~CGitIgnoreItem()
229 if(m_pExcludeList)
230 git_free_exclude_list(m_pExcludeList);
231 if (m_buffer)
232 free(m_buffer);
233 m_pExcludeList=NULL;
234 m_buffer = NULL;
236 __time64_t m_LastModifyTime;
237 CStringA m_BaseDir;
238 BYTE *m_buffer;
239 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.empty())
291 return -1;
293 if (pos >= (int)vector.size())
294 return -1;
296 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
298 for (int i = 0; i < (int)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 = (int)vector.size();
314 for (int i = pos; i < (int)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 = (int)vector.size() - 1;
344 int start = 0;
345 int mid = (start+end)/2;
347 if (vector.empty())
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;
360 else if (cmp < 0)
361 start = mid + 1;
362 else // (cmp > 0)
363 end = mid;
365 mid=(start +end ) /2;
368 if(len <0)
370 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
371 return mid;
373 else
375 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
376 return mid;
378 return -1;
381 class CGitAdminDirMap:public std::map<CString, CString>
383 public:
384 CComCriticalSection m_critIndexSec;
385 std::map<CString, CString> m_reverseLookup;
387 CGitAdminDirMap() { m_critIndexSec.Init(); }
388 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
390 CString GetAdminDir(const CString &path)
392 CString thePath = path;
393 thePath.MakeLower();
394 CAutoLocker lock(m_critIndexSec);
395 if(this->find(thePath) == end())
397 if (PathIsDirectory(thePath + _T("\\.git")))
399 (*this)[thePath] = thePath + _T("\\.git\\");
400 m_reverseLookup[thePath + _T("\\.git")] = thePath;
401 return (*this)[thePath];
403 else
405 FILE * pFile = _tfsopen(thePath + _T("\\.git"), _T("r"), SH_DENYWR);
406 if (pFile)
408 int size = 65536;
409 std::unique_ptr<char[]> buffer(new char[size]);
410 SecureZeroMemory(buffer.get(), size);
411 if (fread(buffer.get(), sizeof(char), size, pFile))
413 fclose(pFile);
414 CStringA strA(buffer.get());
415 if (strA.Left(8) == "gitdir: ")
417 CString str = CUnicodeUtils::GetUnicode(strA.Trim().Mid(8)); // 8 = len("gitdir: ")
418 str.Replace(_T("/"), _T("\\"));
419 str.TrimRight(_T("\\"));
420 if (str.GetLength() > 0 && str[0] == _T('.'))
422 str = thePath + _T("\\") + str;
423 CString newPath;
424 PathCanonicalize(newPath.GetBuffer(MAX_PATH), str.GetBuffer());
425 newPath.ReleaseBuffer();
426 str.ReleaseBuffer();
427 str = newPath;
429 (*this)[thePath] = str + _T("\\");
430 m_reverseLookup[str.MakeLower()] = path;
431 return (*this)[thePath];
434 else
435 fclose(pFile);
437 return thePath + _T("\\.git\\"); // in case of an error stick to old behavior
440 else
441 return (*this)[thePath];
444 CString GetWorkingCopy(const CString &gitDir)
446 CString path = gitDir;
447 path.MakeLower();
448 CAutoLocker lock(m_critIndexSec);
449 if (m_reverseLookup.find(path) == m_reverseLookup.end())
450 return gitDir;
451 else
452 return m_reverseLookup[path];