LibreOffice Module desktop (master)  1
lockfile.cxx
Go to the documentation of this file.
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This file is part of the LibreOffice project.
4  *
5  * This Source Code Form is subject to the terms of the Mozilla Public
6  * License, v. 2.0. If a copy of the MPL was not distributed with this
7  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8  *
9  * This file incorporates work covered by the following license notice:
10  *
11  * Licensed to the Apache Software Foundation (ASF) under one or more
12  * contributor license agreements. See the NOTICE file distributed
13  * with this work for additional information regarding copyright
14  * ownership. The ASF licenses this file to you under the Apache
15  * License, Version 2.0 (the "License"); you may not use this file
16  * except in compliance with the License. You may obtain a copy of
17  * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18  */
19 
20 #include <sal/config.h>
21 
22 #include <memory>
23 
24 #include <time.h>
25 #ifndef _WIN32
26 #include <unistd.h>
27 #else
28 #if !defined WIN32_LEAN_AND_MEAN
29 # define WIN32_LEAN_AND_MEAN
30 #endif
31 #include <windows.h>
32 #endif
33 #include <comphelper/random.hxx>
34 #include <sal/types.h>
35 #include <osl/file.hxx>
36 #include <osl/security.hxx>
37 #include <unotools/bootstrap.hxx>
38 #include <tools/config.hxx>
39 
40 #include <lockfile.hxx>
41 
42 using namespace ::osl;
43 using namespace ::utl;
44 
45 
46 static OString impl_getHostname()
47 {
48  OString aHost;
49 #ifdef _WIN32
50  /*
51  prevent windows from connecting to the net to get its own
52  hostname by using the netbios name
53  */
54  DWORD sz = MAX_COMPUTERNAME_LENGTH + 1;
55  auto szHost = std::make_unique<char[]>(sz);
56  if (GetComputerNameA(szHost.get(), &sz))
57  aHost = OString(szHost.get());
58  else
59  aHost = OString("UNKNOWN");
60 #else
61  /* Don't do dns lookup on Linux either */
62  char pHostName[1024];
63 
64  if ( gethostname( pHostName, sizeof( pHostName ) - 1 ) == 0 )
65  {
66  pHostName[sizeof( pHostName ) - 1] = '\0';
67  aHost = OString( pHostName );
68  }
69  else
70  aHost = OString("UNKNOWN");
71 #endif
72 
73  return aHost;
74 }
75 
76 namespace desktop {
77 
78  Lockfile::Lockfile( bool bIPCserver )
79  :m_bIPCserver(bIPCserver)
80  ,m_bRemove(false)
81  ,m_bIsLocked(false)
82  {
83  // build the file-url to use for the lock
84  OUString aUserPath;
86  m_aLockname = aUserPath + "/.lock";
87 
88  // generate ID
89  const int nIdBytes = 16;
90  char tmpId[nIdBytes*2+1];
91  time_t t = time(nullptr);
92  for (int i = 0; i<nIdBytes; i++) {
93  int tmpByte = comphelper::rng::uniform_int_distribution(0, 0xFF);
94  sprintf( tmpId+i*2, "%02X", tmpByte );
95  }
96  tmpId[nIdBytes*2]=0x00;
97  m_aId = OUString::createFromAscii( tmpId );
98 
99  // generate date string
100  char *tmpTime = ctime( &t );
101  if (tmpTime != nullptr) {
102  m_aDate = OUString::createFromAscii( tmpTime );
103  sal_Int32 i = m_aDate.indexOf('\n');
104  if (i > 0)
105  m_aDate = m_aDate.copy(0, i);
106  }
107 
108 
109  // try to create file
110  File aFile(m_aLockname);
111  if (aFile.open( osl_File_OpenFlag_Create ) == File::E_EXIST) {
112  m_bIsLocked = true;
113  } else {
114  // new lock created
115  aFile.close( );
116  syncToFile( );
117  m_bRemove = true;
118  }
119  }
120 
121  bool Lockfile::check( fpExecWarning execWarning )
122  {
123 
124  if (m_bIsLocked) {
125  // lock existed, ask user what to do
126  if (isStale() ||
127  (execWarning != nullptr && (*execWarning)( this ))) {
128  // remove file and create new
129  File::remove( m_aLockname );
130  File aFile(m_aLockname);
131  (void)aFile.open( osl_File_OpenFlag_Create );
132  aFile.close( );
133  syncToFile( );
134  m_bRemove = true;
135  return true;
136  } else {
137  //leave alone and return false
138  m_bRemove = false;
139  return false;
140  }
141  } else {
142  // lock was created by us
143  return true;
144  }
145  }
146 
147  bool Lockfile::isStale() const
148  {
149  // this checks whether the lockfile was created on the same
150  // host by the same user. Should this be the case it is safe
151  // to assume that it is a stale lockfile which can be overwritten
152  OUString aLockname = m_aLockname;
153  Config aConfig(aLockname);
154  aConfig.SetGroup(LOCKFILE_GROUP);
155  OString aIPCserver = aConfig.ReadKey( LOCKFILE_IPCKEY );
156  if (!aIPCserver.equalsIgnoreAsciiCase("true"))
157  return false;
158 
159  OString aHost = aConfig.ReadKey( LOCKFILE_HOSTKEY );
160  OString aUser = aConfig.ReadKey( LOCKFILE_USERKEY );
161 
162  // lockfile from same host?
163  OString myHost( impl_getHostname() );
164  if (aHost == myHost) {
165  // lockfile by same UID
166  OUString myUserName;
167  Security aSecurity;
168  aSecurity.getUserName( myUserName );
169  OString myUser(OUStringToOString(myUserName, RTL_TEXTENCODING_ASCII_US));
170  if (aUser == myUser)
171  return true;
172  }
173  return false;
174  }
175 
176  void Lockfile::syncToFile() const
177  {
178  OUString aLockname = m_aLockname;
179  Config aConfig(aLockname);
180  aConfig.SetGroup(LOCKFILE_GROUP);
181 
182  // get information
183  OString aHost( impl_getHostname() );
184  OUString aUserName;
185  Security aSecurity;
186  aSecurity.getUserName( aUserName );
187  OString aUser = OUStringToOString( aUserName, RTL_TEXTENCODING_ASCII_US );
188  OString aTime = OUStringToOString( m_aDate, RTL_TEXTENCODING_ASCII_US );
189  OString aStamp = OUStringToOString( m_aId, RTL_TEXTENCODING_ASCII_US );
190 
191  // write information
192  aConfig.WriteKey( LOCKFILE_USERKEY, aUser );
193  aConfig.WriteKey( LOCKFILE_HOSTKEY, aHost );
194  aConfig.WriteKey( LOCKFILE_STAMPKEY, aStamp );
195  aConfig.WriteKey( LOCKFILE_TIMEKEY, aTime );
196  aConfig.WriteKey(
198  m_bIPCserver ? OString("true") : OString("false") );
199  aConfig.Flush( );
200  }
201 
203  {
204  // unlock userdata by removing file
205  if ( m_bRemove )
206  File::remove( m_aLockname );
207  }
208 }
209 
210 
211 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
bool check(fpExecWarning execWarning)
Definition: lockfile.cxx:121
static PathStatus locateUserInstallation(OUString &_rURL)
static OString impl_getHostname()
Definition: lockfile.cxx:46
Definition: app.cxx:160
void SetGroup(const OString &rGroup)
#define LOCKFILE_HOSTKEY
Definition: lockfile.hxx:44
OUString m_aLockname
Definition: lockfile.hxx:74
Lockfile(bool bIPCserver=true)
Definition: lockfile.cxx:78
void Flush()
OString ReadKey(const OString &rKey) const
void WriteKey(const OString &rKey, const OString &rValue)
#define LOCKFILE_STAMPKEY
Definition: lockfile.hxx:45
int i
OUString m_aDate
Definition: lockfile.hxx:80
#define LOCKFILE_USERKEY
Definition: lockfile.hxx:43
bool isStale() const
Definition: lockfile.cxx:147
XPropertyListType t
OUString m_aId
Definition: lockfile.hxx:79
OString OUStringToOString(const OUString &str, ConnectionSettings const *settings)
#define LOCKFILE_GROUP
Definition: lockfile.hxx:42
#define LOCKFILE_IPCKEY
Definition: lockfile.hxx:47
int uniform_int_distribution(int a, int b)
void syncToFile() const
Definition: lockfile.cxx:176
#define LOCKFILE_TIMEKEY
Definition: lockfile.hxx:46
typedef void(CALLTYPE *GetFuncDataPtr)(sal_uInt16 &nNo