From: Frank Li Date: Tue, 10 Feb 2009 14:33:53 +0000 (+0800) Subject: *Read Index File Directory. Overlay basic working. include "conflict, modified and... X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=89ff529ce09bbb60a81f050806426acec511cc45;p=tortoisegit%2FTortoiseGitJp.git *Read Index File Directory. Overlay basic working. include "conflict, modified and normal" No "Add" "Ignore" .... Signed-off-by: Frank Li --- diff --git a/src/Git/Git.cpp b/src/Git/Git.cpp index 145f47b..1bb0531 100644 --- a/src/Git/Git.cpp +++ b/src/Git/Git.cpp @@ -116,18 +116,19 @@ BOOL g_IsWingitDllload = TRUE; LPBYTE wgGetRevisionID_safe(const char *pszProjectPath, const char *pszName) { - if(g_IsWingitDllload) - return wgGetRevisionID(pszProjectPath,pszName); - else - return NULL; + //if(g_IsWingitDllload) + // return wgGetRevisionID(pszProjectPath,pszName); + //else + return NULL; } BOOL wgEnumFiles_safe(const char *pszProjectPath, const char *pszSubPath, unsigned int nFlags, WGENUMFILECB *pEnumCb, void *pUserData) { - if(g_IsWingitDllload) - return wgEnumFiles(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData); - else - return g_Git.EnumFiles(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData); + //if(g_IsWingitDllload) + // return wgEnumFiles(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData); + //else + // return g_Git.EnumFiles(pszProjectPath,pszSubPath,nFlags,pEnumCb,pUserData); + return FALSE; } BOOL CGit::IsVista() @@ -177,6 +178,7 @@ static void InitWinGitDll() } CGit::CGit(void) { +#if 0 GetCurrentDirectory(MAX_DIRBUFFER,m_CurrentDir.GetBuffer(MAX_DIRBUFFER)); m_CurrentDir.ReleaseBuffer(); // make sure git/bin is in PATH before wingit.dll gets (delay) loaded by wgInit() @@ -185,6 +187,7 @@ CGit::CGit(void) // TODO } InitWinGitDll(); +#endif } CGit::~CGit(void) diff --git a/src/Git/Git.vcproj b/src/Git/Git.vcproj index b990dc2..eed787b 100644 --- a/src/Git/Git.vcproj +++ b/src/Git/Git.vcproj @@ -1,7 +1,7 @@ + + @@ -380,6 +384,10 @@ > + + diff --git a/src/Git/GitFolderStatus.cpp b/src/Git/GitFolderStatus.cpp index 356948e..17f1b3f 100644 --- a/src/Git/GitFolderStatus.cpp +++ b/src/Git/GitFolderStatus.cpp @@ -23,9 +23,11 @@ #include "..\TGitCache\CacheInterface.h" #include "Git.h" //#include "GitGlobal.h" +#include "gitindex.h" extern ShellCache g_ShellCache; +extern CGitIndexFileMap g_IndexFileMap; // get / auto-alloc a string "copy" @@ -231,19 +233,25 @@ const FileStatusCacheEntry * GitFolderStatus::BuildCache(const CTGitPath& filepa { // extract the sub-path (relative to project root) //MessageBox(NULL, filepath.GetDirectory().GetWinPathString(), sProjectRoot, MB_OK); - LPCSTR lpszSubPath = NULL; - CStringA sSubPath; - CString s = filepath.GetDirectory().GetWinPathString(); +// LPCSTR lpszSubPath = NULL; + CString sSubPath; + CString s = filepath.GetWinPathString(); if (s.GetLength() > sProjectRoot.GetLength()) { - sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/)); - lpszSubPath = sSubPath; + sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/); +// lpszSubPath = sSubPath; } //if (lpszSubPath) MessageBoxA(NULL, lpszSubPath, "BuildCache", MB_OK); //MessageBoxA(NULL, CStringA(sProjectRoot), sSubPath, MB_OK); - err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, WGEFF_NoRecurse|WGEFF_FullPath|WGEFF_DirStatusAll, &fillstatusmap, this); + //err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, WGEFF_NoRecurse|WGEFF_FullPath|WGEFF_DirStatusAll, &fillstatusmap, this); + //CTGitPath path; + //path.SetFromWin(sSubPath); + git_wc_status_kind status; + err = g_IndexFileMap.GetFileStatus((CString&)sProjectRoot,sSubPath,&status,true,true,fillstatusmap,this); + + //err = g_IndexFileMap.GetFileStatus(sProjectRoot,&path, /*err = svn_client_status4 (&youngest, filepath.GetDirectory().GetSVNApiPath(pool), &rev, @@ -397,7 +405,7 @@ const FileStatusCacheEntry * GitFolderStatus::GetCachedItem(const CTGitPath& fil return NULL; } -BOOL GitFolderStatus::fillstatusmap(const struct wgFile_s *pFile, void *pUserData) +void GitFolderStatus::fillstatusmap(CString &path,git_wc_status_kind status,void *pUserData) { GitFolderStatus *Stat = (GitFolderStatus*)pUserData; @@ -411,11 +419,11 @@ BOOL GitFolderStatus::fillstatusmap(const struct wgFile_s *pFile, void *pUserDat // s.rev = -1; s.owner = Stat->owners.GetString(NULL); - s.status = git_wc_status_none; + s.status = status; //s.status = GitStatus::GetMoreImportant(s.status, status->text_status); //s.status = GitStatus::GetMoreImportant(s.status, status->prop_status); - s.status = GitStatusFromWingit(pFile->nStatus); + //s.status = GitStatusFromWingit(pFile->nStatus); // TODO ?: s.blaha = pFile->nStage @@ -423,18 +431,24 @@ BOOL GitFolderStatus::fillstatusmap(const struct wgFile_s *pFile, void *pUserDat //s.tree_conflict = (status->tree_conflict != NULL); s.askedcounter = GITFOLDERSTATUS_CACHETIMES; - stdstring str; - if (pFile->sFileName) - { - str = CUnicodeUtils::StdGetUnicode(pFile->sFileName); - std::replace(str.begin(), str.end(), '/', '\\'); + //stdstring str; + //if (pFile->sFileName) + //{ + // str = CUnicodeUtils::StdGetUnicode(pFile->sFileName); + // std::replace(str.begin(), str.end(), '/', '\\'); //MessageBox(NULL, str.c_str(), _T(""), MB_OK); + //} + //else + // str = _T(" "); + if( path.Right(1) == _T("\\")) + { + path=path.Left(path.GetLength()-1); } - else - str = _T(" "); + stdstring str; + str=path; cache[str] = s; - return FALSE; + return; } #if 0 diff --git a/src/Git/GitFolderStatus.h b/src/Git/GitFolderStatus.h index 222a5f3..dba9f4f 100644 --- a/src/Git/GitFolderStatus.h +++ b/src/Git/GitFolderStatus.h @@ -117,7 +117,8 @@ private: DWORD GetTimeoutValue(); //static git_error_t* fillstatusmap (void *baton, const char *path, git_wc_status2_t *status, apr_pool_t *pool); //static git_error_t* findfolderstatus (void *baton, const char *path, git_wc_status2_t *status, apr_pool_t *pool); - static BOOL fillstatusmap(const struct wgFile_s *pFile, void *pUserData); + static void fillstatusmap(CString &path,git_wc_status_kind status,void *pdata); + static CTGitPath folderpath; void ClearCache(); diff --git a/src/Git/GitIndex.cpp b/src/Git/GitIndex.cpp new file mode 100644 index 0000000..b9819eb --- /dev/null +++ b/src/Git/GitIndex.cpp @@ -0,0 +1,300 @@ +#include "StdAfx.h" +#include "Git.h" +#include "atlconv.h" +#include "GitRev.h" +#include "registry.h" +#include "GitConfig.h" +#include +#include "UnicodeUtils.h" +#include "TGitPath.h" +#include "gitindex.h" +#include +#include + +#define FILL_DATA() \ + m_FileName.Empty();\ + g_Git.StringAppend(&m_FileName,(BYTE*)entry->name,CP_OEMCP,Big2lit(entry->flags)&CE_NAMEMASK);\ + m_FileName.Replace(_T('/'),_T('\\'));\ + this->m_Flags=Big2lit(entry->flags);\ + this->m_ModifyTime=Big2lit(entry->mtime.sec); + +int CGitIndex::FillData(ondisk_cache_entry * entry) +{ + FILL_DATA(); + return 0; +} + +int CGitIndex::FillData(ondisk_cache_entry_extended * entry) +{ + FILL_DATA(); + this->m_Flags |= ((int)Big2lit(entry->flags2))<<16; + return 0; +} + +CGitIndexList::CGitIndexList() +{ + this->m_LastModifyTime=0; +} + +int CGitIndexList::ReadIndex(CString IndexFile) +{ + HANDLE hfile=0; + int ret=0; + BYTE *buffer=NULL,*p; + CGitIndex GitIndex; + + try + { + do + { + this->clear(); + this->m_Map.clear(); + + hfile = CreateFile(IndexFile, + GENERIC_READ, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL); + + + if(hfile == INVALID_HANDLE_VALUE) + { + ret = -1 ; + break; + } + + cache_header *header; + DWORD size=0,filesize=0; + + filesize=GetFileSize(hfile,NULL); + + if(filesize == INVALID_FILE_SIZE ) + { + ret =-1; + break; + } + + buffer = new BYTE[filesize]; + p=buffer; + if(buffer == NULL) + { + ret = -1; + break; + } + if(! ReadFile( hfile, buffer,filesize,&size,NULL) ) + { + ret = GetLastError(); + break; + } + + if (size != filesize) + { + ret = -1; + break; + } + header = (cache_header *) buffer; + if( Big2lit(header->hdr_signature) != CACHE_SIGNATURE ) + { + ret = -1; + break; + } + p+= sizeof(cache_header); + + int entries = Big2lit(header->hdr_entries); + for(int i=0;iflags); + if( flags & CE_EXTENDED) + { + GitIndex.FillData(entryex); + p+=ondisk_ce_size(entryex); + + }else + { + GitIndex.FillData(entry); + p+=ondisk_ce_size(entry); + } + + if(p>buffer+filesize) + { + ret = -1; + break; + } + this->push_back(GitIndex); + this->m_Map[GitIndex.m_FileName]=this->size()-1; + + } + }while(0); + }catch(...) + { + ret= -1; + } + + if(hfile != INVALID_HANDLE_VALUE) + CloseHandle(hfile); + if(buffer) + delete buffer; + return ret; +} + +int CGitIndexList::GetFileStatus(CString &gitdir,CString &path,git_wc_status_kind *status,struct __stat64 &buf,FIll_STATUS_CALLBACK callback,void *pData) +{ + + if(status) + { + if(m_Map.find(path) == m_Map.end() ) + { + *status = git_wc_status_unversioned; + }else + { + int index = m_Map[path]; + if(index <0) + return -1; + if(index >= size() ) + return -1; + + if( buf.st_mtime == at(index).m_ModifyTime ) + { + *status = git_wc_status_normal; + }else + { + *status = git_wc_status_modified; + } + + if(at(index).m_Flags & CE_STAGEMASK ) + *status = git_wc_status_conflicted; + else if(at(index).m_Flags & CE_INTENT_TO_ADD) + *status = git_wc_status_added; + + } + if(callback) + callback(gitdir+_T("\\")+path,*status,pData); + } + return 0; +} + +int CGitIndexList::GetStatus(CString &gitdir,CString &path, git_wc_status_kind *status, + BOOL IsFull, BOOL IsRecursive, + FIll_STATUS_CALLBACK callback,void *pData) +{ + int result; + struct __stat64 buf; + git_wc_status_kind dirstatus = git_wc_status_none; + if(status) + { + if(path.IsEmpty()) + result = _tstat64( gitdir, &buf ); + else + result = _tstat64( gitdir+_T("\\")+path, &buf ); + + if(result) + return -1; + + if(buf.st_mode & _S_IFDIR) + { + if(!path.IsEmpty()) + { + if( path.Right(1) != _T("\\")) + path+=_T("\\"); + } + int len =path.GetLength(); + + for(int i=0;i len ) + { + if(at(i).m_FileName.Left(len) == path) + { + if( !IsFull ) + { + *status = git_wc_status_normal; + if(callback) + callback(gitdir+_T("\\")+path,*status,pData); + return 0; + + }else + { + result = _tstat64( gitdir+_T("\\")+at(i).m_FileName, &buf ); + if(result) + continue; + + *status = git_wc_status_none; + GetFileStatus(gitdir,at(i).m_FileName,status,buf,callback,pData); + if( *status != git_wc_status_none ) + { + if( dirstatus == git_wc_status_none) + { + dirstatus = git_wc_status_normal; + } + if( *status != git_wc_status_normal ) + { + dirstatus = git_wc_status_modified; + } + } + + } + } + } + } + + if( dirstatus != git_wc_status_none ) + { + *status = dirstatus; + } + else + { + *status = git_wc_status_unversioned; + } + if(callback) + callback(gitdir+_T("\\")+path,*status,pData); + + return 0; + + }else + { + GetFileStatus(gitdir,path,status,buf,callback,pData); + } + } + return 0; +} + +int CGitIndexFileMap::GetFileStatus(CString &gitdir, CString &path, git_wc_status_kind *status,BOOL IsFull, BOOL IsRecursive, + FIll_STATUS_CALLBACK callback,void *pData) +{ + struct __stat64 buf; + int result; + try + { + CString IndexFile; + IndexFile=gitdir+_T("\\.git\\index"); + /* Get data associated with "crt_stat.c": */ + result = _tstat64( IndexFile, &buf ); + +// WIN32_FILE_ATTRIBUTE_DATA FileInfo; +// GetFileAttributesEx(_T("D:\\tortoisegit\\src\\gpl.txt"),GetFileExInfoStandard,&FileInfo); +// result = _tstat64( _T("D:\\tortoisegit\\src\\gpl.txt"), &buf ); + + if(result) + return result; + + if((*this)[IndexFile].m_LastModifyTime != buf.st_mtime ) + { + if((*this)[IndexFile].ReadIndex(IndexFile)) + return -1; + } + (*this)[IndexFile].m_LastModifyTime = buf.st_mtime; + + (*this)[IndexFile].GetStatus(gitdir,path,status,IsFull,IsRecursive,callback,pData); + + }catch(...) + { + return -1; + } + return 0; +} \ No newline at end of file diff --git a/src/Git/GitStatus.cpp b/src/Git/GitStatus.cpp index 6d549a6..9aeca87 100644 --- a/src/Git/GitStatus.cpp +++ b/src/Git/GitStatus.cpp @@ -33,6 +33,9 @@ //# include "PathUtils.h" #endif #include "git.h" +#include "gitindex.h" + +CGitIndexFileMap g_IndexFileMap; GitStatus::GitStatus(bool * pbCanceled) : status(NULL) @@ -214,23 +217,23 @@ git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t de const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source - LPCSTR lpszSubPath = NULL; - CStringA sSubPath; + //LPCSTR lpszSubPath = NULL; + CString sSubPath; CString s = path.GetWinPathString(); if (s.GetLength() > sProjectRoot.GetLength()) { sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/)); - lpszSubPath = sSubPath; + // lpszSubPath = sSubPath; } #if 1 // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here - UINT nFlags = WGEFF_SingleFile; - if (!bIsRecursive) - nFlags |= WGEFF_NoRecurse; - if (!lpszSubPath) + //UINT nFlags = WGEFF_SingleFile; + //if (!bIsRecursive) + // nFlags |= WGEFF_NoRecurse; + //if (!lpszSubPath) // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?) - nFlags |= WGEFF_EmptyAsNormal; + // nFlags |= WGEFF_EmptyAsNormal; #else // enumerate all files, recursively if requested UINT nFlags = 0; @@ -238,7 +241,9 @@ git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t de nFlags |= WGEFF_NoRecurse; #endif - err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, nFlags, &getallstatus, &statuskind); + //err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, nFlags, &getallstatus, &statuskind); + + err = g_IndexFileMap.GetFileStatus(sProjectRoot,sSubPath,&statuskind); /*err = git_client_status4 (&youngest, path.GetSVNApiPath(pool), @@ -343,26 +348,29 @@ git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false // hashbaton.exthash = exthash; hashbaton.pThis = this; - LPCSTR lpszSubPath = NULL; - CStringA sSubPath; + //LPCSTR lpszSubPath = NULL; + CString sSubPath; CString s = path.GetWinPathString(); if (s.GetLength() > sProjectRoot.GetLength()) { - sSubPath = CStringA(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/)); - lpszSubPath = sSubPath; + sSubPath = CString(s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/)); + // lpszSubPath = sSubPath; } + // when recursion enabled, let wingit determine the recursive status for folders instead of enumerating all files here - UINT nFlags = WGEFF_SingleFile | WGEFF_NoRecurse; - if (!lpszSubPath) - // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?) - nFlags |= WGEFF_EmptyAsNormal; + //UINT nFlags = WGEFF_SingleFile | WGEFF_NoRecurse; + //if (!lpszSubPath) + // // report root dir as normal (otherwise it could be considered git_wc_status_unversioned, which would be wrong?) + // nFlags |= WGEFF_EmptyAsNormal; m_status.prop_status = m_status.text_status = git_wc_status_none; // NOTE: currently wgEnumFiles_safe_safe_safe will not enumerate file if it isn't versioned (so status will be git_wc_status_none) - m_err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, nFlags, &getstatus, &m_status); + //m_err = !wgEnumFiles_safe(CStringA(sProjectRoot), lpszSubPath, nFlags, &getstatus, &m_status); + m_err = g_IndexFileMap.GetFileStatus(sProjectRoot,sSubPath,&m_status.text_status); + /*m_err = git_client_status4 (&youngest, path.GetGitApiPath(m_pool), &rev, @@ -379,7 +387,7 @@ git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false // Error present if function is not under version control - if ((m_err != NULL) /*|| (apr_hash_count(statushash) == 0)*/) + if (m_err) /*|| (apr_hash_count(statushash) == 0)*/ { status = NULL; // return -2; @@ -399,9 +407,9 @@ git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false if (update) { - const BYTE *sha1 = wgGetRevisionID_safe(CStringA(sProjectRoot), NULL); - if (sha1) - youngest = ConvertHashToRevnum(sha1); + //const BYTE *sha1 = wgGetRevisionID_safe(CStringA(sProjectRoot), NULL); + //if (sha1) + // youngest = ConvertHashToRevnum(sha1); } return youngest; diff --git a/src/Git/GitStatus.h b/src/Git/GitStatus.h index a2f757e..9e16536 100644 --- a/src/Git/GitStatus.h +++ b/src/Git/GitStatus.h @@ -261,7 +261,7 @@ private: // git_client_ctx_t * ctx; git_wc_status_kind m_allstatus; ///< used by GetAllStatus and GetAllStatusRecursive // git_error_t * m_err; ///< Subversion error baton - BOOL m_err; + git_error_t m_err; git_wc_status2_t m_status; // used for GetStatus diff --git a/src/Git/gitindex.h b/src/Git/gitindex.h new file mode 100644 index 0000000..9db2ad1 --- /dev/null +++ b/src/Git/gitindex.h @@ -0,0 +1,187 @@ +/* Copy from Git cache.h*/ +#define FLEX_ARRAY 4 + +#pragma pack(push) +#pragma pack(1) +//#pragma pack(show) +#define CACHE_SIGNATURE 0x44495243 /* "DIRC" */ +struct cache_header { + unsigned int hdr_signature; + unsigned int hdr_version; + unsigned int hdr_entries; +}; + +/* + * The "cache_time" is just the low 32 bits of the + * time. It doesn't matter if it overflows - we only + * check it for equality in the 32 bits we save. + */ +struct cache_time { + UINT32 sec; + UINT32 nsec; +}; + +/* + * dev/ino/uid/gid/size are also just tracked to the low 32 bits + * Again - this is just a (very strong in practice) heuristic that + * the inode hasn't changed. + * + * We save the fields in big-endian order to allow using the + * index file over NFS transparently. + */ +struct ondisk_cache_entry { + struct cache_time ctime; + struct cache_time mtime; + UINT32 dev; + UINT32 ino; + UINT32 mode; + UINT32 uid; + UINT32 gid; + UINT32 size; + BYTE sha1[20]; + UINT16 flags; + char name[FLEX_ARRAY]; /* more */ +}; + +/* + * This struct is used when CE_EXTENDED bit is 1 + * The struct must match ondisk_cache_entry exactly from + * ctime till flags + */ +struct ondisk_cache_entry_extended { + struct cache_time ctime; + struct cache_time mtime; + UINT32 dev; + UINT32 ino; + UINT32 mode; + UINT32 uid; + UINT32 gid; + UINT32 size; + BYTE sha1[20]; + UINT16 flags; + UINT16 flags2; + char name[FLEX_ARRAY]; /* more */ +}; + +#pragma pack(pop) + +#define CE_NAMEMASK (0x0fff) +#define CE_STAGEMASK (0x3000) +#define CE_EXTENDED (0x4000) +#define CE_VALID (0x8000) +#define CE_STAGESHIFT 12 +/* + * Range 0xFFFF0000 in ce_flags is divided into + * two parts: in-memory flags and on-disk ones. + * Flags in CE_EXTENDED_FLAGS will get saved on-disk + * if you want to save a new flag, add it in + * CE_EXTENDED_FLAGS + * + * In-memory only flags + */ +#define CE_UPDATE (0x10000) +#define CE_REMOVE (0x20000) +#define CE_UPTODATE (0x40000) +#define CE_ADDED (0x80000) + +#define CE_HASHED (0x100000) +#define CE_UNHASHED (0x200000) + +/* + * Extended on-disk flags + */ +#define CE_INTENT_TO_ADD 0x20000000 +/* CE_EXTENDED2 is for future extension */ +#define CE_EXTENDED2 0x80000000 + +#define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD) + +/* + * Safeguard to avoid saving wrong flags: + * - CE_EXTENDED2 won't get saved until its semantic is known + * - Bits in 0x0000FFFF have been saved in ce_flags already + * - Bits in 0x003F0000 are currently in-memory flags + */ +#if CE_EXTENDED_FLAGS & 0x803FFFFF +#error "CE_EXTENDED_FLAGS out of range" +#endif + +/* + * Copy the sha1 and stat state of a cache entry from one to + * another. But we never change the name, or the hash state! + */ +#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED) + +template +T Big2lit(T data) +{ + T ret; + BYTE *p1=(BYTE*)&data; + BYTE *p2=(BYTE*)&ret; + for(int i=0;i +static inline size_t ce_namelen(T *ce) +{ + size_t len = Big2lit(ce->flags) & CE_NAMEMASK; + if (len < CE_NAMEMASK) + return len; + return strlen(ce->name + CE_NAMEMASK) + CE_NAMEMASK; +} + +#define flexible_size(STRUCT,len) ((offsetof(STRUCT,name) + (len) + 8) & ~7) + +//#define ondisk_cache_entry_size(len) flexible_size(ondisk_cache_entry,len) +//#define ondisk_cache_entry_extended_size(len) flexible_size(ondisk_cache_entry_extended,len) + +//#define ondisk_ce_size(ce) (((ce)->flags & CE_EXTENDED) ? \ +// ondisk_cache_entry_extended_size(ce_namelen(ce)) : \ +// ondisk_cache_entry_size(ce_namelen(ce))) + +template +static inline size_t ondisk_ce_size(T *ce) +{ + return flexible_size(T,ce_namelen(ce)); +} + +class CGitIndex +{ +public: + CString m_FileName; + __time64_t m_ModifyTime; + int m_Flags; + //int m_Status; + + int FillData(ondisk_cache_entry* entry); + int FillData(ondisk_cache_entry_extended* entry); +}; + + +typedef void (*FIll_STATUS_CALLBACK)(CString &path,git_wc_status_kind status,void *pdata); + +class CGitIndexList:public std::vector +{ +protected: + +public: + std::map m_Map; + __time64_t m_LastModifyTime; + CGitIndexList(); + int ReadIndex(CString file); + int GetStatus(CString &gitdir,CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL); +protected: + int GetFileStatus(CString &gitdir,CString &path, git_wc_status_kind * status,struct __stat64 &buf,FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL); + +}; + +class CGitIndexFileMap:public std::map +{ +public: + int GetFileStatus(CString &gitdir,CString &path,git_wc_status_kind * status,BOOL IsFull=false, BOOL IsRecursive=false,FIll_STATUS_CALLBACK callback=NULL,void *pData=NULL); +}; + diff --git a/src/Git/gittype.h b/src/Git/gittype.h index 395aeb5..a66f4b6 100644 --- a/src/Git/gittype.h +++ b/src/Git/gittype.h @@ -88,4 +88,5 @@ public: }; typedef std::vector STRING_VECTOR; typedef std::map MAP_HASH_NAME; -typedef CGitByteArray BYTE_VECTOR; \ No newline at end of file +typedef CGitByteArray BYTE_VECTOR; + diff --git a/src/TGitCache/TSVNCache.vcproj b/src/TGitCache/TSVNCache.vcproj index da24fc1..8859989 100644 --- a/src/TGitCache/TSVNCache.vcproj +++ b/src/TGitCache/TSVNCache.vcproj @@ -1,7 +1,7 @@ + + diff --git a/src/TortoiseProc/TortoiseProc.cpp b/src/TortoiseProc/TortoiseProc.cpp index deaeb03..569b011 100644 --- a/src/TortoiseProc/TortoiseProc.cpp +++ b/src/TortoiseProc/TortoiseProc.cpp @@ -43,6 +43,7 @@ #include "CommonResource.h" #include "..\version.h" #include "..\Settings\Settings.h" +#include "gitindex.h" #define STRUCT_IOVEC_DEFINED //#include "sasl.h" @@ -78,6 +79,8 @@ CTortoiseProcApp::CTortoiseProcApp() retSuccess = false; //CGit git; //git.GetUserName(); + + } CTortoiseProcApp::~CTortoiseProcApp() @@ -107,6 +110,11 @@ CString sOrigCWD; BOOL CTortoiseProcApp::CheckMsysGitDir() { + CGitIndexFileMap map; + //int status; + //CTGitPath path; + //path.SetFromGit(_T("src/gpl.txt")); + //map.GetFileStatus(_T("D:\\TortoiseGit"),&path, &status); return CGit::CheckMsysGitDir(); } CCrashReport crasher("tortoisegit-bug@googlegroups.com", "Crash Report for TortoiseGit " APP_X64_STRING " : " STRPRODUCTVER, TRUE);// crash diff --git a/src/TortoiseShell/ContextMenu.cpp b/src/TortoiseShell/ContextMenu.cpp index 6e26662..c341248 100644 --- a/src/TortoiseShell/ContextMenu.cpp +++ b/src/TortoiseShell/ContextMenu.cpp @@ -156,7 +156,7 @@ CShellExt::MenuInfo CShellExt::menuInfo[] = // ITEMIS_FOLDER, ITEMIS_INSVN, 0, 0, 0, 0, 0, 0 }, { ShellMenuBlame, MENUBLAME, IDI_BLAME, IDS_MENUBLAME, IDS_MENUDESCBLAME, - ITEMIS_INSVN|ITEMIS_ONLYONE, ITEMIS_FOLDER|ITEMIS_ADDED, 0, 0, 0, 0, 0, 0 }, + ITEMIS_NORMAL|ITEMIS_ONLYONE, ITEMIS_FOLDER|ITEMIS_ADDED, 0, 0, 0, 0, 0, 0 }, { ShellMenuIgnoreSub, MENUIGNORE, IDI_IGNORE, IDS_MENUIGNORE, IDS_MENUDESCIGNORE, ITEMIS_INVERSIONEDFOLDER, ITEMIS_IGNORED|ITEMIS_INSVN, 0, 0, 0, 0, 0, 0 }, @@ -335,8 +335,14 @@ STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder, { ATLTRACE2(_T("Exception in GitStatus::GetStatus()\n")); } - //if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none)) - if (askedpath.HasAdminDir()) + + if ( askedpath.IsDirectory() ) + { + if (askedpath.HasAdminDir()) + itemStates |= ITEMIS_INSVN; + } + if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none)) + //if (askedpath.HasAdminDir()) itemStates |= ITEMIS_INSVN; if (status == git_wc_status_ignored) itemStates |= ITEMIS_IGNORED; @@ -437,8 +443,14 @@ STDMETHODIMP CShellExt::Initialize(LPCITEMIDLIST pIDFolder, ATLTRACE2(_T("Exception in GitStatus::GetStatus()\n")); } } - //if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none)) - if (strpath.HasAdminDir()) + + if ( strpath.IsDirectory() ) + { + if (strpath.HasAdminDir()) + itemStates |= ITEMIS_INSVN; + } + if ((status != git_wc_status_unversioned)&&(status != git_wc_status_ignored)&&(status != git_wc_status_none)) + //if (strpath.HasAdminDir()) itemStates |= ITEMIS_INSVN; if (status == git_wc_status_ignored) { diff --git a/src/TortoiseShell/IconOverlay.cpp b/src/TortoiseShell/IconOverlay.cpp index 91acf49..2b76670 100644 --- a/src/TortoiseShell/IconOverlay.cpp +++ b/src/TortoiseShell/IconOverlay.cpp @@ -242,6 +242,10 @@ STDMETHODIMP CShellExt::IsMemberOf(LPCWSTR pwszPath, DWORD /*dwAttrib*/) //as it seems that if one handler returns S_OK then that handler is used, no matter //if other handlers would return S_OK too (they're never called on my machine!) //So we return S_OK for ONLY ONE handler! + + if(g_ShellCache.HasSVNAdminDir(pPath, true) && status == git_wc_status_none) + status = git_wc_status_unversioned; + switch (status) { // note: we can show other overlays if due to lack of enough free overlay diff --git a/src/TortoiseShell/TortoiseShell.vcproj b/src/TortoiseShell/TortoiseShell.vcproj index 9aee418..7dfb43f 100644 --- a/src/TortoiseShell/TortoiseShell.vcproj +++ b/src/TortoiseShell/TortoiseShell.vcproj @@ -84,7 +84,7 @@ IgnoreImportLibrary="true" UseLibraryDependencyInputs="false" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="Crypt32.lib gdiplus.lib shfolder.lib shell32.lib comctl32.lib ws2_32.lib rpcrt4.lib shlwapi.lib wininet.lib version.lib wingit.lib" + AdditionalDependencies="Crypt32.lib gdiplus.lib shfolder.lib shell32.lib comctl32.lib ws2_32.lib rpcrt4.lib shlwapi.lib wininet.lib version.lib" OutputFile="$(OutDir)/TortoiseGit.dll" LinkIncremental="0" SuppressStartupBanner="true" @@ -193,7 +193,7 @@ Name="VCLinkerTool" IgnoreImportLibrary="true" AdditionalOptions="/MACHINE:I386" - AdditionalDependencies="Crypt32.lib gdiplus.lib shfolder.lib shell32.lib comctl32.lib ws2_32.lib rpcrt4.lib shlwapi.lib wininet.lib version.lib wingit.lib" + AdditionalDependencies="Crypt32.lib gdiplus.lib shfolder.lib shell32.lib comctl32.lib ws2_32.lib rpcrt4.lib shlwapi.lib wininet.lib version.lib" OutputFile="$(OutDir)/TortoiseGit.dll" LinkIncremental="1" SuppressStartupBanner="true" @@ -473,6 +473,10 @@ > + + diff --git a/src/TortoiseShell/register.reg b/src/TortoiseShell/register.reg index e44d662..f0e9f4a 100644 Binary files a/src/TortoiseShell/register.reg and b/src/TortoiseShell/register.reg differ diff --git a/src/TortoiseShell/register_recover.reg b/src/TortoiseShell/register_recover.reg new file mode 100644 index 0000000..ac9382f Binary files /dev/null and b/src/TortoiseShell/register_recover.reg differ