No need to check for nullptr on free
[TortoiseGit.git] / src / Git / gitindex.h
blobaa4acec5ec1b13800ab3d6ca0209dae8c3c9ccfe
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;
34 int Print();
37 class CGitIndexList:public std::vector<CGitIndex>
39 protected:
41 public:
42 __time64_t m_LastModifyTime;
44 CGitIndexList();
45 ~CGitIndexList();
47 int ReadIndex(CString file);
48 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);
49 protected:
50 bool m_bCheckContent;
51 __int64 m_iMaxCheckSize;
52 CComCriticalSection m_critRepoSec;
53 CAutoRepository repository;
54 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);
55 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);
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 bool SafeClear(const CString &path)
90 CString thePath = path;
91 thePath.MakeLower();
92 CAutoLocker lock(m_critIndexSec);
93 if (this->find(thePath) == end())
94 return false;
95 (*this)[thePath] = nullptr;
96 return true;
99 bool SafeClearRecursively(const CString &rootpath)
101 CString thePath = rootpath;
102 thePath.MakeLower();
103 CAutoLocker lock(m_critIndexSec);
104 for (auto it = this->begin(); it != this->end(); ++it)
106 if ((*it).first.Find(thePath) == 0)
107 (*this)[(*it).first] = nullptr;
109 return true;
112 int Check(const CString &gitdir, bool *isChanged);
113 int LoadIndex(const CString &gitdir);
115 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
117 bool isChanged=false;
118 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
119 return false;
121 if(isChanged && isLoadUpdatedIndex)
123 LoadIndex(gitdir);
124 return true;
127 return false;
129 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
130 BOOL IsFull=false, BOOL IsRecursive=false,
131 FILL_STATUS_CALLBACK callback = nullptr,
132 void *pData=NULL,CGitHash *pHash=NULL,
133 bool isLoadUpdatedIndex = true, bool * assumeValid = NULL, bool * skipWorktree = NULL);
135 int IsUnderVersionControl(const CString &gitdir,
136 const CString &path,
137 bool isDir,
138 bool *isVersion,
139 bool isLoadUpdateIndex=true);
143 class CGitTreeItem
145 public:
146 CString m_FileName;
147 CGitHash m_Hash;
148 int m_Flags;
151 /* After object create, never change field agains
152 * that needn't lock to get field
154 class CGitHeadFileList:public std::vector<CGitTreeItem>
156 private:
157 int GetPackRef(const CString &gitdir);
158 CReaderWriterLock m_SharedMutex;
160 __time64_t m_LastModifyTimeHead;
161 __time64_t m_LastModifyTimeRef;
162 __time64_t m_LastModifyTimePackRef;
164 CString m_HeadRefFile;
165 CGitHash m_Head;
166 CString m_HeadFile;
167 CString m_Gitdir;
168 CString m_PackRefFile;
170 CGitHash m_TreeHash; /* buffered tree hash value */
172 std::map<CString,CGitHash> m_PackRefMap;
174 public:
175 CGitHeadFileList()
177 m_LastModifyTimeHead=0;
178 m_LastModifyTimeRef=0;
179 m_LastModifyTimePackRef = 0;
182 int ReadTree();
183 int ReadHeadHash(CString gitdir);
184 bool CheckHeadUpdate();
185 bool HeadHashEqualsTreeHash();
186 bool HeadFileIsEmpty();
187 bool HeadIsEmpty();
188 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
191 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
192 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
194 public:
196 CComCriticalSection m_critTreeSec;
198 CGitHeadFileMap() { m_critTreeSec.Init(); }
199 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
201 SHARED_TREE_PTR SafeGet(const CString &path)
203 CString thePath = path;
204 thePath.MakeLower();
205 CAutoLocker lock(m_critTreeSec);
206 if(this->find(thePath) == end())
207 return SHARED_TREE_PTR();
208 else
209 return (*this)[thePath];
212 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
214 CString thePath = path;
215 thePath.MakeLower();
216 CAutoLocker lock(m_critTreeSec);
217 (*this)[thePath] = ptr;
220 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
221 FILL_STATUS_CALLBACK callback = nullptr, void *pData = nullptr,
222 bool isLoaded=false);
223 bool CheckHeadAndUpdate(const CString &gitdir, bool readTree = true);
224 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion);
227 class CGitFileName
229 public:
230 CString m_FileName;
231 CString m_CaseFileName;
234 class CGitIgnoreItem
236 public:
237 CGitIgnoreItem()
239 m_LastModifyTime =0;
240 m_pExcludeList =NULL;
241 m_buffer = NULL;
243 ~CGitIgnoreItem()
245 if(m_pExcludeList)
246 git_free_exclude_list(m_pExcludeList);
247 free(m_buffer);
248 m_pExcludeList=NULL;
249 m_buffer = NULL;
251 __time64_t m_LastModifyTime;
252 CStringA m_BaseDir;
253 BYTE *m_buffer;
254 EXCLUDE_LIST m_pExcludeList;
256 int FetchIgnoreList(const CString &projectroot, const CString &file, bool isGlobal);
259 class CGitIgnoreList
261 private:
262 bool CheckFileChanged(const CString &path);
263 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore, bool isGlobal);
265 int CheckIgnore(const CString &path, const CString &root, bool isDir);
266 int CheckFileAgainstIgnoreList(const CString &ignorefile, const CStringA &patha, const char * base, int &type);
268 // core.excludesfile stuff
269 std::map<CString, CString> m_CoreExcludesfiles;
270 CString m_sMsysGitBinPath;
271 DWORD m_dMsysGitBinPathLastChecked;
272 CReaderWriterLock m_coreExcludefilesSharedMutex;
273 // checks if the msysgit path has changed and return true/false
274 // if the path changed, the cache is update
275 // force is only ised in constructor
276 bool CheckAndUpdateMsysGitBinpath(bool force = true);
277 bool CheckAndUpdateCoreExcludefile(const CString &adminDir);
278 const CString GetWindowsHome();
280 public:
281 CReaderWriterLock m_SharedMutex;
283 CGitIgnoreList(){ CheckAndUpdateMsysGitBinpath(true); }
285 std::map<CString, CGitIgnoreItem> m_Map;
287 bool CheckIgnoreChanged(const CString &gitdir,const CString &path, bool isDir);
288 int LoadAllIgnoreFile(const CString &gitdir, const CString &path, bool isDir);
289 bool IsIgnore(const CString &path, const CString &root, bool isDir);
292 template<class T>
293 int GetRangeInSortVector(const T &vector, LPCTSTR pstr, int len, int *start, int *end, int pos)
295 if( pos < 0)
297 return -1;
299 if(start == 0 || end == NULL)
300 return -1;
302 *start=*end=-1;
304 if (vector.empty())
305 return -1;
307 if (pos >= (int)vector.size())
308 return -1;
310 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
312 for (int i = 0; i < (int)vector.size(); ++i)
314 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
316 if(*start<0)
317 *start =i;
318 *end =i;
321 return -1;
323 else
325 *start =0;
326 *end = (int)vector.size();
328 for (int i = pos; i < (int)vector.size(); ++i)
330 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
332 *end=i;
334 else
336 break;
339 for(int i=pos;i>=0;i--)
341 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
343 *start=i;
345 else
347 break;
351 return 0;
354 template<class T>
355 int SearchInSortVector(const T &vector, LPCTSTR pstr, int len)
357 int end = (int)vector.size() - 1;
358 int start = 0;
359 int mid = (start+end)/2;
361 if (vector.empty())
362 return -1;
364 while(!( start == end && start==mid))
366 int cmp;
367 if(len < 0)
368 cmp = _tcscmp(vector[mid].m_FileName,pstr);
369 else
370 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
372 if (cmp == 0)
373 return mid;
374 else if (cmp < 0)
375 start = mid + 1;
376 else // (cmp > 0)
377 end = mid;
379 mid=(start +end ) /2;
382 if(len <0)
384 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
385 return mid;
387 else
389 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
390 return mid;
392 return -1;
395 class CGitAdminDirMap:public std::map<CString, CString>
397 public:
398 CComCriticalSection m_critIndexSec;
399 std::map<CString, CString> m_reverseLookup;
401 CGitAdminDirMap() { m_critIndexSec.Init(); }
402 ~CGitAdminDirMap() { m_critIndexSec.Term(); }
404 CString GetAdminDir(const CString &path)
406 CString thePath = path;
407 thePath.MakeLower();
408 CAutoLocker lock(m_critIndexSec);
409 if(this->find(thePath) == end())
411 if (PathIsDirectory(path + _T("\\.git")))
413 (*this)[thePath] = path + _T("\\.git\\");
414 m_reverseLookup[thePath + _T("\\.git")] = path;
415 return (*this)[thePath];
417 else
419 FILE * pFile = _tfsopen(path + _T("\\.git"), _T("r"), SH_DENYWR);
420 if (pFile)
422 int size = 65536;
423 std::unique_ptr<char[]> buffer(new char[size]);
424 int length = 0;
425 if ((length = (int)fread(buffer.get(), sizeof(char), size, pFile)) >= 8)
427 fclose(pFile);
428 CStringA strA(buffer.get(), length);
429 if (strA.Left(8) == "gitdir: ")
431 CString str = CUnicodeUtils::GetUnicode(strA.Trim().Mid(8)); // 8 = len("gitdir: ")
432 str.Replace(_T("/"), _T("\\"));
433 str.TrimRight(_T("\\"));
434 if (str.GetLength() > 0 && str[0] == _T('.'))
436 str = path + _T("\\") + str;
437 CString newPath;
438 PathCanonicalize(newPath.GetBuffer(MAX_PATH), str.GetBuffer());
439 newPath.ReleaseBuffer();
440 str.ReleaseBuffer();
441 str = newPath;
443 (*this)[thePath] = str + _T("\\");
444 m_reverseLookup[str.MakeLower()] = path;
445 return (*this)[thePath];
448 else
449 fclose(pFile);
451 return path + _T("\\.git\\"); // in case of an error stick to old behavior
454 else
455 return (*this)[thePath];
458 CString GetWorkingCopy(const CString &gitDir)
460 CString path = gitDir;
461 path.MakeLower();
462 CAutoLocker lock(m_critIndexSec);
463 if (m_reverseLookup.find(path) == m_reverseLookup.end())
464 return gitDir;
465 else
466 return m_reverseLookup[path];