mirror of
https://github.com/Gnucash/gnucash.git
synced 2024-11-25 18:30:23 -06:00
Merge Simon Arlott's 'xml-locking-fixes' into maint.
This commit is contained in:
commit
901fea158f
@ -171,8 +171,11 @@ GncXmlBackend::session_end()
|
||||
if (!m_linkfile.empty())
|
||||
g_unlink (m_linkfile.c_str());
|
||||
|
||||
if (m_lockfd > 0)
|
||||
if (m_lockfd != -1)
|
||||
{
|
||||
close (m_lockfd);
|
||||
m_lockfd = -1;
|
||||
}
|
||||
|
||||
if (!m_lockfile.empty())
|
||||
{
|
||||
@ -638,12 +641,13 @@ GncXmlBackend::get_file_lock ()
|
||||
{
|
||||
/* oops .. file is locked by another user .. */
|
||||
set_error(ERR_BACKEND_LOCKED);
|
||||
m_lockfile.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
m_lockfd = g_open (m_lockfile.c_str(), O_RDWR | O_CREAT | O_EXCL ,
|
||||
S_IRUSR | S_IWUSR);
|
||||
if (m_lockfd < 0)
|
||||
if (m_lockfd == -1)
|
||||
{
|
||||
/* oops .. we can't create the lockfile .. */
|
||||
switch (errno)
|
||||
@ -661,87 +665,11 @@ GncXmlBackend::get_file_lock ()
|
||||
PWARN ("Unable to create the lockfile %s: %s",
|
||||
m_lockfile.c_str(), strerror(errno));
|
||||
set_error(be_err);
|
||||
m_lockfile.clear();
|
||||
return false;
|
||||
}
|
||||
|
||||
/* OK, now work around some NFS atomic lock race condition
|
||||
* mumbo-jumbo. We do this by linking a unique file, and
|
||||
* then examining the link count. At least that's what the
|
||||
* NFS programmers guide suggests.
|
||||
* Note: the "unique filename" must be unique for the
|
||||
* triplet filename-host-process, otherwise accidental
|
||||
* aliases can occur.
|
||||
*/
|
||||
|
||||
/* apparently, even this code may not work for some NFS
|
||||
* implementations. In the long run, I am told that
|
||||
* ftp.debian.org
|
||||
* /pub/debian/dists/unstable/main/source/libs/liblockfile_0.1-6.tar.gz
|
||||
* provides a better long-term solution.
|
||||
*/
|
||||
|
||||
#ifndef G_OS_WIN32
|
||||
auto path = m_lockfile.find_last_of('.');
|
||||
std::stringstream linkfile;
|
||||
if (path != std::string::npos)
|
||||
linkfile << m_lockfile.substr(0, path);
|
||||
else
|
||||
linkfile << m_lockfile;
|
||||
linkfile << "." << gethostid() << "." << getpid() << ".LNK";
|
||||
rc = link (m_lockfile.c_str(), linkfile.str().c_str());
|
||||
if (rc)
|
||||
{
|
||||
/* If hard links aren't supported, just allow the lock. */
|
||||
if (errno == EPERM || errno == ENOSYS
|
||||
# ifdef EOPNOTSUPP
|
||||
|| errno == EOPNOTSUPP
|
||||
# endif
|
||||
# ifdef ENOTSUP
|
||||
|| errno == ENOTSUP
|
||||
# endif
|
||||
)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Otherwise, something else is wrong. */
|
||||
set_error(ERR_BACKEND_LOCKED);
|
||||
g_unlink (linkfile.str().c_str());
|
||||
close (m_lockfd);
|
||||
g_unlink (m_lockfile.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
rc = g_stat (m_lockfile.c_str(), &statbuf);
|
||||
if (rc)
|
||||
{
|
||||
/* oops .. stat failed! This can't happen! */
|
||||
set_error(ERR_BACKEND_LOCKED);
|
||||
std::string msg{"Failed to stat lockfile "};
|
||||
set_message(msg + m_lockfile);
|
||||
g_unlink (linkfile.str().c_str());
|
||||
close (m_lockfd);
|
||||
g_unlink (m_lockfile.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (statbuf.st_nlink != 2)
|
||||
{
|
||||
set_error(ERR_BACKEND_LOCKED);
|
||||
g_unlink (linkfile.str().c_str());
|
||||
close (m_lockfd);
|
||||
g_unlink (m_lockfile.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
m_linkfile = linkfile.str();
|
||||
return true;
|
||||
|
||||
#else /* ifndef G_OS_WIN32 */
|
||||
/* On windows, there is no NFS and the open(,O_CREAT | O_EXCL)
|
||||
is sufficient for locking. */
|
||||
return true;
|
||||
#endif /* ifndef G_OS_WIN32 */
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -60,7 +60,7 @@ private:
|
||||
std::string m_dirname;
|
||||
std::string m_lockfile;
|
||||
std::string m_linkfile;
|
||||
int m_lockfd;
|
||||
int m_lockfd = -1;
|
||||
|
||||
QofBook* m_book = nullptr; /* The primary, main open book */
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user