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.
21 #include "CacheInterface.h"
22 #include "SmartHandle.h"
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();
43 CAutoGeneralHandle token
;
44 BOOL result
= OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY
, token
.GetPointer());
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
);
60 bool SendCacheCommand(BYTE command
, const WCHAR
* path
/* = nullptr */)
63 CString pipeName
= GetCacheCommandPipeName();
64 for (int retry
= 0; retry
< 2; ++retry
)
67 WaitNamedPipe(pipeName
, 50);
70 pipeName
, // pipe name
71 GENERIC_READ
| // read and write access
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
91 CTraceToOutputDebugString::Instance()(__FUNCTION__
": Could not connect to pipe\n");
95 // The pipe connected; change to message-read mode.
96 DWORD dwMode
= PIPE_READMODE_MESSAGE
;
97 if (SetNamedPipeHandleState(
99 &dwMode
, // new pipe mode
100 nullptr, // don't set maximum bytes
101 nullptr)) // don't set maximum time
104 TGITCacheCommand cmd
= { 0 };
105 cmd
.command
= command
;
107 wcsncpy_s(cmd
.path
, path
, _TRUNCATE
);
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
120 if (! fSuccess
|| sizeof(cmd
) != cbWritten
)
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
);
130 // now tell the cache we don't need it's command thread anymore
131 SecureZeroMemory(&cmd
, sizeof(TGITCacheCommand
));
132 cmd
.command
= TGITCACHECOMMAND_END
;
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
);
143 CTraceToOutputDebugString::Instance()(__FUNCTION__
": SetNamedPipeHandleState failed");
150 CBlockCacheForPath::CBlockCacheForPath(const WCHAR
* aPath
)
153 wcsncpy_s(path
, aPath
, _countof(path
) - 1);
155 if (!SendCacheCommand(TGITCACHECOMMAND_BLOCK
, path
))
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.
166 CBlockCacheForPath::~CBlockCacheForPath()
171 for (int retry
= 0; retry
< 3; ++retry
)
176 if (SendCacheCommand(TGITCACHECOMMAND_UNBLOCK
, path
))