Esempio n. 1
0
// Update our composite status and deal with things if it's changed
void CCachedDirectory::UpdateCurrentStatus()
{
    svn_wc_status_kind newStatus = CalculateRecursiveStatus();

    if ((newStatus != m_currentFullStatus)&&(m_ownStatus.IsVersioned()))
    {
        if ((m_currentFullStatus != svn_wc_status_none)&&(m_ownStatus.GetEffectiveStatus() != svn_wc_status_ignored))
        {
            // Our status has changed - tell the shell
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) _T(": Dir %s, status change from %d to %d\n"), m_directoryPath.GetWinPath(), m_currentFullStatus, newStatus);
            CSVNStatusCache::Instance().UpdateShell(m_directoryPath);
        }
        if (m_ownStatus.GetEffectiveStatus() != svn_wc_status_ignored)
            m_currentFullStatus = newStatus;
        else
            m_currentFullStatus = svn_wc_status_ignored;
    }
    // And tell our parent, if we've got one...
    // we tell our parent *always* about our status, even if it hasn't
    // changed. This is to make sure that the parent has really our current
    // status - the parent can decide itself if our status has changed
    // or not.
    CTSVNPath parentPath = m_directoryPath.GetContainingDirectory();
    if(!parentPath.IsEmpty())
    {
        CCachedDirectory * cachedDir = CSVNStatusCache::Instance().GetDirectoryCacheEntry(parentPath);
        if (cachedDir)
            cachedDir->UpdateChildDirectoryStatus(m_directoryPath, m_currentFullStatus);
    }
}
void CEditPropExternalsValue::OnBnClickedShowLog()
{
    UpdateData(TRUE);
    if (::IsWindow(m_pLogDlg->GetSafeHwnd())&&(m_pLogDlg->IsWindowVisible()))
        return;
    CString urlString = m_URLCombo.GetString();
    CTSVNPath logUrl = m_URL;
    if (urlString.GetLength()>1)
    {
        logUrl = CTSVNPath(SVNExternals::GetFullExternalUrl(urlString, m_RepoRoot.GetSVNPathString(), m_URL.GetSVNPathString()));
    }
    else
    {
        logUrl = m_RepoRoot;
        logUrl.AppendPathString(urlString);
    }

    if (!logUrl.IsEmpty())
    {
        delete m_pLogDlg;
        m_pLogDlg = new CLogDlg();
        m_pLogDlg->SetSelect(true);
        m_pLogDlg->m_pNotifyWindow = this;
        m_pLogDlg->m_wParam = 0;
        m_pLogDlg->SetParams(CTSVNPath(logUrl), SVNRev::REV_HEAD, SVNRev::REV_HEAD, 1, TRUE);
        m_pLogDlg->ContinuousSelection(true);
        m_pLogDlg->Create(IDD_LOGMESSAGE, this);
        m_pLogDlg->ShowWindow(SW_SHOW);
    }
    AfxGetApp()->DoWaitCursor(-1);
}
Esempio n. 3
0
void CHooks::AddCWDParam(CString& sCmd, const CTSVNPathList& pathList)
{
    CTSVNPath curDir = pathList.GetCommonRoot().GetDirectory();
    while (!curDir.IsEmpty() && !curDir.Exists())
        curDir = curDir.GetContainingDirectory();

    AddParam(sCmd, curDir.GetWinPathString());
}
Esempio n. 4
0
CStatusCacheEntry CSVNStatusCache::GetStatusForPath(const CTSVNPath& path, DWORD flags,  bool bFetch /* = true */)
{
	bool bRecursive = !!(flags & TSVNCACHE_FLAGS_RECUSIVE_STATUS);

	// Check a very short-lived 'mini-cache' of the last thing we were asked for.
	long now = (long)GetTickCount();
	if(now-m_mostRecentExpiresAt < 0)
	{
		if(path.IsEquivalentToWithoutCase(m_mostRecentAskedPath))
		{
			return m_mostRecentStatus;
		}
	}
	{
		AutoLocker lock(m_critSec);
		m_mostRecentAskedPath = path;
		m_mostRecentExpiresAt = now+1000;
	}

	if (IsPathGood(path) && m_shellCache.IsPathAllowed(path.GetWinPath()))
	{
		// Stop the crawler starting on a new folder while we're doing this much more important task...
		// Please note, that this may be a second "lock" used concurrently to the one in RemoveCacheForPath().
		CCrawlInhibitor crawlInhibit(&m_folderCrawler);

		CTSVNPath dirpath = path.GetContainingDirectory();
		if (dirpath.IsEmpty())
			dirpath = path.GetDirectory();
		CCachedDirectory * cachedDir = GetDirectoryCacheEntry(dirpath);
		if (cachedDir != NULL)
		{
			CStatusCacheEntry entry = cachedDir->GetStatusForMember(path, bRecursive, bFetch);
			{
				AutoLocker lock(m_critSec);
				m_mostRecentStatus = entry;
				return m_mostRecentStatus;
			}
		}
		cachedDir = GetDirectoryCacheEntry(path.GetDirectory());
		if (cachedDir != NULL)
		{
			CStatusCacheEntry entry = cachedDir->GetStatusForMember(path, bRecursive, bFetch);
			{
				AutoLocker lock(m_critSec);
				m_mostRecentStatus = entry;
				return m_mostRecentStatus;
			}
		}

	}
	AutoLocker lock(m_critSec);
	m_mostRecentStatus = CStatusCacheEntry();
	if (m_shellCache.ShowExcludedAsNormal() && path.IsDirectory() && m_shellCache.HasSVNAdminDir(path.GetWinPath(), true))
	{
		m_mostRecentStatus.ForceStatus(svn_wc_status_normal);
	}
	return m_mostRecentStatus;
}
Esempio n. 5
0
CDirectoryWatcher::CDirWatchInfo::CDirWatchInfo(HANDLE hDir, const CTSVNPath& DirectoryName)
    : m_hDir(hDir)
    , m_DirName(DirectoryName)
{
    ATLASSERT(hDir && !DirectoryName.IsEmpty());
    m_Buffer[0] = 0;
    SecureZeroMemory(&m_Overlapped, sizeof(m_Overlapped));
    m_DirPath = m_DirName.GetWinPathString();
    if (m_DirPath.GetAt(m_DirPath.GetLength()-1) != '\\')
        m_DirPath += L"\\";
    m_hDevNotify = 0;
}
Esempio n. 6
0
int SVNBase::ShowErrorDialog( HWND hParent, const CTSVNPath& wcPath, const CString& sErr)
{
    UNREFERENCED_PARAMETER(wcPath);
    int ret = -1;

    CString sError = Err ? GetErrorString(Err) : PostCommitErr;
    if (!sErr.IsEmpty())
        sError = sErr;

    CString sCleanup = CString(MAKEINTRESOURCE(IDS_RUNCLEANUPNOW));
    CString sClose = CString(MAKEINTRESOURCE(IDS_CLOSE));
    CString sInstruction = CString(MAKEINTRESOURCE(IDS_SVNREPORTEDANERROR));

    TASKDIALOGCONFIG tconfig = { 0 };
    tconfig.cbSize = sizeof(TASKDIALOGCONFIG);
    tconfig.hwndParent = hParent;
    tconfig.dwFlags = TDF_ENABLE_HYPERLINKS | TDF_ALLOW_DIALOG_CANCELLATION | TDF_POSITION_RELATIVE_TO_WINDOW | TDF_SIZE_TO_CONTENT;
    tconfig.dwCommonButtons = TDCBF_CLOSE_BUTTON;
    tconfig.pszWindowTitle = L"TortoiseSVN";
    tconfig.pszMainIcon = TD_ERROR_ICON;
    tconfig.pszMainInstruction = sInstruction;
    tconfig.pszContent = (LPCTSTR)sError;
#ifdef HAVE_APPUTILS
    TASKDIALOG_BUTTON aCustomButtons[2];
    aCustomButtons[0].nButtonID = 1000;
    aCustomButtons[0].pszButtonText = sCleanup;
    aCustomButtons[1].nButtonID = IDOK;
    aCustomButtons[1].pszButtonText = sClose;
    if (Err && (Err->apr_err == SVN_ERR_WC_CLEANUP_REQUIRED) && (!wcPath.IsEmpty()))
    {
        tconfig.dwCommonButtons = 0;
        tconfig.dwFlags |= TDF_USE_COMMAND_LINKS;
        tconfig.pButtons = aCustomButtons;
        tconfig.cButtons = _countof(aCustomButtons);
    }
#endif
    TaskDialogIndirect(&tconfig, &ret, NULL, NULL);
#ifdef HAVE_APPUTILS
    if (ret == 1000)
    {
        // run cleanup
        CString sCmd;
        sCmd.Format(L"/command:cleanup /path:\"%s\" /cleanup /nodlg /hwnd:%p",
                    wcPath.GetDirectory().GetWinPath(), (void*)hParent);
        CAppUtils::RunTortoiseProc(sCmd);
    }
#endif
    return ret;
}
Esempio n. 7
0
bool CHooks::ManualPreCommit( HWND hWnd, const CTSVNPathList& pathList, CString& message, DWORD& exitcode, CString& error )
{
    hookiterator it = FindItem(manual_precommit, pathList);
    if (it == end())
        return false;
    if (!ApproveHook(hWnd, it))
        return false;
    CString sCmd = it->second.commandline;
    AddPathParam(sCmd, pathList);
    CTSVNPath temppath = AddMessageFileParam(sCmd, message);
    AddCWDParam(sCmd, pathList);
    exitcode = RunScript(sCmd, pathList, error, it->second.bWait, it->second.bShow);
    if (!exitcode && !temppath.IsEmpty())
    {
        CStringUtils::ReadStringFromTextFile(temppath.GetWinPathString(), message);
    }
    return true;
}
Esempio n. 8
0
    void ContainingDirectoryTest()
    {

        CTSVNPath testPath;
        testPath.SetFromWin(L"c:\\a\\b\\c\\d\\e");
        CTSVNPath dir;
        dir = testPath.GetContainingDirectory();
        ATLASSERT(dir.GetWinPathString() == L"c:\\a\\b\\c\\d");
        dir = dir.GetContainingDirectory();
        ATLASSERT(dir.GetWinPathString() == L"c:\\a\\b\\c");
        dir = dir.GetContainingDirectory();
        ATLASSERT(dir.GetWinPathString() == L"c:\\a\\b");
        dir = dir.GetContainingDirectory();
        ATLASSERT(dir.GetWinPathString() == L"c:\\a");
        dir = dir.GetContainingDirectory();
        ATLASSERT(dir.GetWinPathString() == L"c:\\");
        dir = dir.GetContainingDirectory();
        ATLASSERT(dir.IsEmpty());
        ATLASSERT(dir.GetWinPathString().IsEmpty());
    }
