Merge branch 'new-features'
[TortoiseGit.git] / src / TGitCache / StatusCacheEntry.cpp
blob476c1d5fb7037d351875a549340ff8a0cf6dcb32
1 // TortoiseSVN - a Windows shell extension for easy version control
3 // External Cache Copyright (C) 2005-2006,2008 - TortoiseSVN
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software Foundation,
17 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 #include "StdAfx.h"
20 #include ".\statuscacheentry.h"
21 #include "GitStatus.h"
22 #include "CacheInterface.h"
23 #include "registry.h"
25 DWORD cachetimeout = (DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\Cachetimeout"), CACHETIMEOUT);
27 CStatusCacheEntry::CStatusCacheEntry()
28 : m_bSet(false)
29 , m_bSVNEntryFieldSet(false)
30 , m_kind(git_node_unknown)
31 , m_bReadOnly(false)
32 , m_highestPriorityLocalStatus(git_wc_status_none)
34 SetAsUnversioned();
37 CStatusCacheEntry::CStatusCacheEntry(const git_wc_status_kind status)
38 : m_bSet(true)
39 , m_bSVNEntryFieldSet(false)
40 , m_kind(git_node_unknown)
41 , m_bReadOnly(false)
42 , m_highestPriorityLocalStatus(status)
44 m_GitStatus.prop_status=m_GitStatus.text_status = status;
45 m_discardAtTime = GetTickCount()+cachetimeout;
48 CStatusCacheEntry::CStatusCacheEntry(const git_wc_status2_t* pGitStatus, __int64 lastWriteTime, bool bReadOnly, DWORD validuntil /* = 0*/)
49 : m_bSet(false)
50 , m_bSVNEntryFieldSet(false)
51 , m_kind(git_node_unknown)
52 , m_bReadOnly(false)
53 , m_highestPriorityLocalStatus(git_wc_status_none)
55 SetStatus(pGitStatus);
56 m_lastWriteTime = lastWriteTime;
57 if (validuntil)
58 m_discardAtTime = validuntil;
59 else
60 m_discardAtTime = GetTickCount()+cachetimeout;
61 m_bReadOnly = bReadOnly;
64 bool CStatusCacheEntry::SaveToDisk(FILE * pFile)
66 #define WRITEVALUETOFILE(x) if (fwrite(&x, sizeof(x), 1, pFile)!=1) return false;
67 #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;}
69 unsigned int value = 4;
70 WRITEVALUETOFILE(value); // 'version' of this save-format
71 WRITEVALUETOFILE(m_highestPriorityLocalStatus);
72 WRITEVALUETOFILE(m_lastWriteTime);
73 WRITEVALUETOFILE(m_bSet);
74 WRITEVALUETOFILE(m_bSVNEntryFieldSet);
75 CStringA srev(m_commitRevision); WRITESTRINGTOFILE(srev);
76 WRITESTRINGTOFILE(m_sUrl);
77 WRITESTRINGTOFILE(m_sOwner);
78 WRITESTRINGTOFILE(m_sAuthor);
79 WRITEVALUETOFILE(m_kind);
80 WRITEVALUETOFILE(m_bReadOnly);
81 WRITESTRINGTOFILE(m_sPresentProps);
83 // now save the status struct (without the entry field, because we don't use that) WRITEVALUETOFILE(m_GitStatus.copied);
84 // WRITEVALUETOFILE(m_GitStatus.locked);
85 WRITEVALUETOFILE(m_GitStatus.prop_status);
86 // WRITEVALUETOFILE(m_GitStatus.repos_prop_status);
87 // WRITEVALUETOFILE(m_GitStatus.repos_text_status);
88 // WRITEVALUETOFILE(m_GitStatus.switched);
89 WRITEVALUETOFILE(m_GitStatus.text_status);
90 return true;
93 bool CStatusCacheEntry::LoadFromDisk(FILE * pFile)
95 #define LOADVALUEFROMFILE(x) if (fread(&x, sizeof(x), 1, pFile)!=1) return false;
96 try
98 unsigned int value = 0;
99 LOADVALUEFROMFILE(value);
100 if (value != 4)
101 return false; // not the correct version
102 LOADVALUEFROMFILE(m_highestPriorityLocalStatus);
103 LOADVALUEFROMFILE(m_lastWriteTime);
104 LOADVALUEFROMFILE(m_bSet);
105 LOADVALUEFROMFILE(m_bSVNEntryFieldSet);
106 LOADVALUEFROMFILE(value);
107 if (value != 0)
109 CStringA s;
110 if (fread(s.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
112 s.ReleaseBuffer(0);
113 m_commitRevision.Empty();
114 return false;
116 s.ReleaseBuffer(value);
117 m_commitRevision = s;
119 LOADVALUEFROMFILE(value);
120 if (value != 0)
122 if (value > INTERNET_MAX_URL_LENGTH)
123 return false; // invalid length for an url
124 if (fread(m_sUrl.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
126 m_sUrl.ReleaseBuffer(0);
127 return false;
129 m_sUrl.ReleaseBuffer(value);
131 LOADVALUEFROMFILE(value);
132 if (value != 0)
134 if (fread(m_sOwner.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
136 m_sOwner.ReleaseBuffer(0);
137 return false;
139 m_sOwner.ReleaseBuffer(value);
141 LOADVALUEFROMFILE(value);
142 if (value != 0)
144 if (fread(m_sAuthor.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
146 m_sAuthor.ReleaseBuffer(0);
147 return false;
149 m_sAuthor.ReleaseBuffer(value);
151 LOADVALUEFROMFILE(m_kind);
152 LOADVALUEFROMFILE(m_bReadOnly);
153 LOADVALUEFROMFILE(value);
154 if (value != 0)
156 if (fread(m_sPresentProps.GetBuffer(value+1), sizeof(char), value, pFile)!=value)
158 m_sPresentProps.ReleaseBuffer(0);
159 return false;
161 m_sPresentProps.ReleaseBuffer(value);
163 SecureZeroMemory(&m_GitStatus, sizeof(m_GitStatus));
164 // LOADVALUEFROMFILE(m_GitStatus.copied);
165 // LOADVALUEFROMFILE(m_GitStatus.locked);
166 LOADVALUEFROMFILE(m_GitStatus.prop_status);
167 // LOADVALUEFROMFILE(m_GitStatus.repos_prop_status);
168 // LOADVALUEFROMFILE(m_GitStatus.repos_text_status);
169 // LOADVALUEFROMFILE(m_GitStatus.switched);
170 LOADVALUEFROMFILE(m_GitStatus.text_status);
171 // m_GitStatus.entry = NULL;
172 m_discardAtTime = GetTickCount()+cachetimeout;
174 catch ( CAtlException )
176 return false;
178 return true;
181 void CStatusCacheEntry::SetStatus(const git_wc_status2_t* pGitStatus)
183 if(pGitStatus == NULL)
185 SetAsUnversioned();
187 else
189 m_highestPriorityLocalStatus = GitStatus::GetMoreImportant(pGitStatus->prop_status, pGitStatus->text_status);
190 m_GitStatus = *pGitStatus;
192 // Currently we don't deep-copy the whole entry value, but we do take a few members
193 /* if(pGitStatus->entry != NULL)
195 m_sUrl = pGitStatus->entry->url;
196 m_commitRevision = pGitStatus->entry->cmt_rev;
197 m_bSVNEntryFieldSet = true;
198 m_sOwner = pGitStatus->entry->lock_owner;
199 m_kind = pGitStatus->entry->kind;
200 m_sAuthor = pGitStatus->entry->cmt_author;
201 if (pGitStatus->entry->present_props)
202 m_sPresentProps = pGitStatus->entry->present_props;
204 else*/
206 m_sUrl.Empty();
207 m_commitRevision = GIT_INVALID_REVNUM;
208 m_bSVNEntryFieldSet = false;
210 // m_GitStatus.entry = NULL;
212 m_discardAtTime = GetTickCount()+cachetimeout;
213 m_bSet = true;
217 void CStatusCacheEntry::SetAsUnversioned()
219 SecureZeroMemory(&m_GitStatus, sizeof(m_GitStatus));
220 m_discardAtTime = GetTickCount()+cachetimeout;
221 git_wc_status_kind status = git_wc_status_none;
222 if (m_highestPriorityLocalStatus == git_wc_status_missing)
223 status = git_wc_status_missing;
224 if (m_highestPriorityLocalStatus == git_wc_status_unversioned)
225 status = git_wc_status_unversioned;
226 m_highestPriorityLocalStatus = status;
227 m_GitStatus.prop_status = git_wc_status_none;
228 m_GitStatus.text_status = status;
229 m_lastWriteTime = 0;
232 bool CStatusCacheEntry::HasExpired(long now) const
234 return m_discardAtTime != 0 && (now - m_discardAtTime) >= 0;
237 void CStatusCacheEntry::BuildCacheResponse(TSVNCacheResponse& response, DWORD& responseLength) const
239 SecureZeroMemory(&response, sizeof(response));
240 if(m_bSVNEntryFieldSet)
242 response.m_status = m_GitStatus;
243 wcscpy_s(response.m_entry.cmt_rev, 41, m_commitRevision.GetString());
245 // There is no point trying to set these pointers here, because this is not
246 // the process which will be using the data.
247 // The process which receives this response (generally the TSVN Shell Extension)
248 // must fix-up these pointers when it gets them
249 // response.m_status.entry = NULL;
250 // response.m_entry.url = NULL;
252 response.m_kind = m_kind;
253 response.m_readonly = m_bReadOnly;
255 if (m_sPresentProps.Find("svn:needs-lock")>=0)
257 response.m_needslock = true;
259 else
260 response.m_needslock = false;
261 // The whole of response has been zeroed, so this will copy safely
262 strncat_s(response.m_url, INTERNET_MAX_URL_LENGTH, m_sUrl, _TRUNCATE);
263 strncat_s(response.m_owner, 255, m_sOwner, _TRUNCATE);
264 strncat_s(response.m_author, 255, m_sAuthor, _TRUNCATE);
265 responseLength = sizeof(response);
267 else
269 response.m_status = m_GitStatus;
270 responseLength = sizeof(response.m_status);
273 // directories that are empty or only contain unversioned files will be git_wc_status_incomplete, report as unversioned
274 if (response.m_status.text_status == git_wc_status_incomplete)
276 response.m_status.text_status = response.m_status.prop_status = git_wc_status_unversioned;
280 bool CStatusCacheEntry::IsVersioned() const
282 return m_highestPriorityLocalStatus > git_wc_status_unversioned;
285 bool CStatusCacheEntry::DoesFileTimeMatch(__int64 testTime) const
287 return m_lastWriteTime == testTime;
291 bool CStatusCacheEntry::ForceStatus(git_wc_status_kind forcedStatus)
293 git_wc_status_kind newStatus = forcedStatus;
295 if(newStatus != m_highestPriorityLocalStatus)
297 // We've had a status change
298 m_highestPriorityLocalStatus = newStatus;
299 m_GitStatus.text_status = newStatus;
300 m_GitStatus.prop_status = newStatus;
301 m_discardAtTime = GetTickCount()+cachetimeout;
302 return true;
304 return false;
307 bool
308 CStatusCacheEntry::HasBeenSet() const
310 return m_bSet;
313 void CStatusCacheEntry::Invalidate()
315 m_bSet = false;