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(_T("-%08x%08x"), uid
.HighPart
, uid
.LowPart
);
60 bool SendCacheCommand(BYTE command
, const WCHAR
* path
/* = nullptr */)
64 CString pipeName
= GetCacheCommandPipeName();
65 for (int retry
= 0; retry
< 2; ++retry
)
68 WaitNamedPipe(pipeName
, 50);
71 pipeName
, // pipe name
72 GENERIC_READ
| // read and write access
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
92 CTraceToOutputDebugString::Instance()(__FUNCTION__
": Could not connect to pipe\n");
96 // The pipe connected; change to message-read mode.
97 DWORD dwMode
= PIPE_READMODE_MESSAGE
;
98 if (SetNamedPipeHandleState(
100 &dwMode
, // new pipe mode
101 nullptr, // don't set maximum bytes
102 nullptr)) // don't set maximum time
105 TGITCacheCommand cmd
= { 0 };
106 cmd
.command
= command
;
108 _tcsncpy_s(cmd
.path
, path
, _TRUNCATE
);
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
121 if (! fSuccess
|| sizeof(cmd
) != cbWritten
)
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
);
131 // now tell the cache we don't need it's command thread anymore
132 SecureZeroMemory(&cmd
, sizeof(TGITCacheCommand
));
133 cmd
.command
= TGITCACHECOMMAND_END
;
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
);
144 CTraceToOutputDebugString::Instance()(__FUNCTION__
": SetNamedPipeHandleState failed");
151 CBlockCacheForPath::CBlockCacheForPath(const WCHAR
* aPath
)
154 wcsncpy_s(path
, aPath
, _countof(path
) - 1);
156 if (!SendCacheCommand(TGITCACHECOMMAND_BLOCK
, path
))
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.
167 CBlockCacheForPath::~CBlockCacheForPath()
172 for (int retry
= 0; retry
< 3; ++retry
)
177 if (SendCacheCommand(TGITCACHECOMMAND_UNBLOCK
, path
))