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.
22 #include "gitstatus.h"
23 #include "SharedMutex.h"
29 __time64_t m_ModifyTime
;
40 CAutoReadLock(SharedMutex
* lock
)
43 lock
->AcquireShared();
47 m_Lock
->ReleaseShared();
55 CAutoWriteLock(SharedMutex
* lock
)
58 lock
->AcquireExclusive();
62 m_Lock
->ReleaseExclusive();
66 class CGitIndexList
:public std::vector
<CGitIndex
>
71 __time64_t m_LastModifyTime
;
77 //TRACE(_T("Free Index List 0x%x %s"),this, m_GitFile);
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
);
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
>
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
;
105 CAutoLocker
lock(m_critIndexSec
);
106 if(this->find(thePath
) == end())
107 return SHARED_INDEX_PTR();
109 return (*this)[thePath
];
112 void SafeSet(const CString
&path
, SHARED_INDEX_PTR ptr
)
114 CString thePath
= path
;
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
))
129 if(isChanged
&& isLoadUpdatedIndex
)
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
,
147 bool isLoadUpdateIndex
=true);
159 /* After object create, never change field agains
160 * that needn't lock to get field
162 class CGitHeadFileList
:public std::vector
<CGitTreeItem
>
166 int GetPackRef(const CString
&gitdir
);
169 __time64_t m_LastModifyTimeHead
;
170 __time64_t m_LastModifyTimeRef
;
171 __time64_t m_LastModifyTimePackRef
;
173 CString m_HeadRefFile
;
177 CString m_PackRefFile
;
179 CGitHash m_TreeHash
; /* buffered tree hash value */
181 std::map
<CString
,CGitHash
> m_PackRefMap
;
185 m_LastModifyTimeHead
=0;
186 m_LastModifyTimeRef
=0;
187 m_LastModifyTimePackRef
= 0;
194 //TRACE(_T("Free Index List 0x%x %s"),this, m_GitFile);
199 int ReadHeadHash(CString gitdir
);
200 bool CheckHeadUpdate();
201 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
205 typedef std::tr1::shared_ptr
<CGitHeadFileList
> SHARED_TREE_PTR
;
206 class CGitHeadFileMap
:public std::map
<CString
,SHARED_TREE_PTR
>
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
;
219 CAutoLocker
lock(m_critTreeSec
);
220 if(this->find(thePath
) == end())
221 return SHARED_TREE_PTR();
223 return (*this)[thePath
];
226 void SafeSet(const CString
&path
, SHARED_TREE_PTR ptr
)
228 CString thePath
= path
;
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
)
249 return ptr
->m_Head
!= ptr
->m_TreeHash
;
258 CString m_CaseFileName
;
264 SharedMutex m_SharedMutex
;
269 m_pExcludeList
=NULL
;
274 git_free_exclude_list(m_pExcludeList
);
277 __time64_t m_LastModifyTime
;
279 EXCLUDE_LIST m_pExcludeList
;
280 int FetchIgnoreList(const CString
&projectroot
, const CString
&file
, bool isGlobal
);
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();
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
);
318 int GetRangeInSortVector(T
&vector
,LPTSTR pstr
,int len
, int *start
, int *end
, int pos
)
324 if(start
== 0 || end
== NULL
)
329 if(vector
.size() ==0)
332 if(pos
>= vector
.size())
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 )
351 *end
= vector
.size();
353 for(int i
=pos
;i
<vector
.size();i
++)
355 if( _tcsnccmp(vector
[i
].m_FileName
, pstr
,len
) == 0 )
364 for(int i
=pos
;i
>=0;i
--)
366 if( _tcsnccmp(vector
[i
].m_FileName
, pstr
,len
) == 0 )
380 int SearchInSortVector(T
&vector
, LPTSTR pstr
, int len
)
382 int end
=vector
.size()-1;
384 int mid
= (start
+end
)/2;
386 if(vector
.size() == 0)
389 while(!( start
== end
&& start
==mid
))
393 cmp
= _tcscmp(vector
[mid
].m_FileName
,pstr
);
395 cmp
= _tcsnccmp( vector
[mid
].m_FileName
,pstr
,len
);
409 mid
=(start
+end
) /2;
414 if(_tcscmp(vector
[mid
].m_FileName
,pstr
) == 0)
419 if(_tcsnccmp( vector
[mid
].m_FileName
,pstr
,len
) == 0)
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
);
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
);
440 class CGitAdminDirMap
:public std::map
<CString
, CString
>
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
;
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
];
464 FILE * pFile
= _tfsopen(thePath
+ _T("\\.git"), _T("r"), SH_DENYWR
);
468 auto_buffer
<char> buffer(size
);
469 if (fread(buffer
, sizeof(char), size
, 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
;
482 PathCanonicalize(newPath
.GetBuffer(MAX_PATH
), str
.GetBuffer());
483 newPath
.ReleaseBuffer();
487 (*this)[thePath
] = str
+ _T("\\");
488 m_reverseLookup
[str
.MakeLower()] = path
;
489 return (*this)[thePath
];
494 return thePath
+ _T("\\.git\\"); // in case of an error stick to old behavior
498 return (*this)[thePath
];
501 CString
GetWorkingCopy(const CString
&gitDir
)
503 CString path
= gitDir
;
505 CAutoLocker
lock(m_critIndexSec
);
506 if (m_reverseLookup
.find(path
) == m_reverseLookup
.end())
509 return m_reverseLookup
[path
];