1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2015 - 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 "UnicodeUtils.h"
24 #include "ReaderWriterLock.h"
25 #include "GitAdminDir.h"
31 __time64_t m_ModifyTime
;
32 unsigned short m_Flags
;
39 class CGitIndexList
:public std::vector
<CGitIndex
>
44 __time64_t m_LastModifyTime
;
49 int ReadIndex(CString file
);
50 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);
53 __int64 m_iMaxCheckSize
;
54 CComCriticalSection m_critRepoSec
;
55 CAutoRepository repository
;
56 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);
57 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);
60 typedef std::tr1::shared_ptr
<CGitIndexList
> SHARED_INDEX_PTR
;
61 typedef CComCritSecLock
<CComCriticalSection
> CAutoLocker
;
63 class CGitIndexFileMap
:public std::map
<CString
, SHARED_INDEX_PTR
>
66 CComCriticalSection m_critIndexSec
;
68 CGitIndexFileMap() { m_critIndexSec
.Init(); }
69 ~CGitIndexFileMap() { m_critIndexSec
.Term(); }
71 SHARED_INDEX_PTR
SafeGet(const CString
&path
)
73 CString thePath
= path
;
75 CAutoLocker
lock(m_critIndexSec
);
76 if(this->find(thePath
) == end())
77 return SHARED_INDEX_PTR();
79 return (*this)[thePath
];
82 void SafeSet(const CString
&path
, SHARED_INDEX_PTR ptr
)
84 CString thePath
= path
;
86 CAutoLocker
lock(m_critIndexSec
);
87 (*this)[thePath
] = ptr
;
90 bool SafeClear(const CString
&path
)
92 CString thePath
= path
;
94 CAutoLocker
lock(m_critIndexSec
);
95 if (this->find(thePath
) == end())
97 (*this)[thePath
] = nullptr;
101 bool SafeClearRecursively(const CString
&rootpath
)
103 CString thePath
= rootpath
;
105 CAutoLocker
lock(m_critIndexSec
);
106 for (auto it
= this->begin(); it
!= this->end(); ++it
)
108 if ((*it
).first
.Find(thePath
) == 0)
109 (*this)[(*it
).first
] = nullptr;
114 int Check(const CString
&gitdir
, bool *isChanged
);
115 int LoadIndex(const CString
&gitdir
);
117 bool CheckAndUpdate(const CString
&gitdir
,bool isLoadUpdatedIndex
)
119 bool isChanged
=false;
120 if(isLoadUpdatedIndex
&& Check(gitdir
,&isChanged
))
123 if(isChanged
&& isLoadUpdatedIndex
)
131 int GetFileStatus(const CString
&gitdir
,const CString
&path
,git_wc_status_kind
* status
,
132 BOOL IsFull
=false, BOOL IsRecursive
=false,
133 FILL_STATUS_CALLBACK callback
= nullptr,
134 void *pData
=NULL
,CGitHash
*pHash
=NULL
,
135 bool isLoadUpdatedIndex
= true, bool * assumeValid
= NULL
, bool * skipWorktree
= NULL
);
137 int IsUnderVersionControl(const CString
&gitdir
,
141 bool isLoadUpdateIndex
=true);
153 /* After object create, never change field agains
154 * that needn't lock to get field
156 class CGitHeadFileList
:public std::vector
<CGitTreeItem
>
159 int GetPackRef(const CString
&gitdir
);
160 CReaderWriterLock m_SharedMutex
;
162 __time64_t m_LastModifyTimeHead
;
163 __time64_t m_LastModifyTimeRef
;
164 __time64_t m_LastModifyTimePackRef
;
166 CString m_HeadRefFile
;
170 CString m_PackRefFile
;
172 CGitHash m_TreeHash
; /* buffered tree hash value */
174 std::map
<CString
,CGitHash
> m_PackRefMap
;
179 m_LastModifyTimeHead
=0;
180 m_LastModifyTimeRef
=0;
181 m_LastModifyTimePackRef
= 0;
185 int ReadHeadHash(CString gitdir
);
186 bool CheckHeadUpdate();
187 bool HeadHashEqualsTreeHash();
188 bool HeadFileIsEmpty();
190 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
193 typedef std::tr1::shared_ptr
<CGitHeadFileList
> SHARED_TREE_PTR
;
194 class CGitHeadFileMap
:public std::map
<CString
,SHARED_TREE_PTR
>
198 CComCriticalSection m_critTreeSec
;
200 CGitHeadFileMap() { m_critTreeSec
.Init(); }
201 ~CGitHeadFileMap() { m_critTreeSec
.Term(); }
203 SHARED_TREE_PTR
SafeGet(const CString
&path
)
205 CString thePath
= path
;
207 CAutoLocker
lock(m_critTreeSec
);
208 if(this->find(thePath
) == end())
209 return SHARED_TREE_PTR();
211 return (*this)[thePath
];
214 void SafeSet(const CString
&path
, SHARED_TREE_PTR ptr
)
216 CString thePath
= path
;
218 CAutoLocker
lock(m_critTreeSec
);
219 (*this)[thePath
] = ptr
;
222 int GetFileStatus(const CString
&gitdir
,const CString
&path
,git_wc_status_kind
* status
,BOOL IsFull
=false, BOOL IsRecursive
=false,
223 FILL_STATUS_CALLBACK callback
= nullptr, void *pData
= nullptr,
224 bool isLoaded
=false);
225 bool CheckHeadAndUpdate(const CString
&gitdir
, bool readTree
= true);
226 int IsUnderVersionControl(const CString
&gitdir
, const CString
&path
, bool isDir
, bool *isVersion
);
233 CString m_CaseFileName
;
242 m_pExcludeList
=NULL
;
248 git_free_exclude_list(m_pExcludeList
);
253 __time64_t m_LastModifyTime
;
256 EXCLUDE_LIST m_pExcludeList
;
258 int FetchIgnoreList(const CString
&projectroot
, const CString
&file
, bool isGlobal
);
264 bool CheckFileChanged(const CString
&path
);
265 int FetchIgnoreFile(const CString
&gitdir
, const CString
&gitignore
, bool isGlobal
);
267 int CheckIgnore(const CString
&path
, const CString
&root
, bool isDir
);
268 int CheckFileAgainstIgnoreList(const CString
&ignorefile
, const CStringA
&patha
, const char * base
, int &type
);
270 // core.excludesfile stuff
271 std::map
<CString
, CString
> m_CoreExcludesfiles
;
272 CString m_sMsysGitBinPath
;
273 DWORD m_dMsysGitBinPathLastChecked
;
274 CReaderWriterLock m_coreExcludefilesSharedMutex
;
275 // checks if the msysgit path has changed and return true/false
276 // if the path changed, the cache is update
277 // force is only ised in constructor
278 bool CheckAndUpdateMsysGitBinpath(bool force
= true);
279 bool CheckAndUpdateCoreExcludefile(const CString
&adminDir
);
280 const CString
GetWindowsHome();
283 CReaderWriterLock m_SharedMutex
;
285 CGitIgnoreList(){ CheckAndUpdateMsysGitBinpath(true); }
287 std::map
<CString
, CGitIgnoreItem
> m_Map
;
289 bool CheckIgnoreChanged(const CString
&gitdir
,const CString
&path
, bool isDir
);
290 int LoadAllIgnoreFile(const CString
&gitdir
, const CString
&path
, bool isDir
);
291 bool IsIgnore(const CString
&path
, const CString
&root
, bool isDir
);
295 int GetRangeInSortVector(const T
&vector
, LPCTSTR pstr
, int len
, int *start
, int *end
, int pos
)
301 if(start
== 0 || end
== NULL
)
309 if (pos
>= (int)vector
.size())
312 if( _tcsnccmp(vector
[pos
].m_FileName
, pstr
,len
) != 0)
314 for (int i
= 0; i
< (int)vector
.size(); ++i
)
316 if( _tcsnccmp(vector
[i
].m_FileName
, pstr
,len
) == 0 )
328 *end
= (int)vector
.size();
330 for (int i
= pos
; i
< (int)vector
.size(); ++i
)
332 if( _tcsnccmp(vector
[i
].m_FileName
, pstr
,len
) == 0 )
341 for(int i
=pos
;i
>=0;i
--)
343 if( _tcsnccmp(vector
[i
].m_FileName
, pstr
,len
) == 0 )
357 int SearchInSortVector(const T
&vector
, LPCTSTR pstr
, int len
)
359 int end
= (int)vector
.size() - 1;
361 int mid
= (start
+end
)/2;
366 while(!( start
== end
&& start
==mid
))
370 cmp
= _tcscmp(vector
[mid
].m_FileName
,pstr
);
372 cmp
= _tcsnccmp( vector
[mid
].m_FileName
,pstr
,len
);
381 mid
=(start
+end
) /2;
386 if(_tcscmp(vector
[mid
].m_FileName
,pstr
) == 0)
391 if(_tcsnccmp( vector
[mid
].m_FileName
,pstr
,len
) == 0)
397 class CGitAdminDirMap
:public std::map
<CString
, CString
>
400 CComCriticalSection m_critIndexSec
;
401 std::map
<CString
, CString
> m_reverseLookup
;
403 CGitAdminDirMap() { m_critIndexSec
.Init(); }
404 ~CGitAdminDirMap() { m_critIndexSec
.Term(); }
406 CString
GetAdminDir(const CString
&path
)
408 CString thePath
= path
;
410 CAutoLocker
lock(m_critIndexSec
);
411 if(this->find(thePath
) == end())
413 if (PathIsDirectory(path
+ _T("\\.git")))
415 (*this)[thePath
] = path
+ _T("\\.git\\");
416 m_reverseLookup
[thePath
+ _T("\\.git")] = path
;
417 return (*this)[thePath
];
421 CString result
= GitAdminDir::ReadGitLink(path
, path
+ _T("\\.git"));
422 if (!result
.IsEmpty())
424 (*this)[thePath
] = result
+ _T("\\");
425 m_reverseLookup
[result
.MakeLower()] = path
;
426 return (*this)[thePath
];
429 return path
+ _T("\\.git\\"); // in case of an error stick to old behavior
433 return (*this)[thePath
];
436 CString
GetWorkingCopy(const CString
&gitDir
)
438 CString path
= gitDir
;
440 CAutoLocker
lock(m_critIndexSec
);
441 if (m_reverseLookup
.find(path
) == m_reverseLookup
.end())
444 return m_reverseLookup
[path
];