1 // TortoiseGit - a Windows shell extension for easy version control
3 // External Cache Copyright (C) 2005-2006,2008,2014 - TortoiseSVN
4 // Copyright (C) 2008-2014, 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 "StatusCacheEntry.h"
22 #include "GitStatus.h"
23 #include "CacheInterface.h"
28 ULONGLONG cachetimeout
= (ULONGLONG
)CRegStdDWORD(_T("Software\\TortoiseGit\\Cachetimeout"), LONG_MAX
);
30 CStatusCacheEntry::CStatusCacheEntry()
32 , m_kind(git_node_unknown
)
33 , m_highestPriorityLocalStatus(git_wc_status_none
)
34 , m_bAssumeValid(false)
35 , m_bSkipWorktree(false)
40 CStatusCacheEntry::CStatusCacheEntry(const git_wc_status_kind status
)
42 , m_kind(git_node_unknown
)
43 , m_highestPriorityLocalStatus(status
)
44 , m_bAssumeValid(false)
45 , m_bSkipWorktree(false)
48 m_GitStatus
.prop_status
=m_GitStatus
.text_status
= status
;
49 m_GitStatus
.assumeValid
= m_GitStatus
.skipWorktree
= false;
50 m_discardAtTime
= GetTickCount64() + cachetimeout
;
53 CStatusCacheEntry::CStatusCacheEntry(const git_wc_status2_t
* pGitStatus
, __int64 lastWriteTime
, bool /*bReadOnly*/, LONGLONG validuntil
/* = 0*/)
55 , m_kind(git_node_unknown
)
56 , m_highestPriorityLocalStatus(git_wc_status_none
)
58 SetStatus(pGitStatus
);
59 m_lastWriteTime
= lastWriteTime
;
61 m_discardAtTime
= validuntil
;
63 m_discardAtTime
= GetTickCount64() + cachetimeout
;
66 bool CStatusCacheEntry::SaveToDisk(FILE* pFile
) const
68 #define WRITEVALUETOFILE(x) if (fwrite(&x, sizeof(x), 1, pFile)!=1) return false;
69 #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;}
71 unsigned int value
= CACHEVERION
;
72 WRITEVALUETOFILE(value
); // 'version' of this save-format
73 WRITEVALUETOFILE(m_highestPriorityLocalStatus
);
74 WRITEVALUETOFILE(m_lastWriteTime
);
75 WRITEVALUETOFILE(m_bSet
);
76 WRITEVALUETOFILE(m_kind
);
78 // now save the status struct (without the entry field, because we don't use that)
79 WRITEVALUETOFILE(m_GitStatus
.prop_status
);
80 // WRITEVALUETOFILE(m_GitStatus.repos_prop_status);
81 // WRITEVALUETOFILE(m_GitStatus.repos_text_status);
82 WRITEVALUETOFILE(m_GitStatus
.text_status
);
83 WRITEVALUETOFILE(m_GitStatus
.assumeValid
);
84 WRITEVALUETOFILE(m_GitStatus
.skipWorktree
);
88 bool CStatusCacheEntry::LoadFromDisk(FILE * pFile
)
90 #define LOADVALUEFROMFILE(x) if (fread(&x, sizeof(x), 1, pFile)!=1) return false;
93 unsigned int value
= 0;
94 LOADVALUEFROMFILE(value
);
95 if (value
!= CACHEVERION
)
96 return false; // not the correct version
97 LOADVALUEFROMFILE(m_highestPriorityLocalStatus
);
98 LOADVALUEFROMFILE(m_lastWriteTime
);
99 LOADVALUEFROMFILE(m_bSet
);
100 LOADVALUEFROMFILE(m_kind
);
101 SecureZeroMemory(&m_GitStatus
, sizeof(m_GitStatus
));
102 LOADVALUEFROMFILE(m_GitStatus
.prop_status
);
103 // LOADVALUEFROMFILE(m_GitStatus.repos_prop_status);
104 // LOADVALUEFROMFILE(m_GitStatus.repos_text_status);
105 LOADVALUEFROMFILE(m_GitStatus
.text_status
);
106 LOADVALUEFROMFILE(m_GitStatus
.assumeValid
);
107 LOADVALUEFROMFILE(m_GitStatus
.skipWorktree
);
108 // m_GitStatus.entry = nullptr;
109 m_discardAtTime
= GetTickCount64() + cachetimeout
;
111 catch ( CAtlException
)
118 void CStatusCacheEntry::SetStatus(const git_wc_status2_t
* pGitStatus
)
126 m_highestPriorityLocalStatus
= GitStatus::GetMoreImportant(pGitStatus
->prop_status
, pGitStatus
->text_status
);
127 m_GitStatus
= *pGitStatus
;
128 if (m_kind
!= git_node_dir
)
130 m_bAssumeValid
= pGitStatus
->assumeValid
;
131 m_bSkipWorktree
= pGitStatus
->skipWorktree
;
134 m_discardAtTime
= GetTickCount64() + cachetimeout
;
139 void CStatusCacheEntry::SetAsUnversioned()
141 SecureZeroMemory(&m_GitStatus
, sizeof(m_GitStatus
));
142 m_discardAtTime
= GetTickCount64() + cachetimeout
;
143 git_wc_status_kind status
= git_wc_status_none
;
144 if (m_highestPriorityLocalStatus
== git_wc_status_missing
)
145 status
= git_wc_status_missing
;
146 if (m_highestPriorityLocalStatus
== git_wc_status_unversioned
)
147 status
= git_wc_status_unversioned
;
148 m_highestPriorityLocalStatus
= status
;
149 m_GitStatus
.prop_status
= git_wc_status_none
;
150 m_GitStatus
.text_status
= status
;
152 m_bAssumeValid
= false;
155 bool CStatusCacheEntry::HasExpired(LONGLONG now
) const
157 return m_discardAtTime
!= 0 && (now
- m_discardAtTime
) >= 0;
160 void CStatusCacheEntry::BuildCacheResponse(TGITCacheResponse
& response
, DWORD
& responseLength
) const
162 SecureZeroMemory(&response
, sizeof(response
));
163 response
.m_status
= m_GitStatus
;
164 response
.m_bAssumeValid
= m_bAssumeValid
;
165 response
.m_bSkipWorktree
= m_bSkipWorktree
;
166 responseLength
= sizeof(response
);
168 // directories that are empty or only contain unversioned files will be git_wc_status_incomplete, report as unversioned
169 if (response
.m_status
.text_status
== git_wc_status_incomplete
)
171 response
.m_status
.text_status
= response
.m_status
.prop_status
= git_wc_status_unversioned
;
175 bool CStatusCacheEntry::IsVersioned() const
177 return m_highestPriorityLocalStatus
> git_wc_status_unversioned
;
180 bool CStatusCacheEntry::DoesFileTimeMatch(__int64 testTime
) const
182 return m_lastWriteTime
== testTime
;
186 bool CStatusCacheEntry::ForceStatus(git_wc_status_kind forcedStatus
)
188 git_wc_status_kind newStatus
= forcedStatus
;
190 if(newStatus
!= m_highestPriorityLocalStatus
)
192 // We've had a status change
193 m_highestPriorityLocalStatus
= newStatus
;
194 m_GitStatus
.text_status
= newStatus
;
195 m_GitStatus
.prop_status
= newStatus
;
196 m_discardAtTime
= GetTickCount64() + cachetimeout
;
203 CStatusCacheEntry::HasBeenSet() const
208 void CStatusCacheEntry::Invalidate()