TortoiseGitBlame: Diff shown in wrong order
[TortoiseGit.git] / src / TGitCache / CacheInterface.cpp
blob5a071f54391832f6908a8447acdfde32e0ec20a4
1 // TortoiseGit - a Windows shell extension for easy version control
3 // External Cache Copyright (C) 2007,2009-2012 - TortoiseSVN
4 // Copyright (C) 2008-2013, 2016 - TortoiseGit
6 // This program is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU General Public License
8 // as published by the Free Software Foundation; either version 2
9 // of the License, or (at your option) any later version.
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 // GNU General Public License for more details.
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software Foundation,
18 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 #include "stdafx.h"
21 #include "CacheInterface.h"
22 #include "SmartHandle.h"
23 #include <memory>
25 CString GetCachePipeName()
27 return TGIT_CACHE_PIPE_NAME + GetCacheID();
30 CString GetCacheCommandPipeName()
32 return TGIT_CACHE_COMMANDPIPE_NAME + GetCacheID();
35 CString GetCacheMutexName()
37 return TGIT_CACHE_MUTEX_NAME + GetCacheID();
40 CString GetCacheID()
42 CString t;
43 CAutoGeneralHandle token;
44 BOOL result = OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, token.GetPointer());
45 if(result)
47 DWORD len = 0;
48 GetTokenInformation(token, TokenStatistics, nullptr, 0, &len);
49 if (len >= sizeof (TOKEN_STATISTICS))
51 auto data = std::make_unique<BYTE[]>(len);
52 GetTokenInformation(token, TokenStatistics, data.get(), len, &len);
53 LUID uid = ((PTOKEN_STATISTICS)data.get())->AuthenticationId;
54 t.Format(L"-%08x%08x", uid.HighPart, uid.LowPart);
57 return t;
60 bool SendCacheCommand(BYTE command, const WCHAR* path /* = nullptr */)
62 CAutoFile hPipe;
63 CString pipeName = GetCacheCommandPipeName();
64 for (int retry = 0; retry < 2; ++retry)
66 if (retry > 0)
67 WaitNamedPipe(pipeName, 50);
69 hPipe = CreateFile(
70 pipeName, // pipe name
71 GENERIC_READ | // read and write access
72 GENERIC_WRITE,
73 0, // no sharing
74 nullptr, // default security attributes
75 OPEN_EXISTING, // opens existing pipe
76 FILE_FLAG_OVERLAPPED, // default attributes
77 nullptr); // no template file
79 if (!hPipe && GetLastError() == ERROR_PIPE_BUSY)
81 // TGitCache is running but is busy connecting a different client.
82 // Do not give up immediately but wait for a few milliseconds until
83 // the server has created the next pipe instance
84 continue;
86 break;
89 if (!hPipe)
91 CTraceToOutputDebugString::Instance()(__FUNCTION__ ": Could not connect to pipe\n");
92 return false;
95 // The pipe connected; change to message-read mode.
96 DWORD dwMode = PIPE_READMODE_MESSAGE;
97 if (SetNamedPipeHandleState(
98 hPipe, // pipe handle
99 &dwMode, // new pipe mode
100 nullptr, // don't set maximum bytes
101 nullptr)) // don't set maximum time
103 DWORD cbWritten;
104 TGITCacheCommand cmd = { 0 };
105 cmd.command = command;
106 if (path)
107 wcsncpy_s(cmd.path, path, _TRUNCATE);
109 int retrycount = 2;
110 BOOL fSuccess = FALSE;
113 fSuccess = WriteFile(
114 hPipe, // handle to pipe
115 &cmd, // buffer to write from
116 sizeof(cmd), // number of bytes to write
117 &cbWritten, // number of bytes written
118 nullptr); // not overlapped I/O
119 retrycount--;
120 if (! fSuccess || sizeof(cmd) != cbWritten)
121 Sleep(10);
122 } while ((retrycount) && (! fSuccess || sizeof(cmd) != cbWritten));
124 if (! fSuccess || sizeof(cmd) != cbWritten)
126 CTraceToOutputDebugString::Instance()(__FUNCTION__ ": Could not write to pipe\n");
127 DisconnectNamedPipe(hPipe);
128 return false;
130 // now tell the cache we don't need it's command thread anymore
131 SecureZeroMemory(&cmd, sizeof(TGITCacheCommand));
132 cmd.command = TGITCACHECOMMAND_END;
133 WriteFile(
134 hPipe, // handle to pipe
135 &cmd, // buffer to write from
136 sizeof(cmd), // number of bytes to write
137 &cbWritten, // number of bytes written
138 nullptr); // not overlapped I/O
139 DisconnectNamedPipe(hPipe);
141 else
143 CTraceToOutputDebugString::Instance()(__FUNCTION__ ": SetNamedPipeHandleState failed");
144 return false;
147 return true;
150 CBlockCacheForPath::CBlockCacheForPath(const WCHAR * aPath)
151 : m_bBlocked(false)
153 wcsncpy_s(path, aPath, _countof(path) - 1);
155 if (!SendCacheCommand(TGITCACHECOMMAND_BLOCK, path))
156 return;
158 // Wait a short while to make sure the cache has
159 // processed this command. Without this, we risk
160 // executing the svn command before the cache has
161 // blocked the path and already gets change notifications.
162 Sleep(20);
163 m_bBlocked = true;
166 CBlockCacheForPath::~CBlockCacheForPath()
168 if (!m_bBlocked)
169 return;
171 for (int retry = 0; retry < 3; ++retry)
173 if (retry > 0)
174 Sleep(10);
176 if (SendCacheCommand(TGITCACHECOMMAND_UNBLOCK, path))
177 break;