drop unreferenced code
[TortoiseGit.git] / src / Git / gitindex.h
blob8cd370f21b7a2f2dfc078d9e2c845394698ff823
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2011 - 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 /* Copy from Git cache.h*/
26 #define FLEX_ARRAY 4
28 #pragma pack(push)
29 #pragma pack(1)
30 //#pragma pack(show)
31 #define CACHE_SIGNATURE 0x44495243 /* "DIRC" */
32 struct cache_header {
33 unsigned int hdr_signature;
34 unsigned int hdr_version;
35 unsigned int hdr_entries;
39 * The "cache_time" is just the low 32 bits of the
40 * time. It doesn't matter if it overflows - we only
41 * check it for equality in the 32 bits we save.
43 struct cache_time {
44 UINT32 sec;
45 UINT32 nsec;
49 * dev/ino/uid/gid/size are also just tracked to the low 32 bits
50 * Again - this is just a (very strong in practice) heuristic that
51 * the inode hasn't changed.
53 * We save the fields in big-endian order to allow using the
54 * index file over NFS transparently.
56 struct ondisk_cache_entry {
57 struct cache_time ctime;
58 struct cache_time mtime;
59 UINT32 dev;
60 UINT32 ino;
61 UINT32 mode;
62 UINT32 uid;
63 UINT32 gid;
64 UINT32 size;
65 BYTE sha1[20];
66 UINT16 flags;
67 char name[FLEX_ARRAY]; /* more */
71 * This struct is used when CE_EXTENDED bit is 1
72 * The struct must match ondisk_cache_entry exactly from
73 * ctime till flags
75 struct ondisk_cache_entry_extended {
76 struct cache_time ctime;
77 struct cache_time mtime;
78 UINT32 dev;
79 UINT32 ino;
80 UINT32 mode;
81 UINT32 uid;
82 UINT32 gid;
83 UINT32 size;
84 BYTE sha1[20];
85 UINT16 flags;
86 UINT16 flags2;
87 char name[FLEX_ARRAY]; /* more */
90 #pragma pack(pop)
92 #define CE_NAMEMASK (0x0fff)
93 #define CE_STAGEMASK (0x3000)
94 #define CE_EXTENDED (0x4000)
95 #define CE_VALID (0x8000)
96 #define CE_STAGESHIFT 12
98 * Range 0xFFFF0000 in ce_flags is divided into
99 * two parts: in-memory flags and on-disk ones.
100 * Flags in CE_EXTENDED_FLAGS will get saved on-disk
101 * if you want to save a new flag, add it in
102 * CE_EXTENDED_FLAGS
104 * In-memory only flags
106 #define CE_UPDATE (0x10000)
107 #define CE_REMOVE (0x20000)
108 #define CE_UPTODATE (0x40000)
109 #define CE_ADDED (0x80000)
111 #define CE_HASHED (0x100000)
112 #define CE_UNHASHED (0x200000)
115 * Extended on-disk flags
117 #define CE_INTENT_TO_ADD 0x20000000
118 /* CE_EXTENDED2 is for future extension */
119 #define CE_EXTENDED2 0x80000000
121 #define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)
124 * Safeguard to avoid saving wrong flags:
125 * - CE_EXTENDED2 won't get saved until its semantic is known
126 * - Bits in 0x0000FFFF have been saved in ce_flags already
127 * - Bits in 0x003F0000 are currently in-memory flags
129 #if CE_EXTENDED_FLAGS & 0x803FFFFF
130 #error "CE_EXTENDED_FLAGS out of range"
131 #endif
134 * Copy the sha1 and stat state of a cache entry from one to
135 * another. But we never change the name, or the hash state!
137 #define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
139 template<class T>
140 T Big2lit(T data)
142 T ret;
143 BYTE *p1=(BYTE*)&data;
144 BYTE *p2=(BYTE*)&ret;
145 for(int i=0;i<sizeof(T);i++)
147 p2[sizeof(T)-i-1] = p1[i];
149 return ret;
152 template<class T>
153 static inline size_t ce_namelen(T *ce)
155 size_t len = Big2lit(ce->flags) & CE_NAMEMASK;
156 if (len < CE_NAMEMASK)
157 return len;
158 return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK;
161 #define flexible_size(STRUCT,len) ((offsetof(STRUCT,name) + (len) + 8) & ~7)
163 //#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len)
164 //#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len)
166 //#define ondisk_ce_size(ce) (((ce)->flags & CE_EXTENDED) ? \
167 // ondisk_cache_entry_extended_size(ce_namelen(ce)) : \
168 // ondisk_cache_entry_size(ce_namelen(ce)))
170 template<class T>
171 static inline size_t ondisk_ce_size(T *ce)
173 return flexible_size(T,ce_namelen(ce));
176 class CGitIndex
178 public:
179 CString m_FileName;
180 __time64_t m_ModifyTime;
181 int m_Flags;
182 //int m_Status;
183 CGitHash m_IndexHash;
185 int FillData(ondisk_cache_entry* entry);
186 int FillData(ondisk_cache_entry_extended* entry);
187 int Print();
191 class CAutoReadLock
193 SharedMutex *m_Lock;
194 public:
195 CAutoReadLock(SharedMutex * lock)
197 m_Lock = lock;
198 lock->AcquireShared();
200 ~CAutoReadLock()
202 m_Lock->ReleaseShared();
206 class CAutoWriteLock
208 SharedMutex *m_Lock;
209 public:
210 CAutoWriteLock(SharedMutex * lock)
212 m_Lock = lock;
213 lock->AcquireExclusive();
215 ~CAutoWriteLock()
217 m_Lock->ReleaseExclusive();
221 class CGitIndexList:public std::vector<CGitIndex>
223 protected:
225 public:
226 __time64_t m_LastModifyTime;
228 #ifdef DEBUG
229 CString m_GitFile;
230 ~CGitIndexList()
232 //TRACE(_T("Free Index List 0x%x %s"),this, m_GitFile);
234 #endif
236 CGitIndexList();
238 int ReadIndex(CString file);
239 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);
240 protected:
241 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);
242 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);
245 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
246 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
248 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
250 public:
251 CComCriticalSection m_critIndexSec;
253 CGitIndexFileMap() { m_critIndexSec.Init(); }
254 ~CGitIndexFileMap() { m_critIndexSec.Term(); }
256 SHARED_INDEX_PTR SafeGet(const CString &path)
258 CString thePath = path;
259 thePath.MakeLower();
260 CAutoLocker lock(m_critIndexSec);
261 if(this->find(thePath) == end())
262 return SHARED_INDEX_PTR();
263 else
264 return (*this)[thePath];
267 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
269 CString thePath = path;
270 thePath.MakeLower();
271 CAutoLocker lock(m_critIndexSec);
272 (*this)[thePath] = ptr;
275 int Check(const CString &gitdir, bool *isChanged);
276 int LoadIndex(const CString &gitdir);
278 bool CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
280 bool isChanged=false;
281 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
282 return false;
284 if(isChanged && isLoadUpdatedIndex)
286 LoadIndex(gitdir);
287 return true;
290 return false;
292 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
293 BOOL IsFull=false, BOOL IsRecursive=false,
294 FIll_STATUS_CALLBACK callback=NULL,
295 void *pData=NULL,CGitHash *pHash=NULL,
296 bool isLoadUpdatedIndex=true);
298 int IsUnderVersionControl(const CString &gitdir,
299 const CString &path,
300 bool isDir,
301 bool *isVersion,
302 bool isLoadUpdateIndex=true);
306 class CGitTreeItem
308 public:
309 CString m_FileName;
310 CGitHash m_Hash;
311 int m_Flags;
314 /* After object create, never change field agains
315 * that needn't lock to get field
317 class CGitHeadFileList:public std::vector<CGitTreeItem>
319 private:
321 int GetPackRef(const CString &gitdir);
323 public:
324 __time64_t m_LastModifyTimeHead;
325 __time64_t m_LastModifyTimeRef;
326 __time64_t m_LastModifyTimePackRef;
328 CString m_HeadRefFile;
329 CGitHash m_Head;
330 CString m_HeadFile;
331 CString m_Gitdir;
332 CString m_PackRefFile;
334 CGitHash m_TreeHash; /* buffered tree hash value */
336 std::map<CString,CGitHash> m_PackRefMap;
338 CGitHeadFileList()
340 m_LastModifyTimeHead=0;
341 m_LastModifyTimeRef=0;
342 m_LastModifyTimePackRef = 0;
345 #ifdef DEBUG
346 CString m_GitFile;
347 ~CGitHeadFileList()
349 //TRACE(_T("Free Index List 0x%x %s"),this, m_GitFile);
351 #endif
353 int ReadTree();
354 int ReadHeadHash(CString gitdir);
355 bool CheckHeadUpdate();
356 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
357 //int ReadTree();
360 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
361 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
363 public:
365 CComCriticalSection m_critTreeSec;
367 CGitHeadFileMap() { m_critTreeSec.Init(); }
368 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
370 SHARED_TREE_PTR SafeGet(const CString &path)
372 CString thePath = path;
373 thePath.MakeLower();
374 CAutoLocker lock(m_critTreeSec);
375 if(this->find(thePath) == end())
376 return SHARED_TREE_PTR();
377 else
378 return (*this)[thePath];
381 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
383 CString thePath = path;
384 thePath.MakeLower();
385 CAutoLocker lock(m_critTreeSec);
386 (*this)[thePath] = ptr;
389 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
390 FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,
391 bool isLoaded=false);
392 bool CheckHeadUpdate(const CString &gitdir);
393 int GetHeadHash(const CString &gitdir, CGitHash &hash);
396 bool IsHashChanged(const CString &gitdir)
398 SHARED_TREE_PTR ptr = SafeGet(gitdir);
400 if( ptr.get() == NULL)
401 return false;
403 return ptr->m_Head != ptr->m_TreeHash;
408 class CGitFileName
410 public:
411 CString m_FileName;
412 CString m_CaseFileName;
415 class CGitIgnoreItem
417 public:
418 SharedMutex m_SharedMutex;
420 CGitIgnoreItem()
422 m_LastModifyTime =0;
423 m_pExcludeList =NULL;
425 ~CGitIgnoreItem()
427 if(m_pExcludeList)
428 git_free_exclude_list(m_pExcludeList);
429 m_pExcludeList=NULL;
431 __time64_t m_LastModifyTime;
432 CStringA m_BaseDir;
433 EXCLUDE_LIST m_pExcludeList;
434 int FetchIgnoreList(const CString &projectroot, const CString &file);
437 class CGitIgnoreList
439 private:
440 bool CheckFileChanged(const CString &path);
441 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore);
443 int CheckIgnore(const CString &path,const CString &root);
445 public:
446 SharedMutex m_SharedMutex;
448 CGitIgnoreList(){ m_SharedMutex.Init(); }
449 ~CGitIgnoreList() { m_SharedMutex.Release(); }
451 std::map<CString, CGitIgnoreItem> m_Map;
453 int GetIgnoreFileChangeTimeList(const CString &dir, std::vector<__int64> &timelist);
454 bool CheckIgnoreChanged(const CString &gitdir,const CString &path);
455 int LoadAllIgnoreFile(const CString &gitdir,const CString &path);
456 bool IsIgnore(const CString &path,const CString &root);
459 template<class T>
460 int GetRangeInSortVector(T &vector,LPTSTR pstr,int len, int *start, int *end, int pos)
462 if( pos < 0)
464 return -1;
466 if(start == 0 || end == NULL)
467 return -1;
469 *start=*end=-1;
471 if(vector.size() ==0)
472 return -1;
474 if(pos >= vector.size())
475 return -1;
477 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
479 for(int i=0;i< vector.size();i++)
481 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
483 if(*start<0)
484 *start =i;
485 *end =i;
488 return -1;
490 else
492 *start =0;
493 *end = vector.size();
495 for(int i=pos;i<vector.size();i++)
497 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
499 *end=i;
501 else
503 break;
506 for(int i=pos;i>=0;i--)
508 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
510 *start=i;
512 else
514 break;
518 return 0;
521 template<class T>
522 int SearchInSortVector(T &vector, LPTSTR pstr, int len)
524 int end=vector.size()-1;
525 int start = 0;
526 int mid = (start+end)/2;
528 if(vector.size() == 0)
529 return -1;
531 while(!( start == end && start==mid))
533 int cmp;
534 if(len < 0)
535 cmp = _tcscmp(vector[mid].m_FileName,pstr);
536 else
537 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
539 if(cmp ==0)
540 return mid;
542 if(cmp < 0)
544 start = mid+1;
547 if(cmp > 0)
549 end=mid;
551 mid=(start +end ) /2;
554 if(len <0)
556 if(_tcscmp(vector[mid].m_FileName,pstr) == 0)
557 return mid;
559 else
561 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
562 return mid;
564 return -1;
566 #if 0
568 class CGitStatus
570 protected:
571 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);
572 public:
573 CGitIgnoreList m_IgnoreList;
574 CGitHeadFileMap m_HeadFilesMap;
575 CGitIndexFileMap m_IndexFilesMap;
577 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);
580 #endif