Use ArePathStringsEqualWithCase for comparing paths
[TortoiseGit.git] / src / TGitCache / CacheInterface.cpp
blob6d0361446b5b42114bbaa209be13da937651507f
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(_T("-%08x%08x"), uid.HighPart, uid.LowPart);
57 return t;
60 bool SendCacheCommand(BYTE command, const WCHAR* path /* = nullptr */)
62 int retrycount = 2;
63 CAutoFile hPipe;
64 CString pipeName = GetCacheCommandPipeName();
65 for (int retry = 0; retry < 2; ++retry)
67 if (retry > 0)
68 WaitNamedPipe(pipeName, 50);
70 hPipe = CreateFile(
71 pipeName, // pipe name
72 GENERIC_READ | // read and write access
73 GENERIC_WRITE,
74 0, // no sharing
75 nullptr, // default security attributes
76 OPEN_EXISTING, // opens existing pipe
77 FILE_FLAG_OVERLAPPED, // default attributes
78 nullptr); // no template file
80 if (!hPipe && GetLastError() == ERROR_PIPE_BUSY)
82 // TGitCache is running but is busy connecting a different client.
83 // Do not give up immediately but wait for a few milliseconds until
84 // the server has created the next pipe instance
85 continue;
87 break;
90 if (!hPipe)
92 CTraceToOutputDebugString::Instance()(__FUNCTION__ ": Could not connect to pipe\n");
93 return false;
96 // The pipe connected; change to message-read mode.
97 DWORD dwMode = PIPE_READMODE_MESSAGE;
98 if (SetNamedPipeHandleState(
99 hPipe, // pipe handle
100 &dwMode, // new pipe mode
101 nullptr, // don't set maximum bytes
102 nullptr)) // don't set maximum time
104 DWORD cbWritten;
105 TGITCacheCommand cmd = { 0 };
106 cmd.command = command;
107 if (path)
108 _tcsncpy_s(cmd.path, path, _TRUNCATE);
110 retrycount = 2;
111 BOOL fSuccess = FALSE;
114 fSuccess = WriteFile(
115 hPipe, // handle to pipe
116 &cmd, // buffer to write from
117 sizeof(cmd), // number of bytes to write
118 &cbWritten, // number of bytes written
119 nullptr); // not overlapped I/O
120 retrycount--;
121 if (! fSuccess || sizeof(cmd) != cbWritten)
122 Sleep(10);
123 } while ((retrycount) && (! fSuccess || sizeof(cmd) != cbWritten));
125 if (! fSuccess || sizeof(cmd) != cbWritten)
127 CTraceToOutputDebugString::Instance()(__FUNCTION__ ": Could not write to pipe\n");
128 DisconnectNamedPipe(hPipe);
129 return false;
131 // now tell the cache we don't need it's command thread anymore
132 SecureZeroMemory(&cmd, sizeof(TGITCacheCommand));
133 cmd.command = TGITCACHECOMMAND_END;
134 WriteFile(
135 hPipe, // handle to pipe
136 &cmd, // buffer to write from
137 sizeof(cmd), // number of bytes to write
138 &cbWritten, // number of bytes written
139 nullptr); // not overlapped I/O
140 DisconnectNamedPipe(hPipe);
142 else
144 CTraceToOutputDebugString::Instance()(__FUNCTION__ ": SetNamedPipeHandleState failed");
145 return false;
148 return true;
151 CBlockCacheForPath::CBlockCacheForPath(const WCHAR * aPath)
152 : m_bBlocked(false)
154 wcsncpy_s(path, aPath, _countof(path) - 1);
156 if (!SendCacheCommand(TGITCACHECOMMAND_BLOCK, path))
157 return;
159 // Wait a short while to make sure the cache has
160 // processed this command. Without this, we risk
161 // executing the svn command before the cache has
162 // blocked the path and already gets change notifications.
163 Sleep(20);
164 m_bBlocked = true;
167 CBlockCacheForPath::~CBlockCacheForPath()
169 if (!m_bBlocked)
170 return;
172 for (int retry = 0; retry < 3; ++retry)
174 if (retry > 0)
175 Sleep(10);
177 if (SendCacheCommand(TGITCACHECOMMAND_UNBLOCK, path))
178 break;