CGitDiff::Diff: Diffing with non SHA-1 revisions < 40 chars and slashes failed
[TortoiseGit.git] / src / Git / gitindex.h
blob5f7c22ebe0031021fb20976b140da7297c73eb09
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 int m_Flags;
31 CGitHash m_IndexHash;
33 int Print();
36 class CAutoReadLock
38 SharedMutex *m_Lock;
39 public:
40 CAutoReadLock(SharedMutex * lock)
42 m_Lock = lock;
43 lock->AcquireShared();
45 ~CAutoReadLock()
47 m_Lock->ReleaseShared();
51 class CAutoWriteLock
53 SharedMutex *m_Lock;
54 public:
55 CAutoWriteLock(SharedMutex * lock)
57 m_Lock = lock;
58 lock->AcquireExclusive();
60 ~CAutoWriteLock()
62 m_Lock->ReleaseExclusive();
66 class CGitIndexList:public std::vector<CGitIndex>
68 protected:
70 public:
71 __time64_t m_LastModifyTime;
73 #ifdef DEBUG
74 CString m_GitFile;
75 ~CGitIndexList()
77 //TRACE(_T("Free Index List 0x%x %s"),this, m_GitFile);
79 #endif
81 CGitIndexList();
83 int ReadIndex(CString file);
84 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);
85 protected:
86 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);
87 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);
90 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
91 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
93 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
95 public:
96 CComCriticalSection m_critIndexSec;
98 CGitIndexFileMap() { m_critIndexSec.Init(); }
99 ~CGitIndexFileMap() { m_critIndexSec.Term(); }
101 SHARED_INDEX_PTR SafeGet(const CString &path)
103 CString thePath = path;
104 thePath.MakeLower();
105 CAutoLocker lock(m_critIndexSec);
106 if(this->find(thePath) == end())
107 return SHARED_INDEX_PTR();
108 else
109 return (*this)[thePath];
112 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
114 CString thePath = path;
115 thePath.MakeLower();
116 CAutoLocker lock(m_critIndexSec);
117 (*this)[thePath] = ptr;
120 int Check(const CString &gitdir, bool *isChanged);
121 int LoadIndex(const CString &gitdir);
123 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
125 bool isChanged=false;
126 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
127 return false;
129 if(isChanged && isLoadUpdatedIndex)
131 LoadIndex(gitdir);
132 return true;
135 return false;
137 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
138 BOOL IsFull=false, BOOL IsRecursive=false,
139 FIll_STATUS_CALLBACK callback=NULL,
140 void *pData=NULL,CGitHash *pHash=NULL,
141 bool isLoadUpdatedIndex=true);
143 int IsUnderVersionControl(const CString &gitdir,
144 const CString &path,
145 bool isDir,
146 bool *isVersion,
147 bool isLoadUpdateIndex=true);
151 class CGitTreeItem
153 public:
154 CString m_FileName;
155 CGitHash m_Hash;
156 int m_Flags;
159 /* After object create, never change field agains
160 * that needn't lock to get field
162 class CGitHeadFileList:public std::vector<CGitTreeItem>
164 private:
166 int GetPackRef(const CString &gitdir);
168 public:
169 __time64_t m_LastModifyTimeHead;
170 __time64_t m_LastModifyTimeRef;
171 __time64_t m_LastModifyTimePackRef;
173 CString m_HeadRefFile;
174 CGitHash m_Head;
175 CString m_HeadFile;
176 CString m_Gitdir;
177 CString m_PackRefFile;
179 CGitHash m_TreeHash; /* buffered tree hash value */
181 std::map<CString,CGitHash> m_PackRefMap;
183 CGitHeadFileList()
185 m_LastModifyTimeHead=0;
186 m_LastModifyTimeRef=0;
187 m_LastModifyTimePackRef = 0;
190 #ifdef DEBUG
191 CString m_GitFile;
192 ~CGitHeadFileList()
194 //TRACE(_T("Free Index List 0x%x %s"),this, m_GitFile);
196 #endif
198 int ReadTree();
199 int ReadHeadHash(CString gitdir);
200 bool CheckHeadUpdate();
201 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
202 //int ReadTree();
205 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
206 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
208 public:
210 CComCriticalSection m_critTreeSec;
212 CGitHeadFileMap() { m_critTreeSec.Init(); }
213 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
215 SHARED_TREE_PTR SafeGet(const CString &path)
217 CString thePath = path;
218 thePath.MakeLower();
219 CAutoLocker lock(m_critTreeSec);
220 if(this->find(thePath) == end())
221 return SHARED_TREE_PTR();
222 else
223 return (*this)[thePath];
226 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
228 CString thePath = path;
229 thePath.MakeLower();
230 CAutoLocker lock(m_critTreeSec);
231 (*this)[thePath] = ptr;
234 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
235 FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,
236 bool isLoaded=false);
237 bool CheckHeadUpdate(const CString &gitdir);
238 int GetHeadHash(const CString &gitdir, CGitHash &hash);
239 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
242 bool IsHashChanged(const CString &gitdir)
244 SHARED_TREE_PTR ptr = SafeGet(gitdir);
246 if( ptr.get() == NULL)
247 return false;
249 return ptr->m_Head != ptr->m_TreeHash;
254 class CGitFileName
256 public:
257 CString m_FileName;
258 CString m_CaseFileName;
261 class CGitIgnoreItem
263 public:
264 SharedMutex m_SharedMutex;
266 CGitIgnoreItem()
268 m_LastModifyTime =0;
269 m_pExcludeList =NULL;
271 ~CGitIgnoreItem()
273 if(m_pExcludeList)
274 git_free_exclude_list(m_pExcludeList);
275 m_pExcludeList=NULL;
277 __time64_t m_LastModifyTime;
278 CStringA m_BaseDir;
279 EXCLUDE_LIST m_pExcludeList;
280 int FetchIgnoreList(const CString &projectroot, const CString &file, bool isGlobal);
283 class CGitIgnoreList
285 private:
286 bool CheckFileChanged(const CString &path);
287 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore, bool isGlobal);
289 int CheckIgnore(const CString &path,const CString &root);
290 int CheckFileAgainstIgnoreList(const CString &ignorefile, const CStringA &patha, const char * base, int &type);
292 // core.excludesfile stuff
293 std::map<CString, CString> m_CoreExcludesfiles;
294 CString m_sMsysGitBinPath;
295 DWORD m_dMsysGitBinPathLastChecked;
296 SharedMutex m_coreExcludefilesSharedMutex;
297 // checks if the msysgit path has changed and return true/false
298 // if the path changed, the cache is update
299 // force is only ised in constructor
300 bool CheckAndUpdateMsysGitBinpath(bool force = true);
301 bool CheckAndUpdateCoreExcludefile(const CString &adminDir);
302 const CString GetWindowsHome();
304 public:
305 SharedMutex m_SharedMutex;
307 CGitIgnoreList(){ m_SharedMutex.Init(); m_coreExcludefilesSharedMutex.Init(); CheckAndUpdateMsysGitBinpath(true); }
308 ~CGitIgnoreList() { m_SharedMutex.Release(); m_coreExcludefilesSharedMutex.Release(); }
310 std::map<CString, CGitIgnoreItem> m_Map;
312 bool CheckIgnoreChanged(const CString &gitdir,const CString &path);
313 int LoadAllIgnoreFile(const CString &gitdir,const CString &path);
314 bool IsIgnore(const CString &path,const CString &root);
317 template<class T>
318 int GetRangeInSortVector(T &vector,LPTSTR pstr,int len, int *start, int *end, int pos)
320 if( pos < 0)
322 return -1;
324 if(start == 0 || end == NULL)
325 return -1;
327 *start=*end=-1;
329 if(vector.size() ==0)
330 return -1;
332 if(pos >= vector.size())
333 return -1;
335 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
337 for(int i=0;i< vector.size();i++)
339 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
341 if(*start<0)
342 *start =i;
343 *end =i;
346 return -1;
348 else
350 *start =0;
351 *end = vector.size();
353 for(int i=pos;i<vector.size();i++)
355 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
357 *end=i;
359 else
361 break;
364 for(int i=pos;i>=0;i--)
366 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
368 *start=i;
370 else
372 break;
376 return 0;
379 template<class T>
380 int SearchInSortVector(T &vector, LPTSTR pstr, int len)
382 int end=vector.size()-1;
383 int start = 0;
384 int mid = (start+end)/2;
386 if(vector.size() == 0)
387 return -1;
389 while(!( start == end && start==mid))
391 int cmp;
392 if(len < 0)
393 cmp = _tcscmp(vector[mid].m_FileName,pstr);
394 else
395 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
397 if(cmp ==0)
398 return mid;
400 if(cmp < 0)
402 start = mid+1;
405 if(cmp > 0)
407 end=mid;
409 mid=(start +end ) /2;
412 if(len <0)
414 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
415 return mid;
417 else
419 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
420 return mid;
422 return -1;
424 #if 0
426 class CGitStatus
428 protected:
429 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);
430 public:
431 CGitIgnoreList m_IgnoreList;
432 CGitHeadFileMap m_HeadFilesMap;
433 CGitIndexFileMap m_IndexFilesMap;
435 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);
438 #endif
440 class CGitAdminDirMap:public std::map<CString, CString>
442 public:
443 CComCriticalSection m_critIndexSec;
444 std::map<CString, CString> m_reverseLookup;
446 CGitAdminDirMap() { m_critIndexSec.Init(); }
447 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
449 CString GetAdminDir(const CString &path)
451 CString thePath = path;
452 thePath.MakeLower();
453 CAutoLocker lock(m_critIndexSec);
454 if(this->find(thePath) == end())
456 if (PathIsDirectory(thePath + _T("\\.git")))
458 (*this)[thePath] = thePath + _T("\\.git\\");
459 m_reverseLookup[thePath + _T("\\.git")] = thePath;
460 return (*this)[thePath];
462 else
464 FILE * pFile = _tfsopen(thePath + _T("\\.git"), _T("r"), SH_DENYWR);
465 if (pFile)
467 int size = 65536;
468 auto_buffer<char> buffer(size);
469 if (fread(buffer, sizeof(char), size, pFile))
471 fclose(pFile);
472 CString str = CString(buffer);
473 if (str.Left(8) == _T("gitdir: "))
475 str = str.TrimRight().Mid(8);
476 str.Replace(_T("/"), _T("\\"));
477 str.TrimRight(_T("\\"));
478 if (str.GetLength() > 0 && str[0] == _T('.'))
480 str = thePath + _T("\\") + str;
481 CString newPath;
482 PathCanonicalize(newPath.GetBuffer(MAX_PATH), str.GetBuffer());
483 newPath.ReleaseBuffer();
484 str.ReleaseBuffer();
485 str = newPath;
487 (*this)[thePath] = str + _T("\\");
488 m_reverseLookup[str.MakeLower()] = path;
489 return (*this)[thePath];
492 fclose(pFile);
494 return thePath + _T("\\.git\\"); // in case of an error stick to old behavior
497 else
498 return (*this)[thePath];
501 CString GetWorkingCopy(const CString &gitDir)
503 CString path = gitDir;
504 path.MakeLower();
505 CAutoLocker lock(m_critIndexSec);
506 if (m_reverseLookup.find(path) == m_reverseLookup.end())
507 return gitDir;
508 else
509 return m_reverseLookup[path];