use gitdll gethash and clean up some warning
[TortoiseGit.git] / src / Git / GitStatus.cpp
blob3356144968866845ef3b665dda66a7eccc6663fe
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2003-2008 - 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 "stdafx.h"
21 #ifdef _TORTOISESHELL
22 #include "ShellExt.h"
23 #else
24 #include "registry.h"
25 #endif
26 //#include "resource.h"
27 #include "..\TortoiseShell\resource.h"
28 //#include "git_config.h"
29 #include "GitStatus.h"
30 #include "UnicodeUtils.h"
31 //#include "GitGlobal.h"
32 //#include "GitHelpers.h"
33 #ifdef _MFC_VER
34 //# include "Git.h"
35 //# include "MessageBox.h"
36 //# include "registry.h"
37 //# include "TGitPath.h"
38 //# include "PathUtils.h"
39 #endif
40 #include "git.h"
41 #include "gitindex.h"
42 #include "shellcache.h"
44 CGitIndexFileMap g_IndexFileMap;
45 CGitHeadFileMap g_HeadFileMap;
46 CGitIgnoreList g_IgnoreList;
48 GitStatus::GitStatus(bool * pbCanceled)
49 : status(NULL)
51 #if 0
52 m_pool = git_pool_create (NULL);
54 git_error_clear(git_client_create_context(&ctx, m_pool));
56 if (pbCanceled)
58 ctx->cancel_func = cancel;
59 ctx->cancel_baton = pbCanceled;
62 #ifdef _MFC_VER
63 git_error_clear(git_config_ensure(NULL, m_pool));
65 // set up authentication
66 m_prompt.Init(m_pool, ctx);
68 // set up the configuration
69 m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);
71 if (m_err)
73 ::MessageBox(NULL, this->GetLastErrorMsg(), _T("TortoiseGit"), MB_ICONERROR);
74 git_error_clear(m_err);
75 git_pool_destroy (m_pool); // free the allocated memory
76 exit(-1);
79 // set up the Git_SSH param
80 CString tgit_ssh = CRegString(_T("Software\\TortoiseGit\\SSH"));
81 if (tgit_ssh.IsEmpty())
82 tgit_ssh = CPathUtils::GetAppDirectory() + _T("TortoisePlink.exe");
83 tgit_ssh.Replace('\\', '/');
84 if (!tgit_ssh.IsEmpty())
86 git_config_t * cfg = (git_config_t *)apr_hash_get ((apr_hash_t *)ctx->config, Git_CONFIG_CATEGORY_CONFIG,
87 APR_HASH_KEY_STRING);
88 git_config_set(cfg, Git_CONFIG_SECTION_TUNNELS, "ssh", CUnicodeUtils::GetUTF8(tgit_ssh));
90 #else
91 git_error_clear(git_config_ensure(NULL, m_pool));
93 // set up the configuration
94 m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);
96 #endif
97 #endif
100 GitStatus::~GitStatus(void)
102 #if 0
103 git_error_clear(m_err);
104 git_pool_destroy (m_pool); // free the allocated memory
105 #endif
108 void GitStatus::ClearPool()
110 #if 0
111 git_pool_clear(m_pool);
112 #endif
115 #ifdef _MFC_VER
116 CString GitStatus::GetLastErrorMsg() const
118 // return Git::GetErrorString(m_err);
119 return CString("");
121 #else
122 stdstring GitStatus::GetLastErrorMsg() const
125 stdstring msg;
126 #if 0
127 char errbuf[256];
129 if (m_err != NULL)
131 git_error_t * ErrPtr = m_err;
132 if (ErrPtr->message)
134 msg = CUnicodeUtils::StdGetUnicode(ErrPtr->message);
136 else
138 /* Is this a Subversion-specific error code? */
139 if ((ErrPtr->apr_err > APR_OS_START_USEERR)
140 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))
141 msg = CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));
142 /* Otherwise, this must be an APR error code. */
143 else
145 git_error_t *temp_err = NULL;
146 const char * err_string = NULL;
147 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);
148 if (temp_err)
150 git_error_clear (temp_err);
151 msg = _T("Can't recode error string from APR");
153 else
155 msg = CUnicodeUtils::StdGetUnicode(err_string);
161 while (ErrPtr->child)
163 ErrPtr = ErrPtr->child;
164 msg += _T("\n");
165 if (ErrPtr->message)
167 msg += CUnicodeUtils::StdGetUnicode(ErrPtr->message);
169 else
171 /* Is this a Subversion-specific error code? */
172 if ((ErrPtr->apr_err > APR_OS_START_USEERR)
173 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))
174 msg += CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));
175 /* Otherwise, this must be an APR error code. */
176 else
178 git_error_t *temp_err = NULL;
179 const char * err_string = NULL;
180 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);
181 if (temp_err)
183 git_error_clear (temp_err);
184 msg += _T("Can't recode error string from APR");
186 else
188 msg += CUnicodeUtils::StdGetUnicode(err_string);
194 return msg;
195 } // if (m_err != NULL)
196 #endif
197 return msg;
199 #endif
201 // static method
202 git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth)
204 git_wc_status_kind statuskind;
205 // git_client_ctx_t * ctx;
207 // apr_pool_t * pool;
208 // git_error_t * err;
209 BOOL err;
210 BOOL isDir;
211 CString sProjectRoot;
213 isDir = path.IsDirectory();
214 if (!path.HasAdminDir(&sProjectRoot))
215 return git_wc_status_none;
217 // pool = git_pool_create (NULL); // create the memory pool
219 // git_error_clear(git_client_create_context(&ctx, pool));
221 // git_revnum_t youngest = Git_INVALID_REVNUM;
222 // git_opt_revision_t rev;
223 // rev.kind = git_opt_revision_unspecified;
224 statuskind = git_wc_status_none;
226 const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source
228 CString sSubPath;
229 CString s = path.GetWinPathString();
230 if (s.GetLength() > sProjectRoot.GetLength())
232 if (sProjectRoot.GetLength() == 3 && sProjectRoot[1] == _T(':'))
233 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength());
234 else
235 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/);
238 bool isfull;
240 #ifdef _TORTOISESHELL
241 isfull = (g_ShellCache.GetCacheType() == ShellCache::dllFull);
242 #else
243 isfull = ((DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\CacheType"),
244 GetSystemMetrics(SM_REMOTESESSION) ? ShellCache::dll : ShellCache::exe) == ShellCache::dllFull);
245 #endif
247 if(isDir)
249 err = GetDirStatus(sProjectRoot,sSubPath,&statuskind, isfull,bIsRecursive,isfull,NULL, NULL);
251 }else
253 err = GetFileStatus(sProjectRoot,sSubPath,&statuskind,isfull, false,isfull, NULL,NULL);
256 return statuskind;
259 // static method
260 git_wc_status_kind GitStatus::GetAllStatusRecursive(const CTGitPath& path)
262 return GetAllStatus(path, git_depth_infinity);
265 // static method
266 git_wc_status_kind GitStatus::GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2)
268 if (GetStatusRanking(status1) >= GetStatusRanking(status2))
269 return status1;
270 return status2;
272 // static private method
273 int GitStatus::GetStatusRanking(git_wc_status_kind status)
275 switch (status)
277 case git_wc_status_none:
278 return 0;
279 case git_wc_status_unversioned:
280 return 1;
281 case git_wc_status_ignored:
282 return 2;
283 case git_wc_status_incomplete:
284 return 4;
285 case git_wc_status_normal:
286 case git_wc_status_external:
287 return 5;
288 case git_wc_status_added:
289 return 6;
290 case git_wc_status_missing:
291 return 7;
292 case git_wc_status_deleted:
293 return 8;
294 case git_wc_status_replaced:
295 return 9;
296 case git_wc_status_modified:
297 return 10;
298 case git_wc_status_merged:
299 return 11;
300 case git_wc_status_conflicted:
301 return 12;
302 case git_wc_status_obstructed:
303 return 13;
305 return 0;
308 git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false */, bool noignore /* = false */, bool noexternals /* = false */)
310 // NOTE: unlike the SVN version this one does not cache the enumerated files, because in practice no code in all of
311 // Tortoise uses this, all places that call GetStatus create a temp GitStatus object which gets destroyed right
312 // after the call again
314 // apr_hash_t * statushash;
315 // apr_hash_t * exthash;
316 // apr_array_header_t * statusarray;
317 // const sort_item* item;
319 // git_error_clear(m_err);
320 // statushash = apr_hash_make(m_pool);
321 // exthash = apr_hash_make(m_pool);
322 git_revnum_t youngest = GIT_INVALID_REVNUM;
323 // git_opt_revision_t rev;
324 // rev.kind = git_opt_revision_unspecified;
326 CString sProjectRoot;
327 if ( !path.HasAdminDir(&sProjectRoot) )
328 return youngest;
330 struct hashbaton_t hashbaton;
331 // hashbaton.hash = statushash;
332 // hashbaton.exthash = exthash;
333 hashbaton.pThis = this;
335 bool isfull;
337 #ifdef _TORTOISESHELL
338 isfull = (g_ShellCache.GetCacheType() == ShellCache::dllFull);
339 #else
340 isfull = ((DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\CacheType"),
341 GetSystemMetrics(SM_REMOTESESSION) ? ShellCache::dll : ShellCache::exe) == ShellCache::dllFull);
342 #endif
345 LPCTSTR lpszSubPath = NULL;
346 CString sSubPath;
347 CString s = path.GetWinPathString();
348 if (s.GetLength() > sProjectRoot.GetLength())
350 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength());
351 lpszSubPath = sSubPath;
352 // skip initial slash if necessary
353 if (*lpszSubPath == _T('\\'))
354 lpszSubPath++;
357 m_status.prop_status = m_status.text_status = git_wc_status_none;
359 if(path.IsDirectory())
361 m_err = GetDirStatus(sProjectRoot,CString(lpszSubPath),&m_status.text_status , isfull, false,!noignore, NULL, NULL);
363 }else
365 m_err = GetFileStatus(sProjectRoot,CString(lpszSubPath),&m_status.text_status ,isfull, false,!noignore, NULL,NULL);
369 // Error present if function is not under version control
370 if (m_err) /*|| (apr_hash_count(statushash) == 0)*/
372 status = NULL;
373 return GIT_INVALID_REVNUM;
376 // Convert the unordered hash to an ordered, sorted array
377 /*statusarray = sort_hash (statushash,
378 sort_compare_items_as_paths,
379 m_pool);*/
381 // only the first entry is needed (no recurse)
382 // item = &APR_ARRAY_IDX (statusarray, 0, const sort_item);
384 // status = (git_wc_status2_t *) item->value;
385 status = &m_status;
387 if (update)
389 // done to match TSVN functionality of this function (not sure if any code uses the reutrn val)
390 // if TGit does not need this, then change the return type of function
391 youngest = g_Git.GetHash(_T("HEAD"));
394 return youngest;
397 git_wc_status2_t * GitStatus::GetFirstFileStatus(const CTGitPath& path, CTGitPath& retPath, bool update, git_depth_t depth, bool bNoIgnore /* = true */, bool bNoExternals /* = false */)
399 static git_wc_status2 st;
401 m_fileCache.Reset();
403 m_fileCache.Init( CStringA( path.GetWinPathString().GetString() ) );
404 MessageBox(NULL, path.GetWinPathString(), _T("GetFirstFile"), MB_OK);
405 m_fileCache.m_pFileIter = m_fileCache.m_pFiles;
406 st.text_status = git_wc_status_none;
408 if (m_fileCache.m_pFileIter)
410 switch(m_fileCache.m_pFileIter->nStatus)
412 case WGFS_Normal: st.text_status = git_wc_status_normal; break;
413 case WGFS_Modified: st.text_status = git_wc_status_modified; break;
414 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;
417 //retPath.SetFromGit((const char*)item->key);
419 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;
422 return &st;
424 #if 0
425 const sort_item* item;
427 git_error_clear(m_err);
428 m_statushash = apr_hash_make(m_pool);
429 m_externalhash = apr_hash_make(m_pool);
430 headrev = Git_INVALID_REVNUM;
431 git_opt_revision_t rev;
432 rev.kind = git_opt_revision_unspecified;
433 struct hashbaton_t hashbaton;
434 hashbaton.hash = m_statushash;
435 hashbaton.exthash = m_externalhash;
436 hashbaton.pThis = this;
437 m_statushashindex = 0;
438 m_err = git_client_status4 (&headrev,
439 path.GetGitApiPath(m_pool),
440 &rev,
441 getstatushash,
442 &hashbaton,
443 depth,
444 TRUE, //getall
445 update, //update
446 bNoIgnore, //noignore
447 bNoExternals, //noexternals
448 NULL,
449 ctx,
450 m_pool);
453 // Error present if function is not under version control
454 if ((m_err != NULL) || (apr_hash_count(m_statushash) == 0))
456 return NULL;
459 // Convert the unordered hash to an ordered, sorted array
460 m_statusarray = sort_hash (m_statushash,
461 sort_compare_items_as_paths,
462 m_pool);
464 // only the first entry is needed (no recurse)
465 m_statushashindex = 0;
466 item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);
467 retPath.SetFromGit((const char*)item->key);
468 return (git_wc_status2_t *) item->value;
469 #endif
471 return 0;
474 unsigned int GitStatus::GetVersionedCount() const
476 // return /**/m_fileCache.GetFileCount();
478 unsigned int count = 0;
479 #if 0
480 const sort_item* item;
481 for (unsigned int i=0; i<apr_hash_count(m_statushash); ++i)
483 item = &APR_ARRAY_IDX(m_statusarray, i, const sort_item);
484 if (item)
486 if (GitStatus::GetMoreImportant(((git_wc_status_t *)item->value)->text_status, git_wc_status_ignored)!=git_wc_status_ignored)
487 count++;
490 #endif
491 return count;
494 git_wc_status2_t * GitStatus::GetNextFileStatus(CTGitPath& retPath)
496 static git_wc_status2 st;
498 st.text_status = git_wc_status_none;
500 /*if (m_fileCache.m_pFileIter)
502 switch(m_fileCache.m_pFileIter->nStatus)
504 case WGFS_Normal: st.text_status = git_wc_status_normal; break;
505 case WGFS_Modified: st.text_status = git_wc_status_modified; break;
506 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;
509 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;
512 return &st;
514 #if 0
515 const sort_item* item;
517 if ((m_statushashindex+1) >= apr_hash_count(m_statushash))
518 return NULL;
519 m_statushashindex++;
521 item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);
522 retPath.SetFromGit((const char*)item->key);
523 return (git_wc_status2_t *) item->value;
524 #endif
525 return 0;
528 bool GitStatus::IsExternal(const CTGitPath& path) const
530 #if 0
531 if (apr_hash_get(m_externalhash, path.GetGitApiPath(m_pool), APR_HASH_KEY_STRING))
532 return true;
533 #endif
534 return false;
537 bool GitStatus::IsInExternal(const CTGitPath& path) const
539 #if 0
540 if (apr_hash_count(m_statushash) == 0)
541 return false;
543 GitPool localpool(m_pool);
544 apr_hash_index_t *hi;
545 const char* key;
546 for (hi = apr_hash_first(localpool, m_externalhash); hi; hi = apr_hash_next(hi))
548 apr_hash_this(hi, (const void**)&key, NULL, NULL);
549 if (key)
551 if (CTGitPath(CUnicodeUtils::GetUnicode(key)).IsAncestorOf(path))
552 return true;
555 #endif
556 return false;
560 void GitStatus::GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string)
562 TCHAR * buf;
563 switch (status)
565 case git_wc_status_none:
566 buf = _T("none\0");
567 break;
568 case git_wc_status_unversioned:
569 buf = _T("unversioned\0");
570 break;
571 case git_wc_status_normal:
572 buf = _T("normal\0");
573 break;
574 case git_wc_status_added:
575 buf = _T("added\0");
576 break;
577 case git_wc_status_missing:
578 buf = _T("missing\0");
579 break;
580 case git_wc_status_deleted:
581 buf = _T("deleted\0");
582 break;
583 case git_wc_status_replaced:
584 buf = _T("replaced\0");
585 break;
586 case git_wc_status_modified:
587 buf = _T("modified\0");
588 break;
589 case git_wc_status_merged:
590 buf = _T("merged\0");
591 break;
592 case git_wc_status_conflicted:
593 buf = _T("conflicted\0");
594 break;
595 case git_wc_status_obstructed:
596 buf = _T("obstructed\0");
597 break;
598 case git_wc_status_ignored:
599 buf = _T("ignored");
600 break;
601 case git_wc_status_external:
602 buf = _T("external");
603 break;
604 case git_wc_status_incomplete:
605 buf = _T("incomplete\0");
606 break;
607 default:
608 buf = _T("\0");
609 break;
611 _stprintf_s(string, buflen, _T("%s"), buf);
614 void GitStatus::GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang)
616 switch (status)
618 case git_wc_status_none:
619 LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);
620 break;
621 case git_wc_status_unversioned:
622 LoadStringEx(hInst, IDS_STATUSUNVERSIONED, string, size, lang);
623 break;
624 case git_wc_status_normal:
625 LoadStringEx(hInst, IDS_STATUSNORMAL, string, size, lang);
626 break;
627 case git_wc_status_added:
628 LoadStringEx(hInst, IDS_STATUSADDED, string, size, lang);
629 break;
630 case git_wc_status_missing:
631 LoadStringEx(hInst, IDS_STATUSABSENT, string, size, lang);
632 break;
633 case git_wc_status_deleted:
634 LoadStringEx(hInst, IDS_STATUSDELETED, string, size, lang);
635 break;
636 case git_wc_status_replaced:
637 LoadStringEx(hInst, IDS_STATUSREPLACED, string, size, lang);
638 break;
639 case git_wc_status_modified:
640 LoadStringEx(hInst, IDS_STATUSMODIFIED, string, size, lang);
641 break;
642 case git_wc_status_merged:
643 LoadStringEx(hInst, IDS_STATUSMERGED, string, size, lang);
644 break;
645 case git_wc_status_conflicted:
646 LoadStringEx(hInst, IDS_STATUSCONFLICTED, string, size, lang);
647 break;
648 case git_wc_status_ignored:
649 LoadStringEx(hInst, IDS_STATUSIGNORED, string, size, lang);
650 break;
651 case git_wc_status_obstructed:
652 LoadStringEx(hInst, IDS_STATUSOBSTRUCTED, string, size, lang);
653 break;
654 case git_wc_status_external:
655 LoadStringEx(hInst, IDS_STATUSEXTERNAL, string, size, lang);
656 break;
657 case git_wc_status_incomplete:
658 LoadStringEx(hInst, IDS_STATUSINCOMPLETE, string, size, lang);
659 break;
660 default:
661 LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);
662 break;
666 #ifdef _MFC_VER
667 CString GitStatus::GetDepthString(git_depth_t depth)
669 #if 0
670 CString sDepth;
671 switch (depth)
673 case git_depth_unknown:
674 sDepth.LoadString(IDS_Git_DEPTH_UNKNOWN);
675 break;
676 case git_depth_empty:
677 sDepth.LoadString(IDS_Git_DEPTH_EMPTY);
678 break;
679 case git_depth_files:
680 sDepth.LoadString(IDS_Git_DEPTH_FILES);
681 break;
682 case git_depth_immediates:
683 sDepth.LoadString(IDS_Git_DEPTH_IMMEDIATE);
684 break;
685 case git_depth_infinity:
686 sDepth.LoadString(IDS_Git_DEPTH_INFINITE);
687 break;
689 return sDepth;
690 #endif
691 return CString("");
693 #endif
695 void GitStatus::GetDepthString(HINSTANCE hInst, git_depth_t depth, TCHAR * string, int size, WORD lang)
697 #if 0
698 switch (depth)
700 case git_depth_unknown:
701 LoadStringEx(hInst, IDS_SVN_DEPTH_UNKNOWN, string, size, lang);
702 break;
703 case git_depth_empty:
704 LoadStringEx(hInst, IDS_SVN_DEPTH_EMPTY, string, size, lang);
705 break;
706 case git_depth_files:
707 LoadStringEx(hInst, IDS_SVN_DEPTH_FILES, string, size, lang);
708 break;
709 case git_depth_immediates:
710 LoadStringEx(hInst, IDS_SVN_DEPTH_IMMEDIATE, string, size, lang);
711 break;
712 case git_depth_infinity:
713 LoadStringEx(hInst, IDS_SVN_DEPTH_INFINITE, string, size, lang);
714 break;
716 #endif
720 int GitStatus::LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage)
722 const STRINGRESOURCEIMAGE* pImage;
723 const STRINGRESOURCEIMAGE* pImageEnd;
724 ULONG nResourceSize;
725 HGLOBAL hGlobal;
726 UINT iIndex;
727 int ret;
729 HRSRC hResource = FindResourceEx(hInstance, RT_STRING, MAKEINTRESOURCE(((uID>>4)+1)), wLanguage);
730 if (!hResource)
732 // try the default language before giving up!
733 hResource = FindResource(hInstance, MAKEINTRESOURCE(((uID>>4)+1)), RT_STRING);
734 if (!hResource)
735 return 0;
737 hGlobal = LoadResource(hInstance, hResource);
738 if (!hGlobal)
739 return 0;
740 pImage = (const STRINGRESOURCEIMAGE*)::LockResource(hGlobal);
741 if(!pImage)
742 return 0;
744 nResourceSize = ::SizeofResource(hInstance, hResource);
745 pImageEnd = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+nResourceSize);
746 iIndex = uID&0x000f;
748 while ((iIndex > 0) && (pImage < pImageEnd))
750 pImage = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+(sizeof(STRINGRESOURCEIMAGE)+(pImage->nLength*sizeof(WCHAR))));
751 iIndex--;
753 if (pImage >= pImageEnd)
754 return 0;
755 if (pImage->nLength == 0)
756 return 0;
758 ret = pImage->nLength;
759 if (pImage->nLength > nBufferMax)
761 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength-1);
762 lpBuffer[nBufferMax-1] = 0;
764 else
766 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength);
767 lpBuffer[ret] = 0;
769 return ret;
772 BOOL GitStatus::getallstatus(const struct wgFile_s *pFile, void *pUserData)
774 git_wc_status_kind * s = (git_wc_status_kind *)pUserData;
775 *s = GitStatus::GetMoreImportant(*s, GitStatusFromWingit(pFile->nStatus));
776 return FALSE;
779 BOOL GitStatus::getstatus(const struct wgFile_s *pFile, void *pUserData)
781 git_wc_status2_t * s = (git_wc_status2_t*)pUserData;
782 s->prop_status = s->text_status = GitStatus::GetMoreImportant(s->prop_status, GitStatusFromWingit(pFile->nStatus));
783 return FALSE;
786 #if 0
787 git_error_t * GitStatus::getallstatus(void * baton, const char * /*path*/, git_wc_status2_t * status, apr_pool_t * /*pool*/)
789 git_wc_status_kind * s = (git_wc_status_kind *)baton;
790 *s = GitStatus::GetMoreImportant(*s, status->text_status);
791 *s = GitStatus::GetMoreImportant(*s, status->prop_status);
792 return Git_NO_ERROR;
794 #endif
796 #if 0
797 git_error_t * GitStatus::getstatushash(void * baton, const char * path, git_wc_status2_t * status, apr_pool_t * /*pool*/)
799 hashbaton_t * hash = (hashbaton_t *)baton;
800 const StdStrAVector& filterList = hash->pThis->m_filterFileList;
801 if (status->text_status == git_wc_status_external)
803 apr_hash_set (hash->exthash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, (const void*)1);
804 return Git_NO_ERROR;
806 if(filterList.size() > 0)
808 // We have a filter active - we're only interested in files which are in
809 // the filter
810 if(!binary_search(filterList.begin(), filterList.end(), path))
812 // This item is not in the filter - don't store it
813 return Git_NO_ERROR;
816 git_wc_status2_t * statuscopy = git_wc_dup_status2 (status, hash->pThis->m_pool);
817 apr_hash_set (hash->hash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, statuscopy);
818 return Git_NO_ERROR;
821 apr_array_header_t * GitStatus::sort_hash (apr_hash_t *ht,
822 int (*comparison_func) (const GitStatus::sort_item *, const GitStatus::sort_item *),
823 apr_pool_t *pool)
825 apr_hash_index_t *hi;
826 apr_array_header_t *ary;
828 /* allocate an array with only one element to begin with. */
829 ary = apr_array_make (pool, 1, sizeof(sort_item));
831 /* loop over hash table and push all keys into the array */
832 for (hi = apr_hash_first (pool, ht); hi; hi = apr_hash_next (hi))
834 sort_item *item = (sort_item*)apr_array_push (ary);
836 apr_hash_this (hi, &item->key, &item->klen, &item->value);
839 /* now quick sort the array. */
840 qsort (ary->elts, ary->nelts, ary->elt_size,
841 (int (*)(const void *, const void *))comparison_func);
843 return ary;
846 int GitStatus::sort_compare_items_as_paths (const sort_item *a, const sort_item *b)
848 const char *astr, *bstr;
850 astr = (const char*)a->key;
851 bstr = (const char*)b->key;
852 return git_path_compare_paths (astr, bstr);
854 #endif
856 git_error_t* GitStatus::cancel(void *baton)
858 #if 0
859 volatile bool * canceled = (bool *)baton;
860 if (*canceled)
862 CString temp;
863 temp.LoadString(IDS_Git_USERCANCELLED);
864 return git_error_create(Git_ERR_CANCELLED, NULL, CUnicodeUtils::GetUTF8(temp));
866 return Git_NO_ERROR;
867 #endif
868 return 0;
871 #ifdef _MFC_VER
873 // Set-up a filter to restrict the files which will have their status stored by a get-status
874 void GitStatus::SetFilter(const CTGitPathList& fileList)
876 m_filterFileList.clear();
877 for(int fileIndex = 0; fileIndex < fileList.GetCount(); fileIndex++)
879 // m_filterFileList.push_back(fileList[fileIndex].GetGitApiPath(m_pool));
881 // Sort the list so that we can do binary searches
882 std::sort(m_filterFileList.begin(), m_filterFileList.end());
885 void GitStatus::ClearFilter()
887 m_filterFileList.clear();
890 #endif // _MFC_VER
892 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
894 int GitStatus::GetFileStatus(CString &gitdir,CString &path,git_wc_status_kind * status,BOOL IsFull, BOOL IsRecursive,BOOL IsIgnore, FIll_STATUS_CALLBACK callback,void *pData)
899 TCHAR oldpath[MAX_PATH+1];
900 memset(oldpath,0,MAX_PATH+1);
902 path.Replace(_T('\\'),_T('/'));
904 if(status)
906 git_wc_status_kind st = git_wc_status_none;
907 CGitHash hash;
909 g_IndexFileMap.GetFileStatus(gitdir,path,&st,IsFull,false,callback,pData,&hash);
911 if( st == git_wc_status_conflicted )
913 *status =st;
914 if(callback)
915 callback(gitdir+_T("/")+path,st,false,pData);
916 return 0;
919 if( st == git_wc_status_unversioned )
921 if(!IsIgnore)
923 *status = git_wc_status_unversioned;
924 if(callback)
925 callback(gitdir+_T("/")+path, *status, false,pData);
926 return 0;
929 if( g_IgnoreList.CheckIgnoreChanged(gitdir,path))
931 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
933 if( g_IgnoreList.IsIgnore(path, gitdir) )
935 st = git_wc_status_ignored;
937 *status = st;
938 if(callback)
939 callback(gitdir+_T("/")+path,st, false, pData);
941 return 0;
944 if( st == git_wc_status_normal && IsFull)
947 int ret=g_HeadFileMap.CheckHeadUpdate(gitdir);
948 bool b=false;
950 CAutoReadLock lock(&g_HeadFileMap.m_SharedMutex);
953 CAutoReadLock lock(&g_HeadFileMap[gitdir].m_SharedMutex);
954 b = g_HeadFileMap[gitdir].m_Head != g_HeadFileMap[gitdir].m_TreeHash;
957 if(ret || b)
959 g_HeadFileMap[gitdir].ReadHeadHash(gitdir);
960 // Init Repository
961 if( g_HeadFileMap[gitdir].m_HeadFile.IsEmpty() )
963 *status =st=git_wc_status_added;
964 if(callback)
965 callback(gitdir+_T("/")+path,st,false,pData);
966 return 0;
968 if(g_HeadFileMap[gitdir].ReadTree())
970 g_HeadFileMap[gitdir].m_LastModifyTimeHead = 0;
971 //Check if init repository
972 *status = g_HeadFileMap[gitdir].m_Head.IsEmpty()? git_wc_status_added: st;
973 if(callback)
974 callback(gitdir+_T("/")+path,*status,false,pData);
975 return 0;
979 // Check Head Tree Hash;
981 CAutoReadLock lock(&g_HeadFileMap[gitdir].m_SharedMutex);
983 //add item
984 std::map<CString,int>::iterator it=g_HeadFileMap[gitdir].m_Map.find(path);
986 if(it == g_HeadFileMap[gitdir].m_Map.end())
988 *status =st=git_wc_status_added;
989 ATLTRACE(_T("File miss in head tree %s"), path);
990 if(callback)
991 callback(gitdir+_T("/")+path,st,false, pData);
992 return 0;
995 //staged and not commit
996 if( g_HeadFileMap[gitdir].at(it->second).m_Hash != hash )
998 *status =st=git_wc_status_modified;
999 if(callback)
1000 callback(gitdir+_T("/")+path,st, false, pData);
1001 return 0;
1006 *status =st;
1007 if(callback)
1008 callback(gitdir+_T("/")+path,st,false, pData);
1009 return 0;
1012 catch(...)
1014 if(status)
1015 *status = git_wc_status_none;
1016 return -1;
1019 return 0;
1023 int GitStatus::GetHeadHash(CString &gitdir, CGitHash &hash)
1025 return g_HeadFileMap.GetHeadHash(gitdir, hash);
1028 bool GitStatus::IsGitReposChanged(CString &gitdir,CString &subpaths, int mode)
1030 if( mode & GIT_MODE_INDEX)
1032 bool load = true;
1033 g_IndexFileMap.CheckAndUpdateIndex(gitdir,&load);
1034 return load;
1037 if( mode & GIT_MODE_HEAD)
1039 if(g_HeadFileMap.CheckHeadUpdate(gitdir))
1040 return true;
1043 if( mode & GIT_MODE_IGNORE)
1045 if(g_IgnoreList.CheckIgnoreChanged(gitdir,subpaths))
1046 return true;
1048 return false;
1051 int GitStatus::LoadIgnoreFile(CString &gitdir,CString &subpaths)
1053 return g_IgnoreList.LoadAllIgnoreFile(gitdir,subpaths);
1055 int GitStatus::IsUnderVersionControl(CString &gitdir, CString &path, bool isDir,bool *isVersion)
1057 return g_IndexFileMap.IsUnderVersionControl(gitdir, path, isDir, isVersion);
1060 __int64 GitStatus::GetIndexFileTime(CString &gitdir)
1062 CAutoReadLock lock(&g_IndexFileMap.m_SharedMutex);
1064 if(g_IndexFileMap.find(gitdir) == g_IndexFileMap.end())
1065 return 0;
1067 return g_IndexFileMap[gitdir].m_LastModifyTime;
1070 int GitStatus::GetIgnoreFileChangeTimeList(CString &dir, std::vector<__int64> &timelist)
1072 return g_IgnoreList.GetIgnoreFileChangeTimeList(dir,timelist);
1074 int GitStatus::IsIgnore(CString &gitdir, CString &path, bool *isIgnore)
1076 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,path))
1077 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
1079 *isIgnore = g_IgnoreList.IsIgnore(path,gitdir);
1081 return 0;
1084 int GitStatus::EnumDirStatus(CString &gitdir,CString &subpath,git_wc_status_kind * status,BOOL IsFul, BOOL IsRecursive, BOOL IsIgnore, FIll_STATUS_CALLBACK callback, void *pData)
1088 TCHAR oldpath[MAX_PATH+1];
1089 memset(oldpath,0,MAX_PATH+1);
1091 CString path =subpath;
1093 path.Replace(_T('\\'),_T('/'));
1094 if(!path.IsEmpty())
1095 if(path[path.GetLength()-1] != _T('/'))
1096 path += _T('/'); //Add trail / to show it is directory, not file name.
1098 if(status)
1100 g_IndexFileMap.CheckAndUpdateIndex(gitdir);
1102 int pos;
1105 CAutoReadLock lock(&g_IndexFileMap.m_SharedMutex);
1106 CAutoReadLock lock1(&g_IndexFileMap[gitdir].m_SharedMutex);
1108 pos=SearchInSortVector(g_IndexFileMap[gitdir],path.GetBuffer(),path.GetLength());
1111 if(subpath.IsEmpty() && pos<0)
1112 { // for new init repository
1113 *status = git_wc_status_normal;
1114 if(callback)
1115 callback(gitdir+_T("/")+path, *status, false,pData);
1116 return 0;
1119 //Not In Version Contorl
1120 if(pos<0)
1122 if(!IsIgnore)
1124 *status = git_wc_status_unversioned;
1125 if(callback)
1126 callback(gitdir+_T("/")+path, *status, false,pData);
1127 return 0;
1129 //Check ignore always.
1131 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,path))
1132 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
1134 if(g_IgnoreList.IsIgnore(path,gitdir))
1135 *status = git_wc_status_ignored;
1136 else
1137 *status = git_wc_status_unversioned;
1139 g_HeadFileMap.CheckHeadUpdate(gitdir);
1141 //Check init repository
1144 CAutoReadLock lock(&g_HeadFileMap.m_SharedMutex);
1145 CAutoReadLock lock1(&g_HeadFileMap[gitdir].m_SharedMutex);
1147 if(g_HeadFileMap[gitdir].m_Head.IsEmpty() && path.IsEmpty())
1148 *status = git_wc_status_normal;
1152 }else // In version control
1154 *status = git_wc_status_normal;
1156 g_IndexFileMap.m_SharedMutex.AcquireShared();
1157 g_IndexFileMap[gitdir].m_SharedMutex.AcquireShared();
1159 int start=0;
1160 int end=0;
1161 if(path.IsEmpty())
1163 start=0;
1164 end=g_IndexFileMap[gitdir].size()-1;
1167 GetRangeInSortVector(g_IndexFileMap[gitdir],path.GetBuffer(),path.GetLength(),&start,&end,pos);
1168 CGitIndexList::iterator it;
1170 it = g_IndexFileMap[gitdir].begin()+start;
1172 CString sub, currentPath;
1174 for(int i=start;i<=end;i++,it++)
1176 if( ((*it).m_Flags & CE_STAGEMASK) !=0)
1178 *status = git_wc_status_conflicted;
1181 if( !IsRecursive )
1183 //skip child directory
1184 int pos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1186 if( pos > 0)
1188 currentPath = (*it).m_FileName.Left(pos);
1189 if( callback && (sub != currentPath) )
1191 sub = currentPath;
1192 ATLTRACE(_T("index subdir %s\n"),sub);
1193 if(callback)
1195 g_IndexFileMap[gitdir].m_SharedMutex.ReleaseShared();
1196 g_IndexFileMap.m_SharedMutex.ReleaseShared();
1197 callback(gitdir + _T("\\")+sub, git_wc_status_normal,true, pData);
1198 g_IndexFileMap.m_SharedMutex.AcquireShared();
1199 g_IndexFileMap[gitdir].m_SharedMutex.AcquireShared();
1202 continue;
1206 git_wc_status_kind filestatus = git_wc_status_none;
1208 g_IndexFileMap[gitdir].m_SharedMutex.ReleaseShared();
1209 g_IndexFileMap.m_SharedMutex.ReleaseShared();
1210 GetFileStatus(gitdir,(*it).m_FileName, &filestatus,IsFul, IsRecursive,IsIgnore, callback,pData);
1211 g_IndexFileMap.m_SharedMutex.AcquireShared();
1212 g_IndexFileMap[gitdir].m_SharedMutex.AcquireShared();
1214 *status = max(filestatus, *status) ;
1217 //Check Miss file in index "git rm file"
1218 if( IsFul && (*status != git_wc_status_conflicted))
1220 if(g_HeadFileMap.CheckHeadUpdate(gitdir) || g_HeadFileMap.IsHashChanged(gitdir))
1222 CAutoReadLock lock(&g_HeadFileMap.m_SharedMutex);
1224 g_HeadFileMap[gitdir].ReadHeadHash(gitdir);
1226 if(g_HeadFileMap[gitdir].ReadTree())
1228 //try again
1229 g_Git.SetCurrentDir(gitdir);
1230 ::GetCurrentDirectory(MAX_PATH,oldpath);
1231 ::SetCurrentDirectory(g_Git.m_CurrentDir);
1232 git_init();
1233 g_HeadFileMap[gitdir].ReadTree();
1236 //Check Add
1237 it = ::g_IndexFileMap[gitdir].begin()+start;
1240 CAutoReadLock lock(&g_HeadFileMap.m_SharedMutex);
1241 CAutoReadLock lock1(&g_HeadFileMap[gitdir].m_SharedMutex);
1243 //Check if new init repository
1244 if( g_HeadFileMap[gitdir].size() > 0 || g_HeadFileMap[gitdir].m_Head.IsEmpty() )
1246 //Check Delete
1247 if( *status == git_wc_status_normal )
1249 pos = SearchInSortVector(g_HeadFileMap[gitdir], path.GetBuffer(), path.GetLength());
1250 if(pos <0)
1252 *status = max(git_wc_status_added, *status) ;
1254 }else
1256 int hstart,hend;
1257 GetRangeInSortVector(g_HeadFileMap[gitdir],path.GetBuffer(),path.GetLength(),&hstart,&hend,pos);
1258 CGitHeadFileList::iterator hit;
1259 hit = g_HeadFileMap[gitdir].begin()+hstart;
1260 for(int i=hstart;i<=hend;i++)
1262 if( ::g_IndexFileMap[gitdir].m_Map.find((*hit).m_FileName) == g_IndexFileMap[gitdir].m_Map.end())
1264 *status =max(git_wc_status_deleted, *status);
1265 break;
1267 hit++;
1270 } // endif if( *status == git_wc_status_normal )
1271 }// endif if( g_HeadFileMap[gitdir].size() > 0 || g_HeadFileMap[gitdir].m_Head.IsEmpty() )
1275 g_IndexFileMap[gitdir].m_SharedMutex.ReleaseShared();
1276 g_IndexFileMap.m_SharedMutex.ReleaseShared();
1278 }// end inversion control
1279 if(callback) callback(gitdir+_T("/")+subpath,*status,true, pData);
1280 }//endi if status
1282 if(*oldpath!=0)
1283 ::SetCurrentDirectory(oldpath);
1284 }catch(...)
1286 if(status)
1287 *status = git_wc_status_none;
1290 return 0;
1293 int GitStatus::GetDirStatus(CString &gitdir,CString &subpath,git_wc_status_kind * status,BOOL IsFul, BOOL IsRecursive,BOOL IsIgnore,FIll_STATUS_CALLBACK callback,void *pData)
1297 TCHAR oldpath[MAX_PATH+1];
1298 memset(oldpath,0,MAX_PATH+1);
1300 CString path =subpath;
1302 path.Replace(_T('\\'),_T('/'));
1303 if(!path.IsEmpty())
1304 if(path[path.GetLength()-1] != _T('/'))
1305 path += _T('/'); //Add trail / to show it is directory, not file name.
1307 if(status)
1309 g_IndexFileMap.CheckAndUpdateIndex(gitdir);
1311 CAutoReadLock lock(&g_IndexFileMap.m_SharedMutex);
1312 CAutoReadLock lock1(&g_IndexFileMap[gitdir].m_SharedMutex);
1314 int pos=SearchInSortVector(g_IndexFileMap[gitdir],path.GetBuffer(),path.GetLength());
1316 if(subpath.IsEmpty() && pos<0)
1317 { // for new init repository
1318 *status = git_wc_status_normal;
1319 if(callback)
1320 callback(gitdir+_T("/")+path, *status, false,pData);
1321 return 0;
1324 //Not In Version Contorl
1325 if(pos<0)
1327 if(!IsIgnore)
1329 *status = git_wc_status_unversioned;
1330 if(callback)
1331 callback(gitdir+_T("/")+path, *status, false,pData);
1332 return 0;
1334 //Check ignore always.
1336 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,path))
1337 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
1339 if(g_IgnoreList.IsIgnore(path,gitdir))
1340 *status = git_wc_status_ignored;
1341 else
1342 *status = git_wc_status_unversioned;
1344 g_HeadFileMap.CheckHeadUpdate(gitdir);
1346 CAutoReadLock lock(&g_HeadFileMap.m_SharedMutex);
1347 CAutoReadLock lock1(&g_HeadFileMap[gitdir].m_SharedMutex);
1348 //Check init repository
1349 if(g_HeadFileMap[gitdir].m_Head.IsEmpty() && path.IsEmpty())
1350 *status = git_wc_status_normal;
1353 }else // In version control
1355 *status = git_wc_status_normal;
1357 int start=0;
1358 int end=0;
1359 if(path.IsEmpty())
1361 start=0;
1362 end=g_IndexFileMap[gitdir].size()-1;
1364 GetRangeInSortVector(g_IndexFileMap[gitdir],path.GetBuffer(),path.GetLength(),&start,&end,pos);
1365 CGitIndexList::iterator it;
1367 it = g_IndexFileMap[gitdir].begin()+start;
1369 // Check Conflict;
1370 for(int i=start;i<=end;i++)
1372 if( ((*it).m_Flags & CE_STAGEMASK) !=0)
1374 *status = git_wc_status_conflicted;
1375 if(callback)
1377 int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1378 if(dirpos<0 || IsRecursive)
1379 callback(gitdir+_T("\\")+ it->m_FileName,git_wc_status_conflicted,false,pData);
1380 }else
1381 break;
1383 it++;
1386 if( IsFul && (*status != git_wc_status_conflicted))
1388 *status = git_wc_status_normal;
1390 if(g_HeadFileMap.CheckHeadUpdate(gitdir))
1392 CAutoReadLock lock(&g_HeadFileMap.m_SharedMutex);
1393 CAutoReadLock lock1(&g_HeadFileMap[gitdir].m_SharedMutex);
1395 g_HeadFileMap[gitdir].ReadHeadHash(gitdir);
1397 if(g_HeadFileMap[gitdir].ReadTree())
1399 //try again
1400 g_Git.SetCurrentDir(gitdir);
1401 ::GetCurrentDirectory(MAX_PATH,oldpath);
1402 ::SetCurrentDirectory(g_Git.m_CurrentDir);
1403 git_init();
1404 g_HeadFileMap[gitdir].ReadTree();
1407 //Check Add
1408 it = ::g_IndexFileMap[gitdir].begin()+start;
1412 CAutoReadLock lock(&g_HeadFileMap.m_SharedMutex);
1413 CAutoReadLock lock1(&g_HeadFileMap[gitdir].m_SharedMutex);
1416 //Check if new init repository
1417 if( g_HeadFileMap[gitdir].size() > 0 || g_HeadFileMap[gitdir].m_Head.IsEmpty() )
1419 for(int i=start;i<=end;i++)
1421 if( g_HeadFileMap[gitdir].m_Map.find((*it).m_FileName) == g_HeadFileMap[gitdir].m_Map.end())
1423 pos = -1;
1424 }else
1425 pos = g_HeadFileMap[gitdir].m_Map[(*it).m_FileName];
1427 if(pos < 0)
1429 *status = *status = max(git_wc_status_added, *status) ;
1430 if(callback)
1432 int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1433 if(dirpos<0 || IsRecursive)
1434 callback(gitdir+_T("\\")+ it->m_FileName,git_wc_status_added,false, pData);
1436 }else
1437 break;
1440 if( pos>=0 && g_HeadFileMap[gitdir][pos].m_Hash != (*it).m_IndexHash)
1442 *status = *status = max(git_wc_status_modified, *status) ;
1443 if(callback)
1445 int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1446 if(dirpos<0 || IsRecursive)
1447 callback(gitdir+_T("\\")+ it->m_FileName, git_wc_status_modified,false, pData);
1449 }else
1450 break;
1453 it++;
1456 //Check Delete
1457 if( *status == git_wc_status_normal )
1459 pos = SearchInSortVector(g_HeadFileMap[gitdir], path.GetBuffer(), path.GetLength());
1460 if(pos <0)
1462 *status = git_wc_status_added;
1464 }else
1466 int hstart,hend;
1467 GetRangeInSortVector(g_HeadFileMap[gitdir],path.GetBuffer(),path.GetLength(),&hstart,&hend,pos);
1468 CGitHeadFileList::iterator hit;
1469 hit = g_HeadFileMap[gitdir].begin()+start;
1470 for(int i=hstart;i<=hend;i++)
1472 if( ::g_IndexFileMap[gitdir].m_Map.find((*hit).m_FileName) == g_IndexFileMap[gitdir].m_Map.end())
1474 *status = git_wc_status_deleted;
1475 break;
1477 hit++;
1482 }/* End lock*/
1484 // If define callback, it need update each file status.
1485 // If not define callback, status == git_wc_status_conflicted, needn't check each file status
1486 // because git_wc_status_conflicted is highest.s
1487 if(callback || (*status != git_wc_status_conflicted))
1489 //Check File Time;
1490 //if(IsRecursive)
1492 CString sub, currentPath;
1493 it = g_IndexFileMap[gitdir].begin()+start;
1494 for(int i=start;i<=end;i++,it++)
1496 if( !IsRecursive )
1498 //skip child directory
1499 int pos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1501 if( pos > 0)
1503 currentPath = (*it).m_FileName.Left(pos);
1504 if( callback && (sub != currentPath) )
1506 sub = currentPath;
1507 ATLTRACE(_T("index subdir %s\n"),sub);
1508 if(callback) callback(gitdir + _T("\\")+sub,
1509 git_wc_status_normal,true, pData);
1511 continue;
1515 git_wc_status_kind filestatus = git_wc_status_none;
1517 GetFileStatus(gitdir,(*it).m_FileName, &filestatus,IsFul, IsRecursive,IsIgnore, callback,pData);
1519 *status = max(filestatus, *status) ;
1525 if(callback) callback(gitdir+_T("/")+subpath,*status,true, pData);
1528 if(*oldpath!=0)
1529 ::SetCurrentDirectory(oldpath);
1531 }catch(...)
1533 if(status)
1534 *status = git_wc_status_none;
1535 return -1;
1538 return 0;
1541 bool GitStatus::IsExistIndexLockFile(CString &gitdir)
1543 CString sDirName= gitdir;
1545 for (;;)
1547 if(PathFileExists(sDirName + _T("\\.git")))
1549 if(PathFileExists(sDirName + _T("\\.git\\index.lock")))
1550 return true;
1551 else
1552 return false;
1555 int x = sDirName.ReverseFind(_T('\\'));
1556 if (x < 2)
1557 return false;
1559 sDirName = sDirName.Left(x);
1562 return false;