/* lock.c - Implement basic file locking for GDBM. */
/* This file is part of GDBM, the GNU data base manager.
Copyright (C) 2008, 2011, 2013 Free Software Foundation, Inc.
GDBM is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GDBM is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with GDBM. If not, see . */
/* Include system configuration before all else. */
#include "autoconf.h"
#include "gdbmdefs.h"
#include
#if HAVE_FLOCK
# ifndef LOCK_SH
# define LOCK_SH 1
# endif
# ifndef LOCK_EX
# define LOCK_EX 2
# endif
# ifndef LOCK_NB
# define LOCK_NB 4
# endif
# ifndef LOCK_UN
# define LOCK_UN 8
# endif
#endif
#if defined(F_SETLK) && defined(F_RDLCK) && defined(F_WRLCK)
# define HAVE_FCNTL_LOCK 1
#else
# define HAVE_FCNTL_LOCK 0
#endif
#if 0
int
gdbm_locked (GDBM_FILE dbf)
{
return (dbf->lock_type != LOCKING_NONE);
}
#endif
void
_gdbm_unlock_file (GDBM_FILE dbf)
{
#if HAVE_FCNTL_LOCK
struct flock fl;
#endif
switch (dbf->lock_type)
{
case LOCKING_FLOCK:
#if HAVE_FLOCK
flock (dbf->desc, LOCK_UN);
#endif
break;
case LOCKING_LOCKF:
#if HAVE_LOCKF
lockf (dbf->desc, F_ULOCK, (off_t)0L);
#endif
break;
case LOCKING_FCNTL:
#if HAVE_FCNTL_LOCK
fl.l_type = F_UNLCK;
fl.l_whence = SEEK_SET;
fl.l_start = fl.l_len = (off_t)0L;
fcntl (dbf->desc, F_SETLK, &fl);
#endif
break;
case LOCKING_NONE:
break;
}
dbf->lock_type = LOCKING_NONE;
}
/* Try each supported locking mechanism. */
int
_gdbm_lock_file (GDBM_FILE dbf)
{
#if HAVE_FCNTL_LOCK
struct flock fl;
#endif
int lock_val = -1;
#if HAVE_FLOCK
if (dbf->read_write == GDBM_READER)
lock_val = flock (dbf->desc, LOCK_SH + LOCK_NB);
else
lock_val = flock (dbf->desc, LOCK_EX + LOCK_NB);
if ((lock_val == -1) && (errno == EWOULDBLOCK))
{
dbf->lock_type = LOCKING_NONE;
return lock_val;
}
else if (lock_val != -1)
{
dbf->lock_type = LOCKING_FLOCK;
return lock_val;
}
#endif
#if HAVE_LOCKF
/* Mask doesn't matter for lockf. */
lock_val = lockf (dbf->desc, F_LOCK, (off_t)0L);
if ((lock_val == -1) && (errno == EDEADLK))
{
dbf->lock_type = LOCKING_NONE;
return lock_val;
}
else if (lock_val != -1)
{
dbf->lock_type = LOCKING_LOCKF;
return lock_val;
}
#endif
#if HAVE_FCNTL_LOCK
/* If we're still here, try fcntl. */
if (dbf->read_write == GDBM_READER)
fl.l_type = F_RDLCK;
else
fl.l_type = F_WRLCK;
fl.l_whence = SEEK_SET;
fl.l_start = fl.l_len = (off_t)0L;
lock_val = fcntl (dbf->desc, F_SETLK, &fl);
if (lock_val != -1)
dbf->lock_type = LOCKING_FCNTL;
#endif
if (lock_val == -1)
dbf->lock_type = LOCKING_NONE;
return lock_val;
}