Esempio n. 1
0
bool CRemoteCacheLink::GetStatusFromRemoteCache(const CTGitPath& Path, TGITCacheResponse* pReturnedStatus, bool bRecursive)
{
	if(!EnsurePipeOpen())
	{
		// We've failed to open the pipe - try and start the cache
		// but only if the last try to start the cache was a certain time
		// ago. If we just try over and over again without a small pause
		// in between, the explorer is rendered unusable!
		// Failing to start the cache can have different reasons: missing exe,
		// missing registry key, corrupt exe, ...
		if (((long)GetTickCount() - m_lastTimeout) < 0)
			return false;
		// if we're in protected mode, don't try to start the cache: since we're
		// here, we know we can't access it anyway and starting a new process will
		// trigger a warning dialog in IE7+ on Vista - we don't want that.
		if (GetProcessIntegrityLevel() < SECURITY_MANDATORY_MEDIUM_RID)
			return false;

		if (!RunTGitCacheProcess())
			return false;

		// Wait for the cache to open
		long endTime = (long)GetTickCount()+1000;
		while(!EnsurePipeOpen())
		{
			if(((long)GetTickCount() - endTime) > 0)
			{
				m_lastTimeout = (long)GetTickCount()+10000;
				return false;
			}
		}
		m_lastTimeout = (long)GetTickCount()+10000;
	}

	AutoLocker lock(m_critSec);

	DWORD nBytesRead;
	TGITCacheRequest request;
	request.flags = TGITCACHE_FLAGS_NONOTIFICATIONS;
	if(bRecursive)
	{
		request.flags |= TGITCACHE_FLAGS_RECUSIVE_STATUS;
	}
	wcsncpy_s(request.path, Path.GetWinPath(), _countof(request.path) - 1);
	SecureZeroMemory(&m_Overlapped, sizeof(OVERLAPPED));
	m_Overlapped.hEvent = m_hEvent;
	// Do the transaction in overlapped mode.
	// That way, if anything happens which might block this call
	// we still can get out of it. We NEVER MUST BLOCK THE SHELL!
	// A blocked shell is a very bad user impression, because users
	// who don't know why it's blocked might find the only solution
	// to such a problem is a reboot and therefore they might loose
	// valuable data.
	// One particular situation where the shell could hang is when
	// the cache crashes and our crash report dialog comes up.
	// Sure, it would be better to have no situations where the shell
	// even can get blocked, but the timeout of 10 seconds is long enough
	// so that users still recognize that something might be wrong and
	// report back to us so we can investigate further.

	BOOL fSuccess = TransactNamedPipe(m_hPipe,
		&request, sizeof(request),
		pReturnedStatus, sizeof(*pReturnedStatus),
		&nBytesRead, &m_Overlapped);

	if (!fSuccess)
	{
		if (GetLastError()!=ERROR_IO_PENDING)
		{
			//OutputDebugStringA("TortoiseShell: TransactNamedPipe failed\n");
			ClosePipe();
			return false;
		}

		// TransactNamedPipe is working in an overlapped operation.
		// Wait for it to finish
		DWORD dwWait = WaitForSingleObject(m_hEvent, 10000);
		if (dwWait == WAIT_OBJECT_0)
		{
			fSuccess = GetOverlappedResult(m_hPipe, &m_Overlapped, &nBytesRead, FALSE);
		}
		else
		{
			// the cache didn't respond!
			fSuccess = FALSE;
		}
	}

	if (fSuccess)
	{
		return true;
	}
	ClosePipe();
	return false;
}
Esempio n. 2
0
bool CCacheDlg::GetStatusFromRemoteCache(const CTGitPath& Path, bool bRecursive)
{
	if(!EnsurePipeOpen())
	{
		STARTUPINFO startup = { 0 };
		PROCESS_INFORMATION process = { 0 };
		startup.cb = sizeof(startup);

		CString sCachePath = L"TGitCache.exe";
		if (CreateProcess(sCachePath.GetBuffer(sCachePath.GetLength() + 1), L"", nullptr, nullptr, FALSE, 0, nullptr, nullptr, &startup, &process) == 0)
		{
			// It's not appropriate to do a message box here, because there may be hundreds of calls
			sCachePath.ReleaseBuffer();
			ATLTRACE("Failed to start cache\n");
			return false;
		}
		sCachePath.ReleaseBuffer();

		// Wait for the cache to open
		ULONGLONG endTime = GetTickCount64()+1000;
		while(!EnsurePipeOpen())
		{
			if((GetTickCount64() - endTime) > 0)
			{
				return false;
			}
		}
	}


	DWORD nBytesRead;
	TGITCacheRequest request;
	request.flags = TGITCACHE_FLAGS_NONOTIFICATIONS;
	if(bRecursive)
	{
		request.flags |= TGITCACHE_FLAGS_RECUSIVE_STATUS;
	}
	wcsncpy_s(request.path, Path.GetWinPath(), MAX_PATH);
	SecureZeroMemory(&m_Overlapped, sizeof(OVERLAPPED));
	m_Overlapped.hEvent = m_hEvent;
	// Do the transaction in overlapped mode.
	// That way, if anything happens which might block this call
	// we still can get out of it. We NEVER MUST BLOCK THE SHELL!
	// A blocked shell is a very bad user impression, because users
	// who don't know why it's blocked might find the only solution
	// to such a problem is a reboot and therefore they might loose
	// valuable data.
	// Sure, it would be better to have no situations where the shell
	// even can get blocked, but the timeout of 5 seconds is long enough
	// so that users still recognize that something might be wrong and
	// report back to us so we can investigate further.

	TGITCacheResponse ReturnedStatus;
	BOOL fSuccess = TransactNamedPipe(m_hPipe,
		&request, sizeof(request),
		&ReturnedStatus, sizeof(ReturnedStatus),
		&nBytesRead, &m_Overlapped);

	if (!fSuccess)
	{
		if (GetLastError()!=ERROR_IO_PENDING)
		{
			ClosePipe();
			return false;
		}

		// TransactNamedPipe is working in an overlapped operation.
		// Wait for it to finish
		DWORD dwWait = WaitForSingleObject(m_hEvent, INFINITE);
		if (dwWait == WAIT_OBJECT_0)
		{
			fSuccess = GetOverlappedResult(m_hPipe, &m_Overlapped, &nBytesRead, FALSE);
			return TRUE;
		}
		else
			fSuccess = FALSE;
	}

	ClosePipe();
	return false;
}
Esempio n. 3
0
bool CRemoteCacheLink::GetStatusFromRemoteCache(const CTGitPath& Path, TGITCacheResponse* pReturnedStatus, bool bRecursive)
{
	if(!EnsurePipeOpen())
	{
		// We've failed to open the pipe - try and start the cache
		// but only if the last try to start the cache was a certain time
		// ago. If we just try over and over again without a small pause
		// in between, the explorer is rendered unusable!
		// Failing to start the cache can have different reasons: missing exe,
		// missing registry key, corrupt exe, ...
		if (((long)GetTickCount() - m_lastTimeout) < 0)
			return false;
		STARTUPINFO startup;
		PROCESS_INFORMATION process;
		memset(&startup, 0, sizeof(startup));
		startup.cb = sizeof(startup);
		memset(&process, 0, sizeof(process));

		CString sCachePath = CPathUtils::GetAppDirectory(g_hmodThisDll) + _T("TGitCache.exe");
#ifndef _WIN64
		typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS) (HANDLE, PBOOL);
		LPFN_ISWOW64PROCESS fnIsWow64Process;
		fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandle(TEXT("kernel32")),"IsWow64Process");

		if (NULL != fnIsWow64Process)
		{
			BOOL bIsWow64 = false;
			if (!fnIsWow64Process(GetCurrentProcess(),&bIsWow64))
			{
				bIsWow64 = false;
			}
			if (bIsWow64)
			{
				CRegString tgitinstalled64 = CRegString(_T("Software\\TortoiseGit\\CachePath"), _T(""), false, HKEY_LOCAL_MACHINE, KEY_WOW64_64KEY);
				if (!CString(tgitinstalled64).IsEmpty())
					sCachePath = tgitinstalled64;
			}
		}
		if (!CCreateProcessHelper::CreateProcessDetached(sCachePath, NULL))
		{
			ATLTRACE("Failed to start x64 cache\n");
			CString sCachePath = CPathUtils::GetAppDirectory(g_hmodThisDll) + _T("TGitCache.exe");
			if (!CCreateProcessHelper::CreateProcessDetached(sCachePath, NULL))
			{
				// It's not appropriate to do a message box here, because there may be hundreds of calls
				ATLTRACE("Failed to start cache\n");
				return false;
			}
		}
