fixed possible concurrent modifications of m_pathsToUpdate
[TortoiseGit.git] / src / TGitCache / StatusCacheEntry.cpp
blob2ba3e81009cae58483e1ad051193ca2ef3b43d80
1 // TortoiseGit - a Windows shell extension for easy version control
3 // External Cache Copyright (C) 2005-2006,2008 - TortoiseSVN
4 // Copyright (C) 2008-2012 - 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 ".\statuscacheentry.h"
22 #include "GitStatus.h"
23 #include "CacheInterface.h"
24 #include "registry.h"
26 DWORD cachetimeout = (DWORD)CRegStdDWORD(_T("Software\\TortoiseGit\\Cachetimeout"), CACHETIMEOUT);
28 CStatusCacheEntry::CStatusCacheEntry()
29 : m_bSet(false)
30 , m_bSVNEntryFieldSet(false)
31 , m_kind(git_node_unknown)
32 , m_bReadOnly(false)
33 , m_highestPriorityLocalStatus(git_wc_status_none)
35 SetAsUnversioned();
38 CStatusCacheEntry::CStatusCacheEntry(const git_wc_status_kind status)
39 : m_bSet(true)
40 , m_bSVNEntryFieldSet(false)
41 , m_kind(git_node_unknown)
42 , m_bReadOnly(false)
43 , m_highestPriorityLocalStatus(status)
45 m_GitStatus.prop_status=m_GitStatus.text_status = status;
46 m_discardAtTime = GetTickCount()+cachetimeout;
49 CStatusCacheEntry::CStatusCacheEntry(const git_wc_status2_t* pGitStatus, __int64 lastWriteTime, bool bReadOnly, DWORD validuntil /* = 0*/)
50 : m_bSet(false)
51 , m_bSVNEntryFieldSet(false)
52 , m_kind(git_node_unknown)
53 , m_bReadOnly(false)
54 , m_highestPriorityLocalStatus(git_wc_status_none)
56 SetStatus(pGitStatus);
57 m_lastWriteTime = lastWriteTime;
58 if (validuntil)
59 m_discardAtTime = validuntil;
60 else
61 m_discardAtTime = GetTickCount()+cachetimeout;
62 m_bReadOnly = bReadOnly;
65 bool CStatusCacheEntry::SaveToDisk(FILE * pFile)
67 #define WRITEVALUETOFILE(x) if (fwrite(&x, sizeof(x), 1, pFile)!=1) return false;
68 #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;}
70 unsigned int value = 4;
71 WRITEVALUETOFILE(value); // 'version' of this save-format
72 WRITEVALUETOFILE(m_highestPriorityLocalStatus);
73 WRITEVALUETOFILE(m_lastWriteTime);
74 WRITEVALUETOFILE(m_bSet);
75 WRITEVALUETOFILE(m_bSVNEntryFieldSet);
76 CStringA srev(m_commitRevision); WRITESTRINGTOFILE(srev);
77 WRITESTRINGTOFILE(m_sUrl);
78 WRITESTRINGTOFILE(m_sOwner);
79 WRITESTRINGTOFILE(m_sAuthor);
80 WRITEVALUETOFILE(m_kind);
81 WRITEVALUETOFILE(m_bReadOnly);
82 WRITESTRINGTOFILE(m_sPresentProps);
84 // now save the status struct (without the entry field, because we don't use that) WRITEVALUETOFILE(m_GitStatus.copied);
85 // WRITEVALUETOFILE(m_GitStatus.locked);
86 WRITEVALUETOFILE(m_GitStatus.prop_status);
87 // WRITEVALUETOFILE(m_GitStatus.repos_prop_status);
88 // WRITEVALUETOFILE(m_GitStatus.repos_text_status);
89 // WRITEVALUETOFILE(m_GitStatus.switched);
90 WRITEVALUETOFILE(m_GitStatus.text_status);
91 return true;
94 bool CStatusCacheEntry::LoadFromDisk(FILE * pFile)
96 #define LOADVALUEFROMFILE(x) if (fread(&x, sizeof(x), 1, pFile)!=1) return false;
97 try
99 unsigned int value = 0;
100 LOADVALUEFROMFILE(value);
101 if (value != 4)
102 return false; // not the correct version
103 LOADVALUEFROMFILE(m_highestPriorityLocalStatus);
104 LOADVALUEFROMFILE(m_lastWriteTime);
105 LOADVALUEFROMFILE(m_bSet);
106 LOADVALUEFROMFILE(m_bSVNEntryFieldSet);
107 LOADVALUEFROMFILE(value);
108 if (value != 0)
110 CStringA s;
111 if (fread(s.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
113 s.ReleaseBuffer(0);
114 m_commitRevision.Empty();
115 return false;
117 s.ReleaseBuffer(value);
118 m_commitRevision = s;
120 LOADVALUEFROMFILE(value);
121 if (value != 0)
123 if (value > INTERNET_MAX_URL_LENGTH)
124 return false; // invalid length for an url
125 if (fread(m_sUrl.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
127 m_sUrl.ReleaseBuffer(0);
128 return false;
130 m_sUrl.ReleaseBuffer(value);
132 LOADVALUEFROMFILE(value);
133 if (value != 0)
135 if (fread(m_sOwner.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
137 m_sOwner.ReleaseBuffer(0);
138 return false;
140 m_sOwner.ReleaseBuffer(value);
142 LOADVALUEFROMFILE(value);
143 if (value != 0)
145 if (fread(m_sAuthor.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
147 m_sAuthor.ReleaseBuffer(0);
148 return false;
150 m_sAuthor.ReleaseBuffer(value);
152 LOADVALUEFROMFILE(m_kind);
153 LOADVALUEFROMFILE(m_bReadOnly);
154 LOADVALUEFROMFILE(value);
155 if (value != 0)
157 if (fread(m_sPresentProps.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
159 m_sPresentProps.ReleaseBuffer(0);
160 return false;
162 m_sPresentProps.ReleaseBuffer(value);
164 SecureZeroMemory(&m_GitStatus, sizeof(m_GitStatus));
165 // LOADVALUEFROMFILE(m_GitStatus.copied);
166 // LOADVALUEFROMFILE(m_GitStatus.locked);
167 LOADVALUEFROMFILE(m_GitStatus.prop_status);
168 // LOADVALUEFROMFILE(m_GitStatus.repos_prop_status);
169 // LOADVALUEFROMFILE(m_GitStatus.repos_text_status);
170 // LOADVALUEFROMFILE(m_GitStatus.switched);
171 LOADVALUEFROMFILE(m_GitStatus.text_status);
172 // m_GitStatus.entry = NULL;
173 m_discardAtTime = GetTickCount()+cachetimeout;
175 catch ( CAtlException )
177 return false;
179 return true;
182 void CStatusCacheEntry::SetStatus(const git_wc_status2_t* pGitStatus)
184 if(pGitStatus == NULL)
186 SetAsUnversioned();
188 else
190 m_highestPriorityLocalStatus = GitStatus::GetMoreImportant(pGitStatus->prop_status, pGitStatus->text_status);
191 m_GitStatus = *pGitStatus;
193 // Currently we don't deep-copy the whole entry value, but we do take a few members
194 /* if(pGitStatus->entry != NULL)
196 m_sUrl = pGitStatus->entry->url;
197 m_commitRevision = pGitStatus->entry->cmt_rev;
198 m_bSVNEntryFieldSet = true;
199 m_sOwner = pGitStatus->entry->lock_owner;
200 m_kind = pGitStatus->entry->kind;
201 m_sAuthor = pGitStatus->entry->cmt_author;
202 if (pGitStatus->entry->present_props)
203 m_sPresentProps = pGitStatus->entry->present_props;
205 else*/
207 m_sUrl.Empty();
208 m_commitRevision = GIT_INVALID_REVNUM;
209 m_bSVNEntryFieldSet = false;
211 // m_GitStatus.entry = NULL;
213 m_discardAtTime = GetTickCount()+cachetimeout;
214 m_bSet = true;
218 void CStatusCacheEntry::SetAsUnversioned()
220 SecureZeroMemory(&m_GitStatus, sizeof(m_GitStatus));
221 m_discardAtTime = GetTickCount()+cachetimeout;
222 git_wc_status_kind status = git_wc_status_none;
223 if (m_highestPriorityLocalStatus == git_wc_status_missing)
224 status = git_wc_status_missing;
225 if (m_highestPriorityLocalStatus == git_wc_status_unversioned)
226 status = git_wc_status_unversioned;
227 m_highestPriorityLocalStatus = status;
228 m_GitStatus.prop_status = git_wc_status_none;
229 m_GitStatus.text_status = status;
230 m_lastWriteTime = 0;
233 bool CStatusCacheEntry::HasExpired(long now) const
235 return m_discardAtTime != 0 && (now - m_discardAtTime) >= 0;
238 void CStatusCacheEntry::BuildCacheResponse(TGITCacheResponse& response, DWORD& responseLength) const
240 SecureZeroMemory(&response, sizeof(response));
241 if(m_bSVNEntryFieldSet)
243 response.m_status = m_GitStatus;
244 wcscpy_s(response.m_entry.cmt_rev, 41, m_commitRevision.GetString());
246 // There is no point trying to set these pointers here, because this is not
247 // the process which will be using the data.
248 // The process which receives this response (generally the TSVN Shell Extension)
249 // must fix-up these pointers when it gets them
250 // The whole of response has been zeroed, so this will copy safely
251 responseLength = sizeof(response);
253 else
255 response.m_status = m_GitStatus;
256 responseLength = sizeof(response.m_status);
259 // directories that are empty or only contain unversioned files will be git_wc_status_incomplete, report as unversioned
260 if (response.m_status.text_status == git_wc_status_incomplete)
262 response.m_status.text_status = response.m_status.prop_status = git_wc_status_unversioned;
266 bool CStatusCacheEntry::IsVersioned() const
268 return m_highestPriorityLocalStatus > git_wc_status_unversioned;
271 bool CStatusCacheEntry::DoesFileTimeMatch(__int64 testTime) const
273 return m_lastWriteTime == testTime;
277 bool CStatusCacheEntry::ForceStatus(git_wc_status_kind forcedStatus)
279 git_wc_status_kind newStatus = forcedStatus;
281 if(newStatus != m_highestPriorityLocalStatus)
283 // We've had a status change
284 m_highestPriorityLocalStatus = newStatus;
285 m_GitStatus.text_status = newStatus;
286 m_GitStatus.prop_status = newStatus;
287 m_discardAtTime = GetTickCount()+cachetimeout;
288 return true;
290 return false;
293 bool
294 CStatusCacheEntry::HasBeenSet() const
296 return m_bSet;
299 void CStatusCacheEntry::Invalidate()
301 m_bSet = false;