drop unneeded method
[TortoiseGit.git] / src / Git / GitStatus.cpp
blob753832fb5c650b76ca0ab25a50e10b2729c12675
1 // TortoiseGit - a Windows shell extension for easy version control
3 // Copyright (C) 2008-2012 - 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 #include "registry.h"
22 //#include "resource.h"
23 #include "..\TortoiseShell\resource.h"
24 //#include "git_config.h"
25 #include "GitStatus.h"
26 #include "UnicodeUtils.h"
27 //#include "GitGlobal.h"
28 //#include "GitHelpers.h"
29 #ifdef _MFC_VER
30 //# include "Git.h"
31 //# include "MessageBox.h"
32 //# include "registry.h"
33 //# include "TGitPath.h"
34 //# include "PathUtils.h"
35 #endif
36 #include "git.h"
37 #include "gitindex.h"
38 #include "shellcache.h"
40 extern CGitAdminDirMap g_AdminDirMap;
41 CGitIndexFileMap g_IndexFileMap;
42 CGitHeadFileMap g_HeadFileMap;
43 CGitIgnoreList g_IgnoreList;
45 GitStatus::GitStatus(bool * /*pbCanceled*/)
46 : status(NULL)
48 #if 0
49 m_pool = git_pool_create (NULL);
51 git_error_clear(git_client_create_context(&ctx, m_pool));
53 if (pbCanceled)
55 ctx->cancel_func = cancel;
56 ctx->cancel_baton = pbCanceled;
59 #ifdef _MFC_VER
60 git_error_clear(git_config_ensure(NULL, m_pool));
62 // set up authentication
63 m_prompt.Init(m_pool, ctx);
65 // set up the configuration
66 m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);
68 if (m_err)
70 ::MessageBox(NULL, this->GetLastErrorMsg(), _T("TortoiseGit"), MB_ICONERROR);
71 git_error_clear(m_err);
72 git_pool_destroy (m_pool); // free the allocated memory
73 exit(-1);
76 // set up the Git_SSH param
77 CString tgit_ssh = CRegString(_T("Software\\TortoiseGit\\SSH"));
78 if (tgit_ssh.IsEmpty())
79 tgit_ssh = CPathUtils::GetAppDirectory() + _T("TortoisePlink.exe");
80 tgit_ssh.Replace('\\', '/');
81 if (!tgit_ssh.IsEmpty())
83 git_config_t * cfg = (git_config_t *)apr_hash_get ((apr_hash_t *)ctx->config, Git_CONFIG_CATEGORY_CONFIG,
84 APR_HASH_KEY_STRING);
85 git_config_set(cfg, Git_CONFIG_SECTION_TUNNELS, "ssh", CUnicodeUtils::GetUTF8(tgit_ssh));
87 #else
88 git_error_clear(git_config_ensure(NULL, m_pool));
90 // set up the configuration
91 m_err = git_config_get_config (&(ctx->config), g_pConfigDir, m_pool);
93 #endif
94 #endif
97 GitStatus::~GitStatus(void)
99 #if 0
100 git_error_clear(m_err);
101 git_pool_destroy (m_pool); // free the allocated memory
102 #endif
105 void GitStatus::ClearPool()
107 #if 0
108 git_pool_clear(m_pool);
109 #endif
112 #ifdef _MFC_VER
113 CString GitStatus::GetLastErrorMsg() const
115 // return Git::GetErrorString(m_err);
116 return CString("");
118 #else
119 stdstring GitStatus::GetLastErrorMsg() const
122 stdstring msg;
123 #if 0
124 char errbuf[256];
126 if (m_err != NULL)
128 git_error_t * ErrPtr = m_err;
129 if (ErrPtr->message)
131 msg = CUnicodeUtils::StdGetUnicode(ErrPtr->message);
133 else
135 /* Is this a Subversion-specific error code? */
136 if ((ErrPtr->apr_err > APR_OS_START_USEERR)
137 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))
138 msg = CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));
139 /* Otherwise, this must be an APR error code. */
140 else
142 git_error_t *temp_err = NULL;
143 const char * err_string = NULL;
144 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);
145 if (temp_err)
147 git_error_clear (temp_err);
148 msg = _T("Can't recode error string from APR");
150 else
152 msg = CUnicodeUtils::StdGetUnicode(err_string);
158 while (ErrPtr->child)
160 ErrPtr = ErrPtr->child;
161 msg += _T("\n");
162 if (ErrPtr->message)
164 msg += CUnicodeUtils::StdGetUnicode(ErrPtr->message);
166 else
168 /* Is this a Subversion-specific error code? */
169 if ((ErrPtr->apr_err > APR_OS_START_USEERR)
170 && (ErrPtr->apr_err <= APR_OS_START_CANONERR))
171 msg += CUnicodeUtils::StdGetUnicode(git_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)));
172 /* Otherwise, this must be an APR error code. */
173 else
175 git_error_t *temp_err = NULL;
176 const char * err_string = NULL;
177 temp_err = git_utf_cstring_to_utf8(&err_string, apr_strerror (ErrPtr->apr_err, errbuf, sizeof (errbuf)-1), ErrPtr->pool);
178 if (temp_err)
180 git_error_clear (temp_err);
181 msg += _T("Can't recode error string from APR");
183 else
185 msg += CUnicodeUtils::StdGetUnicode(err_string);
191 return msg;
192 } // if (m_err != NULL)
193 #endif
194 return msg;
196 #endif
198 // static method
199 git_wc_status_kind GitStatus::GetAllStatus(const CTGitPath& path, git_depth_t depth)
201 git_wc_status_kind statuskind;
202 // git_client_ctx_t * ctx;
204 // apr_pool_t * pool;
205 // git_error_t * err;
206 BOOL err;
207 BOOL isDir;
208 CString sProjectRoot;
210 isDir = path.IsDirectory();
211 if (!path.HasAdminDir(&sProjectRoot))
212 return git_wc_status_none;
214 // pool = git_pool_create (NULL); // create the memory pool
216 // git_error_clear(git_client_create_context(&ctx, pool));
218 // git_revnum_t youngest = Git_INVALID_REVNUM;
219 // git_opt_revision_t rev;
220 // rev.kind = git_opt_revision_unspecified;
221 statuskind = git_wc_status_none;
223 const BOOL bIsRecursive = (depth == git_depth_infinity || depth == git_depth_unknown); // taken from SVN source
225 CString sSubPath;
226 CString s = path.GetWinPathString();
227 if (s.GetLength() > sProjectRoot.GetLength())
229 if (sProjectRoot.GetLength() == 3 && sProjectRoot[1] == _T(':'))
230 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength());
231 else
232 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength() - 1/*otherwise it gets initial slash*/);
235 bool isfull = ((DWORD)CRegStdDWORD(_T("Software\\TortoiseGit\\CacheType"),
236 GetSystemMetrics(SM_REMOTESESSION) ? ShellCache::dll : ShellCache::exe) == ShellCache::dllFull);
238 if(isDir)
240 err = GetDirStatus(sProjectRoot,sSubPath,&statuskind, isfull,bIsRecursive,isfull,NULL, NULL);
243 else
245 err = GetFileStatus(sProjectRoot,sSubPath,&statuskind,isfull, false,isfull, NULL,NULL);
248 return statuskind;
251 // static method
252 git_wc_status_kind GitStatus::GetAllStatusRecursive(const CTGitPath& path)
254 return GetAllStatus(path, git_depth_infinity);
257 // static method
258 git_wc_status_kind GitStatus::GetMoreImportant(git_wc_status_kind status1, git_wc_status_kind status2)
260 if (GetStatusRanking(status1) >= GetStatusRanking(status2))
261 return status1;
262 return status2;
264 // static private method
265 int GitStatus::GetStatusRanking(git_wc_status_kind status)
267 switch (status)
269 case git_wc_status_none:
270 return 0;
271 case git_wc_status_unversioned:
272 return 1;
273 case git_wc_status_ignored:
274 return 2;
275 case git_wc_status_incomplete:
276 return 4;
277 case git_wc_status_normal:
278 case git_wc_status_external:
279 return 5;
280 case git_wc_status_added:
281 return 6;
282 case git_wc_status_missing:
283 return 7;
284 case git_wc_status_deleted:
285 return 8;
286 case git_wc_status_replaced:
287 return 9;
288 case git_wc_status_modified:
289 return 10;
290 case git_wc_status_merged:
291 return 11;
292 case git_wc_status_conflicted:
293 return 12;
294 case git_wc_status_obstructed:
295 return 13;
297 return 0;
300 git_revnum_t GitStatus::GetStatus(const CTGitPath& path, bool update /* = false */, bool noignore /* = false */, bool /*noexternals*/ /* = false */)
302 // NOTE: unlike the SVN version this one does not cache the enumerated files, because in practice no code in all of
303 // Tortoise uses this, all places that call GetStatus create a temp GitStatus object which gets destroyed right
304 // after the call again
306 // apr_hash_t * statushash;
307 // apr_hash_t * exthash;
308 // apr_array_header_t * statusarray;
309 // const sort_item* item;
311 // git_error_clear(m_err);
312 // statushash = apr_hash_make(m_pool);
313 // exthash = apr_hash_make(m_pool);
314 git_revnum_t youngest = GIT_INVALID_REVNUM;
315 // git_opt_revision_t rev;
316 // rev.kind = git_opt_revision_unspecified;
318 CString sProjectRoot;
319 if ( !path.HasAdminDir(&sProjectRoot) )
320 return youngest;
322 struct hashbaton_t hashbaton;
323 // hashbaton.hash = statushash;
324 // hashbaton.exthash = exthash;
325 hashbaton.pThis = this;
327 bool isfull = ((DWORD)CRegStdDWORD(_T("Software\\TortoiseGit\\CacheType"),
328 GetSystemMetrics(SM_REMOTESESSION) ? ShellCache::dll : ShellCache::exe) == ShellCache::dllFull);
331 LPCTSTR lpszSubPath = NULL;
332 CString sSubPath;
333 CString s = path.GetWinPathString();
334 if (s.GetLength() > sProjectRoot.GetLength())
336 sSubPath = s.Right(s.GetLength() - sProjectRoot.GetLength());
337 lpszSubPath = sSubPath;
338 // skip initial slash if necessary
339 if (*lpszSubPath == _T('\\'))
340 lpszSubPath++;
343 m_status.prop_status = m_status.text_status = git_wc_status_none;
345 if(path.IsDirectory())
347 m_err = GetDirStatus(sProjectRoot,CString(lpszSubPath),&m_status.text_status , isfull, false,!noignore, NULL, NULL);
350 else
352 m_err = GetFileStatus(sProjectRoot,CString(lpszSubPath),&m_status.text_status ,isfull, false,!noignore, NULL,NULL);
356 // Error present if function is not under version control
357 if (m_err) /*|| (apr_hash_count(statushash) == 0)*/
359 status = NULL;
360 return GIT_INVALID_REVNUM;
363 // Convert the unordered hash to an ordered, sorted array
364 /*statusarray = sort_hash (statushash,
365 sort_compare_items_as_paths,
366 m_pool);*/
368 // only the first entry is needed (no recurse)
369 // item = &APR_ARRAY_IDX (statusarray, 0, const sort_item);
371 // status = (git_wc_status2_t *) item->value;
372 status = &m_status;
374 if (update)
376 // done to match TSVN functionality of this function (not sure if any code uses the reutrn val)
377 // if TGit does not need this, then change the return type of function
378 youngest = g_Git.GetHash(_T("HEAD"));
381 return youngest;
384 git_wc_status2_t * GitStatus::GetFirstFileStatus(const CTGitPath& /*path*/, CTGitPath& /*retPath*/, bool /*update*/, git_depth_t /*depth*/, bool /*bNoIgnore*/ /* = true */, bool /*bNoExternals*/ /* = false */)
386 static git_wc_status2 st;
388 m_fileCache.Reset();
390 m_fileCache.Init( CStringA( path.GetWinPathString().GetString() ) );
391 MessageBox(NULL, path.GetWinPathString(), _T("GetFirstFile"), MB_OK);
392 m_fileCache.m_pFileIter = m_fileCache.m_pFiles;
393 st.text_status = git_wc_status_none;
395 if (m_fileCache.m_pFileIter)
397 switch(m_fileCache.m_pFileIter->nStatus)
399 case WGFS_Normal: st.text_status = git_wc_status_normal; break;
400 case WGFS_Modified: st.text_status = git_wc_status_modified; break;
401 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;
404 //retPath.SetFromGit((const char*)item->key);
406 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;
409 return &st;
411 #if 0
412 const sort_item* item;
414 git_error_clear(m_err);
415 m_statushash = apr_hash_make(m_pool);
416 m_externalhash = apr_hash_make(m_pool);
417 headrev = Git_INVALID_REVNUM;
418 git_opt_revision_t rev;
419 rev.kind = git_opt_revision_unspecified;
420 struct hashbaton_t hashbaton;
421 hashbaton.hash = m_statushash;
422 hashbaton.exthash = m_externalhash;
423 hashbaton.pThis = this;
424 m_statushashindex = 0;
425 m_err = git_client_status4 (&headrev,
426 path.GetGitApiPath(m_pool),
427 &rev,
428 getstatushash,
429 &hashbaton,
430 depth,
431 TRUE, //getall
432 update, //update
433 bNoIgnore, //noignore
434 bNoExternals, //noexternals
435 NULL,
436 ctx,
437 m_pool);
440 // Error present if function is not under version control
441 if ((m_err != NULL) || (apr_hash_count(m_statushash) == 0))
443 return NULL;
446 // Convert the unordered hash to an ordered, sorted array
447 m_statusarray = sort_hash (m_statushash,
448 sort_compare_items_as_paths,
449 m_pool);
451 // only the first entry is needed (no recurse)
452 m_statushashindex = 0;
453 item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);
454 retPath.SetFromGit((const char*)item->key);
455 return (git_wc_status2_t *) item->value;
456 #endif
458 return 0;
461 unsigned int GitStatus::GetVersionedCount() const
463 // return /**/m_fileCache.GetFileCount();
465 unsigned int count = 0;
466 #if 0
467 const sort_item* item;
468 for (unsigned int i=0; i<apr_hash_count(m_statushash); ++i)
470 item = &APR_ARRAY_IDX(m_statusarray, i, const sort_item);
471 if (item)
473 if (GitStatus::GetMoreImportant(((git_wc_status_t *)item->value)->text_status, git_wc_status_ignored)!=git_wc_status_ignored)
474 count++;
477 #endif
478 return count;
481 git_wc_status2_t * GitStatus::GetNextFileStatus(CTGitPath& /*retPath*/)
483 static git_wc_status2 st;
485 st.text_status = git_wc_status_none;
487 /*if (m_fileCache.m_pFileIter)
489 switch(m_fileCache.m_pFileIter->nStatus)
491 case WGFS_Normal: st.text_status = git_wc_status_normal; break;
492 case WGFS_Modified: st.text_status = git_wc_status_modified; break;
493 case WGFS_Deleted: st.text_status = git_wc_status_deleted; break;
496 m_fileCache.m_pFileIter = m_fileCache.m_pFileIter->pNext;
499 return &st;
501 #if 0
502 const sort_item* item;
504 if ((m_statushashindex+1) >= apr_hash_count(m_statushash))
505 return NULL;
506 m_statushashindex++;
508 item = &APR_ARRAY_IDX (m_statusarray, m_statushashindex, const sort_item);
509 retPath.SetFromGit((const char*)item->key);
510 return (git_wc_status2_t *) item->value;
511 #endif
512 return 0;
515 bool GitStatus::IsExternal(const CTGitPath& /*path*/) const
517 #if 0
518 if (apr_hash_get(m_externalhash, path.GetGitApiPath(m_pool), APR_HASH_KEY_STRING))
519 return true;
520 #endif
521 return false;
524 bool GitStatus::IsInExternal(const CTGitPath& /*path*/) const
526 #if 0
527 if (apr_hash_count(m_statushash) == 0)
528 return false;
530 GitPool localpool(m_pool);
531 apr_hash_index_t *hi;
532 const char* key;
533 for (hi = apr_hash_first(localpool, m_externalhash); hi; hi = apr_hash_next(hi))
535 apr_hash_this(hi, (const void**)&key, NULL, NULL);
536 if (key)
538 if (CTGitPath(CUnicodeUtils::GetUnicode(key)).IsAncestorOf(path))
539 return true;
542 #endif
543 return false;
547 void GitStatus::GetStatusString(git_wc_status_kind status, size_t buflen, TCHAR * string)
549 TCHAR * buf;
550 switch (status)
552 case git_wc_status_none:
553 buf = _T("none\0");
554 break;
555 case git_wc_status_unversioned:
556 buf = _T("unversioned\0");
557 break;
558 case git_wc_status_normal:
559 buf = _T("normal\0");
560 break;
561 case git_wc_status_added:
562 buf = _T("added\0");
563 break;
564 case git_wc_status_missing:
565 buf = _T("missing\0");
566 break;
567 case git_wc_status_deleted:
568 buf = _T("deleted\0");
569 break;
570 case git_wc_status_replaced:
571 buf = _T("replaced\0");
572 break;
573 case git_wc_status_modified:
574 buf = _T("modified\0");
575 break;
576 case git_wc_status_merged:
577 buf = _T("merged\0");
578 break;
579 case git_wc_status_conflicted:
580 buf = _T("conflicted\0");
581 break;
582 case git_wc_status_obstructed:
583 buf = _T("obstructed\0");
584 break;
585 case git_wc_status_ignored:
586 buf = _T("ignored");
587 break;
588 case git_wc_status_external:
589 buf = _T("external");
590 break;
591 case git_wc_status_incomplete:
592 buf = _T("incomplete\0");
593 break;
594 default:
595 buf = _T("\0");
596 break;
598 _stprintf_s(string, buflen, _T("%s"), buf);
601 void GitStatus::GetStatusString(HINSTANCE hInst, git_wc_status_kind status, TCHAR * string, int size, WORD lang)
603 switch (status)
605 case git_wc_status_none:
606 LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);
607 break;
608 case git_wc_status_unversioned:
609 LoadStringEx(hInst, IDS_STATUSUNVERSIONED, string, size, lang);
610 break;
611 case git_wc_status_normal:
612 LoadStringEx(hInst, IDS_STATUSNORMAL, string, size, lang);
613 break;
614 case git_wc_status_added:
615 LoadStringEx(hInst, IDS_STATUSADDED, string, size, lang);
616 break;
617 case git_wc_status_missing:
618 LoadStringEx(hInst, IDS_STATUSABSENT, string, size, lang);
619 break;
620 case git_wc_status_deleted:
621 LoadStringEx(hInst, IDS_STATUSDELETED, string, size, lang);
622 break;
623 case git_wc_status_replaced:
624 LoadStringEx(hInst, IDS_STATUSREPLACED, string, size, lang);
625 break;
626 case git_wc_status_modified:
627 LoadStringEx(hInst, IDS_STATUSMODIFIED, string, size, lang);
628 break;
629 case git_wc_status_merged:
630 LoadStringEx(hInst, IDS_STATUSMERGED, string, size, lang);
631 break;
632 case git_wc_status_conflicted:
633 LoadStringEx(hInst, IDS_STATUSCONFLICTED, string, size, lang);
634 break;
635 case git_wc_status_ignored:
636 LoadStringEx(hInst, IDS_STATUSIGNORED, string, size, lang);
637 break;
638 case git_wc_status_obstructed:
639 LoadStringEx(hInst, IDS_STATUSOBSTRUCTED, string, size, lang);
640 break;
641 case git_wc_status_external:
642 LoadStringEx(hInst, IDS_STATUSEXTERNAL, string, size, lang);
643 break;
644 case git_wc_status_incomplete:
645 LoadStringEx(hInst, IDS_STATUSINCOMPLETE, string, size, lang);
646 break;
647 default:
648 LoadStringEx(hInst, IDS_STATUSNONE, string, size, lang);
649 break;
653 #ifdef _MFC_VER
654 CString GitStatus::GetDepthString(git_depth_t depth)
656 #if 0
657 CString sDepth;
658 switch (depth)
660 case git_depth_unknown:
661 sDepth.LoadString(IDS_Git_DEPTH_UNKNOWN);
662 break;
663 case git_depth_empty:
664 sDepth.LoadString(IDS_Git_DEPTH_EMPTY);
665 break;
666 case git_depth_files:
667 sDepth.LoadString(IDS_Git_DEPTH_FILES);
668 break;
669 case git_depth_immediates:
670 sDepth.LoadString(IDS_Git_DEPTH_IMMEDIATE);
671 break;
672 case git_depth_infinity:
673 sDepth.LoadString(IDS_Git_DEPTH_INFINITE);
674 break;
676 return sDepth;
677 #endif
678 return CString("");
680 #endif
682 void GitStatus::GetDepthString(HINSTANCE /*hInst*/, git_depth_t /*depth*/, TCHAR * /*string*/, int /*size*/, WORD /*lang*/)
684 #if 0
685 switch (depth)
687 case git_depth_unknown:
688 LoadStringEx(hInst, IDS_SVN_DEPTH_UNKNOWN, string, size, lang);
689 break;
690 case git_depth_empty:
691 LoadStringEx(hInst, IDS_SVN_DEPTH_EMPTY, string, size, lang);
692 break;
693 case git_depth_files:
694 LoadStringEx(hInst, IDS_SVN_DEPTH_FILES, string, size, lang);
695 break;
696 case git_depth_immediates:
697 LoadStringEx(hInst, IDS_SVN_DEPTH_IMMEDIATE, string, size, lang);
698 break;
699 case git_depth_infinity:
700 LoadStringEx(hInst, IDS_SVN_DEPTH_INFINITE, string, size, lang);
701 break;
703 #endif
707 int GitStatus::LoadStringEx(HINSTANCE hInstance, UINT uID, LPTSTR lpBuffer, int nBufferMax, WORD wLanguage)
709 const STRINGRESOURCEIMAGE* pImage;
710 const STRINGRESOURCEIMAGE* pImageEnd;
711 ULONG nResourceSize;
712 HGLOBAL hGlobal;
713 UINT iIndex;
714 int ret;
716 HRSRC hResource = FindResourceEx(hInstance, RT_STRING, MAKEINTRESOURCE(((uID>>4)+1)), wLanguage);
717 if (!hResource)
719 // try the default language before giving up!
720 hResource = FindResource(hInstance, MAKEINTRESOURCE(((uID>>4)+1)), RT_STRING);
721 if (!hResource)
722 return 0;
724 hGlobal = LoadResource(hInstance, hResource);
725 if (!hGlobal)
726 return 0;
727 pImage = (const STRINGRESOURCEIMAGE*)::LockResource(hGlobal);
728 if(!pImage)
729 return 0;
731 nResourceSize = ::SizeofResource(hInstance, hResource);
732 pImageEnd = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+nResourceSize);
733 iIndex = uID&0x000f;
735 while ((iIndex > 0) && (pImage < pImageEnd))
737 pImage = (const STRINGRESOURCEIMAGE*)(LPBYTE(pImage)+(sizeof(STRINGRESOURCEIMAGE)+(pImage->nLength*sizeof(WCHAR))));
738 iIndex--;
740 if (pImage >= pImageEnd)
741 return 0;
742 if (pImage->nLength == 0)
743 return 0;
745 ret = pImage->nLength;
746 if (pImage->nLength > nBufferMax)
748 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength-1);
749 lpBuffer[nBufferMax-1] = 0;
751 else
753 wcsncpy_s(lpBuffer, nBufferMax, pImage->achString, pImage->nLength);
754 lpBuffer[ret] = 0;
756 return ret;
759 BOOL GitStatus::getallstatus(const struct wgFile_s *pFile, void *pUserData)
761 git_wc_status_kind * s = (git_wc_status_kind *)pUserData;
762 *s = GitStatus::GetMoreImportant(*s, GitStatusFromWingit(pFile->nStatus));
763 return FALSE;
766 BOOL GitStatus::getstatus(const struct wgFile_s *pFile, void *pUserData)
768 git_wc_status2_t * s = (git_wc_status2_t*)pUserData;
769 s->prop_status = s->text_status = GitStatus::GetMoreImportant(s->prop_status, GitStatusFromWingit(pFile->nStatus));
770 return FALSE;
773 #if 0
774 git_error_t * GitStatus::getallstatus(void * baton, const char * /*path*/, git_wc_status2_t * status, apr_pool_t * /*pool*/)
776 git_wc_status_kind * s = (git_wc_status_kind *)baton;
777 *s = GitStatus::GetMoreImportant(*s, status->text_status);
778 *s = GitStatus::GetMoreImportant(*s, status->prop_status);
779 return Git_NO_ERROR;
781 #endif
783 #if 0
784 git_error_t * GitStatus::getstatushash(void * baton, const char * path, git_wc_status2_t * status, apr_pool_t * /*pool*/)
786 hashbaton_t * hash = (hashbaton_t *)baton;
787 const StdStrAVector& filterList = hash->pThis->m_filterFileList;
788 if (status->text_status == git_wc_status_external)
790 apr_hash_set (hash->exthash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, (const void*)1);
791 return Git_NO_ERROR;
793 if(filterList.size() > 0)
795 // We have a filter active - we're only interested in files which are in
796 // the filter
797 if(!binary_search(filterList.begin(), filterList.end(), path))
799 // This item is not in the filter - don't store it
800 return Git_NO_ERROR;
803 git_wc_status2_t * statuscopy = git_wc_dup_status2 (status, hash->pThis->m_pool);
804 apr_hash_set (hash->hash, apr_pstrdup(hash->pThis->m_pool, path), APR_HASH_KEY_STRING, statuscopy);
805 return Git_NO_ERROR;
808 apr_array_header_t * GitStatus::sort_hash (apr_hash_t *ht,
809 int (*comparison_func) (const GitStatus::sort_item *, const GitStatus::sort_item *),
810 apr_pool_t *pool)
812 apr_hash_index_t *hi;
813 apr_array_header_t *ary;
815 /* allocate an array with only one element to begin with. */
816 ary = apr_array_make (pool, 1, sizeof(sort_item));
818 /* loop over hash table and push all keys into the array */
819 for (hi = apr_hash_first (pool, ht); hi; hi = apr_hash_next (hi))
821 sort_item *item = (sort_item*)apr_array_push (ary);
823 apr_hash_this (hi, &item->key, &item->klen, &item->value);
826 /* now quick sort the array. */
827 qsort (ary->elts, ary->nelts, ary->elt_size,
828 (int (*)(const void *, const void *))comparison_func);
830 return ary;
833 int GitStatus::sort_compare_items_as_paths (const sort_item *a, const sort_item *b)
835 const char *astr, *bstr;
837 astr = (const char*)a->key;
838 bstr = (const char*)b->key;
839 return git_path_compare_paths (astr, bstr);
841 #endif
843 tgit_error_t* GitStatus::cancel(void * /*baton*/)
845 #if 0
846 volatile bool * canceled = (bool *)baton;
847 if (*canceled)
849 CString temp;
850 temp.LoadString(IDS_Git_USERCANCELLED);
851 return git_error_create(Git_ERR_CANCELLED, NULL, CUnicodeUtils::GetUTF8(temp));
853 return Git_NO_ERROR;
854 #endif
855 return 0;
858 #ifdef _MFC_VER
860 // Set-up a filter to restrict the files which will have their status stored by a get-status
861 void GitStatus::SetFilter(const CTGitPathList& fileList)
863 m_filterFileList.clear();
864 for(int fileIndex = 0; fileIndex < fileList.GetCount(); fileIndex++)
866 // m_filterFileList.push_back(fileList[fileIndex].GetGitApiPath(m_pool));
868 // Sort the list so that we can do binary searches
869 std::sort(m_filterFileList.begin(), m_filterFileList.end());
872 void GitStatus::ClearFilter()
874 m_filterFileList.clear();
877 #endif // _MFC_VER
879 typedef CComCritSecLock<CComCriticalSection> CAutoLocker;
881 int GitStatus::GetFileStatus(const CString &gitdir,const CString &pathParam,git_wc_status_kind * status,BOOL IsFull, BOOL /*IsRecursive*/,BOOL IsIgnore, FIll_STATUS_CALLBACK callback,void *pData)
885 CString path = pathParam;
887 TCHAR oldpath[MAX_PATH+1];
888 memset(oldpath,0,MAX_PATH+1);
890 path.Replace(_T('\\'),_T('/'));
892 CString lowcasepath =path;
893 lowcasepath.MakeLower();
895 if(status)
897 git_wc_status_kind st = git_wc_status_none;
898 CGitHash hash;
900 g_IndexFileMap.GetFileStatus(gitdir,path,&st,IsFull,false,callback,pData,&hash);
902 if( st == git_wc_status_conflicted )
904 *status =st;
905 if(callback)
906 callback(gitdir+_T("/")+path,st,false,pData);
907 return 0;
910 if( st == git_wc_status_unversioned )
912 if(!IsIgnore)
914 *status = git_wc_status_unversioned;
915 if(callback)
916 callback(gitdir+_T("/")+path, *status, false,pData);
917 return 0;
920 if( g_IgnoreList.CheckIgnoreChanged(gitdir,path))
922 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
924 if( g_IgnoreList.IsIgnore(path, gitdir) )
926 st = git_wc_status_ignored;
928 *status = st;
929 if(callback)
930 callback(gitdir+_T("/")+path,st, false, pData);
932 return 0;
935 if( st == git_wc_status_normal && IsFull)
938 g_HeadFileMap.CheckHeadUpdate(gitdir);
939 bool b=false;
941 SHARED_TREE_PTR treeptr;
943 treeptr=g_HeadFileMap.SafeGet(gitdir);
945 b = treeptr->m_Head != treeptr->m_TreeHash;
947 if(b)
949 treeptr->ReadHeadHash(gitdir);
951 // Init Repository
952 if( treeptr->m_HeadFile.IsEmpty() )
954 *status =st=git_wc_status_added;
955 if(callback)
956 callback(gitdir+_T("/")+path,st,false,pData);
957 return 0;
959 if(treeptr->ReadTree())
961 treeptr->m_LastModifyTimeHead = 0;
962 //Check if init repository
963 *status = treeptr->m_Head.IsEmpty()? git_wc_status_added: st;
964 if(callback)
965 callback(gitdir+_T("/")+path,*status,false,pData);
966 return 0;
968 g_HeadFileMap.SafeSet(gitdir, treeptr);
971 // Check Head Tree Hash;
973 //add item
975 int start =SearchInSortVector(*treeptr,lowcasepath.GetBuffer(),-1);
976 lowcasepath.ReleaseBuffer();
978 if(start<0)
980 *status =st=git_wc_status_added;
981 ATLTRACE(_T("File miss in head tree %s"), path);
982 if(callback)
983 callback(gitdir+_T("/")+path,st,false, pData);
984 return 0;
987 //staged and not commit
988 if( treeptr->at(start).m_Hash != hash )
990 *status =st=git_wc_status_modified;
991 if(callback)
992 callback(gitdir+_T("/")+path,st, false, pData);
993 return 0;
998 *status =st;
999 if(callback)
1000 callback(gitdir+_T("/")+path,st,false, pData);
1001 return 0;
1004 catch(...)
1006 if(status)
1007 *status = git_wc_status_none;
1008 return -1;
1011 return 0;
1015 int GitStatus::GetHeadHash(const CString &gitdir, CGitHash &hash)
1017 return g_HeadFileMap.GetHeadHash(gitdir, hash);
1020 bool GitStatus::IsGitReposChanged(const CString &gitdir,const CString &subpaths, int mode)
1022 if( mode & GIT_MODE_INDEX)
1024 return g_IndexFileMap.CheckAndUpdate(gitdir, true);
1027 if( mode & GIT_MODE_HEAD)
1029 if(g_HeadFileMap.CheckHeadUpdate(gitdir))
1030 return true;
1033 if( mode & GIT_MODE_IGNORE)
1035 if(g_IgnoreList.CheckIgnoreChanged(gitdir,subpaths))
1036 return true;
1038 return false;
1041 int GitStatus::LoadIgnoreFile(const CString &gitdir,const CString &subpaths)
1043 return g_IgnoreList.LoadAllIgnoreFile(gitdir,subpaths);
1045 int GitStatus::IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir,bool *isVersion)
1047 return g_IndexFileMap.IsUnderVersionControl(gitdir, path, isDir, isVersion);
1050 __int64 GitStatus::GetIndexFileTime(const CString &gitdir)
1052 SHARED_INDEX_PTR ptr=g_IndexFileMap.SafeGet(gitdir);
1053 if(ptr.get() == NULL)
1054 return 0;
1056 return ptr->m_LastModifyTime;
1059 int GitStatus::IsIgnore(const CString &gitdir, const CString &path, bool *isIgnore)
1061 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,path))
1062 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
1064 *isIgnore = g_IgnoreList.IsIgnore(path,gitdir);
1066 return 0;
1069 static bool SortFileName(CGitFileName &Item1, CGitFileName &Item2)
1071 return Item1.m_FileName.Compare(Item2.m_FileName)<0;
1074 int GitStatus::GetFileList(const CString &gitdir, const CString &subpath, std::vector<CGitFileName> &list)
1076 WIN32_FIND_DATA data;
1077 HANDLE handle=::FindFirstFile(gitdir+_T("\\")+subpath+_T("\\*.*"), &data);
1080 if(_tcscmp(data.cFileName, _T(".git")) == 0)
1081 continue;
1083 if(_tcscmp(data.cFileName, _T(".")) == 0)
1084 continue;
1086 if(_tcscmp(data.cFileName, _T("..")) == 0)
1087 continue;
1089 CGitFileName filename;
1091 filename.m_CaseFileName = filename.m_FileName = data.cFileName;
1092 filename.m_FileName.MakeLower();
1094 if(data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1096 filename.m_FileName += _T('/');
1099 list.push_back(filename);
1101 }while(::FindNextFile(handle, &data));
1103 FindClose(handle);
1105 std::sort(list.begin(), list.end(), SortFileName);
1106 return 0;
1109 int GitStatus::EnumDirStatus(const CString &gitdir,const CString &subpath,git_wc_status_kind * status,BOOL IsFul, BOOL IsRecursive, BOOL IsIgnore, FIll_STATUS_CALLBACK callback, void *pData)
1113 TCHAR oldpath[MAX_PATH+1];
1114 memset(oldpath,0,MAX_PATH+1);
1116 CString path =subpath;
1118 path.Replace(_T('\\'),_T('/'));
1119 if(!path.IsEmpty())
1120 if(path[path.GetLength()-1] != _T('/'))
1121 path += _T('/'); //Add trail / to show it is directory, not file name.
1123 CString lowcasepath = path;
1124 lowcasepath.MakeLower();
1126 std::vector<CGitFileName> filelist;
1127 GetFileList(gitdir, subpath, filelist);
1129 if(status)
1131 g_IndexFileMap.CheckAndUpdate(gitdir,true);
1133 if(g_HeadFileMap.CheckHeadUpdate(gitdir) || g_HeadFileMap.IsHashChanged(gitdir))
1135 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1136 treeptr->ReadHeadHash(gitdir);
1137 if(!treeptr->ReadTree())
1139 g_HeadFileMap.SafeSet(gitdir, treeptr);
1143 SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);
1144 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1146 if( indexptr.get() == NULL)
1147 return -1;
1149 std::vector<CGitFileName>::iterator it;
1150 CString onepath;
1151 CString casepath;
1152 for(it = filelist.begin(); it<filelist.end();it++)
1154 casepath=onepath = path;
1155 onepath.MakeLower();
1156 onepath += it->m_FileName;
1157 casepath += it->m_CaseFileName;
1159 LPTSTR onepathBuffer = onepath.GetBuffer();
1160 int pos = SearchInSortVector(*indexptr, onepathBuffer, onepath.GetLength());
1161 int posintree = SearchInSortVector(*treeptr, onepathBuffer, onepath.GetLength());
1162 onepath.ReleaseBuffer();
1164 bool bIsDir =false;
1165 if(onepath.GetLength()>0 && onepath[onepath.GetLength()-1] == _T('/'))
1166 bIsDir =true;
1168 if(pos <0 && posintree<0)
1170 if(onepath.GetLength() ==0)
1171 continue;
1173 if(bIsDir) /*check if it is directory*/
1175 if(::PathFileExists(gitdir+onepath+_T("/.git")))
1176 { /* That is git submodule */
1177 *status = git_wc_status_unknown;
1178 if(callback)
1179 callback(gitdir+_T("/")+casepath, *status, bIsDir, pData);
1180 continue;
1184 if(!IsIgnore)
1186 *status = git_wc_status_unversioned;
1187 if(callback)
1188 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1189 continue;
1192 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,casepath))
1193 g_IgnoreList.LoadAllIgnoreFile(gitdir,casepath);
1195 if(g_IgnoreList.IsIgnore(casepath,gitdir))
1196 *status = git_wc_status_ignored;
1197 else
1198 *status = git_wc_status_unversioned;
1200 if(callback)
1201 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1204 else if(pos <0 && posintree>=0) /* check if file delete in index */
1206 *status = git_wc_status_modified;
1207 if(callback)
1208 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1211 else if(pos >=0 && posintree <0) /* Check if file added */
1213 *status = git_wc_status_added;
1214 if(callback)
1215 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1217 else
1219 if(onepath.GetLength() ==0)
1220 continue;
1222 if(onepath[onepath.GetLength()-1] == _T('/'))
1224 *status = git_wc_status_normal;
1225 if(callback)
1226 callback(gitdir+_T("/")+casepath, *status, bIsDir,pData);
1228 else
1230 git_wc_status_kind filestatus;
1231 GetFileStatus(gitdir,casepath, &filestatus,IsFul, IsRecursive,IsIgnore, callback,pData);
1235 }/*End of For*/
1237 /* Check deleted file in system */
1238 LPTSTR lowcasepathBuffer = lowcasepath.GetBuffer();
1239 int start=0, end=0;
1240 int pos=SearchInSortVector(*indexptr, lowcasepathBuffer, lowcasepath.GetLength());
1242 if(pos>=0 && GetRangeInSortVector(*indexptr, lowcasepathBuffer, lowcasepath.GetLength(), &start, &end, pos))
1244 CGitIndexList::iterator it;
1245 CString oldstring;
1247 for(it = indexptr->begin()+start; it <= indexptr->begin()+end; it++)
1249 int start = lowcasepath.GetLength();
1250 int index = (*it).m_FileName.Find(_T('/'), start);
1251 if(index<0)
1252 index = (*it).m_FileName.GetLength();
1254 CString filename = (*it).m_FileName.Mid(start, index-start);
1255 if(oldstring != filename)
1257 oldstring = filename;
1258 if(SearchInSortVector(filelist, filename.GetBuffer(), filename.GetLength())<0)
1260 *status = git_wc_status_deleted;
1261 if(callback)
1262 callback(gitdir+_T("/")+filename, *status, false,pData);
1268 start = end =0;
1269 pos=SearchInSortVector(*treeptr, lowcasepathBuffer, lowcasepath.GetLength());
1270 if(pos>=0 && GetRangeInSortVector(*treeptr, lowcasepathBuffer, lowcasepath.GetLength(), &start, &end, pos) == 0)
1272 CGitHeadFileList::iterator it;
1273 CString oldstring;
1275 for(it = treeptr->begin()+start; it <= treeptr->begin()+end; it++)
1277 int start = lowcasepath.GetLength();
1278 int index = (*it).m_FileName.Find(_T('/'), start);
1279 if(index<0)
1280 index = (*it).m_FileName.GetLength();
1282 CString filename = (*it).m_FileName.Mid(start, index-start);
1283 if(oldstring != filename)
1285 oldstring = filename;
1286 if(SearchInSortVector(filelist, filename.GetBuffer(), filename.GetLength())<0)
1288 *status = git_wc_status_modified;
1289 if(callback)
1290 callback(gitdir+_T("/")+(*it).m_FileName, *status, false,pData);
1295 lowcasepath.ReleaseBuffer();
1297 }/*End of if status*/
1298 }catch(...)
1300 return -1;
1302 return 0;
1305 int GitStatus::GetDirStatus(const CString &gitdir,const CString &subpath,git_wc_status_kind * status,BOOL IsFul, BOOL IsRecursive,BOOL IsIgnore,FIll_STATUS_CALLBACK callback,void *pData)
1309 TCHAR oldpath[MAX_PATH+1];
1310 memset(oldpath,0,MAX_PATH+1);
1312 CString path =subpath;
1314 path.Replace(_T('\\'),_T('/'));
1315 if(!path.IsEmpty())
1316 if(path[path.GetLength()-1] != _T('/'))
1317 path += _T('/'); //Add trail / to show it is directory, not file name.
1319 CString lowcasepath = path;
1320 lowcasepath.MakeLower();
1322 if(status)
1324 g_IndexFileMap.CheckAndUpdate(gitdir, true);
1326 SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);
1328 if (indexptr == NULL)
1330 *status = git_wc_status_unversioned;
1331 return 0;
1334 if(subpath.IsEmpty() && (!indexptr.use_count()))
1335 { // for new init repository
1336 *status = git_wc_status_normal;
1337 if(callback)
1338 callback(gitdir+_T("/")+path, *status, false,pData);
1339 return 0;
1342 int pos=SearchInSortVector(*indexptr,lowcasepath.GetBuffer(),lowcasepath.GetLength());
1343 lowcasepath.ReleaseBuffer();
1345 //Not In Version Contorl
1346 if(pos<0)
1348 if(!IsIgnore)
1350 *status = git_wc_status_unversioned;
1351 if(callback)
1352 callback(gitdir+_T("/")+path, *status, false,pData);
1353 return 0;
1355 //Check ignore always.
1357 if(::g_IgnoreList.CheckIgnoreChanged(gitdir,path))
1358 g_IgnoreList.LoadAllIgnoreFile(gitdir,path);
1360 if(g_IgnoreList.IsIgnore(path,gitdir))
1361 *status = git_wc_status_ignored;
1362 else
1363 *status = git_wc_status_unversioned;
1365 g_HeadFileMap.CheckHeadUpdate(gitdir);
1367 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1368 //Check init repository
1369 if(treeptr->m_Head.IsEmpty() && path.IsEmpty())
1370 *status = git_wc_status_normal;
1374 else // In version control
1376 *status = git_wc_status_normal;
1378 int start=0;
1379 int end=0;
1380 if(path.IsEmpty())
1382 start=0;
1383 end=indexptr->size()-1;
1385 LPTSTR lowcasepathBuffer = lowcasepath.GetBuffer();
1386 GetRangeInSortVector(*indexptr, lowcasepathBuffer, lowcasepath.GetLength(), &start, &end, pos);
1387 lowcasepath.ReleaseBuffer();
1388 CGitIndexList::iterator it;
1390 it = indexptr->begin()+start;
1392 // Check Conflict;
1393 for(int i=start;i<=end;i++)
1395 if( ((*it).m_Flags & CE_STAGEMASK) !=0)
1397 *status = git_wc_status_conflicted;
1398 if(callback)
1400 int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1401 if(dirpos<0 || IsRecursive)
1402 callback(gitdir+_T("\\")+ it->m_FileName,git_wc_status_conflicted,false,pData);
1404 else
1405 break;
1407 it++;
1410 if( IsFul && (*status != git_wc_status_conflicted))
1412 *status = git_wc_status_normal;
1414 if(g_HeadFileMap.CheckHeadUpdate(gitdir))
1416 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1418 treeptr->ReadHeadHash(gitdir);
1420 if(treeptr->ReadTree())
1422 g_HeadFileMap.SafeSet(gitdir, treeptr);
1425 //Check Add
1426 it = indexptr->begin()+start;
1430 //Check if new init repository
1431 SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
1433 if( treeptr->size() > 0 || treeptr->m_Head.IsEmpty() )
1435 for(int i=start;i<=end;i++)
1437 pos =SearchInSortVector(*treeptr, (*it).m_FileName.GetBuffer(), -1);
1438 (*it).m_FileName.ReleaseBuffer();
1440 if(pos < 0)
1442 *status = max(git_wc_status_modified, *status); // added file found
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_added,false, pData);
1450 else
1451 break;
1454 if( pos>=0 && treeptr->at(pos).m_Hash != (*it).m_IndexHash)
1456 *status = max(git_wc_status_modified, *status); // modified file found
1457 if(callback)
1459 int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1460 if(dirpos<0 || IsRecursive)
1461 callback(gitdir+_T("\\")+ it->m_FileName, git_wc_status_modified,false, pData);
1464 else
1465 break;
1468 it++;
1471 //Check Delete
1472 if( *status == git_wc_status_normal )
1474 pos = SearchInSortVector(*treeptr, lowcasepathBuffer, lowcasepath.GetLength());
1475 if(pos <0)
1477 *status = max(git_wc_status_modified, *status); // added file found
1480 else
1482 int hstart,hend;
1483 GetRangeInSortVector(*treeptr, lowcasepathBuffer, lowcasepath.GetLength(), &hstart, &hend, pos);
1484 CGitHeadFileList::iterator hit;
1485 hit = treeptr->begin() + hstart;
1486 CGitHeadFileList::iterator lastElement = treeptr->end();
1487 for(int i=hstart; i <= hend && hit != lastElement; i++)
1489 if( SearchInSortVector(*indexptr,(*hit).m_FileName.GetBuffer(),-1) < 0)
1491 (*hit).m_FileName.ReleaseBuffer();
1492 *status = max(git_wc_status_modified, *status); // deleted file found
1493 break;
1495 (*hit).m_FileName.ReleaseBuffer();
1496 hit++;
1501 }/* End lock*/
1503 lowcasepath.ReleaseBuffer();
1504 // If define callback, it need update each file status.
1505 // If not define callback, status == git_wc_status_conflicted, needn't check each file status
1506 // because git_wc_status_conflicted is highest.s
1507 if(callback || (*status != git_wc_status_conflicted))
1509 //Check File Time;
1510 //if(IsRecursive)
1512 CString sub, currentPath;
1513 it = indexptr->begin()+start;
1514 for(int i=start;i<=end;i++,it++)
1516 if( !IsRecursive )
1518 //skip child directory
1519 int pos = (*it).m_FileName.Find(_T('/'), path.GetLength());
1521 if( pos > 0)
1523 currentPath = (*it).m_FileName.Left(pos);
1524 if( callback && (sub != currentPath) )
1526 sub = currentPath;
1527 ATLTRACE(_T("index subdir %s\n"),sub);
1528 if(callback) callback(gitdir + _T("\\")+sub,
1529 git_wc_status_normal,true, pData);
1531 continue;
1535 git_wc_status_kind filestatus = git_wc_status_none;
1537 GetFileStatus(gitdir,(*it).m_FileName, &filestatus,IsFul, IsRecursive,IsIgnore, callback,pData);
1539 if (filestatus > git_wc_status_normal && filestatus != git_wc_status_conflicted)
1540 *status = git_wc_status_modified; // folders can only be modified or conflicted
1546 if(callback) callback(gitdir+_T("/")+subpath,*status,true, pData);
1549 }catch(...)
1551 if(status)
1552 *status = git_wc_status_none;
1553 return -1;
1556 return 0;
1559 bool GitStatus::IsExistIndexLockFile(const CString &gitdir)
1561 CString sDirName= gitdir;
1563 for (;;)
1565 if(PathFileExists(sDirName + _T("\\.git")))
1567 if(PathFileExists(g_AdminDirMap.GetAdminDir(gitdir) + _T("index.lock")))
1568 return true;
1569 else
1570 return false;
1573 int x = sDirName.ReverseFind(_T('\\'));
1574 if (x < 2)
1575 return false;
1577 sDirName = sDirName.Left(x);
1580 return false;