lean4-htt/src/util/file_lock.cpp
Leonardo de Moura c07345d47f fix(util/file_lock): handle permission denied at lock creation
see #925

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
2015-12-15 09:48:20 -08:00

100 lines
2.5 KiB
C++

/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <string>
#include <sys/file.h>
#include <errno.h>
#include "util/exception.h"
#include "util/sstream.h"
#include "util/file_lock.h"
#ifdef LEAN_WINDOWS
#include <windows.h>
#include <io.h>
#define LOCK_SH 1 /* shared lock */
#define LOCK_EX 2 /* exclusive lock */
#define LOCK_NB 4 /* don't block when locking */
#define LOCK_UN 8 /* unlock */
static BOOL lock(HANDLE h, int non_blocking, int exclusive) {
DWORD lower, upper;
OVERLAPPED ovlp;
int flags = 0;
lower = GetFileSize(h, &upper);
memset (&ovlp, 0, sizeof(ovlp));
if (non_blocking)
flags |= LOCKFILE_FAIL_IMMEDIATELY;
if (exclusive)
flags |= LOCKFILE_EXCLUSIVE_LOCK;
return LockFileEx(h, flags, 0, lower, upper, &ovlp);
}
static BOOL unlock(HANDLE h) {
DWORD lower, upper;
lower = GetFileSize(h, &upper);
return UnlockFile(h, 0, 0, lower, upper);
}
int flock(int fd, int op) {
HANDLE h = (HANDLE)_get_osfhandle(fd);
DWORD res;
int non_blocking;
if (h == INVALID_HANDLE_VALUE)
return -1;
non_blocking = op & LOCK_NB;
op &= ~LOCK_NB;
switch (op) {
case LOCK_SH:
res = lock(h, non_blocking, 0);
break;
case LOCK_EX:
res = lock(h, non_blocking, 1);
break;
case LOCK_UN:
res = unlock(h);
break;
default:
return -1;
}
return !res ? -1 : 0;
}
#else
#include <unistd.h>
#endif
namespace lean {
file_lock::file_lock(char const * fname, bool exclusive):
m_fname(fname), m_fd(-1) {
m_fname += ".lock";
m_fd = open(m_fname.c_str(), O_CREAT, 0xFFFF);
if (m_fd == -1) {
if (errno == EACCES) {
// We don't have permission to create the file, the folder containing fname is probably readonly.
// fname is probably part of the Lean installation in a system directory.
// So, we ignore the file_lock in this case.
} else {
throw exception(sstream() << "failed to lock file '" << fname << "'");
}
} else {
int status = flock(m_fd, exclusive ? LOCK_EX : LOCK_SH);
if (status == -1)
throw exception(sstream() << "failed to lock file '" << fname << "'");
}
}
file_lock::~file_lock() {
if (m_fd != -1) {
std::remove(m_fname.c_str());
flock(m_fd, LOCK_UN);
close(m_fd);
}
}
}