1 // TortoiseSVN - a Windows shell extension for easy version control
\r
3 // External Cache Copyright (C) 2005-2006,2008 - TortoiseSVN
\r
5 // This program is free software; you can redistribute it and/or
\r
6 // modify it under the terms of the GNU General Public License
\r
7 // as published by the Free Software Foundation; either version 2
\r
8 // of the License, or (at your option) any later version.
\r
10 // This program is distributed in the hope that it will be useful,
\r
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
13 // GNU General Public License for more details.
\r
15 // You should have received a copy of the GNU General Public License
\r
16 // along with this program; if not, write to the Free Software Foundation,
\r
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
\r
20 #include ".\statuscacheentry.h"
\r
21 #include "GitStatus.h"
\r
22 #include "CacheInterface.h"
\r
23 #include "registry.h"
\r
25 DWORD cachetimeout = (DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\Cachetimeout"), CACHETIMEOUT);
\r
27 CStatusCacheEntry::CStatusCacheEntry()
\r
29 , m_bSVNEntryFieldSet(false)
\r
30 // , m_kind(svn_node_unknown)
\r
31 , m_bReadOnly(false)
\r
32 , m_highestPriorityLocalStatus(git_wc_status_none)
\r
37 CStatusCacheEntry::CStatusCacheEntry(const git_wc_status2_t* pGitStatus, __int64 lastWriteTime, bool bReadOnly, DWORD validuntil /* = 0*/)
\r
39 , m_bSVNEntryFieldSet(false)
\r
40 // , m_kind(svn_node_unknown)
\r
41 , m_bReadOnly(false)
\r
42 , m_highestPriorityLocalStatus(git_wc_status_none)
\r
44 SetStatus(pGitStatus);
\r
45 m_lastWriteTime = lastWriteTime;
\r
47 m_discardAtTime = validuntil;
\r
49 m_discardAtTime = GetTickCount()+cachetimeout;
\r
50 m_bReadOnly = bReadOnly;
\r
53 bool CStatusCacheEntry::SaveToDisk(FILE * pFile)
\r
55 #define WRITEVALUETOFILE(x) if (fwrite(&x, sizeof(x), 1, pFile)!=1) return false;
\r
56 #define WRITESTRINGTOFILE(x) if (x.IsEmpty()) {value=0;WRITEVALUETOFILE(value);}else{value=x.GetLength();WRITEVALUETOFILE(value);if (fwrite((LPCSTR)x, sizeof(char), value, pFile)!=value) return false;}
\r
58 unsigned int value = 4;
\r
59 WRITEVALUETOFILE(value); // 'version' of this save-format
\r
60 WRITEVALUETOFILE(m_highestPriorityLocalStatus);
\r
61 WRITEVALUETOFILE(m_lastWriteTime);
\r
62 WRITEVALUETOFILE(m_bSet);
\r
63 WRITEVALUETOFILE(m_bSVNEntryFieldSet);
\r
64 WRITEVALUETOFILE(m_commitRevision);
\r
65 WRITESTRINGTOFILE(m_sUrl);
\r
66 WRITESTRINGTOFILE(m_sOwner);
\r
67 WRITESTRINGTOFILE(m_sAuthor);
\r
68 // WRITEVALUETOFILE(m_kind);
\r
69 WRITEVALUETOFILE(m_bReadOnly);
\r
70 WRITESTRINGTOFILE(m_sPresentProps);
\r
72 // now save the status struct (without the entry field, because we don't use that) WRITEVALUETOFILE(m_GitStatus.copied);
\r
73 // WRITEVALUETOFILE(m_GitStatus.locked);
\r
74 // WRITEVALUETOFILE(m_GitStatus.prop_status);
\r
75 // WRITEVALUETOFILE(m_GitStatus.repos_prop_status);
\r
76 // WRITEVALUETOFILE(m_GitStatus.repos_text_status);
\r
77 // WRITEVALUETOFILE(m_GitStatus.switched);
\r
78 // WRITEVALUETOFILE(m_GitStatus.text_status);
\r
82 bool CStatusCacheEntry::LoadFromDisk(FILE * pFile)
\r
84 #define LOADVALUEFROMFILE(x) if (fread(&x, sizeof(x), 1, pFile)!=1) return false;
\r
87 unsigned int value = 0;
\r
88 LOADVALUEFROMFILE(value);
\r
90 return false; // not the correct version
\r
91 LOADVALUEFROMFILE(m_highestPriorityLocalStatus);
\r
92 LOADVALUEFROMFILE(m_lastWriteTime);
\r
93 LOADVALUEFROMFILE(m_bSet);
\r
94 LOADVALUEFROMFILE(m_bSVNEntryFieldSet);
\r
95 LOADVALUEFROMFILE(m_commitRevision);
\r
96 LOADVALUEFROMFILE(value);
\r
99 if (value > INTERNET_MAX_URL_LENGTH)
\r
100 return false; // invalid length for an url
\r
101 if (fread(m_sUrl.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
\r
103 m_sUrl.ReleaseBuffer(0);
\r
106 m_sUrl.ReleaseBuffer(value);
\r
108 LOADVALUEFROMFILE(value);
\r
111 if (fread(m_sOwner.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
\r
113 m_sOwner.ReleaseBuffer(0);
\r
116 m_sOwner.ReleaseBuffer(value);
\r
118 LOADVALUEFROMFILE(value);
\r
121 if (fread(m_sAuthor.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
\r
123 m_sAuthor.ReleaseBuffer(0);
\r
126 m_sAuthor.ReleaseBuffer(value);
\r
128 // LOADVALUEFROMFILE(m_kind);
\r
129 LOADVALUEFROMFILE(m_bReadOnly);
\r
130 LOADVALUEFROMFILE(value);
\r
133 if (fread(m_sPresentProps.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
\r
135 m_sPresentProps.ReleaseBuffer(0);
\r
138 m_sPresentProps.ReleaseBuffer(value);
\r
140 SecureZeroMemory(&m_GitStatus, sizeof(m_GitStatus));
\r
141 // LOADVALUEFROMFILE(m_GitStatus.copied);
\r
142 // LOADVALUEFROMFILE(m_GitStatus.locked);
\r
143 // LOADVALUEFROMFILE(m_GitStatus.prop_status);
\r
144 // LOADVALUEFROMFILE(m_GitStatus.repos_prop_status);
\r
145 // LOADVALUEFROMFILE(m_GitStatus.repos_text_status);
\r
146 // LOADVALUEFROMFILE(m_GitStatus.switched);
\r
147 // LOADVALUEFROMFILE(m_GitStatus.text_status);
\r
148 // m_GitStatus.entry = NULL;
\r
149 m_discardAtTime = GetTickCount()+cachetimeout;
\r
151 catch ( CAtlException )
\r
158 void CStatusCacheEntry::SetStatus(const git_wc_status2_t* pGitStatus)
\r
160 if(pGitStatus == NULL)
\r
162 SetAsUnversioned();
\r
166 m_highestPriorityLocalStatus = GitStatus::GetMoreImportant(pGitStatus->prop_status, pGitStatus->text_status);
\r
167 m_GitStatus = *pGitStatus;
\r
169 // Currently we don't deep-copy the whole entry value, but we do take a few members
\r
171 if(pGitStatus->entry != NULL)
\r
173 m_sUrl = pGitStatus->entry->url;
\r
174 m_commitRevision = pGitStatus->entry->cmt_rev;
\r
175 m_bSVNEntryFieldSet = true;
\r
176 m_sOwner = pGitStatus->entry->lock_owner;
\r
177 m_kind = pGitStatus->entry->kind;
\r
178 m_sAuthor = pGitStatus->entry->cmt_author;
\r
179 if (pGitStatus->entry->present_props)
\r
180 m_sPresentProps = pGitStatus->entry->present_props;
\r
185 m_commitRevision = 0;
\r
186 m_bSVNEntryFieldSet = false;
\r
188 m_GitStatus.entry = NULL;
\r
191 m_discardAtTime = GetTickCount()+cachetimeout;
\r
196 void CStatusCacheEntry::SetAsUnversioned()
\r
198 SecureZeroMemory(&m_GitStatus, sizeof(m_GitStatus));
\r
199 m_discardAtTime = GetTickCount()+cachetimeout;
\r
200 git_wc_status_kind status = git_wc_status_none;
\r
201 if (m_highestPriorityLocalStatus == git_wc_status_missing)
\r
202 status = git_wc_status_missing;
\r
203 if (m_highestPriorityLocalStatus == git_wc_status_unversioned)
\r
204 status = git_wc_status_unversioned;
\r
205 m_highestPriorityLocalStatus = status;
\r
206 m_GitStatus.prop_status = git_wc_status_none;
\r
207 m_GitStatus.text_status = status;
\r
208 m_lastWriteTime = 0;
\r
211 bool CStatusCacheEntry::HasExpired(long now) const
\r
213 return m_discardAtTime != 0 && (now - m_discardAtTime) >= 0;
\r
216 void CStatusCacheEntry::BuildCacheResponse(TSVNCacheResponse& response, DWORD& responseLength) const
\r
218 SecureZeroMemory(&response, sizeof(response));
\r
219 if(m_bSVNEntryFieldSet)
\r
221 response.m_status = m_GitStatus;
\r
222 // response.m_entry.cmt_rev = m_commitRevision;
\r
224 // There is no point trying to set these pointers here, because this is not
\r
225 // the process which will be using the data.
\r
226 // The process which receives this response (generally the TSVN Shell Extension)
\r
227 // must fix-up these pointers when it gets them
\r
228 // response.m_status.entry = NULL;
\r
229 // response.m_entry.url = NULL;
\r
231 // response.m_kind = m_kind;
\r
232 response.m_readonly = m_bReadOnly;
\r
234 if (m_sPresentProps.Find("svn:needs-lock")>=0)
\r
236 response.m_needslock = true;
\r
239 response.m_needslock = false;
\r
240 // The whole of response has been zeroed, so this will copy safely
\r
241 strncat_s(response.m_url, INTERNET_MAX_URL_LENGTH, m_sUrl, _TRUNCATE);
\r
242 strncat_s(response.m_owner, 255, m_sOwner, _TRUNCATE);
\r
243 strncat_s(response.m_author, 255, m_sAuthor, _TRUNCATE);
\r
244 responseLength = sizeof(response);
\r
248 response.m_status = m_GitStatus;
\r
249 responseLength = sizeof(response.m_status);
\r
253 bool CStatusCacheEntry::IsVersioned() const
\r
255 return m_highestPriorityLocalStatus > git_wc_status_unversioned;
\r
258 bool CStatusCacheEntry::DoesFileTimeMatch(__int64 testTime) const
\r
260 return m_lastWriteTime == testTime;
\r
264 bool CStatusCacheEntry::ForceStatus(git_wc_status_kind forcedStatus)
\r
266 git_wc_status_kind newStatus = forcedStatus;
\r
268 if(newStatus != m_highestPriorityLocalStatus)
\r
270 // We've had a status change
\r
271 m_highestPriorityLocalStatus = newStatus;
\r
272 m_GitStatus.text_status = newStatus;
\r
273 m_GitStatus.prop_status = newStatus;
\r
274 m_discardAtTime = GetTickCount()+cachetimeout;
\r
281 CStatusCacheEntry::HasBeenSet() const
\r
286 void CStatusCacheEntry::Invalidate()
\r