Example #1
0
int CGitIndexFileMap::IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir,bool *isVersion, bool isLoadUpdateIndex)
{
	try
	{
		if (path.IsEmpty())
		{
			*isVersion = true;
			return 0;
		}

		CString subpath = path;
		subpath.Replace(_T('\\'), _T('/'));
		if(isDir)
			subpath += _T('/');

		subpath.MakeLower();

		CheckAndUpdate(gitdir, isLoadUpdateIndex);

		SHARED_INDEX_PTR pIndex = this->SafeGet(gitdir);

		if(pIndex.get())
		{
			if(isDir)
				*isVersion = (SearchInSortVector(*pIndex, subpath.GetBuffer(), subpath.GetLength()) >= 0);
			else
				*isVersion = (SearchInSortVector(*pIndex, subpath.GetBuffer(), -1) >= 0);
		}

	}catch(...)
	{
		return -1;
	}
	return 0;
}
Example #2
0
int CGitHeadFileMap::IsUnderVersionControl(const CString &gitdir, const CString &path, bool isDir, bool *isVersion)
{
    try
    {
        if (path.IsEmpty())
        {
            *isVersion = true;
            return 0;
        }

        CString subpath = path;
        subpath.Replace(_T('\\'), _T('/'));
        if(isDir)
            subpath += _T('/');

        subpath.MakeLower();

        CheckHeadAndUpdate(gitdir);

        SHARED_TREE_PTR treeptr = SafeGet(gitdir);

        // Init Repository
        if (treeptr->HeadFileIsEmpty())
        {
            *isVersion = false;
            return 0;
        }
        else if (treeptr->empty())
        {
            *isVersion = false;
            return 1;
        }

        if(isDir)
            *isVersion = (SearchInSortVector(*treeptr, subpath, subpath.GetLength()) >= 0);
        else
            *isVersion = (SearchInSortVector(*treeptr, subpath, -1) >= 0);
    }
    catch(...)
    {
        return -1;
    }

    return 0;
}
Example #3
0
int CGitIndexList::GetFileStatus(const CString &gitdir,const CString &pathorg,git_wc_status_kind *status,__int64 time,FIll_STATUS_CALLBACK callback,void *pData, CGitHash *pHash)
{
	if(status)
	{
		CString path = pathorg;
		path.MakeLower();

		int start = SearchInSortVector(*this, ((CString&)path).GetBuffer(), -1);
		((CString&)path).ReleaseBuffer();

		if (start < 0)
		{
			*status = git_wc_status_unversioned;
			if (pHash)
				pHash->Empty();

		}
		else
		{
 			int index = start;
			if (index <0)
				return -1;
			if (index >= size() )
				return -1;

			if (time == 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(pHash)
				*pHash = at(index).m_IndexHash;
		}

	}

	if(callback && status)
			callback(gitdir + _T("\\") + pathorg, *status, false, pData);
	return 0;
}
Example #4
0
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)
{
	try
	{
		CString path =subpath;

		path.Replace(_T('\\'),_T('/'));
		if(!path.IsEmpty())
			if(path[path.GetLength()-1] !=  _T('/'))
				path += _T('/'); //Add trail / to show it is directory, not file name.

		CString lowcasepath = path;
		lowcasepath.MakeLower();

		if(status)
		{
			g_IndexFileMap.CheckAndUpdate(gitdir, true);

			SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);

			if (indexptr == NULL)
			{
				*status = git_wc_status_unversioned;
				return 0;
			}

			int pos = SearchInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength());

			//Not In Version Contorl
			if(pos<0)
			{
				if(!IsIgnore)
				{
					*status = git_wc_status_unversioned;
					if(callback)
						callback(gitdir + _T("/") + path, *status, false, pData, false, false);
					return 0;
				}
				//Check ignore always.
				{
					if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, true))
						g_IgnoreList.LoadAllIgnoreFile(gitdir, path, true);

					if (g_IgnoreList.IsIgnore(path, gitdir, true))
						*status = git_wc_status_ignored;
					else
						*status = git_wc_status_unversioned;

					g_HeadFileMap.CheckHeadAndUpdate(gitdir, false);

					SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
					//Check init repository
					if (treeptr->HeadIsEmpty() && path.IsEmpty())
						*status = git_wc_status_normal;
				}

			}
			else  // In version control
			{
				*status = git_wc_status_normal;

				int start=0;
				int end=0;
				if(path.IsEmpty())
				{
					start=0;
					end = (int)indexptr->size() - 1;
				}
				GetRangeInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos);
				CGitIndexList::iterator it;

				it = indexptr->begin()+start;

				// Check Conflict;
				for (int i = start; i <= end; ++i)
				{
					if (((*it).m_Flags & GIT_IDXENTRY_STAGEMASK) !=0)
					{
						*status = git_wc_status_conflicted;
						if(callback)
						{
							int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
							if(dirpos<0 || IsRecursive)
								callback(gitdir + _T("\\") + it->m_FileName, git_wc_status_conflicted, false, pData, false, false);
						}
						else
							break;
					}
					++it;
				}

				if( IsFul && (*status != git_wc_status_conflicted))
				{
					*status = git_wc_status_normal;

					g_HeadFileMap.CheckHeadAndUpdate(gitdir);

					//Check Add
					it = indexptr->begin()+start;


					{
						//Check if new init repository
						SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);

						if (!treeptr->empty() || treeptr->HeadIsEmpty())
						{
							for (int i = start; i<= end; ++i)
							{
								pos = SearchInSortVector(*treeptr, (*it).m_FileName, -1);

								if(pos < 0)
								{
									*status = max(git_wc_status_added, *status); // added file found
									if(callback)
									{
										int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
										if(dirpos<0 || IsRecursive)
											callback(gitdir + _T("\\") + it->m_FileName, git_wc_status_added, false, pData, false, false);

									}
									else
										break;
								}

								if( pos>=0 && treeptr->at(pos).m_Hash != (*it).m_IndexHash)
								{
									*status = max(git_wc_status_modified, *status); // modified file found
									if(callback)
									{
										int dirpos = (*it).m_FileName.Find(_T('/'), path.GetLength());
										if(dirpos<0 || IsRecursive)
											callback(gitdir + _T("\\") + it->m_FileName, git_wc_status_modified, false, pData, ((*it).m_Flags & GIT_IDXENTRY_VALID) && !((*it).m_Flags & GIT_IDXENTRY_SKIP_WORKTREE), ((*it).m_Flags & GIT_IDXENTRY_SKIP_WORKTREE) != 0);

									}
									else
										break;
								}

								++it;
							}

							//Check Delete
							if( *status == git_wc_status_normal )
							{
								pos = SearchInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength());
								if(pos <0)
								{
									*status = max(git_wc_status_added, *status); // added file found

								}
								else
								{
									int hstart,hend;
									GetRangeInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength(), &hstart, &hend, pos);
									CGitHeadFileList::iterator hit;
									hit = treeptr->begin() + hstart;
									CGitHeadFileList::iterator lastElement = treeptr->end();
									for (int i = hstart; i <= hend && hit != lastElement; ++i)
									{
										if (SearchInSortVector(*indexptr, (*hit).m_FileName, -1) < 0)
										{
											*status = max(git_wc_status_deleted, *status); // deleted file found
											break;
										}
										++hit;
									}
								}
							}
						}
					}/* End lock*/
				}
				// If define callback, it need update each file status.
				// If not define callback, status == git_wc_status_conflicted, needn't check each file status
				// because git_wc_status_conflicted is highest.s
				if(callback || (*status != git_wc_status_conflicted))
				{
					//Check File Time;
					//if(IsRecursive)
					{
						CString sub, currentPath;
						it = indexptr->begin()+start;
						for (int i = start; i <= end; ++i, ++it)
						{
							if( !IsRecursive )
							{
								//skip child directory
								int pos = (*it).m_FileName.Find(_T('/'), path.GetLength());

								if( pos > 0)
								{
									currentPath = (*it).m_FileName.Left(pos);
									if( callback && (sub != currentPath) )
									{
										sub = currentPath;
										CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": index subdir %s\n"),sub);
										if(callback) callback(gitdir + _T("\\") + sub,
											git_wc_status_normal, true, pData, false, false);
									}
									continue;
								}
							}

							git_wc_status_kind filestatus = git_wc_status_none;
							bool assumeValid = false;
							bool skipWorktree = false;
							GetFileStatus(gitdir, (*it).m_FileName, &filestatus, IsFul, IsRecursive, IsIgnore, callback, pData, &assumeValid, &skipWorktree);
						}
					}
				}
			}

			if(callback) callback(gitdir + _T("/") + subpath, *status, true, pData, false, false);
		}

	}catch(...)
	{
		if(status)
			*status = git_wc_status_none;
		return -1;
	}

	return 0;
}
Example #5
0
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)
{
	try
	{
		CString path =subpath;

		path.Replace(_T('\\'),_T('/'));
		if(!path.IsEmpty())
			if(path[path.GetLength()-1] !=  _T('/'))
				path += _T('/'); //Add trail / to show it is directory, not file name.

		CString lowcasepath = path;
		lowcasepath.MakeLower();

		std::vector<CGitFileName> filelist;
		GetFileList(gitdir, subpath, filelist);

		if(status)
		{
			g_IndexFileMap.CheckAndUpdate(gitdir,true);

			g_HeadFileMap.CheckHeadAndUpdate(gitdir);

			SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);
			SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);

			std::vector<CGitFileName>::iterator it;

			// new git working tree has no index file
			if (indexptr.get() == NULL)
			{
				for (it = filelist.begin(); it < filelist.end(); ++it)
				{
					CString casepath = path + it->m_CaseFileName;

					bool bIsDir = false;
					if (it->m_FileName.GetLength() > 0 && it->m_FileName[it->m_FileName.GetLength() - 1] == _T('/'))
						bIsDir = true;

					if (IsIgnore)
					{
						if (g_IgnoreList.CheckIgnoreChanged(gitdir, casepath, bIsDir))
							g_IgnoreList.LoadAllIgnoreFile(gitdir, casepath, bIsDir);

						if (g_IgnoreList.IsIgnore(casepath, gitdir, bIsDir))
							*status = git_wc_status_ignored;
						else if (bIsDir)
							continue;
						else
							*status = git_wc_status_unversioned;
					}
					else if (bIsDir)
						continue;
					else
						*status = git_wc_status_unversioned;

					if(callback)
						callback(gitdir + _T("/") + casepath, *status, bIsDir, pData, false, false);
				}
				return 0;
			}

			CString onepath;
			CString casepath;
			for (it = filelist.begin(); it < filelist.end(); ++it)
			{
				casepath=onepath = path;
				onepath.MakeLower();
				onepath += it->m_FileName;
				casepath += it->m_CaseFileName;

				bool bIsDir = false;
				if (!onepath.IsEmpty() && onepath[onepath.GetLength() - 1] == _T('/'))
					bIsDir = true;

				int matchLength = -1;
				if (bIsDir)
					matchLength = onepath.GetLength();
				int pos = SearchInSortVector(*indexptr, onepath, matchLength);
				int posintree = SearchInSortVector(*treeptr, onepath, matchLength);

				if(pos <0 && posintree<0)
				{
					if (onepath.IsEmpty())
						continue;

					if(!IsIgnore)
					{
						*status = git_wc_status_unversioned;
						if(callback)
							callback(gitdir + _T("/") + casepath, *status, bIsDir, pData, false, false);
						continue;
					}

					if (g_IgnoreList.CheckIgnoreChanged(gitdir, casepath, bIsDir))
						g_IgnoreList.LoadAllIgnoreFile(gitdir, casepath, bIsDir);

					if (g_IgnoreList.IsIgnore(casepath, gitdir, bIsDir))
						*status = git_wc_status_ignored;
					else
						*status = git_wc_status_unversioned;

					if(callback)
						callback(gitdir + _T("/") + casepath, *status, bIsDir, pData, false, false);

				}
				else if(pos <0 && posintree>=0) /* check if file delete in index */
				{
					*status = git_wc_status_deleted;
					if(callback)
						callback(gitdir + _T("/") + casepath, *status, bIsDir, pData, false, false);

				}
				else if(pos >=0 && posintree <0) /* Check if file added */
				{
					*status = git_wc_status_added;
					if(callback)
						callback(gitdir + _T("/") + casepath, *status, bIsDir, pData, false, false);
				}
				else
				{
					if (onepath.IsEmpty())
						continue;

					if (bIsDir)
					{
						*status = git_wc_status_normal;
						if(callback)
							callback(gitdir + _T("/") + casepath, *status, bIsDir, pData, false, false);
					}
					else
					{
						bool assumeValid = false;
						bool skipWorktree = false;
						git_wc_status_kind filestatus;
						GetFileStatus(gitdir, casepath, &filestatus, IsFul, IsRecursive, IsIgnore, callback, pData, &assumeValid, &skipWorktree);
					}
				}

			}/*End of For*/

			/* Check deleted file in system */
			int start=0, end=0;
			int pos = SearchInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength()); // match path prefix, (sub)folders end with slash
			std::map<CString, bool> skipWorktreeMap;

			if (GetRangeInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos) == 0)
			{
				CGitIndexList::iterator it;
				CString oldstring;

				for (it = indexptr->begin() + start; it <= indexptr->begin() + end; ++it)
				{
					int commonPrefixLength = lowcasepath.GetLength();
					int index = (*it).m_FileName.Find(_T('/'), commonPrefixLength);
					if(index<0)
						index = (*it).m_FileName.GetLength();
					else
						++index; // include slash at the end for subfolders, so that we do not match files by mistake

					CString filename = (*it).m_FileName.Mid(commonPrefixLength, index - commonPrefixLength);
					if(oldstring != filename)
					{
						oldstring = filename;
						if (SearchInSortVector(filelist, filename, filename.GetLength()) < 0)
						{
							bool skipWorktree = false;
							*status = git_wc_status_deleted;
							if (((*it).m_Flags & GIT_IDXENTRY_SKIP_WORKTREE) != 0)
							{
								skipWorktreeMap[filename] = true;
								skipWorktree = true;
								*status = git_wc_status_normal;
							}
							if(callback)
								callback(gitdir + _T("/") + (*it).m_FileName, *status, false, pData, false, skipWorktree);
						}
					}
				}
			}

			start = end =0;
			pos = SearchInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength()); // match path prefix, (sub)folders end with slash
			if (GetRangeInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos) == 0)
			{
				CGitHeadFileList::iterator it;
				CString oldstring;

				for (it = treeptr->begin() + start; it <= treeptr->begin() + end; ++it)
				{
					int commonPrefixLength = lowcasepath.GetLength();
					int index = (*it).m_FileName.Find(_T('/'), commonPrefixLength);
					if(index<0)
						index = (*it).m_FileName.GetLength();
					else
						++index; // include slash at the end for subfolders, so that we do not match files by mistake

					CString filename = (*it).m_FileName.Mid(commonPrefixLength, index - commonPrefixLength);
					if (oldstring != filename && skipWorktreeMap[filename] != true)
					{
						oldstring = filename;
						if (SearchInSortVector(filelist, filename, filename.GetLength()) < 0)
						{
							*status = git_wc_status_deleted;
							if(callback)
								callback(gitdir + _T("/") + (*it).m_FileName, *status, false, pData, false, false);
						}
					}
				}
			}

		}/*End of if status*/
	}catch(...)
	{
		return -1;
	}
	return 0;

}
Example #6
0
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, bool * assumeValid, bool * skipWorktree)
{
	try
	{
		CString path = pathParam;

		path.Replace(_T('\\'),_T('/'));

		CString lowcasepath =path;
		lowcasepath.MakeLower();

		if(status)
		{
			git_wc_status_kind st = git_wc_status_none;
			CGitHash hash;

			g_IndexFileMap.GetFileStatus(gitdir, path, &st, IsFull, false, callback, pData, &hash, true, assumeValid, skipWorktree);

			if( st == git_wc_status_conflicted )
			{
				*status =st;
				if (callback && assumeValid && skipWorktree)
					callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree);
				return 0;
			}

			if( st == git_wc_status_unversioned )
			{
				if(!IsIgnore)
				{
					*status = git_wc_status_unversioned;
					if (callback && assumeValid && skipWorktree)
						callback(gitdir + _T("/") + path, *status, false, pData, *assumeValid, *skipWorktree);
					return 0;
				}

				if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, false))
				{
					g_IgnoreList.LoadAllIgnoreFile(gitdir, path, false);
				}
				if (g_IgnoreList.IsIgnore(path, gitdir, false))
				{
					st = git_wc_status_ignored;
				}
				*status = st;
				if (callback && assumeValid && skipWorktree)
					callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree);

				return 0;
			}

			if ((st == git_wc_status_normal || st == git_wc_status_modified) && IsFull)
			{
				{
					g_HeadFileMap.CheckHeadAndUpdate(gitdir);

					SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);

					// Check Head Tree Hash;
					{
						//add item

						int start = SearchInSortVector(*treeptr, lowcasepath, -1);

						if(start<0)
						{
							*status =st=git_wc_status_added;
							CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": File miss in head tree %s"), path);
							if (callback && assumeValid && skipWorktree)
								callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree);
							return 0;
						}

						//staged and not commit
						if( treeptr->at(start).m_Hash != hash )
						{
							*status =st=git_wc_status_modified;
							if (callback && assumeValid && skipWorktree)
								callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree);
							return 0;
						}
					}
				}
			}
			*status =st;
			if (callback && assumeValid && skipWorktree)
				callback(gitdir + _T("/") + path, st, false, pData, *assumeValid, *skipWorktree);
			return 0;
		}
	}
	catch(...)
	{
		if(status)
			*status = git_wc_status_none;
		return -1;
	}

	return 0;

}
int CGitIndexList::GetFileStatus(const CString &gitdir, const CString &pathorg, git_wc_status_kind *status, __int64 time, __int64 filesize, FILL_STATUS_CALLBACK callback, void *pData, CGitHash *pHash, bool * assumeValid, bool * skipWorktree)
{
	if (!status)
		return 0;

	CString path = pathorg;
	path.MakeLower();

	int index = SearchInSortVector(*this, path, -1);

	if (index < 0)
	{
		*status = git_wc_status_unversioned;
		if (pHash)
			pHash->Empty();

		if (callback && assumeValid && skipWorktree)
			callback(CombinePath(gitdir, pathorg), *status, false, pData, *assumeValid, *skipWorktree);

		return 0;
	}

	// skip-worktree has higher priority than assume-valid
	if (at(index).m_FlagsExtended & GIT_IDXENTRY_SKIP_WORKTREE)
	{
		*status = git_wc_status_normal;
		if (skipWorktree)
			*skipWorktree = true;
	}
	else if (at(index).m_Flags & GIT_IDXENTRY_VALID)
	{
		*status = git_wc_status_normal;
		if (assumeValid)
			*assumeValid = true;
	}
	else if (filesize != at(index).m_Size)
		*status = git_wc_status_modified;
	else if (time == at(index).m_ModifyTime)
		*status = git_wc_status_normal;
	else if (repository && filesize < m_iMaxCheckSize)
	{
		git_oid actual;
		CStringA fileA = CUnicodeUtils::GetMulti(pathorg, CP_UTF8);
		m_critRepoSec.Lock(); // prevent concurrent access to repository instance and especially filter-lists
		if (!git_repository_hashfile(&actual, repository, fileA, GIT_OBJ_BLOB, nullptr) && !git_oid_cmp(&actual, (const git_oid*)at(index).m_IndexHash.m_hash))
		{
			at(index).m_ModifyTime = time;
			*status = git_wc_status_normal;
		}
		else
			*status = git_wc_status_modified;
		m_critRepoSec.Unlock();
	}
	else
		*status = git_wc_status_modified;

	if (at(index).m_Flags & GIT_IDXENTRY_STAGEMASK)
		*status = git_wc_status_conflicted;
	else if (at(index).m_FlagsExtended & GIT_IDXENTRY_INTENT_TO_ADD)
		*status = git_wc_status_added;

	if (pHash)
		*pHash = at(index).m_IndexHash;

	if (callback && assumeValid && skipWorktree)
		callback(CombinePath(gitdir, pathorg), *status, false, pData, *assumeValid, *skipWorktree);

	return 0;
}
Example #8
0
int GitStatus::GetDirStatus(const CString& gitdir, const CString& subpath, git_wc_status_kind* status, BOOL IsFul, BOOL IsRecursive, BOOL IsIgnore)
{
	if (!status)
		return 0;

	CString path = subpath;

	path.Replace(_T('\\'), _T('/'));
	if (!path.IsEmpty() && path[path.GetLength() - 1] != _T('/'))
		path += _T('/'); //Add trail / to show it is directory, not file name.

	g_IndexFileMap.CheckAndUpdate(gitdir, true);

	SHARED_INDEX_PTR indexptr = g_IndexFileMap.SafeGet(gitdir);

	if (!indexptr)
	{
		*status = git_wc_status_unversioned;
		return 0;
	}

	CString lowcasepath = path;
	lowcasepath.MakeLower();

	int pos = SearchInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength());

	// Not In Version Contorl
	if (pos < 0)
	{
		if (!IsIgnore)
		{
			*status = git_wc_status_unversioned;
			return 0;
		}

		// Check ignore always.
		if (g_IgnoreList.CheckIgnoreChanged(gitdir, path, true))
			g_IgnoreList.LoadAllIgnoreFile(gitdir, path, true);

		if (g_IgnoreList.IsIgnore(path, gitdir, true))
			*status = git_wc_status_ignored;
		else
			*status = git_wc_status_unversioned;

		g_HeadFileMap.CheckHeadAndUpdate(gitdir);

		SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);
		// Check init repository
		if (treeptr->HeadIsEmpty() && path.IsEmpty())
			*status = git_wc_status_normal;
		// check if only one file in repository is deleted in index
		else if (path.IsEmpty() && !treeptr->empty())
			*status = git_wc_status_deleted;

		return 0;
	}

	// In version control
	*status = git_wc_status_normal;

	int start = 0;
	int end = 0;

	GetRangeInSortVector(*indexptr, lowcasepath, lowcasepath.GetLength(), &start, &end, pos);

	// Check Conflict;
	for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; indexptr->m_bHasConflicts && it <= itlast; ++it)
	{
		if (((*it).m_Flags & GIT_IDXENTRY_STAGEMASK) != 0)
		{
			*status = git_wc_status_conflicted;
			break;
		}
	}

	if (IsFul && (*status != git_wc_status_conflicted))
	{
		*status = git_wc_status_normal;

		g_HeadFileMap.CheckHeadAndUpdate(gitdir);

		// Check Add
		{
			// Check if new init repository
			SHARED_TREE_PTR treeptr = g_HeadFileMap.SafeGet(gitdir);

			if (!treeptr->empty() || treeptr->HeadIsEmpty())
			{
				for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; it <= itlast; ++it)
				{
					pos = SearchInSortVector(*treeptr, (*it).m_FileName, -1);

					if (pos < 0)
					{
						*status = max(git_wc_status_added, *status); // added file found
						break;
					}

					if (pos >= 0 && treeptr->at(pos).m_Hash != (*it).m_IndexHash)
					{
						*status = max(git_wc_status_modified, *status); // modified file found
						break;
					}
				}

				// Check Delete
				if (*status == git_wc_status_normal)
				{
					pos = SearchInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength());
					if (pos < 0)
						*status = max(git_wc_status_added, *status); // added file found
					else
					{
						int hstart, hend;
						GetRangeInSortVector(*treeptr, lowcasepath, lowcasepath.GetLength(), &hstart, &hend, pos);
						for (auto hit = treeptr->cbegin() + hstart, lastElement = treeptr->cbegin() + hend; hit <= lastElement; ++hit)
						{
							if (SearchInSortVector(*indexptr, (*hit).m_FileName, -1) < 0)
							{
								*status = max(git_wc_status_deleted, *status); // deleted file found
								break;
							}
						}
					}
				}
			}
		} /* End lock*/
	}

	// When status == git_wc_status_conflicted, needn't check each file status
	// because git_wc_status_conflicted is highest.s
	if (*status == git_wc_status_conflicted)
		return 0;

	for (auto it = indexptr->cbegin() + start, itlast = indexptr->cbegin() + end; it <= itlast; ++it)
	{
		//skip child directory
		if (!IsRecursive && (*it).m_FileName.Find(_T('/'), path.GetLength()) > 0)
			continue;

		git_wc_status_kind filestatus = git_wc_status_none;
		bool assumeValid = false;
		bool skipWorktree = false;
		GetFileStatus(gitdir, (*it).m_FileName, &filestatus, IsFul, IsRecursive, IsIgnore, nullptr, nullptr, &assumeValid, &skipWorktree);
		switch (filestatus)
		{
		case git_wc_status_added:
		case git_wc_status_modified:
		case git_wc_status_deleted:
		case git_wc_status_conflicted:
			*status = GetMoreImportant(filestatus, *status);
		}
	}

	return 0;
}