integrate libgit2 read tree function
[TortoiseGit.git] / src / Git / gitindex.h
blob0d5d638ed8cefbd20e2c6601dda49ca342337f8c
1 #include "GitHash.h"
2 #include "gitdll.h"
3 #include "gitstatus.h"
4 #include "SharedMutex.h"
6 /* Copy from Git cache.h*/
7 #define FLEX_ARRAY 4
9 #pragma pack(push)
10 #pragma pack(1)
11 //#pragma pack(show)
12 #define CACHE_SIGNATURE 0x44495243 /* "DIRC" */
13 struct cache_header {
14 unsigned int hdr_signature;
15 unsigned int hdr_version;
16 unsigned int hdr_entries;
20 * The "cache_time" is just the low 32 bits of the
21 * time. It doesn't matter if it overflows - we only
22 * check it for equality in the 32 bits we save.
24 struct cache_time {
25 UINT32 sec;
26 UINT32 nsec;
30 * dev/ino/uid/gid/size are also just tracked to the low 32 bits
31 * Again - this is just a (very strong in practice) heuristic that
32 * the inode hasn't changed.
34 * We save the fields in big-endian order to allow using the
35 * index file over NFS transparently.
37 struct ondisk_cache_entry {
38 struct cache_time ctime;
39 struct cache_time mtime;
40 UINT32 dev;
41 UINT32 ino;
42 UINT32 mode;
43 UINT32 uid;
44 UINT32 gid;
45 UINT32 size;
46 BYTE sha1[20];
47 UINT16 flags;
48 char name[FLEX_ARRAY]; /* more */
52 * This struct is used when CE_EXTENDED bit is 1
53 * The struct must match ondisk_cache_entry exactly from
54 * ctime till flags
56 struct ondisk_cache_entry_extended {
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 UINT16 flags2;
68 char name[FLEX_ARRAY]; /* more */
71 #pragma pack(pop)
73 #define CE_NAMEMASK (0x0fff)
74 #define CE_STAGEMASK (0x3000)
75 #define CE_EXTENDED (0x4000)
76 #define CE_VALID (0x8000)
77 #define CE_STAGESHIFT 12
79 * Range 0xFFFF0000 in ce_flags is divided into
80 * two parts: in-memory flags and on-disk ones.
81 * Flags in CE_EXTENDED_FLAGS will get saved on-disk
82 * if you want to save a new flag, add it in
83 * CE_EXTENDED_FLAGS
85 * In-memory only flags
87 #define CE_UPDATE (0x10000)
88 #define CE_REMOVE (0x20000)
89 #define CE_UPTODATE (0x40000)
90 #define CE_ADDED (0x80000)
92 #define CE_HASHED (0x100000)
93 #define CE_UNHASHED (0x200000)
96 * Extended on-disk flags
98 #define CE_INTENT_TO_ADD 0x20000000
99 /* CE_EXTENDED2 is for future extension */
100 #define CE_EXTENDED2 0x80000000
102 #define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD)
105 * Safeguard to avoid saving wrong flags:
106 * - CE_EXTENDED2 won't get saved until its semantic is known
107 * - Bits in 0x0000FFFF have been saved in ce_flags already
108 * - Bits in 0x003F0000 are currently in-memory flags
110 #if CE_EXTENDED_FLAGS & 0x803FFFFF
111 #error "CE_EXTENDED_FLAGS out of range"
112 #endif
115 * Copy the sha1 and stat state of a cache entry from one to
116 * another. But we never change the name, or the hash state!
118 #define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
120 template<class T>
121 T Big2lit(T data)
123 T ret;
124 BYTE *p1=(BYTE*)&data;
125 BYTE *p2=(BYTE*)&ret;
126 for(int i=0;i<sizeof(T);i++)
128 p2[sizeof(T)-i-1] = p1[i];
130 return ret;
133 template<class T>
134 static inline size_t ce_namelen(T *ce)
136 size_t len = Big2lit(ce->flags) & CE_NAMEMASK;
137 if (len < CE_NAMEMASK)
138 return len;
139 return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK;
142 #define flexible_size(STRUCT,len) ((offsetof(STRUCT,name) + (len) + 8) & ~7)
144 //#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len)
145 //#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len)
147 //#define ondisk_ce_size(ce) (((ce)->flags & CE_EXTENDED) ? \
148 // ondisk_cache_entry_extended_size(ce_namelen(ce)) : \
149 // ondisk_cache_entry_size(ce_namelen(ce)))
151 template<class T>
152 static inline size_t ondisk_ce_size(T *ce)
154 return flexible_size(T,ce_namelen(ce));
157 class CGitIndex
159 public:
160 CString m_FileName;
161 __time64_t m_ModifyTime;
162 int m_Flags;
163 //int m_Status;
164 CGitHash m_IndexHash;
166 int FillData(ondisk_cache_entry* entry);
167 int FillData(ondisk_cache_entry_extended* entry);
168 int Print();
172 class CAutoReadLock
174 SharedMutex *m_Lock;
175 public:
176 CAutoReadLock(SharedMutex * lock)
178 m_Lock = lock;
179 lock->AcquireShared();
181 ~CAutoReadLock()
183 m_Lock->ReleaseShared();
187 class CAutoWriteLock
189 SharedMutex *m_Lock;
190 public:
191 CAutoWriteLock(SharedMutex * lock)
193 m_Lock = lock;
194 lock->AcquireExclusive();
196 ~CAutoWriteLock()
198 m_Lock->ReleaseExclusive();
202 class CGitIndexList:public std::vector<CGitIndex>
204 protected:
206 public:
207 __time64_t m_LastModifyTime;
209 #ifdef DEBUG
210 CString m_GitFile;
211 ~CGitIndexList()
213 TRACE(_T("Free Index List 0x%x %s"),this, m_GitFile);
215 #endif
217 CGitIndexList();
219 int ReadIndex(CString file);
220 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);
221 protected:
222 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);
223 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);
226 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
227 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
229 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
231 public:
232 CComCriticalSection m_critIndexSec;
234 CGitIndexFileMap() { m_critIndexSec.Init(); }
235 ~CGitIndexFileMap() { m_critIndexSec.Term(); }
237 SHARED_INDEX_PTR SafeGet(const CString &path)
239 CAutoLocker lock(m_critIndexSec);
240 if(this->find(path) == end())
241 return SHARED_INDEX_PTR();
242 else
243 return (*this)[path];
246 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
248 CAutoLocker lock(m_critIndexSec);
249 (*this)[path] = ptr;
252 int Check(const CString &gitdir, bool *isChanged);
253 int LoadIndex(const CString &gitdir);
255 void CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
257 bool isChanged=false;
258 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
259 return ;
261 if(isChanged && isLoadUpdatedIndex)
262 LoadIndex(gitdir);
264 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
265 BOOL IsFull=false, BOOL IsRecursive=false,
266 FIll_STATUS_CALLBACK callback=NULL,
267 void *pData=NULL,CGitHash *pHash=NULL,
268 bool isLoadUpdatedIndex=true);
270 int IsUnderVersionControl(const CString &gitdir,
271 const CString &path,
272 bool isDir,
273 bool *isVersion,
274 bool isLoadUpdateIndex=true);
278 class CGitTreeItem
280 public:
281 CString m_FileName;
282 CGitHash m_Hash;
283 int m_Flags;
286 /* After object create, never change field agains
287 * that needn't lock to get field
289 class CGitHeadFileList:public std::vector<CGitTreeItem>
291 private:
293 int GetPackRef(const CString &gitdir);
295 public:
296 __time64_t m_LastModifyTimeHead;
297 __time64_t m_LastModifyTimeRef;
298 __time64_t m_LastModifyTimePackRef;
300 CString m_HeadRefFile;
301 CGitHash m_Head;
302 CString m_HeadFile;
303 CString m_Gitdir;
304 CString m_PackRefFile;
306 CGitHash m_TreeHash; /* buffered tree hash value */
308 std::map<CString,CGitHash> m_PackRefMap;
310 CGitHeadFileList()
312 m_LastModifyTimeHead=0;
313 m_LastModifyTimeRef=0;
314 m_LastModifyTimePackRef = 0;
317 #ifdef DEBUG
318 CString m_GitFile;
319 ~CGitHeadFileList()
321 TRACE(_T("Free Index List 0x%x %s"),this, m_GitFile);
323 #endif
325 int ReadTree();
326 int ReadHeadHash(CString gitdir);
327 bool CheckHeadUpdate();
328 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
329 //int ReadTree();
332 typedef std::tr1::shared_ptr<CGitHeadFileList> SHARED_TREE_PTR;
333 class CGitHeadFileMap:public std::map<CString,SHARED_TREE_PTR>
335 public:
337 CComCriticalSection m_critTreeSec;
339 CGitHeadFileMap() { m_critTreeSec.Init(); }
340 ~CGitHeadFileMap() { m_critTreeSec.Term(); }
342 SHARED_TREE_PTR SafeGet(const CString &path)
344 CAutoLocker lock(m_critTreeSec);
345 if(this->find(path) == end())
346 return SHARED_TREE_PTR();
347 else
348 return (*this)[path];
351 void SafeSet(const CString &path, SHARED_TREE_PTR ptr)
353 CAutoLocker lock(m_critTreeSec);
354 (*this)[path] = ptr;
357 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,
358 FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL,
359 bool isLoaded=false);
360 int CheckHeadUpdate(const CString &gitdir);
361 int GetHeadHash(const CString &gitdir, CGitHash &hash);
363 #if 0
364 bool IsHashChanged(const CString &gitdir)
366 CAutoReadLock lock(&m_SharedMutex);
367 if( find(gitdir) == end())
368 return false;
370 CAutoReadLock lock1(&(*this).m_SharedMutex);
371 return (*this)[gitdir].m_Head != (*this)[gitdir].m_TreeHash;
373 #endif
378 class CGitIgnoreItem
380 public:
381 SharedMutex m_SharedMutex;
383 CGitIgnoreItem()
385 m_LastModifyTime =0;
386 m_pExcludeList =NULL;
388 ~CGitIgnoreItem()
390 if(m_pExcludeList)
391 git_free_exclude_list(m_pExcludeList);
392 m_pExcludeList=NULL;
394 __time64_t m_LastModifyTime;
395 CStringA m_BaseDir;
396 EXCLUDE_LIST m_pExcludeList;
397 int FetchIgnoreList(const CString &projectroot, const CString &file);
400 class CGitIgnoreList
402 private:
403 bool CheckFileChanged(const CString &path);
404 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore);
406 int CheckIgnore(const CString &path,const CString &root);
408 public:
409 SharedMutex m_SharedMutex;
411 CGitIgnoreList(){ m_SharedMutex.Init(); }
412 ~CGitIgnoreList() { m_SharedMutex.Release(); }
414 std::map<CString, CGitIgnoreItem> m_Map;
416 int GetIgnoreFileChangeTimeList(const CString &dir, std::vector<__int64> &timelist);
417 bool CheckIgnoreChanged(const CString &gitdir,const CString &path);
418 int LoadAllIgnoreFile(const CString &gitdir,const CString &path);
419 bool IsIgnore(const CString &path,const CString &root);
422 template<class T>
423 int GetRangeInSortVector(T &vector,LPTSTR pstr,int len, int *start, int *end, int pos)
425 if( pos < 0)
427 return -1;
429 if(start == 0 || end == NULL)
430 return -1;
432 *start=*end=-1;
433 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
435 for(int i=0;i< vector.size();i++)
437 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
439 if(*start<0)
440 *start =i;
441 *end =i;
444 return -1;
445 }else
447 *start =0;
448 *end = vector.size();
450 for(int i=pos;i<vector.size();i++)
452 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
454 *end=i;
455 }else
457 break;
460 for(int i=pos;i>=0;i--)
462 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
464 *start=i;
465 }else
467 break;
471 return 0;
474 template<class T>
475 int SearchInSortVector(T &vector, LPTSTR pstr, int len)
477 int end=vector.size()-1;
478 int start = 0;
479 int mid = (start+end)/2;
481 if(vector.size() == 0)
482 return -1;
484 while(!( start == end && start==mid))
486 int cmp;
487 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
489 if(cmp ==0)
490 return mid;
492 if(cmp < 0)
494 start = mid+1;
497 if(cmp > 0)
499 end=mid;
501 mid=(start +end ) /2;
505 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
506 return mid;
508 return -1;
510 #if 0
512 class CGitStatus
514 protected:
515 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);
516 public:
517 CGitIgnoreList m_IgnoreList;
518 CGitHeadFileMap m_HeadFilesMap;
519 CGitIndexFileMap m_IndexFilesMap;
521 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);
524 #endif