Exemplo n.º 1
0
int CTGitPath::GetAdminDirMask() const
{
	int status = 0;
	CString topdir;
	if (!GitAdminDir::HasAdminDir(GetWinPathString(), &topdir))
	{
		return status;
	}

	// ITEMIS_INGIT will be revoked if necessary in TortoiseShell/ContextMenu.cpp
	status |= ITEMIS_INGIT|ITEMIS_INVERSIONEDFOLDER;

	if (IsDirectory())
	{
		status |= ITEMIS_FOLDERINGIT;
		if (IsWCRoot())
		{
			status |= ITEMIS_WCROOT;

			CString topProjectDir;
			if (GitAdminDir::HasAdminDir(GetWinPathString(), false, &topProjectDir))
			{
				if (PathFileExists(topProjectDir + _T("\\.gitmodules")))
				{
					CAutoConfig config(true);
					git_config_add_file_ondisk(config, CGit::GetGitPathStringA(topProjectDir + _T("\\.gitmodules")), GIT_CONFIG_LEVEL_APP, FALSE);
					CString relativePath = GetWinPathString().Mid(topProjectDir.GetLength());
					relativePath.Replace(_T("\\"), _T("/"));
					relativePath.Trim(_T("/"));
					CStringA submodulePath = CUnicodeUtils::GetUTF8(relativePath);
					if (git_config_foreach_match(config, "submodule\\..*\\.path", 
						[](const git_config_entry *entry, void *data) { return entry->value == *(CStringA *)data ? GIT_EUSER : 0; }, &submodulePath) == GIT_EUSER)
						status |= ITEMIS_SUBMODULE;
				}
			}
		}
	}

	CString dotGitPath;
	GitAdminDir::GetAdminDirPath(topdir, dotGitPath);

	if (PathFileExists(dotGitPath + _T("BISECT_START")))
		status |= ITEMIS_BISECT;

	if (PathFileExists(dotGitPath + _T("MERGE_HEAD")))
		status |= ITEMIS_MERGEACTIVE;

	if (PathFileExists(dotGitPath + _T("refs\\stash")))
		status |= ITEMIS_STASH;

	if (PathFileExists(dotGitPath + _T("svn")))
		status |= ITEMIS_GITSVN;

	if (PathFileExists(topdir + _T("\\.gitmodules")))
		status |= ITEMIS_SUBMODULECONTAINER;

	return status;
}
Exemplo n.º 2
0
CTGitPath CTGitPath::GetSubPath(const CTGitPath &root)
{
	CTGitPath path;

	if(GetWinPathString().Left(root.GetWinPathString().GetLength()) == root.GetWinPathString())
	{
		CString str=GetWinPathString();
		path.SetFromWin(str.Right(str.GetLength()-root.GetWinPathString().GetLength()-1));
	}
	return path;
}
Exemplo n.º 3
0
CTGitPath CTGitPathList::GetCommonRoot() const
{
	if (IsEmpty())
		return CTGitPath();

	if (GetCount() == 1)
		return m_paths[0];

	// first entry is common root for itself
	// (add trailing '\\' to detect partial matches of the last path element)
	CString root = m_paths[0].GetWinPathString() + _T('\\');
	int rootLength = root.GetLength();

	// determine common path string prefix
	for (auto it = m_paths.cbegin() + 1; it != m_paths.cend(); ++it)
	{
		CString path = it->GetWinPathString() + _T('\\');

		int newLength = CStringUtils::GetMatchingLength(root, path);
		if (newLength != rootLength)
		{
			root.Delete(newLength, rootLength);
			rootLength = newLength;
		}
	}

	// remove the last (partial) path element
	if (rootLength > 0)
		root.Delete(root.ReverseFind(_T('\\')), rootLength);

	// done
	return CTGitPath(root);
}
Exemplo n.º 4
0
const CString& CTGitPath::GetUIPathString() const
{
	if (m_sUIPath.IsEmpty())
	{
		m_sUIPath = GetWinPathString();
	}
	return m_sUIPath;
}
Exemplo n.º 5
0
bool CTGitPath::HasRebaseApply() const
{
	CString topdir;
	if (!GitAdminDir::HasAdminDir(GetWinPathString(), &topdir))
	{
		return false;
	}

	CString dotGitPath;
	GitAdminDir::GetAdminDirPath(topdir, dotGitPath);

	return !!PathFileExists(dotGitPath + _T("rebase-apply"));
}
Exemplo n.º 6
0
bool CTGitPath::IsMergeActive() const
{
	CString topdir;
	if (!GitAdminDir::HasAdminDir(GetWinPathString(), &topdir))
	{
		return false;
	}

	CString dotGitPath;
	GitAdminDir::GetAdminDirPath(topdir, dotGitPath);

	return !!PathFileExists(dotGitPath + _T("MERGE_HEAD"));
}
Exemplo n.º 7
0
bool CTGitPath::IsBisectActive() const
{
	CString topdir;
	if (!GitAdminDir::HasAdminDir(GetWinPathString(), &topdir))
	{
		return false;
	}

	CString dotGitPath;
	GitAdminDir::GetAdminDirPath(topdir, dotGitPath);

	return !!PathFileExists(dotGitPath + _T("BISECT_START"));
}
Exemplo n.º 8
0
bool CTGitPath::HasGitSVNDir() const
{
	CString topdir;
	if (!GitAdminDir::HasAdminDir(GetWinPathString(), &topdir))
	{
		return false;
	}

	CString dotGitPath;
	GitAdminDir::GetAdminDirPath(topdir, dotGitPath);

	return !!PathFileExists(dotGitPath + _T("svn"));
}
Exemplo n.º 9
0
const CString& CTSVNPath::GetUIPathString() const
{
    if (m_sUIPath.IsEmpty())
    {
#if defined(_MFC_VER)
        //BUGBUG HORRIBLE!!! - CPathUtils::IsEscaped doesn't need to be MFC-only
        if (IsUrl())
        {
            m_sUIPath = CPathUtils::PathUnescape(GetSVNPathString());
            m_sUIPath.Replace(L"file:////", L"file://");

        }
        else
#endif
        {
            m_sUIPath = GetWinPathString();
        }
    }
    return m_sUIPath;
}
Exemplo n.º 10
0
bool CTGitPath::HasStashDir() const
{
	CString topdir;
	if(!GitAdminDir::HasAdminDir(GetWinPathString(),&topdir))
	{
		return false;
	}

	CString dotGitPath;
	GitAdminDir::GetAdminDirPath(topdir, dotGitPath);

	if (!!PathFileExists(dotGitPath + _T("refs\\stash")))
		return true;

	CAutoFile hfile = CreateFile(dotGitPath + _T("packed-refs"), GENERIC_READ, 
		FILE_SHARE_READ | FILE_SHARE_DELETE | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
	if (!hfile)
		return false;

	DWORD filesize = ::GetFileSize(hfile, nullptr);
	if (filesize == 0)
		return false;

	DWORD size = 0;
	auto buff = std::make_unique<char[]>(filesize + 1);
	ReadFile(hfile, buff.get(), filesize, &size, nullptr);
	buff.get()[filesize] = '\0';

	if (size != filesize)
		return false;

	for (DWORD i = 0; i < filesize;)
	{
		if (buff[i] == '#' || buff[i] == '^')
		{
			while (buff[i] != '\n')
			{
				++i;
				if (i == filesize)
					break;
			}
			++i;
		}

		if (i >= filesize)
			break;

		while (buff[i] != ' ')
		{
			++i;
			if (i == filesize)
				break;
		}

		++i;
		if (i >= filesize)
			break;

		if (i <= filesize - 10 && (buff[i + 10] == '\n' || buff[i + 10] == '\0') && !strncmp("refs/stash", buff.get() + i, 10))
			return true;
		while (buff[i] != '\n')
		{
			++i;
			if (i == filesize)
				break;
		}

		while (buff[i] == '\n')
		{
			++i;
			if (i == filesize)
				break;
		}
	}
	return false;
}
Exemplo n.º 11
0
//////////////////////////////////////////////////////////////////////////
// IDataObject
//////////////////////////////////////////////////////////////////////////
STDMETHODIMP GitDataObject::GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
{
	if (!pformatetcIn)
		return E_INVALIDARG;
	if (!pmedium)
		return E_POINTER;
	pmedium->hGlobal = nullptr;

	if ((pformatetcIn->tymed & TYMED_ISTREAM) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILECONTENTS))
	{
		// supports the IStream format.
		// The lindex param is the index of the file to return
		CString filepath;
		IStream* pIStream = nullptr;

		// Note: we don't get called for directories since those are simply created and don't
		// need to be fetched.

		// Note2: It would be really nice if we could get a stream from the subversion library
		// from where we could read the file contents. But the Subversion lib is not implemented
		// to *read* from a remote stream but so that the library *writes* to a stream we pass.
		// Since we can't get such a read stream, we have to fetch the file in whole first to
		// a temp location and then pass the shell an IStream for that temp file.

		if (m_revision.IsEmpty())
		{
			if ((pformatetcIn->lindex >= 0) && (pformatetcIn->lindex < (LONG)m_allPaths.size()))
				filepath = g_Git.CombinePath(m_allPaths[pformatetcIn->lindex]);
		}
		else
		{
			filepath = CTempFiles::Instance().GetTempFilePath(true).GetWinPathString();
			if ((pformatetcIn->lindex >= 0) && (pformatetcIn->lindex < (LONG)m_allPaths.size()))
			{
				if (g_Git.GetOneFile(m_revision.ToString(), m_allPaths[pformatetcIn->lindex], filepath))
				{
					DeleteFile(filepath);
					return STG_E_ACCESSDENIED;
				}
			}
		}

		HRESULT res = SHCreateStreamOnFileEx(filepath, STGM_READ, FILE_ATTRIBUTE_NORMAL, FALSE, nullptr, &pIStream);
		if (res == S_OK)
		{
			// http://blogs.msdn.com/b/oldnewthing/archive/2014/09/18/10558763.aspx
			LARGE_INTEGER liZero = { 0, 0 };
			pIStream->Seek(liZero, STREAM_SEEK_END, nullptr);

			pmedium->pstm = pIStream;
			pmedium->tymed = TYMED_ISTREAM;
			return S_OK;
		}
		return res;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILEDESCRIPTOR))
	{
		for (int i = 0; i < m_gitPaths.GetCount(); ++i)
		{
			if (m_gitPaths[i].m_Action & (CTGitPath::LOGACTIONS_MISSING | CTGitPath::LOGACTIONS_DELETED) || m_gitPaths[i].IsDirectory())
				continue;
			m_allPaths.push_back(m_gitPaths[i]);
		}

		size_t dataSize = sizeof(FILEGROUPDESCRIPTOR) + ((max(1, m_allPaths.size()) - 1) * sizeof(FILEDESCRIPTOR));
		HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, dataSize);

		FILEGROUPDESCRIPTOR* files = (FILEGROUPDESCRIPTOR*)GlobalLock(data);
		files->cItems = static_cast<UINT>(m_allPaths.size());
		int index = 0;
		for (auto it = m_allPaths.cbegin(); it != m_allPaths.cend(); ++it)
		{
			CString temp(m_iStripLength > 0 ? it->GetWinPathString().Mid(m_iStripLength + 1) : (m_iStripLength == 0 ? it->GetWinPathString() : it->GetUIFileOrDirectoryName()));
			if (temp.GetLength() < MAX_PATH)
				wcscpy_s(files->fgd[index].cFileName, (LPCTSTR)temp);
			else
			{
				files->cItems--;
				continue;
			}
			files->fgd[index].dwFlags = FD_ATTRIBUTES | FD_PROGRESSUI | FD_FILESIZE | FD_LINKUI;
			files->fgd[index].dwFileAttributes = FILE_ATTRIBUTE_NORMAL;

			// Always set the file size to 0 even if we 'know' the file size (infodata.size64).
			// Because for text files, the file size is too low due to the EOLs getting converted
			// to CRLF (from LF as stored in the repository). And a too low file size set here
			// prevents the shell from reading the full file later - it only reads the stream up
			// to the number of bytes specified here. Which means we would end up with a truncated
			// text file (binary files are still ok though).
			files->fgd[index].nFileSizeLow = 0;
			files->fgd[index].nFileSizeHigh = 0;

			++index;
		}

		GlobalUnlock(data);

		pmedium->hGlobal = data;
		pmedium->tymed = TYMED_HGLOBAL;
		return S_OK;
	}
	// handling CF_PREFERREDDROPEFFECT is necessary to tell the shell that it should *not* ask for the
	// CF_FILEDESCRIPTOR until the drop actually occurs. If we don't handle CF_PREFERREDDROPEFFECT, the shell
	// will ask for the file descriptor for every object (file/folder) the mouse pointer hovers over and is
	// a potential drop target.
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->cfFormat == CF_PREFERREDDROPEFFECT))
	{
		HGLOBAL data = GlobalAlloc(GMEM_MOVEABLE | GMEM_SHARE | GMEM_ZEROINIT, sizeof(DWORD));
		DWORD* effect = (DWORD*)GlobalLock(data);
		(*effect) = DROPEFFECT_COPY;
		GlobalUnlock(data);
		pmedium->hGlobal = data;
		pmedium->tymed = TYMED_HGLOBAL;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_TEXT))
	{
		// caller wants text
		// create the string from the path list
		CString text;
		if (!m_gitPaths.IsEmpty())
		{
			// create a single string where the URLs are separated by newlines
			for (int i = 0; i < m_gitPaths.GetCount(); ++i)
			{
				text += m_gitPaths[i].GetWinPathString();
				text += L"\r\n";
			}
		}
		CStringA texta = CUnicodeUtils::GetUTF8(text);
		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GHND, (texta.GetLength() + 1) * sizeof(char));
		if (pmedium->hGlobal)
		{
			char* pMem = (char*)GlobalLock(pmedium->hGlobal);
			strcpy_s(pMem, texta.GetLength() + 1, (LPCSTR)texta);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = nullptr;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && ((pformatetcIn->cfFormat == CF_UNICODETEXT) || (pformatetcIn->cfFormat == CF_INETURL) || (pformatetcIn->cfFormat == CF_SHELLURL)))
	{
		// caller wants Unicode text
		// create the string from the path list
		CString text;
		if (!m_gitPaths.IsEmpty())
		{
			// create a single string where the URLs are separated by newlines
			for (int i = 0; i < m_gitPaths.GetCount(); ++i)
			{
				if (pformatetcIn->cfFormat == CF_UNICODETEXT)
					text += m_gitPaths[i].GetWinPathString();
				else
					text += g_Git.CombinePath(m_gitPaths[i]);
				text += L"\r\n";
			}
		}
		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GHND, (text.GetLength() + 1) * sizeof(TCHAR));
		if (pmedium->hGlobal)
		{
			TCHAR* pMem = (TCHAR*)GlobalLock(pmedium->hGlobal);
			wcscpy_s(pMem, text.GetLength() + 1, (LPCTSTR)text);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = nullptr;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_HDROP))
	{
		int nLength = 0;

		for (int i = 0; i < m_gitPaths.GetCount(); ++i)
		{
			if (m_gitPaths[i].m_Action & (CTGitPath::LOGACTIONS_MISSING | CTGitPath::LOGACTIONS_DELETED) || m_gitPaths[i].IsDirectory())
				continue;

			nLength += g_Git.CombinePath(m_gitPaths[i]).GetLength();
			nLength += 1; // '\0' separator
		}

		int nBufferSize = sizeof(DROPFILES) + (nLength + 1) * sizeof(TCHAR);
		auto pBuffer = std::make_unique<char[]>(nBufferSize);
		SecureZeroMemory(pBuffer.get(), nBufferSize);

		DROPFILES* df = (DROPFILES*)pBuffer.get();
		df->pFiles = sizeof(DROPFILES);
		df->fWide = 1;

		TCHAR* pFilenames = (TCHAR*)(pBuffer.get() + sizeof(DROPFILES));
		TCHAR* pCurrentFilename = pFilenames;

		for (int i = 0; i < m_gitPaths.GetCount(); ++i)
		{
			if (m_gitPaths[i].m_Action & (CTGitPath::LOGACTIONS_MISSING | CTGitPath::LOGACTIONS_DELETED) || m_gitPaths[i].IsDirectory())
				continue;
			CString str = g_Git.CombinePath(m_gitPaths[i]);
			wcscpy_s(pCurrentFilename, str.GetLength() + 1, (LPCWSTR)str);
			pCurrentFilename += str.GetLength();
			*pCurrentFilename = '\0'; // separator between file names
			pCurrentFilename++;
		}
		*pCurrentFilename = '\0'; // terminate array

		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, nBufferSize);
		if (pmedium->hGlobal)
		{
			LPVOID pMem = ::GlobalLock(pmedium->hGlobal);
			if (pMem)
				memcpy(pMem, pBuffer.get(), nBufferSize);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = nullptr;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_FILE_ATTRIBUTES_ARRAY))
	{
		int nBufferSize = sizeof(FILE_ATTRIBUTES_ARRAY) + m_gitPaths.GetCount() * sizeof(DWORD);
		auto pBuffer = std::make_unique<char[]>(nBufferSize);
		SecureZeroMemory(pBuffer.get(), nBufferSize);

		FILE_ATTRIBUTES_ARRAY* cf = (FILE_ATTRIBUTES_ARRAY*)pBuffer.get();
		cf->cItems = m_gitPaths.GetCount();
		cf->dwProductFileAttributes = DWORD_MAX;
		cf->dwSumFileAttributes = 0;
		for (int i = 0; i < m_gitPaths.GetCount(); ++i)
		{
			DWORD fileattribs = FILE_ATTRIBUTE_NORMAL;
			cf->rgdwFileAttributes[i] = fileattribs;
			cf->dwProductFileAttributes &= fileattribs;
			cf->dwSumFileAttributes |= fileattribs;
		}

		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GMEM_ZEROINIT | GMEM_MOVEABLE | GMEM_DDESHARE, nBufferSize);
		if (pmedium->hGlobal)
		{
			LPVOID pMem = ::GlobalLock(pmedium->hGlobal);
			if (pMem)
				memcpy(pMem, pBuffer.get(), nBufferSize);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = nullptr;
		return S_OK;
	}

	for (size_t i = 0; i < m_vecFormatEtc.size(); ++i)
	{
		if ((pformatetcIn->tymed == m_vecFormatEtc[i]->tymed) &&
			(pformatetcIn->dwAspect == m_vecFormatEtc[i]->dwAspect) &&
			(pformatetcIn->cfFormat == m_vecFormatEtc[i]->cfFormat))
		{
			CopyMedium(pmedium, m_vecStgMedium[i], m_vecFormatEtc[i]);
			return S_OK;
		}
	}

	return DV_E_FORMATETC;
}