8 #include "UnicodeUtils.h"
11 #include <sys/types.h>
14 typedef CComCritSecLock
<CComCriticalSection
> CAutoLocker
;
18 g_Git.StringAppend(&m_FileName,(BYTE*)entry->name,CP_ACP,Big2lit(entry->flags)&CE_NAMEMASK);\
19 this->m_Flags=Big2lit(entry->flags);\
20 this->m_ModifyTime=Big2lit(entry->mtime.sec);\
21 this->m_IndexHash=(char*)(entry->sha1);
23 int CGitIndex::FillData(ondisk_cache_entry
* entry
)
29 int CGitIndex::FillData(ondisk_cache_entry_extended
* entry
)
32 this->m_Flags
|= ((int)Big2lit(entry
->flags2
))<<16;
36 int CGitIndex::Print()
38 _tprintf(_T("0x%08X 0x%08X %s %s\n"),
39 (int)this->m_ModifyTime
,
41 this->m_IndexHash
.ToString(),
47 CGitIndexList::CGitIndexList()
49 this->m_LastModifyTime
=0;
52 int CGitIndexList::ReadIndex(CString IndexFile
)
66 hfile
= CreateFile(IndexFile
,
71 FILE_ATTRIBUTE_NORMAL
,
75 if(hfile
== INVALID_HANDLE_VALUE
)
82 DWORD size
=0,filesize
=0;
84 filesize
=GetFileSize(hfile
,NULL
);
86 if(filesize
== INVALID_FILE_SIZE
)
92 buffer
= new BYTE
[filesize
];
99 if(! ReadFile( hfile
, buffer
,filesize
,&size
,NULL
) )
101 ret
= GetLastError();
105 if (size
!= filesize
)
110 header
= (cache_header
*) buffer
;
111 if( Big2lit(header
->hdr_signature
) != CACHE_SIGNATURE
)
116 p
+= sizeof(cache_header
);
118 int entries
= Big2lit(header
->hdr_entries
);
119 for(int i
=0;i
<entries
;i
++)
121 ondisk_cache_entry
*entry
;
122 ondisk_cache_entry_extended
*entryex
;
123 entry
=(ondisk_cache_entry
*)p
;
124 entryex
=(ondisk_cache_entry_extended
*)p
;
125 int flags
=Big2lit(entry
->flags
);
126 if( flags
& CE_EXTENDED
)
128 GitIndex
.FillData(entryex
);
129 p
+=ondisk_ce_size(entryex
);
133 GitIndex
.FillData(entry
);
134 p
+=ondisk_ce_size(entry
);
137 if(p
>buffer
+filesize
)
142 this->push_back(GitIndex
);
143 this->m_Map
[GitIndex
.m_FileName
]=this->size()-1;
152 if(hfile
!= INVALID_HANDLE_VALUE
)
159 int CGitIndexList::GetFileStatus(CString
&gitdir
,CString
&path
,git_wc_status_kind
*status
,__int64 time
,FIll_STATUS_CALLBACK callback
,void *pData
, CGitHash
*pHash
)
164 if(m_Map
.find(path
) == m_Map
.end() )
166 *status
= git_wc_status_unversioned
;
173 int index
= m_Map
[path
];
179 if( time
== at(index
).m_ModifyTime
)
181 *status
= git_wc_status_normal
;
184 *status
= git_wc_status_modified
;
187 if(at(index
).m_Flags
& CE_STAGEMASK
)
188 *status
= git_wc_status_conflicted
;
189 else if(at(index
).m_Flags
& CE_INTENT_TO_ADD
)
190 *status
= git_wc_status_added
;
193 *pHash
= at(index
).m_IndexHash
;
196 callback(gitdir
+_T("\\")+path
,*status
,false, pData
);
201 int CGitIndexList::GetStatus(CString
&gitdir
,CString
&path
, git_wc_status_kind
*status
,
202 BOOL IsFull
, BOOL IsRecursive
,
203 FIll_STATUS_CALLBACK callback
,void *pData
,
207 git_wc_status_kind dirstatus
= git_wc_status_none
;
214 result
= g_Git
.GetFileModifyTime(gitdir
,&time
,&isDir
);
216 result
= g_Git
.GetFileModifyTime( gitdir
+_T("\\")+path
, &time
, &isDir
);
220 *status
= git_wc_status_deleted
;
222 callback(gitdir
+_T("\\")+path
,git_wc_status_deleted
,false, pData
);
230 if( path
.Right(1) != _T("\\"))
233 int len
=path
.GetLength();
235 for(int i
=0;i
<size();i
++)
237 if( at(i
).m_FileName
.GetLength() > len
)
239 if(at(i
).m_FileName
.Left(len
) == path
)
243 *status
= git_wc_status_normal
;
245 callback(gitdir
+_T("\\")+path
,*status
,false, pData
);
250 result
= g_Git
.GetFileModifyTime( gitdir
+_T("\\")+at(i
).m_FileName
, &time
);
254 *status
= git_wc_status_none
;
255 GetFileStatus(gitdir
,at(i
).m_FileName
,status
,time
,callback
,pData
);
256 if( *status
!= git_wc_status_none
)
258 if( dirstatus
== git_wc_status_none
)
260 dirstatus
= git_wc_status_normal
;
262 if( *status
!= git_wc_status_normal
)
264 dirstatus
= git_wc_status_modified
;
273 if( dirstatus
!= git_wc_status_none
)
279 *status
= git_wc_status_unversioned
;
282 callback(gitdir
+_T("\\")+path
,*status
,false, pData
);
288 GetFileStatus(gitdir
,path
,status
,time
,callback
,pData
,pHash
);
294 int CGitIndexFileMap::CheckAndUpdateIndex(CString
&gitdir
,bool *loaded
)
302 IndexFile
=gitdir
+_T("\\.git\\index");
303 /* Get data associated with "crt_stat.c": */
304 result
= g_Git
.GetFileModifyTime( IndexFile
, &time
);
306 // WIN32_FILE_ATTRIBUTE_DATA FileInfo;
307 // GetFileAttributesEx(_T("D:\\tortoisegit\\src\\gpl.txt"),GetFileExInfoStandard,&FileInfo);
308 // result = _tstat64( _T("D:\\tortoisegit\\src\\gpl.txt"), &buf );
316 if((*this)[gitdir
].m_LastModifyTime
!= time
)
318 if((*this)[gitdir
].ReadIndex(IndexFile
))
323 (*this)[gitdir
].m_LastModifyTime
= time
;
332 int CGitIndexFileMap::GetFileStatus(CString
&gitdir
, CString
&path
, git_wc_status_kind
*status
,BOOL IsFull
, BOOL IsRecursive
,
333 FIll_STATUS_CALLBACK callback
,void *pData
,
339 CheckAndUpdateIndex(gitdir
);
340 (*this)[gitdir
].GetStatus(gitdir
,path
,status
,IsFull
,IsRecursive
,callback
,pData
,pHash
);
349 int CGitIndexFileMap::IsUnderVersionControl(CString
&gitdir
, CString
&path
, bool isDir
,bool *isVersion
)
358 CString subpath
=path
;
359 subpath
.Replace(_T('\\'), _T('/'));
363 CheckAndUpdateIndex(gitdir
);
366 *isVersion
= (SearchInSortVector((*this)[gitdir
], subpath
.GetBuffer(), subpath
.GetLength()) >= 0);
370 *isVersion
= ((*this)[gitdir
].m_Map
.find(subpath
) != (*this)[gitdir
].m_Map
.end());
379 int CGitHeadFileList::ReadHeadHash(CString gitdir
)
381 CString HeadFile
= gitdir
;
382 HeadFile
+= _T("\\.git\\HEAD");
387 m_HeadFile
= HeadFile
;
389 if( g_Git
.GetFileModifyTime(m_HeadFile
,&m_LastModifyTimeHead
))
392 hfile
= CreateFile(HeadFile
,
397 FILE_ATTRIBUTE_NORMAL
,
400 if(hfile
== INVALID_HANDLE_VALUE
)
403 DWORD size
=0,filesize
=0;
404 unsigned char buffer
[40] ;
405 ReadFile(hfile
,buffer
,4,&size
,NULL
);
410 if(strcmp((const char*)buffer
,"ref:") == 0)
412 filesize
= GetFileSize(hfile
,NULL
);
414 unsigned char *p
= (unsigned char*)malloc(filesize
-4);
416 ReadFile(hfile
,p
,filesize
-4,&size
,NULL
);
418 m_HeadRefFile
.Empty();
419 g_Git
.StringAppend(&this->m_HeadRefFile
,p
,CP_ACP
,filesize
-4);
421 m_HeadRefFile
=gitdir
+_T("\\.git\\")+m_HeadRefFile
.Trim();
422 m_HeadRefFile
.Replace(_T('/'),_T('\\'));
425 if(g_Git
.GetFileModifyTime(m_HeadRefFile
,&time
,NULL
))
430 href
= CreateFile(m_HeadRefFile
,
435 FILE_ATTRIBUTE_NORMAL
,
438 if(href
== INVALID_HANDLE_VALUE
)
441 ReadFile(href
,buffer
,40,&size
,NULL
);
445 this->m_Head
.ConvertFromStrA((char*)buffer
);
447 this->m_LastModifyTimeRef
= time
;
451 ReadFile(hfile
,buffer
+4,40-4,&size
,NULL
);
455 m_HeadRefFile
.Empty();
457 this->m_Head
.ConvertFromStrA((char*)buffer
);
463 bool CGitHeadFileList::CheckHeadUpdate()
465 if(this->m_HeadFile
.IsEmpty())
470 if( g_Git
.GetFileModifyTime(m_HeadFile
,&mtime
))
473 if(mtime
!= this->m_LastModifyTimeHead
)
476 if(!this->m_HeadRefFile
.IsEmpty())
478 if(g_Git
.GetFileModifyTime(m_HeadRefFile
,&mtime
))
481 if(mtime
!= this->m_LastModifyTimeRef
)
488 int CGitHeadFileList::ReadTree()
490 if( this->m_Head
.IsEmpty())
493 CAutoLocker
lock(g_Git
.m_critGitDllSec
);
495 if(m_Gitdir
!= g_Git
.m_CurrentDir
)
497 g_Git
.SetCurrentDir(m_Gitdir
);
498 SetCurrentDirectory(g_Git
.m_CurrentDir
);
501 return git_read_tree(this->m_Head
.m_hash
,CGitHeadFileList::CallBack
,this);
504 int CGitHeadFileList::CallBack(const unsigned char *sha1
, const char *base
, int baselen
,
505 const char *pathname
, unsigned mode
, int stage
, void *context
)
507 #define S_IFGITLINK 0160000
509 CGitHeadFileList
*p
= (CGitHeadFileList
*)context
;
512 if( (mode
&S_IFMT
) != S_IFGITLINK
)
513 return READ_TREE_RECURSIVE
;
516 unsigned int cur
= p
->size();
517 p
->resize(p
->size()+1);
518 p
->at(cur
).m_Hash
= (char*)sha1
;
519 p
->at(cur
).m_FileName
.Empty();
522 g_Git
.StringAppend(&p
->at(cur
).m_FileName
,(BYTE
*)base
,CP_ACP
,baselen
);
524 g_Git
.StringAppend(&p
->at(cur
).m_FileName
,(BYTE
*)pathname
,CP_ACP
);
526 //p->at(cur).m_FileName.Replace(_T('/'),_T('\\'));
528 p
->m_Map
[p
->at(cur
).m_FileName
]=cur
;
530 if( (mode
&S_IFMT
) == S_IFGITLINK
)
533 return READ_TREE_RECURSIVE
;
536 int CGitIgnoreItem::FetchIgnoreList(CString
&file
)
538 if(this->m_pExcludeList
)
540 free(m_pExcludeList
);
545 if(g_Git
.GetFileModifyTime(file
,&m_LastModifyTime
))
548 if(git_create_exclude_list(&this->m_pExcludeList
))
552 HANDLE hfile
= CreateFile(file
,
557 FILE_ATTRIBUTE_NORMAL
,
561 if(hfile
== INVALID_HANDLE_VALUE
)
566 DWORD size
=0,filesize
=0;
568 filesize
=GetFileSize(hfile
,NULL
);
570 if(filesize
== INVALID_FILE_SIZE
)
575 BYTE
*buffer
= new BYTE
[filesize
+1];
582 if(! ReadFile( hfile
, buffer
,filesize
,&size
,NULL
) )
584 return GetLastError();
588 for(int i
=0;i
<size
;i
++)
590 if( buffer
[i
] == '\n' || buffer
[i
] =='\r' || i
==(size
-1) )
597 if(p
[0] != '#' && p
[0] != 0)
598 git_add_exclude((const char*)p
, 0,0,this->m_pExcludeList
);
608 bool CGitIgnoreList::CheckFileChanged(CString
&path
)
611 int ret
=g_Git
.GetFileModifyTime(path
, &time
);
613 bool cacheExist
= (m_Map
.find(path
) != m_Map
.end());
614 // both cache and file is not exist
615 if( (ret
!= 0) && (!cacheExist
))
618 // file exist but cache miss
619 if( (ret
== 0) && (!cacheExist
))
622 // file not exist but cache exist
623 if( (ret
!= 0) && (cacheExist
))
626 // file exist and cache exist
627 if( m_Map
[path
].m_LastModifyTime
== time
)
634 bool CGitIgnoreList::CheckIgnoreChanged(CString
&gitdir
,CString
&path
)
641 while(!temp
.IsEmpty())
645 if(PathFileExists(temp
))
647 CString gitignore
=temp
;
648 gitignore
+= _T("ignore");
649 if( CheckFileChanged(gitignore
) )
652 temp
+=_T("\\info\\exclude");
654 if( CheckFileChanged(temp
) )
661 if( CheckFileChanged(temp
) )
667 for( i
=temp
.GetLength() -1;i
>=0;i
--)
669 if(temp
[i
] == _T('\\'))
681 int CGitIgnoreList::LoadAllIgnoreFile(CString
&gitdir
,CString
&path
)
689 while(!temp
.IsEmpty())
693 if(PathFileExists(temp
))
695 CString gitignore
= temp
;
696 gitignore
+= _T("ignore");
697 if( CheckFileChanged(gitignore
) )
699 m_Map
[gitignore
].FetchIgnoreList(gitignore
);
702 temp
+=_T("\\info\\exclude");
704 if( CheckFileChanged(temp
) )
706 return m_Map
[temp
].FetchIgnoreList(temp
);
712 if( CheckFileChanged(temp
) )
714 m_Map
[temp
].FetchIgnoreList(temp
);
720 for( i
=temp
.GetLength() -1;i
>=0;i
--)
722 if(temp
[i
] == _T('\\'))
733 bool CGitIgnoreList::IsIgnore(CString
&path
,CString
&projectroot
)
737 str
.Replace(_T('\\'),_T('/'));
740 ret
= CheckIgnore(path
, projectroot
);
743 int start
=str
.ReverseFind(_T('/'));
748 ret
= CheckIgnore(str
, projectroot
);
753 int CGitIgnoreList::CheckIgnore(CString
&path
,CString
&projectroot
)
757 CString temp
=projectroot
+_T("\\")+path
;
760 patha
= CUnicodeUtils::GetMulti(path
,CP_ACP
) ;
761 patha
.Replace('\\','/');
763 if(g_Git
.GetFileModifyTime(temp
,&time
,&dir
))
772 while(!temp
.IsEmpty())
775 x
=temp
.ReverseFind(_T('\\'));
779 temp
+=_T("\\.gitignore");
780 if(this->m_Map
.find(temp
) == m_Map
.end() )
787 patha
.Replace('\\', '/');
788 int pos
=patha
.ReverseFind('/');
789 base
= pos
>=0? patha
.GetBuffer()+pos
+1:patha
.GetBuffer();
791 int ret
=git_check_excluded_1( patha
, patha
.GetLength(), base
, &type
, m_Map
[temp
].m_pExcludeList
);
798 temp
= temp
.Left(temp
.GetLength()-11);
799 temp
+=_T("\\.git\\info\\exclude");
801 if(this->m_Map
.find(temp
) == m_Map
.end() )
806 int ret
=git_check_excluded_1( patha
, patha
.GetLength(), NULL
,&type
, m_Map
[temp
].m_pExcludeList
);
814 temp
= temp
.Left(temp
.GetLength()-18);
822 int CGitStatus::GetStatus(CString
&gitdir
, CString
&path
, git_wc_status_kind
*status
, BOOL IsFull
, BOOL IsRecursive
, FIll_STATUS_CALLBACK callback
, void *pData
)
828 git_wc_status_kind dirstatus
= git_wc_status_none
;
831 g_Git
.GetFileModifyTime(path
,&time
,&dir
);
839 result
= _tstat64( gitdir
, &buf
);
841 result
= _tstat64( gitdir
+_T("\\")+path
, &buf
);
846 if(buf
.st_mode
& _S_IFDIR
)
850 if( path
.Right(1) != _T("\\"))
853 int len
=path
.GetLength();
855 for(int i
=0;i
<size();i
++)
857 if( at(i
).m_FileName
.GetLength() > len
)
859 if(at(i
).m_FileName
.Left(len
) == path
)
863 *status
= git_wc_status_normal
;
865 callback(gitdir
+_T("\\")+path
,*status
,pData
);
870 result
= _tstat64( gitdir
+_T("\\")+at(i
).m_FileName
, &buf
);
874 *status
= git_wc_status_none
;
875 GetFileStatus(gitdir
,at(i
).m_FileName
,status
,buf
,callback
,pData
);
876 if( *status
!= git_wc_status_none
)
878 if( dirstatus
== git_wc_status_none
)
880 dirstatus
= git_wc_status_normal
;
882 if( *status
!= git_wc_status_normal
)
884 dirstatus
= git_wc_status_modified
;
893 if( dirstatus
!= git_wc_status_none
)
899 *status
= git_wc_status_unversioned
;
902 callback(gitdir
+_T("\\")+path
,*status
,pData
);
908 GetFileStatus(gitdir
,path
,status
,buf
,callback
,pData
);