Change git Index use shared Ptr
[TortoiseGit.git] / src / Git / GitIndex.cpp
blob54286c743d315827b6482892a3aae4c05a53e68c
1 #include "StdAfx.h"
2 #include "Git.h"
3 #include "atlconv.h"
4 #include "GitRev.h"
5 #include "registry.h"
6 #include "GitConfig.h"
7 #include <map>
8 #include "UnicodeUtils.h"
9 #include "TGitPath.h"
10 #include "gitindex.h"
11 #include <sys/types.h>
12 #include <sys/stat.h>
16 #define FILL_DATA() \
17 m_FileName.Empty();\
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)
25 FILL_DATA();
26 return 0;
29 int CGitIndex::FillData(ondisk_cache_entry_extended * entry)
31 FILL_DATA();
32 this->m_Flags |= ((int)Big2lit(entry->flags2))<<16;
33 return 0;
36 int CGitIndex::Print()
38 _tprintf(_T("0x%08X 0x%08X %s %s\n"),
39 (int)this->m_ModifyTime,
40 this->m_Flags,
41 this->m_IndexHash.ToString(),
42 this->m_FileName);
44 return 0;
47 CGitIndexList::CGitIndexList()
49 this->m_LastModifyTime=0;
52 int CGitIndexList::ReadIndex(CString IndexFile)
54 HANDLE hfile=INVALID_HANDLE_VALUE;
55 HANDLE hmap = INVALID_HANDLE_VALUE;
56 int ret=0;
57 BYTE *buffer=NULL,*p;
58 CGitIndex GitIndex;
60 try
64 this->clear();
66 hfile = CreateFile(IndexFile,
67 GENERIC_READ,
68 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
69 NULL,
70 OPEN_EXISTING,
71 FILE_ATTRIBUTE_NORMAL,
72 NULL);
75 if(hfile == INVALID_HANDLE_VALUE)
77 ret = -1 ;
78 break;
81 hmap = CreateFileMapping(hfile, NULL, PAGE_READONLY,0,0,NULL);
82 if(hmap == INVALID_HANDLE_VALUE)
84 ret = -1;
85 break;
88 buffer = (BYTE*)MapViewOfFile(hmap,FILE_MAP_READ,0,0,0);
89 if(buffer == NULL)
91 ret = -1;
92 break;
95 cache_header *header;
96 header = (cache_header *) buffer;
98 if( Big2lit(header->hdr_signature) != CACHE_SIGNATURE )
100 ret = -1;
101 break;
103 p+= sizeof(cache_header);
105 int entries = Big2lit(header->hdr_entries);
106 resize(entries);
108 for(int i=0;i<entries;i++)
110 ondisk_cache_entry *entry;
111 ondisk_cache_entry_extended *entryex;
112 entry=(ondisk_cache_entry*)p;
113 entryex=(ondisk_cache_entry_extended*)p;
114 int flags=Big2lit(entry->flags);
115 if( flags & CE_EXTENDED)
117 GitIndex.FillData(entryex);
118 p+=ondisk_ce_size(entryex);
119 }else
121 GitIndex.FillData(entry);
122 p+=ondisk_ce_size(entry);
125 this->push_back(GitIndex);
127 }while(0);
128 }catch(...)
130 ret= -1;
133 if(buffer)
134 UnmapViewOfFile(buffer);
136 if(hmap != INVALID_HANDLE_VALUE)
137 CloseHandle(hfile);
139 if(hfile != INVALID_HANDLE_VALUE)
140 CloseHandle(hfile);
142 return ret;
145 int CGitIndexList::GetFileStatus(const CString &gitdir,const CString &path,git_wc_status_kind *status,__int64 time,FIll_STATUS_CALLBACK callback,void *pData, CGitHash *pHash)
147 if(status)
149 int start=SearchInSortVector(*this, ((CString&)path).GetBuffer(), path.GetLength());
150 ((CString&)path).ReleaseBuffer();
152 if( start<0 )
154 *status = git_wc_status_unversioned;
155 if(pHash)
156 pHash->Empty();
158 }else
160 int index = start;
161 if(index <0)
162 return -1;
163 if(index >= size() )
164 return -1;
166 if( time == at(index).m_ModifyTime )
168 *status = git_wc_status_normal;
169 }else
171 *status = git_wc_status_modified;
174 if(at(index).m_Flags & CE_STAGEMASK )
175 *status = git_wc_status_conflicted;
176 else if(at(index).m_Flags & CE_INTENT_TO_ADD)
177 *status = git_wc_status_added;
179 if(pHash)
180 *pHash = at(index).m_IndexHash;
185 if(callback && status)
186 callback(gitdir+_T("\\")+path,*status,false, pData);
187 return 0;
190 int CGitIndexList::GetStatus(const CString &gitdir,const CString &pathParam, git_wc_status_kind *status,
191 BOOL IsFull, BOOL IsRecursive,
192 FIll_STATUS_CALLBACK callback,void *pData,
193 CGitHash *pHash)
195 int result;
196 git_wc_status_kind dirstatus = git_wc_status_none;
197 __int64 time;
198 bool isDir=false;
199 CString path = pathParam;
201 if(status)
203 if(path.IsEmpty())
204 result = g_Git.GetFileModifyTime(gitdir,&time,&isDir);
205 else
206 result = g_Git.GetFileModifyTime( gitdir+_T("\\")+path, &time, &isDir );
208 if(result)
210 *status = git_wc_status_deleted;
211 if(callback)
212 callback(gitdir+_T("\\")+path,git_wc_status_deleted,false, pData);
214 return 0;
216 if(isDir)
218 if(!path.IsEmpty())
220 if( path.Right(1) != _T("\\"))
221 path+=_T("\\");
223 int len =path.GetLength();
225 for(int i=0;i<size();i++)
227 if( at(i).m_FileName.GetLength() > len )
229 if(at(i).m_FileName.Left(len) == path)
231 if( !IsFull )
233 *status = git_wc_status_normal;
234 if(callback)
235 callback(gitdir+_T("\\")+path,*status,false, pData);
236 return 0;
238 }else
240 result = g_Git.GetFileModifyTime( gitdir+_T("\\")+at(i).m_FileName , &time);
241 if(result)
242 continue;
244 *status = git_wc_status_none;
245 GetFileStatus(gitdir,at(i).m_FileName,status,time,callback,pData);
246 if( *status != git_wc_status_none )
248 if( dirstatus == git_wc_status_none)
250 dirstatus = git_wc_status_normal;
252 if( *status != git_wc_status_normal )
254 dirstatus = git_wc_status_modified;
261 } /* End For */
263 if( dirstatus != git_wc_status_none )
265 *status = dirstatus;
267 else
269 *status = git_wc_status_unversioned;
271 if(callback)
272 callback(gitdir+_T("\\")+path,*status,false, pData);
274 return 0;
276 }else
278 GetFileStatus(gitdir,path,status,time,callback,pData,pHash);
281 return 0;
284 int CGitIndexFileMap::Check(const CString &gitdir, bool *isChanged)
286 __int64 time;
287 int result;
289 CString IndexFile;
290 IndexFile=gitdir+_T("\\.git\\index");
291 /* Get data associated with "crt_stat.c": */
292 result = g_Git.GetFileModifyTime( IndexFile, &time );
294 if(result)
295 return result;
297 SHARED_INDEX_PTR pIndex;
298 pIndex = this->SafeGet(gitdir);
300 if(pIndex.get() == NULL)
302 if(isChanged)
303 *isChanged = true;
306 if(pIndex->m_LastModifyTime == time)
308 if(isChanged)
309 *isChanged = false;
311 else
313 if(isChanged)
314 *isChanged = true;
316 return 0;
319 int CGitIndexFileMap::LoadIndex(const CString &gitdir)
323 SHARED_INDEX_PTR pIndex(new CGitIndexList);
325 if(pIndex->ReadIndex(gitdir+_T("\\.git\\index")))
326 return -1;
328 this->SafeSet(gitdir,pIndex);
330 }catch(...)
332 return -1;
334 return 0;
337 int CGitIndexFileMap::GetFileStatus(const CString &gitdir, const CString &path, git_wc_status_kind *status,BOOL IsFull, BOOL IsRecursive,
338 FIll_STATUS_CALLBACK callback,void *pData,
339 CGitHash *pHash,
340 bool isLoadUpdatedIndex)
344 CheckAndUpdate(gitdir, isLoadUpdatedIndex);
346 SHARED_INDEX_PTR pIndex = this->SafeGet(gitdir);
347 if(pIndex.get() != NULL)
349 pIndex->GetStatus(gitdir,path,status,IsFull,IsRecursive,callback,pData,pHash);
352 }catch(...)
354 return -1;
356 return 0;
359 int CGitIndexFileMap::IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir,bool *isVersion, bool isLoadUpdateIndex)
363 if(path.IsEmpty())
365 *isVersion =true;
366 return 0;
369 CString subpath=path;
370 subpath.Replace(_T('\\'), _T('/'));
371 if(isDir)
372 subpath+=_T('/');
374 CheckAndUpdate(gitdir, isLoadUpdateIndex);
376 SHARED_INDEX_PTR pIndex = this->SafeGet(gitdir);
378 if(pIndex.get())
380 *isVersion = (SearchInSortVector(*pIndex, subpath.GetBuffer(), subpath.GetLength()) >= 0);
383 }catch(...)
385 return -1;
387 return 0;
390 int CGitHeadFileList::GetPackRef(const CString &gitdir)
392 CString PackRef = gitdir;
393 PackRef += _T("\\.git\\packed-refs");
395 __int64 mtime;
396 if( g_Git.GetFileModifyTime(PackRef, &mtime))
398 CAutoWriteLock lock(&this->m_SharedMutex);
399 //packed refs is not existed
400 this->m_PackRefFile.Empty();
401 this->m_PackRefMap.clear();
402 return 0;
404 }else if(mtime == m_LastModifyTimePackRef)
406 return 0;
408 }else
410 CAutoWriteLock lock(&this->m_SharedMutex);
411 this->m_PackRefFile = PackRef;
412 this->m_LastModifyTimePackRef = mtime;
415 int ret =0;
417 CAutoWriteLock lock(&this->m_SharedMutex);
419 this->m_PackRefMap.clear();
421 HANDLE hfile = CreateFile(PackRef,
422 GENERIC_READ,
423 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
424 NULL,
425 OPEN_EXISTING,
426 FILE_ATTRIBUTE_NORMAL,
427 NULL);
430 if(hfile == INVALID_HANDLE_VALUE)
432 ret = -1;
433 break;
436 int filesize = GetFileSize(hfile,NULL);
437 DWORD size =0;
438 char *buff;
439 buff = new char[filesize];
441 ReadFile(hfile,buff,filesize,&size,NULL);
443 if(size != filesize)
445 ret = -1;
446 break;
449 CString hash;
450 CString ref;
452 for(int i=0;i<filesize;i++)
454 hash.Empty();
455 ref.Empty();
456 if(buff[i] == '#')
458 while(buff[i] != '\n')
459 { i++;
460 if( i==filesize)
461 break;
463 i++;
466 if( i== filesize)
467 break;
469 while(buff[i] != ' ')
471 hash.AppendChar(buff[i]);
472 i++;
473 if(i==filesize)
474 break;
477 i++;
478 if( i== filesize)
479 break;
481 while(buff[i] != '\n')
483 ref.AppendChar(buff[i]);
484 i++;
485 if( i== filesize)
486 break;
489 i++;
491 if( !ref.IsEmpty() )
493 this->m_PackRefMap[ref] = hash;
499 delete buff;
501 }while(0);
503 if( hfile != INVALID_HANDLE_VALUE)
504 CloseHandle(hfile);
506 return ret;
509 int CGitHeadFileList::ReadHeadHash(CString gitdir)
511 CString HeadFile = gitdir;
512 HeadFile += _T("\\.git\\HEAD");
515 HANDLE hfile=INVALID_HANDLE_VALUE;
516 HANDLE href = INVALID_HANDLE_VALUE;
518 int ret = 0;
519 m_Gitdir = gitdir;
521 m_HeadFile = HeadFile;
523 if( g_Git.GetFileModifyTime(m_HeadFile,&m_LastModifyTimeHead))
524 return -1;
528 CAutoWriteLock lock(&this->m_SharedMutex);
532 hfile = CreateFile(HeadFile,
533 GENERIC_READ,
534 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
535 NULL,
536 OPEN_EXISTING,
537 FILE_ATTRIBUTE_NORMAL,
538 NULL);
540 if(hfile == INVALID_HANDLE_VALUE)
542 ret = -1;
543 break;
546 DWORD size=0,filesize=0;
547 unsigned char buffer[40] ;
548 ReadFile(hfile,buffer,4,&size,NULL);
549 if(size !=4)
551 ret = -1;
552 break;
554 buffer[4]=0;
555 if(strcmp((const char*)buffer,"ref:") == 0)
557 filesize = GetFileSize(hfile,NULL);
559 unsigned char *p = (unsigned char*)malloc(filesize -4);
561 ReadFile(hfile,p,filesize-4,&size,NULL);
563 m_HeadRefFile.Empty();
564 g_Git.StringAppend(&this->m_HeadRefFile,p,CP_ACP,filesize-4);
565 CString ref = this->m_HeadRefFile;
566 ref=ref.Trim();
567 int start =0;
568 ref=ref.Tokenize(_T("\n"),start);
569 free(p);
570 m_HeadRefFile=gitdir+_T("\\.git\\")+m_HeadRefFile.Trim();
571 m_HeadRefFile.Replace(_T('/'),_T('\\'));
573 __int64 time;
574 if(g_Git.GetFileModifyTime(m_HeadRefFile,&time,NULL))
576 m_HeadRefFile.Empty();
577 if( GetPackRef(gitdir))
579 ret = -1;
580 break;
582 if(this->m_PackRefMap.find(ref) == m_PackRefMap.end())
584 ret = -1;
585 break;
587 this ->m_Head = m_PackRefMap[ref];
588 ret =0;
589 break;
592 href = CreateFile(m_HeadRefFile,
593 GENERIC_READ,
594 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
595 NULL,
596 OPEN_EXISTING,
597 FILE_ATTRIBUTE_NORMAL,
598 NULL);
600 if(href == INVALID_HANDLE_VALUE)
602 m_HeadRefFile.Empty();
604 if( GetPackRef(gitdir))
606 ret = -1;
607 break;
610 if(this->m_PackRefMap.find(ref) == m_PackRefMap.end())
612 ret = -1;
613 break;
615 this ->m_Head = m_PackRefMap[ref];
616 ret =0;
617 break;
619 ReadFile(href,buffer,40,&size,NULL);
620 if(size != 40)
622 ret =-1;
623 break;
625 this->m_Head.ConvertFromStrA((char*)buffer);
627 this->m_LastModifyTimeRef = time;
629 }else
631 ReadFile(hfile,buffer+4,40-4,&size,NULL);
632 if(size !=36)
634 ret =-1;
635 break;
637 m_HeadRefFile.Empty();
639 this->m_Head.ConvertFromStrA((char*)buffer);
641 }while(0);
642 }catch(...)
644 ret = -1;
647 if(hfile != INVALID_HANDLE_VALUE)
648 CloseHandle(hfile);
649 if(href != INVALID_HANDLE_VALUE)
650 CloseHandle(href);
652 return ret;
655 bool CGitHeadFileList::CheckHeadUpdate()
657 if(this->m_HeadFile.IsEmpty())
658 return true;
660 __int64 mtime=0;
662 if( g_Git.GetFileModifyTime(m_HeadFile,&mtime))
663 return true;
665 if(mtime != this->m_LastModifyTimeHead)
666 return true;
668 if(!this->m_HeadRefFile.IsEmpty())
670 if(g_Git.GetFileModifyTime(m_HeadRefFile,&mtime))
671 return true;
673 if(mtime != this->m_LastModifyTimeRef)
674 return true;
677 if(!this->m_PackRefFile.IsEmpty())
679 if(g_Git.GetFileModifyTime(m_PackRefFile,&mtime))
680 return true;
682 if(mtime != this->m_LastModifyTimePackRef)
683 return true;
685 return false;
688 int CGitHeadFileList::ReadTree()
690 int ret;
691 if( this->m_Head.IsEmpty())
692 return -1;
696 CAutoLocker lock(g_Git.m_critGitDllSec);
697 CAutoWriteLock lock1(&this->m_SharedMutex);
699 if(m_Gitdir != g_Git.m_CurrentDir)
701 g_Git.SetCurrentDir(m_Gitdir);
702 SetCurrentDirectory(g_Git.m_CurrentDir);
703 git_init();
706 this->m_Map.clear();
707 this->clear();
709 ret = git_read_tree(this->m_Head.m_hash,CGitHeadFileList::CallBack,this);
710 if(!ret)
711 m_TreeHash = m_Head;
713 } catch(...)
715 return -1;
717 return ret;
720 int CGitHeadFileList::CallBack(const unsigned char *sha1, const char *base, int baselen,
721 const char *pathname, unsigned mode, int stage, void *context)
723 #define S_IFGITLINK 0160000
725 CGitHeadFileList *p = (CGitHeadFileList*)context;
726 if( mode&S_IFDIR )
728 if( (mode&S_IFMT) != S_IFGITLINK)
729 return READ_TREE_RECURSIVE;
732 unsigned int cur = p->size();
733 p->resize(p->size()+1);
734 p->at(cur).m_Hash = (char*)sha1;
735 p->at(cur).m_FileName.Empty();
737 if(base)
738 g_Git.StringAppend(&p->at(cur).m_FileName,(BYTE*)base,CP_ACP,baselen);
740 g_Git.StringAppend(&p->at(cur).m_FileName,(BYTE*)pathname,CP_ACP);
742 //p->at(cur).m_FileName.Replace(_T('/'),_T('\\'));
744 p->m_Map[p->at(cur).m_FileName]=cur;
746 if( (mode&S_IFMT) == S_IFGITLINK)
747 return 0;
749 return READ_TREE_RECURSIVE;
752 int CGitIgnoreItem::FetchIgnoreList(const CString &projectroot, const CString &file)
754 CAutoWriteLock lock(&this->m_SharedMutex);
756 if(this->m_pExcludeList)
758 free(m_pExcludeList);
759 m_pExcludeList=NULL;
762 this->m_BaseDir.Empty();
763 if( projectroot.GetLength() < file.GetLength())
765 CString base = file.Mid(projectroot.GetLength()+1);
766 base.Replace(_T('\\'), _T('/'));
767 if(base != _T(".git/info/exclude"))
769 int start=base.ReverseFind(_T('/'));
770 if(start>=0)
772 base=base.Left(start);
773 this->m_BaseDir = CUnicodeUtils::GetMulti(base,CP_ACP) ;
779 if(g_Git.GetFileModifyTime(file,&m_LastModifyTime))
780 return -1;
782 if(git_create_exclude_list(&this->m_pExcludeList))
783 return -1;
786 HANDLE hfile = CreateFile(file,
787 GENERIC_READ,
788 FILE_SHARE_READ|FILE_SHARE_DELETE|FILE_SHARE_WRITE,
789 NULL,
790 OPEN_EXISTING,
791 FILE_ATTRIBUTE_NORMAL,
792 NULL);
795 if(hfile == INVALID_HANDLE_VALUE)
797 return -1 ;
800 DWORD size=0,filesize=0;
802 filesize=GetFileSize(hfile,NULL);
804 if(filesize == INVALID_FILE_SIZE )
806 CloseHandle(hfile);
807 return -1;
810 BYTE *buffer = new BYTE[filesize+1];
812 if(buffer == NULL)
814 CloseHandle(hfile);
815 return -1;
818 if(! ReadFile( hfile, buffer,filesize,&size,NULL) )
820 CloseHandle(hfile);
821 return GetLastError();
824 CloseHandle(hfile);
826 BYTE *p = buffer;
827 for(int i=0;i<size;i++)
829 if( buffer[i] == '\n' || buffer[i] =='\r' || i==(size-1) )
831 if (buffer[i] == '\n' || buffer[i] =='\r')
832 buffer[i]=0;
833 if( i== size-1)
834 buffer[size]=0;
836 if(p[0] != '#' && p[0] != 0)
837 git_add_exclude((const char*)p,
838 this->m_BaseDir.GetBuffer(),
839 m_BaseDir.GetLength(),
840 this->m_pExcludeList);
842 p=buffer+i+1;
845 /* Can't free buffer, exluced list will use this buffer*/
846 //delete buffer;
847 //buffer=NULL;
849 return 0;
852 bool CGitIgnoreList::CheckFileChanged(const CString &path)
854 __int64 time=0;
856 int ret=g_Git.GetFileModifyTime(path, &time);
858 this->m_SharedMutex.AcquireShared();
859 bool cacheExist = (m_Map.find(path) != m_Map.end());
860 this->m_SharedMutex.ReleaseShared();
862 if (!cacheExist && ret == 0)
864 CAutoWriteLock lock(&this->m_SharedMutex);
865 m_Map[path].m_LastModifyTime = 0;
866 m_Map[path].m_SharedMutex.Init();
868 // both cache and file is not exist
869 if( (ret != 0) && (!cacheExist))
870 return false;
872 // file exist but cache miss
873 if( (ret == 0) && (!cacheExist))
874 return true;
876 // file not exist but cache exist
877 if( (ret != 0) && (cacheExist))
879 return true;
881 // file exist and cache exist
884 CAutoReadLock lock(&this->m_SharedMutex);
885 if( m_Map[path].m_LastModifyTime == time )
886 return false;
888 return true;
892 bool CGitIgnoreList::CheckIgnoreChanged(const CString &gitdir,const CString &path)
894 CString temp;
895 temp=gitdir;
896 temp+=_T("\\");
897 temp+=path;
899 temp.Replace(_T('/'), _T('\\'));
901 while(!temp.IsEmpty())
903 temp+=_T("\\.git");
905 if(CGit::GitPathFileExists(temp))
907 CString gitignore=temp;
908 gitignore += _T("ignore");
909 if( CheckFileChanged(gitignore) )
910 return true;
912 temp+=_T("\\info\\exclude");
914 if( CheckFileChanged(temp) )
915 return true;
916 else
917 return false;
918 }else
920 temp+=_T("ignore");
921 if( CheckFileChanged(temp) )
922 return true;
925 int found=0;
926 int i;
927 for( i=temp.GetLength() -1;i>=0;i--)
929 if(temp[i] == _T('\\'))
930 found ++;
932 if(found == 2)
933 break;
936 temp = temp.Left(i);
938 return true;
941 int CGitIgnoreList::FetchIgnoreFile(const CString &gitdir, const CString &gitignore)
943 if(CGit::GitPathFileExists(gitignore)) //if .gitignore remove, we need remote cache
945 CAutoWriteLock lock(&this->m_SharedMutex);
946 if(m_Map.find(gitignore) == m_Map.end())
947 m_Map[gitignore].m_SharedMutex.Init();
949 m_Map[gitignore].FetchIgnoreList(gitdir,gitignore);
951 else
953 CAutoWriteLock lock(&this->m_SharedMutex);
954 if(m_Map.find(gitignore) != m_Map.end())
955 m_Map[gitignore].m_SharedMutex.Release();
957 m_Map.erase(gitignore);
959 return 0;
962 int CGitIgnoreList::LoadAllIgnoreFile(const CString &gitdir,const CString &path)
964 CString temp;
966 temp=gitdir;
967 temp+=_T("\\");
968 temp+=path;
970 temp.Replace(_T('/'), _T('\\'));
972 while(!temp.IsEmpty())
974 temp+=_T("\\.git");
976 if(CGit::GitPathFileExists(temp))
978 CString gitignore = temp;
979 gitignore += _T("ignore");
980 if( CheckFileChanged(gitignore) )
982 FetchIgnoreFile(gitdir,gitignore);
985 temp+=_T("\\info\\exclude");
987 if( CheckFileChanged(temp) )
989 return FetchIgnoreFile(gitdir,temp);
992 return 0;
994 }else
996 temp+=_T("ignore");
997 if( CheckFileChanged(temp) )
999 FetchIgnoreFile(gitdir,temp);
1003 int found=0;
1004 int i;
1005 for( i=temp.GetLength() -1;i>=0;i--)
1007 if(temp[i] == _T('\\'))
1008 found ++;
1010 if(found == 2)
1011 break;
1014 temp = temp.Left(i);
1016 return 0;
1018 int CGitIgnoreList::GetIgnoreFileChangeTimeList(const CString &path, std::vector<__int64> &timelist)
1020 CString temp=path;
1021 CString ignore=temp;
1022 int start =0;
1025 CAutoReadLock lock(&this->m_SharedMutex);
1027 ignore=temp;
1028 ignore+=_T("\\.gitignore");
1029 std::map<CString, CGitIgnoreItem>::iterator itMap;
1030 itMap = m_Map.find(ignore);
1031 if(itMap == m_Map.end())
1033 timelist.push_back(0);
1035 }else
1037 timelist.push_back(itMap->second.m_LastModifyTime);
1040 ignore =temp;
1041 ignore += _T("\\.git\\info\\exclude");
1043 itMap = m_Map.find(ignore);
1044 if(itMap == m_Map.end())
1047 }else
1049 timelist.push_back(itMap->second.m_LastModifyTime);
1050 return 0;
1053 ignore=temp;
1054 ignore+=_T("\\.git");
1056 if(CGit::GitPathFileExists(ignore))
1057 return 0;
1059 start = temp.ReverseFind(_T('\\'));
1060 if(start>0)
1061 temp=temp.Left(start);
1063 }while(start>0);
1065 return -1;
1068 bool CGitIgnoreList::IsIgnore(const CString &path,const CString &projectroot)
1070 CString str=path;
1072 str.Replace(_T('\\'),_T('/'));
1074 int ret;
1075 ret = CheckIgnore(path, projectroot);
1076 while(ret < 0)
1078 int start=str.ReverseFind(_T('/'));
1079 if(start<0)
1080 return (ret == 1);
1082 str=str.Left(start);
1083 ret = CheckIgnore(str, projectroot);
1086 return (ret == 1);
1088 int CGitIgnoreList::CheckIgnore(const CString &path,const CString &projectroot)
1090 __int64 time=0;
1091 bool dir=0;
1092 CString temp=projectroot+_T("\\")+path;
1093 temp.Replace(_T('/'), _T('\\'));
1095 CStringA patha;
1097 patha = CUnicodeUtils::GetMulti(path,CP_ACP) ;
1098 patha.Replace('\\','/');
1100 if(g_Git.GetFileModifyTime(temp,&time,&dir))
1101 return -1;
1103 int type=0;
1104 if( dir )
1105 type = DT_DIR;
1106 else
1107 type = DT_REG;
1109 while(!temp.IsEmpty())
1111 int x;
1112 x=temp.ReverseFind(_T('\\'));
1113 if(x<0) x=0;
1114 temp=temp.Left(x);
1116 temp+=_T("\\.gitignore");
1118 char *base;
1120 patha.Replace('\\', '/');
1121 int pos=patha.ReverseFind('/');
1122 base = pos>=0? patha.GetBuffer()+pos+1:patha.GetBuffer();
1124 CAutoReadLock lock(&this->m_SharedMutex);
1126 if(this->m_Map.find(temp) == m_Map.end() )
1129 }else
1131 int ret=-1;
1133 if(m_Map[temp].m_pExcludeList)
1134 ret = git_check_excluded_1( patha, patha.GetLength(), base, &type, m_Map[temp].m_pExcludeList);
1136 if(ret == 1)
1137 return 1;
1138 if(ret == 0)
1139 return 0;
1142 temp = temp.Left(temp.GetLength()-11);
1143 temp +=_T("\\.git\\info\\exclude");
1145 if(this->m_Map.find(temp) == m_Map.end() )
1148 }else
1150 int ret=-1;
1152 if(m_Map[temp].m_pExcludeList)
1153 ret = git_check_excluded_1( patha, patha.GetLength(), base, &type, m_Map[temp].m_pExcludeList);
1155 if(ret == 1)
1156 return 1;
1157 if(ret == 0)
1158 return 0;
1160 return -1;
1162 temp = temp.Left(temp.GetLength()-18);
1165 return -1;
1168 int CGitHeadFileMap::CheckHeadUpdate(const CString &gitdir)
1170 m_SharedMutex.AcquireShared();
1171 if( find(gitdir) == end())
1173 m_SharedMutex.ReleaseShared();
1174 m_SharedMutex.AcquireExclusive();
1175 (*this)[gitdir].m_LastModifyTimeRef = 0; /* Insert new item*/
1176 (*this)[gitdir].m_SharedMutex.Init();
1177 m_SharedMutex.ReleaseExclusive();
1178 }else
1180 m_SharedMutex.ReleaseShared();
1183 m_SharedMutex.AcquireShared();
1184 int ret= (*this)[gitdir].CheckHeadUpdate();
1185 m_SharedMutex.ReleaseShared();
1187 return ret;
1190 int CGitHeadFileMap::GetHeadHash(const CString &gitdir, CGitHash &hash)
1192 if(CheckHeadUpdate(gitdir))
1194 CAutoReadLock(&this->m_SharedMutex);
1195 (*this)[gitdir].ReadHeadHash(gitdir);
1197 }else
1199 CAutoReadLock(&this->m_SharedMutex);
1200 hash = (*this)[gitdir].m_Head;
1202 return 0;
1204 #if 0
1206 int CGitStatus::GetStatus(const CString &gitdir, const CString &path, git_wc_status_kind *status, BOOL IsFull, BOOL IsRecursive , FIll_STATUS_CALLBACK callback , void *pData)
1208 int result;
1209 __int64 time;
1210 bool dir;
1212 git_wc_status_kind dirstatus = git_wc_status_none;
1213 if(status)
1215 g_Git.GetFileModifyTime(path,&time,&dir);
1216 if( dir)
1218 }else
1222 if(path.IsEmpty())
1223 result = _tstat64( gitdir, &buf );
1224 else
1225 result = _tstat64( gitdir+_T("\\")+path, &buf );
1227 if(result)
1228 return -1;
1230 if(buf.st_mode & _S_IFDIR)
1232 if(!path.IsEmpty())
1234 if( path.Right(1) != _T("\\"))
1235 path+=_T("\\");
1237 int len =path.GetLength();
1239 for(int i=0;i<size();i++)
1241 if( at(i).m_FileName.GetLength() > len )
1243 if(at(i).m_FileName.Left(len) == path)
1245 if( !IsFull )
1247 *status = git_wc_status_normal;
1248 if(callback)
1249 callback(gitdir+_T("\\")+path,*status,pData);
1250 return 0;
1252 }else
1254 result = _tstat64( gitdir+_T("\\")+at(i).m_FileName, &buf );
1255 if(result)
1256 continue;
1258 *status = git_wc_status_none;
1259 GetFileStatus(gitdir,at(i).m_FileName,status,buf,callback,pData);
1260 if( *status != git_wc_status_none )
1262 if( dirstatus == git_wc_status_none)
1264 dirstatus = git_wc_status_normal;
1266 if( *status != git_wc_status_normal )
1268 dirstatus = git_wc_status_modified;
1277 if( dirstatus != git_wc_status_none )
1279 *status = dirstatus;
1281 else
1283 *status = git_wc_status_unversioned;
1285 if(callback)
1286 callback(gitdir+_T("\\")+path,*status,pData);
1288 return 0;
1290 }else
1292 GetFileStatus(gitdir,path,status,buf,callback,pData);
1295 return 0;
1298 #endif