cleaups
[TortoiseGit.git] / src / Git / gitindex.h
blobf72477d0859e585be8912097aefc50cd72dd9e90
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 std::map<CString,int> m_Map;
227 __time64_t m_LastModifyTime;
229 SharedMutex m_SharedMutex;
231 CGitIndexList();
232 int ReadIndex(CString file);
233 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);
234 protected:
235 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);
236 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);
239 class CGitTreeItem
241 public:
242 CString m_FileName;
243 CGitHash m_Hash;
244 int m_Flags;
247 class CGitHeadFileList:public std::vector<CGitTreeItem>
249 private:
251 int GetPackRef(const CString &gitdir);
253 public:
254 std::map<CString,int> m_Map;
255 __time64_t m_LastModifyTimeHead;
256 __time64_t m_LastModifyTimeRef;
257 __time64_t m_LastModifyTimePackRef;
259 CString m_HeadRefFile;
260 CGitHash m_Head;
261 CString m_HeadFile;
262 CString m_Gitdir;
263 CString m_PackRefFile;
265 SharedMutex m_SharedMutex;
267 std::map<CString,CGitHash> m_PackRefMap;
269 CGitHash m_TreeHash; /* buffered tree hash value */
271 CGitHeadFileList()
273 m_LastModifyTimeHead=0;
274 m_LastModifyTimeRef=0;
275 m_LastModifyTimePackRef = 0;
278 int ReadHeadHash(CString gitdir);
279 bool CheckHeadUpdate();
281 static int CallBack(const unsigned char *, const char *, int, const char *, unsigned int, int, void *);
282 int ReadTree();
285 class CGitHeadFileMap:public std::map<CString,CGitHeadFileList>
287 public:
289 SharedMutex m_SharedMutex;
291 CGitHeadFileMap(){ m_SharedMutex.Init(); }
292 ~CGitHeadFileMap() { m_SharedMutex.Release(); }
294 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);
295 int CheckHeadUpdate(const CString &gitdir);
296 int GetHeadHash(const CString &gitdir, CGitHash &hash);
298 bool IsHashChanged(const CString &gitdir)
300 CAutoReadLock lock(&m_SharedMutex);
301 if( find(gitdir) == end())
302 return false;
304 CAutoReadLock lock1(&(*this).m_SharedMutex);
305 return (*this)[gitdir].m_Head != (*this)[gitdir].m_TreeHash;
310 class CGitIndexFileMap:public std::map<CString,CGitIndexList>
312 public:
313 SharedMutex m_SharedMutex;
315 CGitIndexFileMap(){ m_SharedMutex.Init(); }
316 ~CGitIndexFileMap() { m_SharedMutex.Release(); }
318 int CheckAndUpdateIndex(const CString &gitdir,bool *loaded=NULL);
320 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,CGitHash *pHash=NULL);
322 int IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir,bool *isVersion);
325 class CGitIgnoreItem
327 public:
328 SharedMutex m_SharedMutex;
330 CGitIgnoreItem()
332 m_LastModifyTime =0;
333 m_pExcludeList =NULL;
335 ~CGitIgnoreItem()
337 if(m_pExcludeList)
338 git_free_exclude_list(m_pExcludeList);
339 m_pExcludeList=NULL;
341 __time64_t m_LastModifyTime;
342 CStringA m_BaseDir;
343 EXCLUDE_LIST m_pExcludeList;
344 int FetchIgnoreList(const CString &projectroot, const CString &file);
347 class CGitIgnoreList
349 private:
350 bool CheckFileChanged(const CString &path);
351 int FetchIgnoreFile(const CString &gitdir, const CString &gitignore);
353 int CheckIgnore(const CString &path,const CString &root);
355 public:
356 SharedMutex m_SharedMutex;
358 CGitIgnoreList(){ m_SharedMutex.Init(); }
359 ~CGitIgnoreList() { m_SharedMutex.Release(); }
361 std::map<CString, CGitIgnoreItem> m_Map;
363 int GetIgnoreFileChangeTimeList(const CString &dir, std::vector<__int64> &timelist);
364 bool CheckIgnoreChanged(const CString &gitdir,const CString &path);
365 int LoadAllIgnoreFile(const CString &gitdir,const CString &path);
366 bool IsIgnore(const CString &path,const CString &root);
369 template<class T>
370 int GetRangeInSortVector(T &vector,LPTSTR pstr,int len, int *start, int *end, int pos)
372 if( pos < 0)
374 return -1;
376 if(start == 0 || end == NULL)
377 return -1;
379 *start=*end=-1;
380 if( _tcsnccmp(vector[pos].m_FileName, pstr,len) != 0)
382 for(int i=0;i< vector.size();i++)
384 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
386 if(*start<0)
387 *start =i;
388 *end =i;
391 return -1;
392 }else
394 *start =0;
395 *end = vector.size();
397 for(int i=pos;i<vector.size();i++)
399 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
401 *end=i;
402 }else
404 break;
407 for(int i=pos;i>=0;i--)
409 if( _tcsnccmp(vector[i].m_FileName, pstr,len) == 0 )
411 *start=i;
412 }else
414 break;
418 return 0;
421 template<class T>
422 int SearchInSortVector(T &vector, LPTSTR pstr, int len)
424 int end=vector.size()-1;
425 int start = 0;
426 int mid = (start+end)/2;
428 if(vector.size() == 0)
429 return -1;
431 while(!( start == end && start==mid))
433 int cmp;
434 cmp = _tcsnccmp( vector[mid].m_FileName,pstr,len );
436 if(cmp ==0)
437 return mid;
439 if(cmp < 0)
441 start = mid+1;
444 if(cmp > 0)
446 end=mid;
448 mid=(start +end ) /2;
452 if(_tcsnccmp( vector[mid].m_FileName,pstr,len ) == 0)
453 return mid;
455 return -1;
457 #if 0
459 class CGitStatus
461 protected:
462 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);
463 public:
464 CGitIgnoreList m_IgnoreList;
465 CGitHeadFileMap m_HeadFilesMap;
466 CGitIndexFileMap m_IndexFilesMap;
468 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);
471 #endif