32 #include <sys/types.h>    44 # include <cygwin/version.h>    45 # include <sys/cygwin.h>    48 #ifdef FLINTLOCK_USE_FLOCK    49 # include <sys/file.h>    60 #  define F_OFD_GETLK   36    61 #  define F_OFD_SETLK   37    62 #  define F_OFD_SETLKW  38    78     if (filename.empty()) 
return false;
    80 #if defined __CYGWIN__ || defined __WIN32__    81     if (hFile != INVALID_HANDLE_VALUE) 
return true;
    85 #elif defined FLINTLOCK_USE_FLOCK    86     if (fd != -1) 
return true;
    91     if (fd != -1) 
return true;
    92     int lockfd = 
open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | 
O_CLOEXEC, 0666);
    95         reason why = ((errno == EMFILE || errno == ENFILE) ? FDLIMIT : UNKNOWN);
    96         throw_databaselockerror(why, filename, 
"Testing lock");
   101     fl.l_whence = SEEK_SET;
   105     while (fcntl(lockfd, F_GETLK, &fl) == -1) {
   106         if (errno != EINTR) {
   115             reason why = (e == ENOLCK ? UNSUPPORTED : UNKNOWN);
   116             throw_databaselockerror(why, filename, 
"Testing lock");
   120     return fl.l_type != F_UNLCK;
   129 #if defined __CYGWIN__ || defined __WIN32__   130     Assert(hFile == INVALID_HANDLE_VALUE);
   133 #if CYGWIN_VERSION_API_MAJOR == 0 && CYGWIN_VERSION_API_MINOR < 181   134     cygwin_conv_to_win32_path(filename.c_str(), fnm);
   136     if (cygwin_conv_path(CCP_POSIX_TO_WIN_A|CCP_RELATIVE, filename.c_str(),
   137                          fnm, MAX_PATH) < 0) {
   138         explanation.assign(
"cygwin_conv_path failed: ");
   144     const char *fnm = filename.c_str();
   150     hFile = CreateFile(fnm, GENERIC_WRITE, FILE_SHARE_READ,
   151                        NULL, OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
   152     if (hFile != INVALID_HANDLE_VALUE) 
return SUCCESS;
   153     if (GetLastError() == ERROR_ALREADY_EXISTS) {
   160     explanation = string();
   162 #elif defined FLINTLOCK_USE_FLOCK   177     int lockfd = 
open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | 
O_CLOEXEC, 0666);
   180         explanation.assign(
"Couldn't open lockfile: ");
   182         return ((errno == EMFILE || errno == ENFILE) ? FDLIMIT : UNKNOWN);
   186     if (!wait) op |= LOCK_NB;
   187     while (flock(lockfd, op) == -1) {
   188         if (errno != EINTR) {
   210     int lockfd = 
open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC | 
O_CLOEXEC, 0666);
   213         explanation.assign(
"Couldn't open lockfile: ");
   215         return ((errno == EMFILE || errno == ENFILE) ? FDLIMIT : UNKNOWN);
   228     static bool f_ofd_setlk_fails = 
false;
   229     if (!f_ofd_setlk_fails) {
   232         fl.l_whence = SEEK_SET;
   236         while (fcntl(lockfd, wait ? F_OFD_SETLKW : F_OFD_SETLK, &fl) == -1) {
   237             if (errno != EINTR) {
   238                 if (errno == EINVAL) {
   247                     case EACCES: 
case EAGAIN:
   260         f_ofd_setlk_fails = 
true;
   265     if (socketpair(AF_UNIX, SOCK_STREAM|
SOCK_CLOEXEC, PF_UNSPEC, fds) < 0) {
   267         explanation.assign(
"Couldn't create socketpair: ");
   269         reason why = ((errno == EMFILE || errno == ENFILE) ? FDLIMIT : UNKNOWN);
   276     if (
rare(fds[1] == 2)) swap(fds[0], fds[1]);
   278     pid_t child = fork();
   289         int parentfd = fds[1];
   308         bool lockfd_cloexec_cleared = 
false;
   309         int dup_parent_to_first = parentfd == 0 ? 1 : 0;
   310         if (
rare(lockfd < 2)) {
   311             int oldlockfd = lockfd;
   314             lockfd = dup2(lockfd, 2);
   315             if (
rare(lockfd < 0)) 
goto report_dup_failure;
   316             lockfd_cloexec_cleared = 
true;
   318             dup_parent_to_first = oldlockfd;
   325         if (
rare(dup2(parentfd, dup_parent_to_first) < 0)) {
   327             _exit((errno == EMFILE || errno == ENFILE) ? FDLIMIT : UNKNOWN);
   330         if (
rare(dup2(dup_parent_to_first, dup_parent_to_first ^ 1) < 0))
   331             goto report_dup_failure;
   336             lockfd = dup2(lockfd, 2);
   337             if (
rare(lockfd < 0)) 
goto report_dup_failure;
   338         } 
else if (!lockfd_cloexec_cleared && 
O_CLOEXEC != 0) {
   339 #if defined F_SETFD && defined FD_CLOEXEC   340             (void)fcntl(lockfd, F_SETFD, 0);
   344             if (
rare(dup2(lockfd, 3) < 0 || dup2(3, lockfd) < 0))
   345                 goto report_dup_failure;
   354             fl.l_whence = SEEK_SET;
   357             while (fcntl(lockfd, wait ? F_SETLKW : F_SETLK, &fl) == -1) {
   358                 if (errno != EINTR) {
   361                     if (errno == EACCES || errno == EAGAIN) {
   363                     } 
else if (errno == ENOLCK) {
   375             while (write(1, 
"", 1) < 0) {
   381                 if (errno != EINTR) _exit(UNKNOWN);
   387         if (chdir(
"/") < 0) {
   397         execl(
"/bin/cat", 
"/bin/cat", static_cast<void*>(NULL));
   400         while (read(0, &ch, 1) != 0) {
   411         explanation.assign(
"Couldn't fork: ");
   420         ssize_t n = read(fds[0], &ch, 1);
   432         if (errno != EINTR) {
   434             explanation.assign(
"Error reading from child process: ");
   443     while (waitpid(child, &status, 0) < 0) {
   444         if (errno != EINTR) 
return UNKNOWN;
   448     if (WIFEXITED(status)) {
   449         int exit_status = WEXITSTATUS(status);
   450         if (
usual(exit_status > 0 && exit_status <= UNKNOWN))
   451             why = 
static_cast<reason>(exit_status);
   460 #if defined __CYGWIN__ || defined __WIN32__   461     if (hFile == INVALID_HANDLE_VALUE) 
return;
   463     hFile = INVALID_HANDLE_VALUE;
   464 #elif defined FLINTLOCK_USE_FLOCK   473     if (pid == 0) 
return;
   485     if (kill(pid, SIGKILL) == 0) {
   487         while (waitpid(pid, &status, 0) < 0) {
   488             if (errno != EINTR) 
break;
   496                                    const string & db_dir,
   497                                    const string & explanation)
 const   499     string msg(
"Unable to get write lock on ");
   502         msg += 
": already locked";
   504         msg += 
": locking probably not supported by this FS";
   506         msg += 
": too many open files";
   508         if (!explanation.empty())
   509             msg += 
": " + explanation;
 
void throw_databaselockerror(FlintLock::reason why, const std::string &db_dir, const std::string &explanation) const
Throw Xapian::DatabaseLockError. 
 
void release()
Release the lock. 
 
include <sys/socket.h> with portability workarounds. 
 
Convert errno value to std::string, thread-safe if possible. 
 
Implementation of closefrom() function. 
 
WritableDatabase open()
Construct a WritableDatabase object for a new, empty InMemory database. 
 
Flint-compatible database locking. 
 
bool test() const
Test if the lock is held. 
 
Hierarchy of classes which Xapian can throw as exceptions. 
 
DatabaseLockError indicates failure to lock a database. 
 
void errno_to_string(int e, string &s)
 
Indicates an attempt to use a feature which is unavailable. 
 
static void throw_cannot_test_lock()
 
reason lock(bool exclusive, bool wait, std::string &explanation)
Attempt to obtain the lock. 
 
Various assertion macros. 
 
include <fcntl.h>, but working around broken platforms.