Change git Index use shared Ptr
[TortoiseGit.git] / src / Git / gitindex.h
blobbdb0f29b87e320cb766d66135b494a7bd388f7fe
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 CGitIndexList();
210 int ReadIndex(CString file);
211 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);
212 protected:
213 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);
214 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);
217 typedef std::tr1::shared_ptr<CGitIndexList> SHARED_INDEX_PTR;
218 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
220 class CGitIndexFileMap:public std::map<CString, SHARED_INDEX_PTR>
222 public:
223 CComCriticalSection m_critGitDllSec;
225 CGitIndexFileMap() { m_critGitDllSec.Init(); }
226 ~CGitIndexFileMap() { m_critGitDllSec.Term(); }
228 SHARED_INDEX_PTR SafeGet(const CString &path)
230 CAutoLocker lock(m_critGitDllSec);
231 if(this->find(path) == end())
232 return SHARED_INDEX_PTR();
233 else
234 return (*this)[path];
237 void SafeSet(const CString &path, SHARED_INDEX_PTR ptr)
239 CAutoLocker lock(m_critGitDllSec);
240 (*this)[path] = ptr;
243 int Check(const CString &gitdir, bool *isChanged);
244 int LoadIndex(const CString &gitdir);
246 void CheckAndUpdate(const CString &gitdir,bool isLoadUpdatedIndex)
248 bool isChanged=false;
249 if(isLoadUpdatedIndex && Check(gitdir,&isChanged))
250 return ;
252 if(isChanged && isLoadUpdatedIndex)
253 LoadIndex(gitdir);
255 int GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind * status,
256 BOOL IsFull=false, BOOL IsRecursive=false,
257 FIll_STATUS_CALLBACK callback=NULL,
258 void *pData=NULL,CGitHash *pHash=NULL,
259 bool isLoadUpdatedIndex=true);
261 int IsUnderVersionControl(const CString &gitdir,
262 const CString &path,
263 bool isDir,
264 bool *isVersion,
265 bool isLoadUpdateIndex=true);
269 class CGitTreeItem
271 public:
272 CString m_FileName;
273 CGitHash m_Hash;
274 int m_Flags;
277 class CGitHeadFileList:public std::vector<CGitTreeItem>
279 private:
281 int GetPackRef(const CString &gitdir);
283 public:
284 std::map<CString,int> m_Map;
285 __time64_t m_LastModifyTimeHead;
286 __time64_t m_LastModifyTimeRef;
287 __time64_t m_LastModifyTimePackRef;
289 CString m_HeadRefFile;
290 CGitHash m_Head;
291 CString m_HeadFile;
292 CString m_Gitdir;
293 CString m_PackRefFile;
295 SharedMutex m_SharedMutex;
297 std::map<CString,CGitHash> m_PackRefMap;
299 CGitHash m_TreeHash; /* buffered tree hash value */
301 CGitHeadFileList()
303 m_LastModifyTimeHead=0;
304 m_LastModifyTimeRef=0;
305 m_LastModifyTimePackRef = 0;
308 int ReadHeadHash(CString gitdir);
309 bool CheckHeadUpdate();
311 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
312 int ReadTree();
315 class CGitHeadFileMap:public std::map<CString,CGitHeadFileList>
317 public:
319 SharedMutex m_SharedMutex;
321 CGitHeadFileMap(){ m_SharedMutex.Init(); }
322 ~CGitHeadFileMap() { m_SharedMutex.Release(); }
324 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);
325 int CheckHeadUpdate(const CString &gitdir);
326 int GetHeadHash(const CString &gitdir, CGitHash &hash);
328 bool IsHashChanged(const CString &gitdir)
330 CAutoReadLock lock(&m_SharedMutex);
331 if( find(gitdir) == end())
332 return false;
334 CAutoReadLock lock1(&(*this).m_SharedMutex);
335 return (*this)[gitdir].m_Head != (*this)[gitdir].m_TreeHash;
341 class CGitIgnoreItem
343 public:
344 SharedMutex m_SharedMutex;
346 CGitIgnoreItem()
348 m_LastModifyTime =0;
349 m_pExcludeList =NULL;
351 ~CGitIgnoreItem()
353 if(m_pExcludeList)
354 git_free_exclude_list(m_pExcludeList);
355 m_pExcludeList=NULL;
357 __time64_t m_LastModifyTime;
358 CStringA m_BaseDir;
359 EXCLUDE_LIST m_pExcludeList;
360 int FetchIgnoreList(const CString &projectroot, const CString &file);
363 class CGitIgnoreList
365 private:
366 bool CheckFileChanged(const CString &path);
367 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore);
369 int CheckIgnore(const CString &path,const CString &root);
371 public:
372 SharedMutex m_SharedMutex;
374 CGitIgnoreList(){ m_SharedMutex.Init(); }
375 ~CGitIgnoreList() { m_SharedMutex.Release(); }
377 std::map<CString, CGitIgnoreItem> m_Map;
379 int GetIgnoreFileChangeTimeList(const CString &dir, std::vector<__int64> &timelist);
380 bool CheckIgnoreChanged(const CString &gitdir,const CString &path);
381 int LoadAllIgnoreFile(const CString &gitdir,const CString &path);
382 bool IsIgnore(const CString &path,const CString &root);
385 template<class T>
386 int GetRangeInSortVector(T &vector,LPTSTR pstr,int len, int *start, int *end, int pos)
388 if( pos < 0)
390 return -1;
392 if(start == 0 || end == NULL)
393 return -1;
395 *start=*end=-1;
396 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
398 for(int i=0;i< vector.size();i++)
400 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
402 if(*start<0)
403 *start =i;
404 *end =i;
407 return -1;
408 }else
410 *start =0;
411 *end = vector.size();
413 for(int i=pos;i<vector.size();i++)
415 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
417 *end=i;
418 }else
420 break;
423 for(int i=pos;i>=0;i--)
425 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
427 *start=i;
428 }else
430 break;
434 return 0;
437 template<class T>
438 int SearchInSortVector(T &vector, LPTSTR pstr, int len)
440 int end=vector.size()-1;
441 int start = 0;
442 int mid = (start+end)/2;
444 if(vector.size() == 0)
445 return -1;
447 while(!( start == end && start==mid))
449 int cmp;
450 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
452 if(cmp ==0)
453 return mid;
455 if(cmp < 0)
457 start = mid+1;
460 if(cmp > 0)
462 end=mid;
464 mid=(start +end ) /2;
468 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
469 return mid;
471 return -1;
473 #if 0
475 class CGitStatus
477 protected:
478 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);
479 public:
480 CGitIgnoreList m_IgnoreList;
481 CGitHeadFileMap m_HeadFilesMap;
482 CGitIndexFileMap m_IndexFilesMap;
484 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);
487 #endif