void CRepoCreationFinished::OnBnClickedCreatefolders()
{
    // create the default folder structure in a temp folder
    CTSVNPath tempDir = CTempFiles::Instance().GetTempDirPath(true);
    if (tempDir.IsEmpty())
    {
        ::MessageBox(m_hWnd, CString(MAKEINTRESOURCE(IDS_ERR_CREATETEMPDIR)), CString(MAKEINTRESOURCE(IDS_APPNAME)), MB_ICONERROR);
        return;
    }
    CTSVNPath tempDirSub = tempDir;
    tempDirSub.AppendPathString(L"trunk");
    CreateDirectory(tempDirSub.GetWinPath(), NULL);
    tempDirSub = tempDir;
    tempDirSub.AppendPathString(L"branches");
    CreateDirectory(tempDirSub.GetWinPath(), NULL);
    tempDirSub = tempDir;
    tempDirSub.AppendPathString(L"tags");
    CreateDirectory(tempDirSub.GetWinPath(), NULL);

    CString url;
    if (m_RepoPath.GetWinPathString().GetAt(0) == '\\')    // starts with '\' means an UNC path
    {
        CString p = m_RepoPath.GetWinPathString();
        p.TrimLeft('\\');
        url = L"file://"+p;
    }
    else
        url = L"file:///"+m_RepoPath.GetWinPathString();

    // import the folder structure into the new repository
    SVN svn;
    if (!svn.Import(tempDir, CTSVNPath(url), CString(MAKEINTRESOURCE(IDS_MSG_IMPORTEDSTRUCTURE)), NULL, svn_depth_infinity, true, true, false))
    {
        svn.ShowErrorDialog(m_hWnd);
        return;
    }
    MessageBox(CString(MAKEINTRESOURCE(IDS_MSG_IMPORTEDSTRUCTUREFINISHED)), L"TortoiseSVN", MB_ICONINFORMATION);
    DialogEnableWindow(IDC_CREATEFOLDERS, FALSE);
}
Esempio n. 10
0
hookiterator CHooks::FindItem(hooktype t, const CTSVNPathList& pathList)
{
    hookkey key;
    for (int i=0; i<pathList.GetCount(); ++i)
    {
        CTSVNPath path = pathList[i];
        do
        {
            key.htype = t;
            key.path = path;
            hookiterator it = find(key);
            if (it != end())
            {
                return it;
            }
            path = path.GetContainingDirectory();
        } while(!path.IsEmpty());
    }

    // try the wc root path
    key.htype = t;
    key.path = m_wcRootPath;
    hookiterator it = find(key);
    if (it != end())
    {
        return it;
    }

    // look for a script with a path as '*'
    key.htype = t;
    key.path = CTSVNPath(L"*");
    it = find(key);
    if (it != end())
    {
        return it;
    }

    return end();
}
Esempio n. 11
0
bool CHooks::CheckCommit(HWND hWnd, const CTSVNPathList& pathList, CString& message, DWORD& exitcode, CString& error)
{
    exitcode = 0;
    hookiterator it = FindItem(check_commit_hook, pathList);
    if (it == end())
        return false;
    if (!ApproveHook(hWnd, it))
    {
        exitcode = 1;
        error.LoadString(IDS_ERR_HOOKNOTAPPROVED);
        return false;
    }
    CString sCmd = it->second.commandline;
    AddPathParam(sCmd, pathList);
    CTSVNPath temppath = AddMessageFileParam(sCmd, message);
    AddCWDParam(sCmd, pathList);
    exitcode = RunScript(sCmd, pathList, error, it->second.bWait, it->second.bShow);
    if (!exitcode && !temppath.IsEmpty())
    {
        CStringUtils::ReadStringFromTextFile(temppath.GetWinPathString(), message);
    }
    return true;
}
Esempio n. 12
0
DWORD CHooks::RunScript(CString cmd, const CTSVNPathList& paths, CString& error, bool bWait, bool bShow)
{
    DWORD exitcode = 0;
    SECURITY_ATTRIBUTES sa;
    SecureZeroMemory(&sa, sizeof(sa));
    sa.nLength = sizeof(sa);
    sa.bInheritHandle = TRUE;

    CTSVNPath curDir = paths.GetCommonRoot().GetDirectory();
    while (!curDir.IsEmpty() && !curDir.Exists())
        curDir = curDir.GetContainingDirectory();
    if (curDir.IsEmpty())
    {
        WCHAR buf[MAX_PATH] = {0};
        GetTempPath(MAX_PATH, buf);
        curDir.SetFromWin(buf, true);
    }

    CAutoFile hOut ;
    CAutoFile hRedir;
    CAutoFile hErr;

    // clear the error string
    error.Empty();

    // Create Temp File for redirection
    TCHAR szTempPath[MAX_PATH] = { 0 };
    TCHAR szOutput[MAX_PATH] = { 0 };
    TCHAR szErr[MAX_PATH] = { 0 };
    GetTempPath(_countof(szTempPath),szTempPath);
    GetTempFileName(szTempPath, L"svn", 0, szErr);

    // setup redirection handles
    // output handle must be WRITE mode, share READ
    // redirect handle must be READ mode, share WRITE
    hErr   = CreateFile(szErr, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY,    0);

    if (!hErr)
    {
        error = CFormatMessageWrapper();
        return (DWORD)-1;
    }

    hRedir = CreateFile(szErr, GENERIC_READ, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);

    if (!hRedir)
    {
        error = CFormatMessageWrapper();
        return (DWORD)-1;
    }

    GetTempFileName(szTempPath, L"svn", 0, szOutput);
    hOut   = CreateFile(szOutput, GENERIC_WRITE, FILE_SHARE_READ, &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_TEMPORARY, 0);

    if (!hOut)
    {
        error = CFormatMessageWrapper();
        return (DWORD)-1;
    }

    // setup startup info, set std out/err handles
    // hide window
    STARTUPINFO si;
    SecureZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    si.dwFlags     = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
    si.hStdOutput  = hOut;
    si.hStdError   = hErr;
    si.wShowWindow = bShow ? SW_SHOW : SW_HIDE;

    PROCESS_INFORMATION pi;
    SecureZeroMemory(&pi, sizeof(pi));

    if (!CreateProcess(NULL, cmd.GetBuffer(), NULL, NULL, TRUE, 0, NULL, curDir.IsEmpty() ? NULL : curDir.GetWinPath(), &si, &pi))
    {
        const DWORD err = GetLastError();  // preserve the CreateProcess error
        error = CFormatMessageWrapper(err);
        SetLastError(err);
        cmd.ReleaseBuffer();
        return (DWORD)-1;
    }
    cmd.ReleaseBuffer();

    CloseHandle(pi.hThread);

    // wait for process to finish, capture redirection and
    // send it to the parent window/console
    if (bWait)
    {
        DWORD dw;
        char buf[10*1024];
        do
        {
            SecureZeroMemory(&buf,sizeof(buf));
            while (ReadFile(hRedir, &buf, sizeof(buf)-1, &dw, NULL))
            {
                if (dw == 0)
                    break;
                error += CString(CStringA(buf,dw));
                SecureZeroMemory(&buf,sizeof(buf));
            }
        } while (WaitForSingleObject(pi.hProcess, 100) != WAIT_OBJECT_0);

        // perform any final flushing
        while (ReadFile(hRedir, &buf, sizeof(buf)-1, &dw, NULL))
        {
            if (dw == 0)
                break;

            error += CString(CStringA(buf, dw));
            SecureZeroMemory(&buf,sizeof(buf));
        }
        WaitForSingleObject(pi.hProcess, INFINITE);
        GetExitCodeProcess(pi.hProcess, &exitcode);
    }
    CloseHandle(pi.hProcess);
    DeleteFile(szOutput);
    DeleteFile(szErr);

    return exitcode;
}
bool ConflictEditorCommand::Execute()
{
    CTSVNPath merge = cmdLinePath;
    CTSVNPath directory = merge.GetDirectory();
    bool bRet = false;
    bool bAlternativeTool = !!parser.HasKey(L"alternative");

    // Use Subversion 1.10 API to resolve possible tree conlifcts.
    SVNConflictInfo conflict;
    if (!conflict.Get(merge))
    {
        conflict.ShowErrorDialog(GetExplorerHWND());
        return false;
    }

    // Resolve tree conflicts first.
    if (conflict.HasTreeConflict())
    {
        CProgressDlg progressDlg;
        progressDlg.SetTitle(IDS_PROC_EDIT_TREE_CONFLICTS);
        CString sProgressLine;
        sProgressLine.LoadString(IDS_PROGRS_FETCHING_TREE_CONFLICT_INFO);
        progressDlg.SetLine(1, sProgressLine);
        progressDlg.SetShowProgressBar(false);
        progressDlg.ShowModal(GetExplorerHWND(), FALSE);
        conflict.SetProgressDlg(&progressDlg);
        if (!conflict.FetchTreeDetails())
        {
            // Ignore errors while fetching additional tree conflict information.
            // Use still may want to resolve it manually.
            conflict.ClearSVNError();
        }
        progressDlg.Stop();
        conflict.SetProgressDlg(NULL);

        CNewTreeConflictEditorDlg dlg;
        dlg.SetConflictInfo(&conflict);

        dlg.DoModal(GetExplorerHWND());
        if (dlg.IsCancelled())
            return false;

        if (dlg.GetResult() == svn_client_conflict_option_postpone)
            return false;

        // Send notififcation that status may be changed. We cannot use
        // '/resolvemsghwnd' here because satus of multiple files may be changed
        // during tree conflict resolution.
        if (parser.HasVal(L"refreshmsghwnd"))
        {
            HWND refreshMsgWnd = (HWND)parser.GetLongLongVal(L"refreshmsghwnd");
            UINT WM_REFRESH_STATUS_MSG = RegisterWindowMessage(L"TORTOISESVN_REFRESH_STATUS_MSG");
            ::PostMessage(refreshMsgWnd, WM_REFRESH_STATUS_MSG, 0, 0);
        }
    }

    // we have the conflicted file (%merged)
    // now look for the other required files

    SVNInfo info;
    const SVNInfoData * pInfoData = info.GetFirstFileInfo(merge, SVNRev(), SVNRev());
    if (pInfoData == NULL)
        return false;

    for (auto conflIt = pInfoData->conflicts.cbegin(); conflIt != pInfoData->conflicts.cend(); ++conflIt)
    {
        switch (conflIt->kind)
        {
        case svn_wc_conflict_kind_text:
        {
            // we have a text conflict, use our merge tool to resolve the conflict

            CTSVNPath theirs = CTSVNPath(conflIt->conflict_new);
            CTSVNPath mine = CTSVNPath(conflIt->conflict_wrk);
            CTSVNPath base = CTSVNPath(conflIt->conflict_old);
            if (mine.IsEmpty())
                mine = merge;
            bRet = !!CAppUtils::StartExtMerge(CAppUtils::MergeFlags().AlternativeTool(bAlternativeTool),
                                              base, theirs, mine, merge, true, CString(), CString(), CString(), CString(), merge.GetFileOrDirectoryName());
        }
        break;
        case svn_wc_conflict_kind_property:
        {
            // we have a property conflict
            CTSVNPath prej(conflIt->prejfile);
            CEditPropConflictDlg dlg;
            dlg.SetPrejFile(prej);
            dlg.SetConflictedItem(merge);
            dlg.SetPropertyName(conflIt->propname);
            dlg.SetPropValues(conflIt->propvalue_base, conflIt->propvalue_working, conflIt->propvalue_incoming_old, conflIt->propvalue_incoming_new);
            bRet = (dlg.DoModal() != IDCANCEL);
        }
        break;
        case svn_wc_conflict_kind_tree:
        {
            CTSVNPath treeConflictPath = CTSVNPath(conflIt->treeconflict_path);

            CTreeConflictEditorDlg dlg;
            dlg.SetPath(treeConflictPath);
            dlg.SetConflictLeftSources(conflIt->src_left_version_url, conflIt->src_left_version_path, conflIt->src_left_version_rev, conflIt->src_left_version_kind);
            dlg.SetConflictRightSources(conflIt->src_right_version_url, conflIt->src_right_version_path, conflIt->src_right_version_rev, conflIt->src_right_version_kind);
            dlg.SetConflictReason(conflIt->treeconflict_reason);
            dlg.SetConflictAction(conflIt->treeconflict_action);
            dlg.SetConflictOperation(conflIt->treeconflict_operation);
            dlg.SetKind(conflIt->treeconflict_nodekind);
            INT_PTR dlgRet = dlg.DoModal();
            bRet = (dlgRet != IDCANCEL);
        }
        break;
        }
    }

    return bRet;
}
Esempio n. 14
0
bool SVNDiff::DiffWCFile(const CTSVNPath& filePath,
                         bool ignoreprops,
                         svn_wc_status_kind status, /* = svn_wc_status_none */
                         svn_wc_status_kind text_status /* = svn_wc_status_none */,
                         svn_wc_status_kind prop_status /* = svn_wc_status_none */,
                         svn_wc_status_kind remotetext_status /* = svn_wc_status_none */,
                         svn_wc_status_kind remoteprop_status /* = svn_wc_status_none */)
{
    CTSVNPath basePath;
    CTSVNPath remotePath;
    SVNRev remoteRev;
    svn_revnum_t baseRev = 0;

    // first diff the remote properties against the wc props
    // TODO: should we attempt to do a three way diff with the properties too
    // if they're modified locally and remotely?
    if (!ignoreprops && (remoteprop_status > svn_wc_status_normal))
    {
        DiffProps(filePath, SVNRev::REV_HEAD, SVNRev::REV_WC, baseRev);
    }
    if (!ignoreprops && (prop_status > svn_wc_status_normal)&&(filePath.IsDirectory()))
    {
        DiffProps(filePath, SVNRev::REV_WC, SVNRev::REV_BASE, baseRev);
    }
    if (filePath.IsDirectory())
        return true;

    if ((status > svn_wc_status_normal) || (text_status > svn_wc_status_normal))
    {
        basePath = SVN::GetPristinePath(filePath);
        if (baseRev == 0)
        {
            SVNStatus stat;
            CTSVNPath dummy;
            svn_client_status_t * s = stat.GetFirstFileStatus(filePath, dummy);
            if (s)
                baseRev = s->revision >= 0 ? s->revision : s->changed_rev;
        }
        // If necessary, convert the line-endings on the file before diffing
        if ((DWORD)CRegDWORD(L"Software\\TortoiseSVN\\ConvertBase", TRUE))
        {
            CTSVNPath temporaryFile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, filePath, SVNRev::REV_BASE);
            if (!m_pSVN->Export(filePath, temporaryFile, SVNRev(SVNRev::REV_BASE), SVNRev(SVNRev::REV_BASE)))
            {
                temporaryFile.Reset();
            }
            else
            {
                basePath = temporaryFile;
                SetFileAttributes(basePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
            }
        }
    }

    if (remotetext_status > svn_wc_status_normal)
    {
        remotePath = CTempFiles::Instance().GetTempFilePath(false, filePath, SVNRev::REV_HEAD);

        CProgressDlg progDlg;
        progDlg.SetTitle(IDS_APPNAME);
        progDlg.SetTime(false);
        m_pSVN->SetAndClearProgressInfo(&progDlg, true);    // activate progress bar
        progDlg.ShowModeless(GetHWND());
        progDlg.FormatPathLine(1, IDS_PROGRESSGETFILE, (LPCTSTR)filePath.GetUIFileOrDirectoryName());
        remoteRev = SVNRev::REV_HEAD;
        if (!m_pSVN->Export(filePath, remotePath, remoteRev, remoteRev))
        {
            progDlg.Stop();
            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
            m_pSVN->ShowErrorDialog(GetHWND());
            return false;
        }
        progDlg.Stop();
        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
        SetFileAttributes(remotePath.GetWinPath(), FILE_ATTRIBUTE_READONLY);
    }

    CString name = filePath.GetUIFileOrDirectoryName();
    CString n1, n2, n3;
    n1.Format(IDS_DIFF_WCNAME, (LPCTSTR)name);
    if (baseRev)
        n2.FormatMessage(IDS_DIFF_BASENAMEREV, (LPCTSTR)name, baseRev);
    else
        n2.Format(IDS_DIFF_BASENAME, (LPCTSTR)name);
    n3.Format(IDS_DIFF_REMOTENAME, (LPCTSTR)name);

    if ((text_status <= svn_wc_status_normal)&&(prop_status <= svn_wc_status_normal)&&(status <= svn_wc_status_normal))
    {
        // Hasn't changed locally - diff remote against WC
        return CAppUtils::StartExtDiff(
            filePath, remotePath, n1, n3, filePath, filePath, SVNRev::REV_WC, remoteRev, remoteRev, CAppUtils::DiffFlags().AlternativeTool(m_bAlternativeTool),
            m_JumpLine, filePath.GetFileOrDirectoryName(), L"");
    }
    else if (remotePath.IsEmpty())
    {
        return DiffFileAgainstBase(filePath, baseRev, ignoreprops, status, text_status, prop_status);
    }
    else
    {
        // Three-way diff
        CAppUtils::MergeFlags flags;
        flags.bAlternativeTool = m_bAlternativeTool;
        flags.bReadOnly = true;
        return !!CAppUtils::StartExtMerge(flags,
            basePath, remotePath, filePath, CTSVNPath(), false, n2, n3, n1, CString(), filePath.GetFileOrDirectoryName());
    }
}
Esempio n. 15
0
bool SyncCommand::Execute()
{
    bool bRet = false;
    CRegString rSyncPath(L"Software\\TortoiseSVN\\SyncPath");
    CTSVNPath syncPath = CTSVNPath(CString(rSyncPath));
    CTSVNPath syncFolder = syncPath;
    CRegDWORD regCount(L"Software\\TortoiseSVN\\SyncCounter");
    CRegDWORD regSyncAuth(L"Software\\TortoiseSVN\\SyncAuth");
    bool bSyncAuth = DWORD(regSyncAuth) != 0;
    if (!cmdLinePath.IsEmpty())
        syncPath = cmdLinePath;
    if (syncPath.IsEmpty() && !parser.HasKey(L"askforpath"))
    {
        return false;
    }
    syncPath.AppendPathString(L"tsvnsync.tsex");

    BOOL bWithLocals = FALSE;
    if (parser.HasKey(L"askforpath"))
    {
        // ask for the path first, then for the password
        // this is used for a manual import/export
        CString path;
        bool bGotPath = FileOpenSave(path, bWithLocals, !!parser.HasKey(L"load"), GetExplorerHWND());
        if (bGotPath)
        {
            syncPath = CTSVNPath(path);
            if (!parser.HasKey(L"load") && syncPath.GetFileExtension().IsEmpty())
                syncPath.AppendRawString(L".tsex");
        }
        else
            return false;
    }


    CSimpleIni iniFile;
    iniFile.SetMultiLine(true);
    SVNAuthData authData;

    CAutoRegKey hMainKey;
    RegOpenKeyEx(HKEY_CURRENT_USER, L"Software\\TortoiseSVN", 0, KEY_READ, hMainKey.GetPointer());
    FILETIME filetime = { 0 };
    RegQueryInfoKey(hMainKey, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &filetime);

    bool bCloudIsNewer = false;
    if (!parser.HasKey(L"save"))
    {
        // open the file in read mode
        CAutoFile hFile = CreateFile(syncPath.GetWinPathString(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile.IsValid())
        {
            // load the file
            LARGE_INTEGER fsize = { 0 };
            if (GetFileSizeEx(hFile, &fsize))
            {
                auto filebuf = std::make_unique<char[]>(DWORD(fsize.QuadPart));
                DWORD bytesread = 0;
                if (ReadFile(hFile, filebuf.get(), DWORD(fsize.QuadPart), &bytesread, NULL))
                {
                    // decrypt the file contents
                    std::string encrypted;
                    if (bytesread > 0)
                        encrypted = std::string(filebuf.get(), bytesread);
                    CRegString regPW(L"Software\\TortoiseSVN\\SyncPW");
                    CString password;
                    if (parser.HasKey(L"askforpath") && parser.HasKey(L"load"))
                    {
                        INT_PTR dlgret = 0;
                        bool bPasswordMatches = true;
                        do
                        {
                            bPasswordMatches = true;
                            CPasswordDlg passDlg(CWnd::FromHandle(GetExplorerHWND()));
                            passDlg.m_bForSave = !!parser.HasKey(L"save");
                            dlgret = passDlg.DoModal();
                            password = passDlg.m_sPW1;
                            if ((dlgret == IDOK) && (parser.HasKey(L"load")))
                            {
                                std::string passworda = CUnicodeUtils::StdGetUTF8((LPCWSTR)password);
                                std::string decrypted = CStringUtils::Decrypt(encrypted, passworda);
                                if ((decrypted.size() < 3) || (decrypted.substr(0, 3) != "***"))
                                {
                                    bPasswordMatches = false;
                                }
                            }
                        } while ((dlgret == IDOK) && !bPasswordMatches);
                        if (dlgret != IDOK)
                            return false;
                    }
                    else
                    {
                        auto passwordbuf = CStringUtils::Decrypt(CString(regPW));
                        if (passwordbuf.get())
                        {
                            password = passwordbuf.get();
                        }
                        else
                        {
                            // password does not match or it couldn't be read from
                            // the registry!
                            //
                            TaskDialog(GetExplorerHWND(), AfxGetResourceHandle(), MAKEINTRESOURCE(IDS_APPNAME), MAKEINTRESOURCE(IDS_ERR_ERROROCCURED), MAKEINTRESOURCE(IDS_SYNC_WRONGPASSWORD), TDCBF_OK_BUTTON, TD_ERROR_ICON, NULL);
                            CString sCmd = L" /command:settings /page:21";
                            CAppUtils::RunTortoiseProc(sCmd);
                            return false;
                        }
                    }
                    std::string passworda = CUnicodeUtils::StdGetUTF8((LPCWSTR)password);
                    std::string decrypted = CStringUtils::Decrypt(encrypted, passworda);
                    if (decrypted.size() >= 3)
                    {
                        if (decrypted.substr(0, 3) == "***")
                        {
                            decrypted = decrypted.substr(3);
                            // pass the decrypted data to the ini file
                            iniFile.LoadFile(decrypted.c_str(), decrypted.size());
                            int inicount = _wtoi(iniFile.GetValue(L"sync", L"synccounter", L""));
                            if (inicount != 0)
                            {
                                if (int(DWORD(regCount)) < inicount)
                                {
                                    bCloudIsNewer = true;
                                    regCount = inicount;
                                }
                            }

                            // load the auth data, but do not overwrite already stored auth data!
                            if (bSyncAuth)
                                authData.ImportAuthData(syncFolder.GetWinPathString(), password);
                        }
                        else
                        {
                            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error decrypting, password may be wrong\n");
                            return false;
                        }
                    }
                }
            }
        }
        else
        {
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error opening file %s, Error %u\n", syncPath.GetWinPath(), GetLastError());
            auto lasterr = GetLastError();
            if ((lasterr != ERROR_FILE_NOT_FOUND) && (lasterr != ERROR_PATH_NOT_FOUND))
                return false;
        }
    }

    if (parser.HasKey(L"load"))
        bCloudIsNewer = true;
    if (parser.HasKey(L"save"))
        bCloudIsNewer = false;

    bool bHaveChanges = false;

    if (bWithLocals || parser.HasKey(L"local"))
    {
        // remove all blocks that are allowed for local exports
        for (const auto& allow : regBlockLocalArray)
        {
            regBlockArray.erase(std::remove(regBlockArray.begin(), regBlockArray.end(), allow), regBlockArray.end());
        }
    }
    // go through all registry values and update either the registry
    // or the ini file, depending on which is newer
    for (const auto& regname : regUseArray)
    {
        bool bChanges = HandleRegistryKey(regname, iniFile, bCloudIsNewer);
        bHaveChanges = bHaveChanges || bChanges;
    }
    if (bWithLocals || parser.HasKey(L"local"))
    {
        for (const auto& regname : regUseLocalArray)
        {
            bool bChanges = HandleRegistryKey(regname, iniFile, bCloudIsNewer);
            bHaveChanges = bHaveChanges || bChanges;
        }
    }

    if (bCloudIsNewer)
    {
        CString regpath = L"Software\\";

        CSimpleIni::TNamesDepend keys;
        iniFile.GetAllKeys(L"registry_dword", keys);
        for (const auto& k : keys)
        {
            CRegDWORD reg(regpath + k);
            reg = _wtol(iniFile.GetValue(L"registry_dword", k, L""));
        }

        keys.clear();
        iniFile.GetAllKeys(L"registry_qword", keys);
        for (const auto& k : keys)
        {
            CRegQWORD reg(regpath + k);
            reg = _wtoi64(iniFile.GetValue(L"registry_qword", k, L""));
        }

        keys.clear();
        iniFile.GetAllKeys(L"registry_string", keys);
        for (const auto& k : keys)
        {
            CRegString reg(regpath + k);
            reg = CString(iniFile.GetValue(L"registry_string", k, L""));
        }
    }
    {
        // sync project monitor settings
        CString sDataFilePath = CPathUtils::GetAppDataDirectory();
        sDataFilePath += L"\\MonitoringData.ini";
        CSimpleIni monitorIni;
        monitorIni.SetMultiLine(true);
        if (bCloudIsNewer)
        {
            CSimpleIni origMonitorIni;
            origMonitorIni.SetMultiLine(true);
            origMonitorIni.LoadFile(sDataFilePath);

            CSimpleIni::TNamesDepend keys;
            iniFile.GetAllKeys(L"ini_monitor", keys);
            for (const auto& k : keys)
            {
                CString sKey = k;
                CString sSection = sKey.Left(sKey.Find('.'));
                sKey = sKey.Mid(sKey.Find('.') + 1);
                if (sKey.CompareNoCase(L"name") == 0)
                {
                    // make sure the non-synced values are still used
                    monitorIni.SetValue(sSection, L"lastchecked", origMonitorIni.GetValue(sSection, L"lastchecked", L"0"));
                    monitorIni.SetValue(sSection, L"lastcheckedrobots", origMonitorIni.GetValue(sSection, L"lastcheckedrobots", L"0"));
                    monitorIni.SetValue(sSection, L"lastHEAD", origMonitorIni.GetValue(sSection, L"lastHEAD", L"0"));
                    monitorIni.SetValue(sSection, L"UnreadItems", origMonitorIni.GetValue(sSection, L"UnreadItems", L"0"));
                    monitorIni.SetValue(sSection, L"unreadFirst", origMonitorIni.GetValue(sSection, L"unreadFirst", L"0"));
                    monitorIni.SetValue(sSection, L"WCPathOrUrl", origMonitorIni.GetValue(sSection, L"WCPathOrUrl", L""));
                }
                CString sValue = CString(iniFile.GetValue(L"ini_monitor", k, L""));
                if ((sKey.Compare(L"username") == 0) || (sKey.Compare(L"password") == 0))
                {
                    sValue = CStringUtils::Encrypt(sValue);
                }
                monitorIni.SetValue(sSection, sKey, sValue);
            }
            FILE * pFile = NULL;
            errno_t err = 0;
            int retrycount = 5;
            CString sTempfile = CTempFiles::Instance().GetTempFilePathString();
            do
            {
                err = _tfopen_s(&pFile, sTempfile, L"wb");
                if ((err == 0) && pFile)
                {
                    monitorIni.SaveFile(pFile);
                    err = fclose(pFile);
                }
                if (err)
                {
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error saving %s, retrycount %d\n", (LPCWSTR)sTempfile, retrycount);
                    Sleep(500);
                }
            } while (err && retrycount--);
            if (err == 0)
            {
                if (!CopyFile(sTempfile, sDataFilePath, FALSE))
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error copying %s to %s, Error %u\n", (LPCWSTR)sTempfile, (LPCWSTR)sDataFilePath, GetLastError());
                else
                {
                    // now send a message to a possible running monitor to force it
                    // to reload the ini file. Otherwise it would overwrite the ini
                    // file without using the synced data!
                    HWND hWnd = FindWindow(NULL, CString(MAKEINTRESOURCE(IDS_MONITOR_DLGTITLE)));
                    if (hWnd)
                    {
                        UINT TSVN_COMMITMONITOR_RELOADINI = RegisterWindowMessage(L"TSVNCommitMonitor_ReloadIni");
                        PostMessage(hWnd, TSVN_COMMITMONITOR_RELOADINI, 0, 0);
                    }
                }
            }
        }
        else
        {
            CSimpleIni::TNamesDepend mitems;
            if (PathFileExists(sDataFilePath))
            {
                int retrycount = 5;
                SI_Error err = SI_OK;
                do
                {
                    err = monitorIni.LoadFile(sDataFilePath);
                    if (err == SI_FILE)
                    {
                        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error loading %s, retrycount %d\n", (LPCWSTR)sDataFilePath, retrycount);
                        Sleep(500);
                    }
                } while ((err == SI_FILE) && retrycount--);

                if (err == SI_FILE)
                {
                    return false;
                }
                monitorIni.GetAllSections(mitems);
            }

            for (const auto& mitem : mitems)
            {
                CString sSection = mitem;
                CString Name = monitorIni.GetValue(mitem, L"Name", L"");
                if (!Name.IsEmpty())
                {
                    CString newval = monitorIni.GetValue(mitem, L"WCPathOrUrl", L"");
                    iniFile.SetValue(L"ini_monitor", sSection + L".Name", Name);
                    CString oldval = iniFile.GetValue(L"ini_monitor", sSection + L".WCPathOrUrl", L"");
                    bHaveChanges |= ((newval != oldval) && (!oldval.IsEmpty()));
                    // only save monitored working copies if local settings are included, or
                    // if the monitored path is an url.
                    // Don't save paths to working copies for non-local stores
                    if (bWithLocals || newval.IsEmpty() || !PathIsDirectory(newval))
                        iniFile.SetValue(L"ini_monitor", sSection + L".WCPathOrUrl", newval);

                    newval = monitorIni.GetValue(mitem, L"interval", L"5");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".interval", L"0");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".interval", newval);

                    newval = monitorIni.GetValue(mitem, L"minminutesinterval", L"0");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".minminutesinterval", L"0");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".minminutesinterval", newval);

                    newval = CStringUtils::Decrypt(monitorIni.GetValue(mitem, L"username", L"")).get();
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".username", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".username", newval);

                    newval = CStringUtils::Decrypt(monitorIni.GetValue(mitem, L"password", L"")).get();
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".password", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".password", newval);

                    newval = monitorIni.GetValue(mitem, L"MsgRegex", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".MsgRegex", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".MsgRegex", newval);

                    newval = monitorIni.GetValue(mitem, L"ignoreauthors", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".ignoreauthors", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".ignoreauthors", newval);

                    newval = monitorIni.GetValue(mitem, L"parentTreePath", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".parentTreePath", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".parentTreePath", newval);

                    newval = monitorIni.GetValue(mitem, L"uuid", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".uuid", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".uuid", newval);

                    newval = monitorIni.GetValue(mitem, L"root", L"");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".root", L"");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".root", newval);

                    ProjectProperties ProjProps;
                    ProjProps.LoadFromIni(monitorIni, sSection);
                    ProjProps.SaveToIni(iniFile, L"ini_monitor", sSection + L".pp_");
                }
                else if (sSection.CompareNoCase(L"global") == 0)
                {
                    CString newval = monitorIni.GetValue(mitem, L"PlaySound", L"1");
                    CString oldval = iniFile.GetValue(L"ini_monitor", sSection + L".PlaySound", L"1");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".PlaySound", newval);

                    newval = monitorIni.GetValue(mitem, L"ShowNotifications", L"1");
                    oldval = iniFile.GetValue(L"ini_monitor", sSection + L".ShowNotifications", L"1");
                    bHaveChanges |= newval != oldval;
                    iniFile.SetValue(L"ini_monitor", sSection + L".ShowNotifications", newval);
                }
            }
        }
    }

    {
        // sync TortoiseMerge regex filters
        CSimpleIni regexIni;
        regexIni.SetMultiLine(true);
        CString sDataFilePath = CPathUtils::GetAppDataDirectory();
        sDataFilePath += L"\\regexfilters.ini";

        if (bCloudIsNewer)
        {
            CSimpleIni origRegexIni;

            if (PathFileExists(sDataFilePath))
            {
                int retrycount = 5;
                SI_Error err = SI_OK;
                do
                {
                    err = origRegexIni.LoadFile(sDataFilePath);
                    if (err == SI_FILE)
                    {
                        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error loading %s, retrycount %d\n", (LPCWSTR)sDataFilePath, retrycount);
                        Sleep(500);
                    }
                } while ((err == SI_FILE) && retrycount--);

                if (err == SI_FILE)
                {
                    return false;
                }
            }

            CSimpleIni::TNamesDepend keys;
            iniFile.GetAllKeys(L"ini_tmergeregex", keys);
            for (const auto& k : keys)
            {
                CString sKey = k;
                CString sSection = sKey.Left(sKey.Find('.'));
                sKey = sKey.Mid(sKey.Find('.') + 1);
                CString sValue = CString(iniFile.GetValue(L"ini_tmergeregex", k, L""));
                regexIni.SetValue(sSection, sKey, sValue);
            }
            FILE * pFile = NULL;
            errno_t err = 0;
            int retrycount = 5;
            CString sTempfile = CTempFiles::Instance().GetTempFilePathString();
            do
            {
                err = _tfopen_s(&pFile, sTempfile, L"wb");
                if ((err == 0) && pFile)
                {
                    regexIni.SaveFile(pFile);
                    err = fclose(pFile);
                }
                if (err)
                {
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error saving %s, retrycount %d\n", (LPCWSTR)sTempfile, retrycount);
                    Sleep(500);
                }
            } while (err && retrycount--);
            if (err == 0)
            {
                if (!CopyFile(sTempfile, sDataFilePath, FALSE))
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error copying %s to %s, Error: %u\n", (LPCWSTR)sTempfile, (LPCWSTR)sDataFilePath, GetLastError());
            }
        }
        else
        {
            if (PathFileExists(sDataFilePath))
            {
                int retrycount = 5;
                SI_Error err = SI_OK;
                do
                {
                    err = regexIni.LoadFile(sDataFilePath);
                    if (err == SI_FILE)
                    {
                        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error loading %s, retrycount %d\n", (LPCWSTR)sDataFilePath, retrycount);
                        Sleep(500);
                    }
                } while ((err == SI_FILE) && retrycount--);

                if (err == SI_FILE)
                {
                    return false;
                }
            }

            CSimpleIni::TNamesDepend mitems;
            regexIni.GetAllSections(mitems);
            for (const auto& mitem : mitems)
            {
                CString sSection = mitem;

                CString newval = regexIni.GetValue(mitem, L"regex", L"");
                CString oldval = iniFile.GetValue(L"ini_tmergeregex", sSection + L".regex", L"");
                bHaveChanges |= newval != oldval;
                iniFile.SetValue(L"ini_tmergeregex", sSection + L".regex", newval);

                newval = regexIni.GetValue(mitem, L"replace", L"5");
                oldval = iniFile.GetValue(L"ini_tmergeregex", sSection + L".replace", L"0");
                bHaveChanges |= newval != oldval;
                iniFile.SetValue(L"ini_tmergeregex", sSection + L".replace", newval);
            }
        }
    }


    if (bHaveChanges)
    {
        iniFile.SetValue(L"sync", L"version", TSVN_SYNC_VERSION_STR);
        DWORD count = regCount;
        ++count;
        regCount = count;
        CString tmp;
        tmp.Format(L"%lu", count);
        iniFile.SetValue(L"sync", L"synccounter", tmp);

        // save the ini file
        std::string iniData;
        iniFile.SaveString(iniData);
        iniData = "***" + iniData;
        // encrypt the string

        CString password;
        if (parser.HasKey(L"askforpath"))
        {
            CPasswordDlg passDlg(CWnd::FromHandle(GetExplorerHWND()));
            passDlg.m_bForSave = true;
            if (passDlg.DoModal() != IDOK)
                return false;
            password = passDlg.m_sPW1;
        }
        else
        {
            CRegString regPW(L"Software\\TortoiseSVN\\SyncPW");
            auto passwordbuf = CStringUtils::Decrypt(CString(regPW));
            if (passwordbuf.get())
            {
                password = passwordbuf.get();
            }
        }

        std::string passworda = CUnicodeUtils::StdGetUTF8((LPCWSTR)password);

        std::string encrypted = CStringUtils::Encrypt(iniData, passworda);
        CPathUtils::MakeSureDirectoryPathExists(syncPath.GetContainingDirectory().GetWinPathString());
        CString sTempfile = CTempFiles::Instance().GetTempFilePathString();
        CAutoFile hFile = CreateFile(sTempfile, GENERIC_WRITE, FILE_SHARE_READ, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
        if (hFile.IsValid())
        {
            DWORD written = 0;
            if (WriteFile(hFile, encrypted.c_str(), DWORD(encrypted.size()), &written, NULL))
            {
                if (hFile.CloseHandle())
                {
                    if (!CopyFile(sTempfile, syncPath.GetWinPath(), FALSE))
                    {
                        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error copying %s to %s, Error: %u\n", (LPCWSTR)sTempfile, syncPath.GetWinPath(), GetLastError());
                    }
                    else
                        bRet = true;
                }
                else
                    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error closing file %s, Error: %u\n", (LPCWSTR)sTempfile, GetLastError());
            }
            else
                CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error writing to file %s, Error: %u\n", (LPCWSTR)sTempfile, GetLastError());
        }
        else
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Error creating file %s for writing, Error: %u\n", (LPCWSTR)sTempfile, GetLastError());

        if (bSyncAuth)
        {
            // now save all auth data
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth");
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth\\svn.simple");
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth\\svn.ssl.client-passphrase");
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth\\svn.ssl.server");
            CPathUtils::MakeSureDirectoryPathExists(syncFolder.GetWinPathString() + L"\\auth\\svn.username");
            authData.ExportAuthData(syncFolder.GetWinPathString(), password);
        }
    }


    return bRet;
}
Esempio n. 16
0
bool SVNDiff::UnifiedDiff(CTSVNPath& tempfile, const CTSVNPath& url1, const SVNRev& rev1, const CTSVNPath& url2, const SVNRev& rev2, const SVNRev& peg, const CString& options, bool bIgnoreAncestry /* = false */, bool bIgnoreProperties /* = true */)
{
    tempfile = CTempFiles::Instance().GetTempFilePath(m_bRemoveTempFiles, CTSVNPath(L"Test.diff"));
    bool bIsUrl = !!SVN::PathIsURL(url1);

    CProgressDlg progDlg;
    progDlg.SetTitle(IDS_APPNAME);
    progDlg.SetLine(1, CString(MAKEINTRESOURCE(IDS_PROGRESS_UNIFIEDDIFF)));
    progDlg.SetTime(false);
    m_pSVN->SetAndClearProgressInfo(&progDlg);
    progDlg.ShowModeless(GetHWND());
    // find the root of the files
    CTSVNPathList plist;
    plist.AddPath(url1);
    plist.AddPath(url2);
    CTSVNPath relativeTo = plist.GetCommonRoot();
    if (!relativeTo.IsUrl())
    {
        if (!relativeTo.IsDirectory())
            relativeTo = relativeTo.GetContainingDirectory();
    }
    if (relativeTo.IsEmpty() && url1.Exists() && url2.IsUrl())
    {
        // the source path exists, i.e. it's a local path, so
        // use this as the relative url
        relativeTo = url1.GetDirectory();
    }
    // the 'relativeTo' path must be a path: svn throws an error if it's used for urls.
    else if ((!url2.IsEquivalentTo(url1) && (relativeTo.IsEquivalentTo(url1) || relativeTo.IsEquivalentTo(url2))) || url1.IsUrl() || url2.IsUrl())
        relativeTo.Reset();
    if ((!url1.IsEquivalentTo(url2))||((rev1.IsWorking() || rev1.IsBase())&&(rev2.IsWorking() || rev2.IsBase())))
    {
        if (!m_pSVN->Diff(url1, rev1, url2, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, bIgnoreAncestry, tempfile))
        {
            progDlg.Stop();
            m_pSVN->SetAndClearProgressInfo((HWND)NULL);
            m_pSVN->ShowErrorDialog(GetHWND());
            return false;
        }
    }
    else
    {
        if (!m_pSVN->PegDiff(url1, (peg.IsValid() ? peg : (bIsUrl ? m_headPeg : SVNRev::REV_WC)), rev1, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, false, tempfile))
        {
            if (!m_pSVN->Diff(url1, rev1, url2, rev2, relativeTo, svn_depth_infinity, true, false, false, false, false, false, bIgnoreProperties, false, options, false, tempfile))
            {
                progDlg.Stop();
                m_pSVN->SetAndClearProgressInfo((HWND)NULL);
                m_pSVN->ShowErrorDialog(GetHWND());
                return false;
            }
        }
    }
    if (CAppUtils::CheckForEmptyDiff(tempfile))
    {
        progDlg.Stop();
        m_pSVN->SetAndClearProgressInfo((HWND)NULL);
        TaskDialog(GetHWND(), AfxGetResourceHandle(), MAKEINTRESOURCE(IDS_APPNAME), MAKEINTRESOURCE(IDS_ERR_ERROROCCURED), MAKEINTRESOURCE(IDS_ERR_EMPTYDIFF), TDCBF_OK_BUTTON, TD_ERROR_ICON, NULL);
        return false;
    }
    progDlg.Stop();
    m_pSVN->SetAndClearProgressInfo((HWND)NULL);
    return true;
}
Esempio n. 17
0
void CShellUpdater::WorkerThread()
{
    HANDLE hWaitHandles[2];
    hWaitHandles[0] = m_hTerminationEvent;
    hWaitHandles[1] = m_hWakeEvent;

    for(;;)
    {
        DWORD waitResult = WaitForMultipleObjects(_countof(hWaitHandles), hWaitHandles, FALSE, INFINITE);

        // exit event/working loop if the first event (m_hTerminationEvent)
        // has been signaled or if one of the events has been abandoned
        // (i.e. ~CShellUpdater() is being executed)
        if(waitResult == WAIT_OBJECT_0 || waitResult == WAIT_ABANDONED_0 || waitResult == WAIT_ABANDONED_0+1)
        {
            // Termination event
            break;
        }
        // wait some time before we notify the shell
        Sleep(50);
        for(;;)
        {
            CTSVNPath workingPath;
            if (!m_bRunning)
                return;
            Sleep(0);
            {
                AutoLocker lock(m_critSec);
                if(m_pathsToUpdate.empty())
                {
                    // Nothing left to do
                    break;
                }
                
                if(InterlockedExchange(&m_bItemsAddedSinceLastUpdate, FALSE))
                {
                    m_pathsToUpdate.erase(std::unique(m_pathsToUpdate.begin(), m_pathsToUpdate.end(), &CTSVNPath::PredLeftEquivalentToRight), m_pathsToUpdate.end());
                }

                workingPath = m_pathsToUpdate.front();
                m_pathsToUpdate.pop_front();
            }
            if (workingPath.IsEmpty())
                continue;
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": shell notification for %s\n", workingPath.GetWinPath());
            if (workingPath.IsDirectory())
            {
                // first send a notification about a sub folder change, so explorer doesn't discard
                // the folder notification. Since we only know for sure that the subversion admin
                // dir is present, we send a notification for that folder.
                CString admindir = workingPath.GetWinPathString() + L"\\" + g_SVNAdminDir.GetAdminDirName();
                SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, (LPCTSTR)admindir, NULL);
                SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL);
                // Sending an UPDATEDIR notification somehow overwrites/deletes the UPDATEITEM message. And without
                // that message, the folder overlays in the current view don't get updated without hitting F5.
                // Drawback is, without UPDATEDIR, the left tree view isn't always updated...

                //SHChangeNotify(SHCNE_UPDATEDIR, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL);
            }
            else
                SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH | SHCNF_FLUSHNOWAIT, workingPath.GetWinPath(), NULL);
        }
    }
    _endthread();
}
Esempio n. 18
0
CStatusCacheEntry CSVNStatusCache::GetStatusForPath(const CTSVNPath& path, DWORD flags,  bool bFetch /* = true */)
{
    bool bRecursive = !!(flags & TSVNCACHE_FLAGS_RECUSIVE_STATUS);

    // Check a very short-lived 'mini-cache' of the last thing we were asked for.
    LONGLONG now = (LONGLONG)GetTickCount64();
    if(now-m_mostRecentExpiresAt < 0)
    {
        if(path.IsEquivalentToWithoutCase(m_mostRecentAskedPath))
        {
            return m_mostRecentStatus;
        }
    }
    {
        AutoLocker lock(m_critSec);
        m_mostRecentAskedPath = path;
        m_mostRecentExpiresAt = now+1000;
    }

    if (m_shellCache.IsPathAllowed(path.GetWinPath()))
    {
        if (IsPathGood(path))
        {
            // Stop the crawler starting on a new folder while we're doing this much more important task...
            // Please note, that this may be a second "lock" used concurrently to the one in RemoveCacheForPath().
            CCrawlInhibitor crawlInhibit(&m_folderCrawler);

            CTSVNPath dirpath = path.GetContainingDirectory();
            if (dirpath.IsEmpty())
                dirpath = path.GetDirectory();
            CCachedDirectory * cachedDir = GetDirectoryCacheEntry(dirpath);
            if (cachedDir != NULL)
            {
                CStatusCacheEntry entry = cachedDir->GetStatusForMember(path, bRecursive, bFetch);
                {
                    AutoLocker lock(m_critSec);
                    m_mostRecentStatus = entry;
                    return m_mostRecentStatus;
                }
            }
            cachedDir = GetDirectoryCacheEntry(path.GetDirectory());
            if (cachedDir != NULL)
            {
                CStatusCacheEntry entry = cachedDir->GetStatusForMember(path, bRecursive, bFetch);
                {
                    AutoLocker lock(m_critSec);
                    m_mostRecentStatus = entry;
                    return m_mostRecentStatus;
                }
            }

        }
        else
        {
            // path is blocked for some reason: return the cached status if we have one
            // we do here only a cache search, absolutely no disk access is allowed!
            CCachedDirectory::ItDir itMap = m_directoryCache.find(path);
            if ((itMap != m_directoryCache.end())&&(itMap->second))
            {
                // We've found this directory in the cache
                CCachedDirectory * cachedDir = itMap->second;
                CStatusCacheEntry entry = cachedDir->GetCacheStatusForMember(path);
                {
                    AutoLocker lock(m_critSec);
                    m_mostRecentStatus = entry;
                    return m_mostRecentStatus;
                }
            }

        }
    }
    AutoLocker lock(m_critSec);
    m_mostRecentStatus = CStatusCacheEntry();
    if (m_shellCache.ShowExcludedAsNormal() && path.IsDirectory() && m_shellCache.IsVersioned(path.GetWinPath(), true, true))
    {
        m_mostRecentStatus.ForceStatus(svn_wc_status_normal);
    }
    return m_mostRecentStatus;
}
Esempio n. 19
0
//////////////////////////////////////////////////////////////////////////
// IDataObject
//////////////////////////////////////////////////////////////////////////
STDMETHODIMP SVNDataObject::GetData(FORMATETC* pformatetcIn, STGMEDIUM* pmedium)
{
	if (pformatetcIn == NULL)
		return E_INVALIDARG;
	if (pmedium == NULL)
		return E_POINTER;
	pmedium->hGlobal = NULL;

	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

		// 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.
		CTSVNPath filepath;
		IStream * pIStream = NULL;
		if (m_revision.IsWorking())
		{
			if ((pformatetcIn->lindex >= 0)&&(pformatetcIn->lindex < (LONG)m_allPaths.size()))
			{
				filepath = m_allPaths[pformatetcIn->lindex].rootpath;
			}
		}
		else
		{
			filepath = CTempFiles::Instance().GetTempFilePath(true);
			if ((pformatetcIn->lindex >= 0)&&(pformatetcIn->lindex < (LONG)m_allPaths.size()))
			{
				if (!m_svn.Cat(CTSVNPath(m_allPaths[pformatetcIn->lindex].infodata.url), m_pegRev, m_revision, filepath))
				{
					DeleteFile(filepath.GetWinPath());
					return STG_E_ACCESSDENIED;
				}
			}
		}
		HRESULT res = SHCreateStreamOnFile(filepath.GetWinPath(), STGM_READ, &pIStream);
		if (res == S_OK)
		{
			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))
	{
		// now it is time to get all sub folders for the directories we have
		SVNInfo svnInfo;
		// find the common directory of all the paths
		CTSVNPath commonDir;
		bool bAllUrls = true;
		for (int i=0; i<m_svnPaths.GetCount(); ++i)
		{
			if (!m_svnPaths[i].IsUrl())
				bAllUrls = false;
			if (commonDir.IsEmpty())
				commonDir = m_svnPaths[i].GetContainingDirectory();
			if (!commonDir.IsEquivalentTo(m_svnPaths[i].GetContainingDirectory()))
			{
				commonDir.Reset();
				break;
			}
		}
		if (bAllUrls && (m_svnPaths.GetCount() > 1) && !commonDir.IsEmpty())
		{
			// if all paths are in the same directory, we can fetch the info recursively
			// from the parent folder to save a lot of time.
			const SVNInfoData * infodata = svnInfo.GetFirstFileInfo(commonDir, m_pegRev, m_revision, svn_depth_infinity);
			while (infodata)
			{
				// check if the returned item is one in our list
				for (int i=0; i<m_svnPaths.GetCount(); ++i)
				{
					if (m_svnPaths[i].IsAncestorOf(CTSVNPath(infodata->url)))
					{
						SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], *infodata};
						m_allPaths.push_back(id);
						break;
					}
				}
				infodata = svnInfo.GetNextFileInfo();
			}
		}
		else
		{
			for (int i = 0; i < m_svnPaths.GetCount(); ++i)
			{
				if (m_svnPaths[i].IsUrl())
				{
					const SVNInfoData * infodata = svnInfo.GetFirstFileInfo(m_svnPaths[i], m_pegRev, m_revision, svn_depth_infinity);
					while (infodata)
					{
						SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], *infodata};
						m_allPaths.push_back(id);
						infodata = svnInfo.GetNextFileInfo();
					}
				}
				else
				{
					SVNDataObject::SVNObjectInfoData id = {m_svnPaths[i], SVNInfoData()};
					m_allPaths.push_back(id);
				}
			}
		}
		size_t dataSize = sizeof(FILEGROUPDESCRIPTOR) + ((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 (vector<SVNDataObject::SVNObjectInfoData>::const_iterator it = m_allPaths.begin(); it != m_allPaths.end(); ++it)
		{
			CString temp;
			if (it->rootpath.IsUrl())
			{
				temp = CUnicodeUtils::GetUnicode(CPathUtils::PathEscape(CUnicodeUtils::GetUTF8(it->rootpath.GetContainingDirectory().GetSVNPathString())));
				temp = it->infodata.url.Mid(temp.GetLength()+1);
				// we have to unescape the urls since the local file system doesn't need them
				// escaped and it would only look really ugly (and be wrong).
				temp = CPathUtils::PathUnescape(temp);
			}
			else
			{
				temp = it->rootpath.GetUIFileOrDirectoryName();
			}
			_tcscpy_s(files->fgd[index].cFileName, MAX_PATH, (LPCTSTR)temp);
			files->fgd[index].dwFlags = FD_ATTRIBUTES | FD_PROGRESSUI | FD_FILESIZE | FD_LINKUI;
			if (it->rootpath.IsUrl())
			{
				files->fgd[index].dwFileAttributes = (it->infodata.kind == svn_node_dir) ? FILE_ATTRIBUTE_DIRECTORY : FILE_ATTRIBUTE_NORMAL;
			}
			else
			{
				files->fgd[index].dwFileAttributes = it->rootpath.IsDirectory() ? FILE_ATTRIBUTE_DIRECTORY : 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_svnPaths.GetCount())
		{
			// create a single string where the URLs are separated by newlines
			for (int i=0; i<m_svnPaths.GetCount(); ++i)
			{
				if (m_svnPaths[i].IsUrl())
					text += m_svnPaths[i].GetSVNPathString();
				else
					text += m_svnPaths[i].GetWinPathString();
				text += _T("\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 = NULL;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_UNICODETEXT))
	{
		// caller wants Unicode text
		// create the string from the path list
		CString text;
		if (m_svnPaths.GetCount())
		{
			// create a single string where the URLs are separated by newlines
			for (int i=0; i<m_svnPaths.GetCount(); ++i)
			{
				if (m_svnPaths[i].IsUrl())
					text += m_svnPaths[i].GetSVNPathString();
				else
					text += m_svnPaths[i].GetWinPathString();
				text += _T("\r\n");
			}
		}
		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GHND, (text.GetLength()+1)*sizeof(TCHAR));
		if (pmedium->hGlobal)
		{
			TCHAR* pMem = (TCHAR*)GlobalLock(pmedium->hGlobal);
			_tcscpy_s(pMem, text.GetLength()+1, (LPCTSTR)text);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = NULL;
		return S_OK;
	}
	else if ((pformatetcIn->tymed & TYMED_HGLOBAL) && (pformatetcIn->dwAspect == DVASPECT_CONTENT) && (pformatetcIn->cfFormat == CF_SVNURL))
	{
		// caller wants the svn url
		// create the string from the path list
		CString text;
		if (m_svnPaths.GetCount())
		{
			// create a single string where the URLs are separated by newlines
			for (int i=0; i<m_svnPaths.GetCount(); ++i)
			{
				if (m_svnPaths[i].IsUrl())
				{
					text += m_svnPaths[i].GetSVNPathString();
					text += _T("?");
					text += m_revision.ToString();
				}
				else
					text += m_svnPaths[i].GetWinPathString();
				text += _T("\r\n");
			}
		}
		pmedium->tymed = TYMED_HGLOBAL;
		pmedium->hGlobal = GlobalAlloc(GHND, (text.GetLength()+1)*sizeof(TCHAR));
		if (pmedium->hGlobal)
		{
			TCHAR* pMem = (TCHAR*)GlobalLock(pmedium->hGlobal);
			_tcscpy_s(pMem, text.GetLength()+1, (LPCTSTR)text);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = NULL;
		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_svnPaths.GetCount();i++)
		{
			nLength += m_svnPaths[i].GetWinPathString().GetLength();
			nLength += 1; // '\0' separator
		}

		int nBufferSize = sizeof(DROPFILES) + (nLength+1)*sizeof(TCHAR);
		char * pBuffer = new char[nBufferSize];

		SecureZeroMemory(pBuffer, nBufferSize);

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

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

		for (int i=0;i<m_svnPaths.GetCount();i++)
		{
			CString str = m_svnPaths[i].GetWinPathString();
			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, nBufferSize);
			GlobalUnlock(pmedium->hGlobal);
		}
		pmedium->pUnkForRelease = NULL;
		delete [] pBuffer;
		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;
}
Esempio n. 20
0
bool CDirectoryWatcher::AddPath(const CTSVNPath& path, bool bCloseInfoMap)
{
    if (!CSVNStatusCache::Instance().IsPathAllowed(path))
        return false;
    if ((!blockedPath.IsEmpty())&&(blockedPath.IsAncestorOf(path)))
    {
        if (GetTickCount64() < blockTickCount)
        {
            CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Path %s prevented from being watched\n", path.GetWinPath());
            return false;
        }
    }

    // ignore the recycle bin
    PTSTR pFound = StrStrI(path.GetWinPath(), L":\\RECYCLER");
    if (pFound != NULL)
    {
        if ((*(pFound + 10) == '\0') || (*(pFound + 10) == '\\'))
            return false;
    }
    pFound = StrStrI(path.GetWinPath(), L":\\$Recycle.Bin");
    if (pFound != NULL)
    {
        if ((*(pFound + 14) == '\0') || (*(pFound + 14) == '\\'))
            return false;
    }

    AutoLocker lock(m_critSec);
    for (int i=0; i<watchedPaths.GetCount(); ++i)
    {
        if (watchedPaths[i].IsAncestorOf(path))
            return false;       // already watched (recursively)
    }

    // now check if with the new path we might have a new root
    CTSVNPath newroot;
    for (int i=0; i<watchedPaths.GetCount(); ++i)
    {
        const CString& watched = watchedPaths[i].GetWinPathString();
        const CString& sPath = path.GetWinPathString();
        int minlen = min(sPath.GetLength(), watched.GetLength());
        int len = 0;
        for (len = 0; len < minlen; ++len)
        {
            if (watched.GetAt(len) != sPath.GetAt(len))
            {
                if ((len > 1)&&(len < minlen))
                {
                    if (sPath.GetAt(len)=='\\')
                    {
                        newroot = CTSVNPath(sPath.Left(len));
                    }
                    else if (watched.GetAt(len)=='\\')
                    {
                        newroot = CTSVNPath(watched.Left(len));
                    }
                }
                break;
            }
        }
        if (len == minlen)
        {
            if (sPath.GetLength() == minlen)
            {
                if (watched.GetLength() > minlen)
                {
                    if (watched.GetAt(len)=='\\')
                    {
                        newroot = path;
                    }
                    else if (sPath.GetLength() == 3 && sPath[1] == ':')
                    {
                        newroot = path;
                    }
                }
            }
            else
            {
                if (sPath.GetLength() > minlen)
                {
                    if (sPath.GetAt(len)=='\\')
                    {
                        newroot = CTSVNPath(watched);
                    }
                    else if (watched.GetLength() == 3 && watched[1] == ':')
                    {
                        newroot = CTSVNPath(watched);
                    }
                }
            }
        }
    }
    if (!newroot.IsEmpty() && SVNHelper::IsVersioned(newroot, false))
    {
        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": AddPath for %s\n", newroot.GetWinPath());
        watchedPaths.AddPath(newroot);
        watchedPaths.RemoveChildren();
        if (bCloseInfoMap)
            ClearInfoMap();

        return true;
    }
    if (!SVNHelper::IsVersioned(path, false))
    {
        CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": Path %s prevented from being watched: not versioned\n", path.GetWinPath());
        return false;
    }
    CTraceToOutputDebugString::Instance()(_T(__FUNCTION__) L": AddPath for %s\n", path.GetWinPath());
    watchedPaths.AddPath(path);
    if (bCloseInfoMap)
        ClearInfoMap();

    return true;
}