OSDN Git Service

GitBlame Use command Line argument to open file
[tortoisegit/TortoiseGitJp.git] / src / TGitCache / StatusCacheEntry.cpp
1 // TortoiseSVN - a Windows shell extension for easy version control\r
2 \r
3 // External Cache Copyright (C) 2005-2006,2008 - TortoiseSVN\r
4 \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
9 \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
14 \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
18 //\r
19 #include "StdAfx.h"\r
20 #include ".\statuscacheentry.h"\r
21 #include "GitStatus.h"\r
22 #include "CacheInterface.h"\r
23 #include "registry.h"\r
24 \r
25 DWORD cachetimeout = (DWORD)CRegStdWORD(_T("Software\\TortoiseGit\\Cachetimeout"), CACHETIMEOUT);\r
26 \r
27 CStatusCacheEntry::CStatusCacheEntry()\r
28         : m_bSet(false)\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
33 {\r
34         SetAsUnversioned();\r
35 }\r
36 \r
37 CStatusCacheEntry::CStatusCacheEntry(const git_wc_status2_t* pGitStatus, __int64 lastWriteTime, bool bReadOnly, DWORD validuntil /* = 0*/)\r
38         : m_bSet(false)\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
43 {\r
44         SetStatus(pGitStatus);\r
45         m_lastWriteTime = lastWriteTime;\r
46         if (validuntil)\r
47                 m_discardAtTime = validuntil;\r
48         else\r
49                 m_discardAtTime = GetTickCount()+cachetimeout;\r
50         m_bReadOnly = bReadOnly;\r
51 }\r
52 \r
53 bool CStatusCacheEntry::SaveToDisk(FILE * pFile)\r
54 {\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
57 \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
71 \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
79         return true;\r
80 }\r
81 \r
82 bool CStatusCacheEntry::LoadFromDisk(FILE * pFile)\r
83 {\r
84 #define LOADVALUEFROMFILE(x) if (fread(&x, sizeof(x), 1, pFile)!=1) return false;\r
85         try\r
86         {\r
87                 unsigned int value = 0;\r
88                 LOADVALUEFROMFILE(value);\r
89                 if (value != 4)\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
97                 if (value != 0)\r
98                 {\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
102                         {\r
103                                 m_sUrl.ReleaseBuffer(0);\r
104                                 return false;\r
105                         }\r
106                         m_sUrl.ReleaseBuffer(value);\r
107                 }\r
108                 LOADVALUEFROMFILE(value);\r
109                 if (value != 0)\r
110                 {\r
111                         if (fread(m_sOwner.GetBuffer(value+1), sizeof(char), value, pFile)!=value)\r
112                         {\r
113                                 m_sOwner.ReleaseBuffer(0);\r
114                                 return false;\r
115                         }\r
116                         m_sOwner.ReleaseBuffer(value);\r
117                 }\r
118                 LOADVALUEFROMFILE(value);\r
119                 if (value != 0)\r
120                 {\r
121                         if (fread(m_sAuthor.GetBuffer(value+1), sizeof(char), value, pFile)!=value)\r
122                         {\r
123                                 m_sAuthor.ReleaseBuffer(0);\r
124                                 return false;\r
125                         }\r
126                         m_sAuthor.ReleaseBuffer(value);\r
127                 }\r
128 //              LOADVALUEFROMFILE(m_kind);\r
129                 LOADVALUEFROMFILE(m_bReadOnly);\r
130                 LOADVALUEFROMFILE(value);\r
131                 if (value != 0)\r
132                 {\r
133                         if (fread(m_sPresentProps.GetBuffer(value+1), sizeof(char), value, pFile)!=value)\r
134                         {\r
135                                 m_sPresentProps.ReleaseBuffer(0);\r
136                                 return false;\r
137                         }\r
138                         m_sPresentProps.ReleaseBuffer(value);\r
139                 }\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
150         }\r
151         catch ( CAtlException )\r
152         {\r
153                 return false;\r
154         }\r
155         return true;\r
156 }\r
157 \r
158 void CStatusCacheEntry::SetStatus(const git_wc_status2_t* pGitStatus)\r
159 {\r
160         if(pGitStatus == NULL)\r
161         {\r
162                 SetAsUnversioned();\r
163         }\r
164         else\r
165         {\r
166                 m_highestPriorityLocalStatus = GitStatus::GetMoreImportant(pGitStatus->prop_status, pGitStatus->text_status);\r
167                 m_GitStatus = *pGitStatus;\r
168 \r
169                 // Currently we don't deep-copy the whole entry value, but we do take a few members\r
170 #if 0\r
171         if(pGitStatus->entry != NULL)\r
172                 {\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
181                 }\r
182                 else\r
183                 {\r
184                         m_sUrl.Empty();\r
185                         m_commitRevision = 0;\r
186                         m_bSVNEntryFieldSet = false;\r
187                 }\r
188                 m_GitStatus.entry = NULL;\r
189 #endif\r
190         }\r
191         m_discardAtTime = GetTickCount()+cachetimeout;\r
192         m_bSet = true;\r
193 }\r
194 \r
195 \r
196 void CStatusCacheEntry::SetAsUnversioned()\r
197 {\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
209 }\r
210 \r
211 bool CStatusCacheEntry::HasExpired(long now) const\r
212 {\r
213         return m_discardAtTime != 0 && (now - m_discardAtTime) >= 0;\r
214 }\r
215 \r
216 void CStatusCacheEntry::BuildCacheResponse(TSVNCacheResponse& response, DWORD& responseLength) const\r
217 {\r
218         SecureZeroMemory(&response, sizeof(response));\r
219         if(m_bSVNEntryFieldSet)\r
220         {\r
221                 response.m_status = m_GitStatus;\r
222 //              response.m_entry.cmt_rev = m_commitRevision;\r
223 \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
230 \r
231 //              response.m_kind = m_kind;\r
232                 response.m_readonly = m_bReadOnly;\r
233 \r
234                 if (m_sPresentProps.Find("svn:needs-lock")>=0)\r
235                 {\r
236                         response.m_needslock = true;\r
237                 }\r
238                 else\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
245         }\r
246         else\r
247         {\r
248                 response.m_status = m_GitStatus;\r
249                 responseLength = sizeof(response.m_status);\r
250         }\r
251 }\r
252 \r
253 bool CStatusCacheEntry::IsVersioned() const\r
254 {\r
255         return m_highestPriorityLocalStatus > git_wc_status_unversioned;\r
256 }\r
257 \r
258 bool CStatusCacheEntry::DoesFileTimeMatch(__int64 testTime) const\r
259 {\r
260         return m_lastWriteTime == testTime;\r
261 }\r
262 \r
263 \r
264 bool CStatusCacheEntry::ForceStatus(git_wc_status_kind forcedStatus)\r
265 {\r
266         git_wc_status_kind newStatus = forcedStatus; \r
267 \r
268         if(newStatus != m_highestPriorityLocalStatus)\r
269         {\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
275                 return true;\r
276         }\r
277         return false;\r
278 }\r
279 \r
280 bool \r
281 CStatusCacheEntry::HasBeenSet() const\r
282 {\r
283         return m_bSet;\r
284 }\r
285 \r
286 void CStatusCacheEntry::Invalidate()\r
287 {\r
288         m_bSet = false;\r
289 }\r