#else
		if (!CCreateProcessHelper::CreateProcessDetached(sCachePath, NULL))
		{
			// It's not appropriate to do a message box here, because there may be hundreds of calls
			ATLTRACE("Failed to start cache\n");
			return false;
		}
#endif
		CloseHandle(process.hThread);
		CloseHandle(process.hProcess);
		sCachePath.ReleaseBuffer();

		// Wait for the cache to open
		long endTime = (long)GetTickCount()+1000;
		while(!EnsurePipeOpen())
		{
			if(((long)GetTickCount() - endTime) > 0)
			{
				m_lastTimeout = (long)GetTickCount()+10000;
				return false;
			}
		}
	}

	AutoLocker lock(m_critSec);

	DWORD nBytesRead;
	TGITCacheRequest request;
	request.flags = TGITCACHE_FLAGS_NONOTIFICATIONS;
	if(bRecursive)
	{
		request.flags |= TGITCACHE_FLAGS_RECUSIVE_STATUS;
	}
	wcsncpy_s(request.path, MAX_PATH+1, Path.GetWinPath(), MAX_PATH);
	SecureZeroMemory(&m_Overlapped, sizeof(OVERLAPPED));
	m_Overlapped.hEvent = m_hEvent;
	// Do the transaction in overlapped mode.
	// That way, if anything happens which might block this call
	// we still can get out of it. We NEVER MUST BLOCK THE SHELL!
	// A blocked shell is a very bad user impression, because users
	// who don't know why it's blocked might find the only solution
	// to such a problem is a reboot and therefore they might lose
	// valuable data.
	// One particular situation where the shell could hang is when
	// the cache crashes and our crash report dialog comes up.
	// Sure, it would be better to have no situations where the shell
	// even can get blocked, but the timeout of 10 seconds is long enough
	// so that users still recognize that something might be wrong and
	// report back to us so we can investigate further.

	BOOL fSuccess = TransactNamedPipe(m_hPipe,
		&request, sizeof(request),
		pReturnedStatus, sizeof(*pReturnedStatus),
		&nBytesRead, &m_Overlapped);

	if (!fSuccess)
	{
		if (GetLastError()!=ERROR_IO_PENDING)
		{
			//OutputDebugStringA("TortoiseShell: TransactNamedPipe failed\n");
			ClosePipe();
			return false;
		}

		// TransactNamedPipe is working in an overlapped operation.
		// Wait for it to finish
		DWORD dwWait = WaitForSingleObject(m_hEvent, 10000);
		if (dwWait == WAIT_OBJECT_0)
		{
			fSuccess = GetOverlappedResult(m_hPipe, &m_Overlapped, &nBytesRead, FALSE);
		}
		else
		{
			// the cache didn't respond!
			fSuccess = FALSE;
		}
	}

	if (fSuccess)
	{
		return true;
	}
	ClosePipe();
	return false;
}