KiCad PCB EDA Suite
Loading...
Searching...
No Matches
lockfile.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors.
5 *
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.
10 *
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.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you may find one here:
18 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
19 * or you may search the http://www.gnu.org website for the version 2 license,
20 * or you may write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
22 */
23
29#ifndef INCLUDE__LOCK_FILE_H_
30#define INCLUDE__LOCK_FILE_H_
31
32#include <wx/wx.h>
33#include <wx/file.h>
34#include <wx/filefn.h>
35#include <wx/log.h>
36#include <wx/filename.h>
37#include <nlohmann/json.hpp>
39
40#define LCK "KICAD_LOCKING"
41
43{
44public:
45 LOCKFILE( const wxString &filename, bool aRemoveOnRelease = true ) :
46 m_originalFile( filename ), m_fileCreated( false ), m_status( false ),
47 m_removeOnRelease( aRemoveOnRelease ), m_errorMsg( "" )
48 {
49 if( filename.IsEmpty() )
50 return;
51
52 wxLogTrace( LCK, "Trying to lock %s", filename );
53 wxFileName fn( filename );
54 fn.SetName( FILEEXT::LockFilePrefix + fn.GetName() );
55 fn.SetExt( fn.GetExt() + '.' + FILEEXT::LockFileExtension );
56
57 if( !fn.IsDirWritable() )
58 {
59 wxLogTrace( LCK, "File is not writable: %s", filename );
60 m_status = true;
61 m_removeOnRelease = false;
62 return;
63 }
64
65 m_lockFilename = fn.GetFullPath();
66
67 wxFile file;
68 try
69 {
70 bool lock_success = false;
71 bool rw_success = false;
72
73 {
74 wxLogNull suppressExpectedErrorMessages;
75
76 lock_success = file.Open( m_lockFilename, wxFile::write_excl );
77
78 if( !lock_success )
79 rw_success = file.Open( m_lockFilename, wxFile::read );
80 }
81
82 if( lock_success )
83 {
84 // Lock file doesn't exist, create one
85 m_fileCreated = true;
86 m_status = true;
87 m_username = wxGetUserId();
88 m_hostname = wxGetHostName();
89 nlohmann::json j;
90 j["username"] = std::string( m_username.mb_str() );
91 j["hostname"] = std::string( m_hostname.mb_str() );
92 std::string lock_info = j.dump();
93 file.Write( lock_info );
94 file.Close();
95 wxLogTrace( LCK, "Locked %s", filename );
96 }
97 else if( rw_success )
98 {
99 // Lock file already exists, read the details
100 wxString lock_info;
101 file.ReadAll( &lock_info );
102 nlohmann::json j = nlohmann::json::parse( std::string( lock_info.mb_str() ) );
103 m_username = wxString( j["username"].get<std::string>() );
104 m_hostname = wxString( j["hostname"].get<std::string>() );
105 file.Close();
106 m_errorMsg = _( "Lock file already exists" );
107 wxLogTrace( LCK, "Existing Lock for %s", filename );
108 }
109 else
110 {
111 throw std::runtime_error( "Failed to open lock file" );
112 }
113 }
114 catch( std::exception& e )
115 {
116 wxLogError( "Got an error trying to lock %s: %s", filename, e.what() );
117
118 // Delete lock file if it was created above but we threw an exception somehow
119 if( m_fileCreated )
120 {
121 wxRemoveFile( m_lockFilename );
122 m_fileCreated = false; // Reset the flag since file has been deleted manually
123 }
124
125 m_errorMsg = _( "Failed to access lock file" );
126 m_status = false;
127 }
128 }
129
131 {
132 UnlockFile();
133 }
134
139 {
140 wxLogTrace( LCK, "Unlocking %s", m_lockFilename );
141
142 // Delete lock file only if the file was created in the constructor and if the file contains the correct user and host names
144 {
146 wxRemoveFile( m_lockFilename );
147
148 m_fileCreated = false; // Reset the flag since file has been deleted manually
149 m_status = false;
150 m_errorMsg = wxEmptyString;
151 }
152 }
153
158 bool OverrideLock( bool aRemoveOnRelease = true )
159 {
160 wxLogTrace( LCK, "Overriding lock on %s", m_lockFilename );
161
162 if( !m_fileCreated )
163 {
164 try
165 {
166 wxFile file;
167 bool success = false;
168
169 {
170 wxLogNull suppressExpectedErrorMessages;
171 success = file.Open( m_lockFilename, wxFile::write );
172 }
173
174 if( success )
175 {
176 m_username = wxGetUserId();
177 m_hostname = wxGetHostName();
178 nlohmann::json j;
179 j["username"] = std::string( m_username.mb_str() );
180 j["hostname"] = std::string( m_hostname.mb_str() );
181 std::string lock_info = j.dump();
182 file.Write( lock_info );
183 file.Close();
184 m_fileCreated = true;
185 m_status = true;
186 m_removeOnRelease = aRemoveOnRelease;
187 m_errorMsg = wxEmptyString;
188 wxLogTrace( LCK, "Successfully overrode lock on %s", m_lockFilename );
189 return true;
190 }
191
192 return false;
193 }
194 catch( std::exception& e )
195 {
196 wxLogError( "Got exception trying to override lock on %s: %s",
197 m_lockFilename, e.what() );
198
199 return false;
200 }
201 }
202 else
203 {
204 wxLogTrace( LCK, "Upgraded lock on %s to delete on release", m_lockFilename );
205 m_removeOnRelease = aRemoveOnRelease;
206 }
207
208 return true;
209 }
210
212 {
213 return m_username == wxGetUserId() && m_hostname == wxGetHostName();
214 }
215
219 wxString GetUsername(){ return m_username; }
220
224 wxString GetHostname(){ return m_hostname; }
225
229 wxString GetErrorMsg(){ return m_errorMsg; }
230
231 bool Locked() const
232 {
233 return m_fileCreated;
234 }
235
236 bool Valid() const
237 {
238 return m_status;
239 }
240
241 explicit operator bool() const
242 {
243 return m_status;
244 }
245
246private:
249 wxString m_username;
250 wxString m_hostname;
254 wxString m_errorMsg;
255
257 {
258 wxFileName fileName( m_lockFilename );
259
260 if( !fileName.FileExists() )
261 {
262 wxLogTrace( LCK, "File does not exist: %s", m_lockFilename );
263 return false;
264 }
265
266 wxFile file;
267 try
268 {
269 if( file.Open( m_lockFilename, wxFile::read ) )
270 {
271 wxString lock_info;
272 file.ReadAll( &lock_info );
273 nlohmann::json j = nlohmann::json::parse( std::string( lock_info.mb_str() ) );
274
275 if( m_username == wxString( j["username"].get<std::string>() )
276 && m_hostname == wxString( j["hostname"].get<std::string>() ) )
277 {
278 wxLogTrace( LCK, "User and host match for lock %s", m_lockFilename );
279 return true;
280 }
281 }
282 }
283 catch( std::exception &e )
284 {
285 wxLogError( "Got exception trying to check user/host for lock on %s: %s",
287 e.what() );
288 }
289
290 wxLogTrace( LCK, "User and host DID NOT match for lock %s", m_lockFilename );
291 return false;
292 }
293};
294
295
296#endif // INCLUDE__LOCK_FILE_H_
bool m_removeOnRelease
Definition: lockfile.h:253
LOCKFILE(const wxString &filename, bool aRemoveOnRelease=true)
Definition: lockfile.h:45
bool m_fileCreated
Definition: lockfile.h:251
wxString m_errorMsg
Definition: lockfile.h:254
bool m_status
Definition: lockfile.h:252
wxString m_lockFilename
Definition: lockfile.h:248
bool OverrideLock(bool aRemoveOnRelease=true)
Forces the lock, overwriting the data that existed already.
Definition: lockfile.h:158
bool Valid() const
Definition: lockfile.h:236
~LOCKFILE()
Definition: lockfile.h:130
wxString m_originalFile
Definition: lockfile.h:247
wxString m_hostname
Definition: lockfile.h:250
wxString GetUsername()
Definition: lockfile.h:219
wxString GetErrorMsg()
Definition: lockfile.h:229
wxString GetHostname()
Definition: lockfile.h:224
bool checkUserAndHost()
Definition: lockfile.h:256
bool Locked() const
Definition: lockfile.h:231
wxString m_username
Definition: lockfile.h:249
bool IsLockedByMe()
Definition: lockfile.h:211
void UnlockFile()
Unlocks and removes the file from the filesystem as long as we still own it.
Definition: lockfile.h:138
#define _(s)
static const std::string LockFileExtension
static const std::string LockFilePrefix
#define LCK
Definition: lockfile.h:40
Definition of file extensions used in Kicad.