aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWerner Koch <[email protected]>2012-01-10 14:16:44 +0000
committerWerner Koch <[email protected]>2012-01-10 14:16:44 +0000
commitb9333cd890a85cae5064ff2b0b97c4ba2afc1a99 (patch)
treecbdb29e5debd97313848a6e8bb271b0300e786bf
parentUpdate copyright years. (diff)
downloadgnupg-b9333cd890a85cae5064ff2b0b97c4ba2afc1a99.tar.gz
gnupg-b9333cd890a85cae5064ff2b0b97c4ba2afc1a99.zip
Replace file locking by the new portable dotlock code.
* include/dotlock.h: New. From current gnupg master. * util/dotlock.c: Ditto. Include util.h. The major changes done in master are: Factor Unix and W32 specific code out into specific functions. Define HAVE_POSIX_SYSTEM. Rearrange some functions. (disable_dotlock): Rename to dotlock_disable. (create_dotlock): Rename to dotlock_create and add a dummy arg. (destroy_dotlock): Rename to dotlock_destroy. (make_dotlock): Rename to dotlock_take. (release_dotlock): Rename to dotlock_release. (remove_lockfiles): Rename to dotlock_remove_lockfiles.
-rw-r--r--configure.ac3
-rw-r--r--g10/gpg.c4
-rw-r--r--g10/gpgv.c15
-rw-r--r--g10/keydb.c10
-rw-r--r--g10/keyring.c212
-rw-r--r--g10/signal.c6
-rw-r--r--g10/tdbio.c48
-rw-r--r--include/dotlock.h112
-rw-r--r--include/util.h18
-rw-r--r--util/dotlock.c1555
10 files changed, 1386 insertions, 597 deletions
diff --git a/configure.ac b/configure.ac
index 8570daa7b..181c07bf5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -933,7 +933,8 @@ AM_CONDITIONAL(ENABLE_AGENT_SUPPORT, test "$agent_support" = yes)
dnl Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS([unistd.h langinfo.h termio.h locale.h getopt.h pwd.h])
+AC_CHECK_HEADERS([unistd.h langinfo.h termio.h locale.h getopt.h pwd.h \
+ signal.h])
# Note that we do not check for iconv here because this is done anyway
# by the gettext checks and thus it allows us to disable the use of
diff --git a/g10/gpg.c b/g10/gpg.c
index 3106d290e..438da523c 100644
--- a/g10/gpg.c
+++ b/g10/gpg.c
@@ -1895,7 +1895,7 @@ main (int argc, char **argv )
secure_randoxmalloc(); /* put random number into secure memory */
may_coredump = disable_core_dumps();
init_signals();
- create_dotlock(NULL); /* register locking cleanup */
+ dotlock_create (NULL, 0); /* Register locking cleanup. */
i18n_init();
opt.command_fd = -1; /* no command fd */
opt.compress_level = -1; /* defaults to standard compress level */
@@ -2607,7 +2607,7 @@ main (int argc, char **argv )
case oNoEscapeFrom: opt.escape_from = 0; break;
case oLockOnce: opt.lock_once = 1; break;
case oLockNever:
- disable_dotlock ();
+ dotlock_disable ();
random_disable_locking ();
break;
case oLockMultiple:
diff --git a/g10/gpgv.c b/g10/gpgv.c
index dfeaa85d7..8d2a8e6b1 100644
--- a/g10/gpgv.c
+++ b/g10/gpgv.c
@@ -148,7 +148,7 @@ main( int argc, char **argv )
tty_no_terminal(1);
tty_batchmode(1);
- disable_dotlock();
+ dotlock_disable ();
set_native_charset (NULL); /* Try to auto set the character set */
@@ -430,9 +430,10 @@ void rl_free_line_state (void) {}
#endif
/* We do not do any locking, so use these stubs here */
-void disable_dotlock(void) {}
-DOTLOCK create_dotlock( const char *file_to_lock ) { return NULL; }
-void destroy_dotlock (DOTLOCK h) {}
-int make_dotlock( DOTLOCK h, long timeout ) { return 0;}
-int release_dotlock( DOTLOCK h ) {return 0;}
-void remove_lockfiles(void) {}
+void dotlock_disable(void) {}
+dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags)
+{ return NULL; }
+void dotlock_destroy (dotlock_t h) {}
+int dotlock_take (dotlock_t h, long timeout) { return 0;}
+int dotlock_release (dotlock_t h) {return 0;}
+void dotlock_remove_lockfiles (void) {}
diff --git a/g10/keydb.c b/g10/keydb.c
index 5a62f18c0..d6d83e252 100644
--- a/g10/keydb.c
+++ b/g10/keydb.c
@@ -76,7 +76,7 @@ static void unlock_all (KEYDB_HANDLE hd);
static int
maybe_create_keyring (char *filename, int force)
{
- DOTLOCK lockhd = NULL;
+ dotlock_t lockhd = NULL;
IOBUF iobuf;
int rc;
mode_t oldmask;
@@ -120,7 +120,7 @@ maybe_create_keyring (char *filename, int force)
/* To avoid races with other instances of gpg trying to create or
update the keyring (it is removed during an update for a short
time), we do the next stuff in a locked state. */
- lockhd = create_dotlock (filename);
+ lockhd = dotlock_create (filename, 0);
if (!lockhd)
{
/* A reason for this to fail is that the directory is not
@@ -136,7 +136,7 @@ maybe_create_keyring (char *filename, int force)
return G10ERR_GENERAL;
}
- if ( make_dotlock (lockhd, -1) )
+ if ( dotlock_take (lockhd, -1) )
{
/* This is something bad. Probably a stale lockfile. */
log_info ("can't lock `%s'\n", filename );
@@ -180,8 +180,8 @@ maybe_create_keyring (char *filename, int force)
leave:
if (lockhd)
{
- release_dotlock (lockhd);
- destroy_dotlock (lockhd);
+ dotlock_release (lockhd);
+ dotlock_destroy (lockhd);
}
return rc;
}
diff --git a/g10/keyring.c b/g10/keyring.c
index fb399d4a2..108e107b2 100644
--- a/g10/keyring.c
+++ b/g10/keyring.c
@@ -30,7 +30,7 @@
#include "util.h"
#include "keyring.h"
#include "packet.h"
-#include "keydb.h"
+#include "keydb.h"
#include "options.h"
#include "main.h" /*for check_key_signature()*/
#include "i18n.h"
@@ -45,14 +45,14 @@ struct off_item {
/*off_t off;*/
};
-typedef struct off_item **OffsetHashTable;
+typedef struct off_item **OffsetHashTable;
typedef struct keyring_name *KR_NAME;
struct keyring_name {
struct keyring_name *next;
int secret;
- DOTLOCK lockhd;
+ dotlock_t lockhd;
int is_locked;
int did_full_scan;
char fname[1];
@@ -76,7 +76,7 @@ struct keyring_handle {
int error;
} current;
struct {
- CONST_KR_NAME kr;
+ CONST_KR_NAME kr;
off_t offset;
size_t pk_no;
size_t uid_no;
@@ -99,7 +99,7 @@ static struct off_item *
new_offset_item (void)
{
struct off_item *k;
-
+
k = xmalloc_clear (sizeof *k);
return k;
}
@@ -118,7 +118,7 @@ release_offset_items (struct off_item *k)
}
#endif
-static OffsetHashTable
+static OffsetHashTable
new_offset_hash_table (void)
{
struct off_item **tbl;
@@ -159,7 +159,7 @@ update_offset_hash_table (OffsetHashTable tbl, u32 *kid, off_t off)
for (k = tbl[(kid[1] & 0x07ff)]; k; k = k->next)
{
- if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
+ if (k->kid[0] == kid[0] && k->kid[1] == kid[1])
{
/*k->off = off;*/
return;
@@ -189,7 +189,7 @@ update_offset_hash_table_from_kb (OffsetHashTable tbl, KBNODE node, off_t off)
}
}
-/*
+/*
* Register a filename for plain keyring files. ptr is set to a
* pointer to be used to create a handles etc, or the already-issued
* pointer if it has already been registered. The function returns 1
@@ -241,12 +241,12 @@ keyring_is_writable (void *token)
return r? !access (r->fname, W_OK) : 0;
}
-
+
/* Create a new handle for the resource associated with TOKEN. SECRET
is just just as a cross-check.
-
+
The returned handle must be released using keyring_release (). */
KEYRING_HANDLE
keyring_new (void *token, int secret)
@@ -255,7 +255,7 @@ keyring_new (void *token, int secret)
KR_NAME resource = token;
assert (resource && !resource->secret == !secret);
-
+
hd = xmalloc_clear (sizeof *hd);
hd->resource = resource;
hd->secret = !!secret;
@@ -263,7 +263,7 @@ keyring_new (void *token, int secret)
return hd;
}
-void
+void
keyring_release (KEYRING_HANDLE hd)
{
if (!hd)
@@ -290,7 +290,7 @@ keyring_get_resource_name (KEYRING_HANDLE hd)
* Lock the keyring with the given handle, or unlok if yes is false.
* We ignore the handle and lock all registered files.
*/
-int
+int
keyring_lock (KEYRING_HANDLE hd, int yes)
{
KR_NAME kr;
@@ -302,7 +302,7 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
if (!keyring_is_writable(kr))
continue;
if (!kr->lockhd) {
- kr->lockhd = create_dotlock( kr->fname );
+ kr->lockhd = dotlock_create (kr->fname, 0);
if (!kr->lockhd) {
log_info ("can't allocate lock for `%s'\n", kr->fname );
rc = G10ERR_GENERAL;
@@ -311,18 +311,18 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
}
if (rc)
return rc;
-
+
/* and now set the locks */
for (kr=kr_names; kr; kr = kr->next) {
if (!keyring_is_writable(kr))
continue;
if (kr->is_locked)
;
- else if (make_dotlock (kr->lockhd, -1) ) {
+ else if (dotlock_take (kr->lockhd, -1) ) {
log_info ("can't lock `%s'\n", kr->fname );
rc = G10ERR_GENERAL;
}
- else
+ else
kr->is_locked = 1;
}
}
@@ -333,12 +333,12 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
continue;
if (!kr->is_locked)
;
- else if (release_dotlock (kr->lockhd))
+ else if (dotlock_release (kr->lockhd))
log_info ("can't unlock `%s'\n", kr->fname );
- else
+ else
kr->is_locked = 0;
}
- }
+ }
return rc;
}
@@ -348,7 +348,7 @@ keyring_lock (KEYRING_HANDLE hd, int yes)
/*
* Return the last found keyring. Caller must free it.
* The returned keyblock has the kbode flag bit 0 set for the node with
- * the public key used to locate the keyblock or flag bit 1 set for
+ * the public key used to locate the keyblock or flag bit 1 set for
* the user ID node.
*/
int
@@ -394,7 +394,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
init_packet (pkt);
continue;
}
- if (rc) {
+ if (rc) {
log_error ("keyring_get_keyblock: read error: %s\n",
g10_errstr(rc) );
rc = G10ERR_INV_KEYRING;
@@ -416,14 +416,14 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
in_cert = 1;
if (pkt->pkttype == PKT_RING_TRUST) {
/*(this code is duplicated after the loop)*/
- if ( lastnode
+ if ( lastnode
&& lastnode->pkt->pkttype == PKT_SIGNATURE
&& (pkt->pkt.ring_trust->sigcache & 1) ) {
- /* This is a ring trust packet with a checked signature
+ /* This is a ring trust packet with a checked signature
* status cache following directly a signature paket.
* Set the cache status into that signature packet. */
PKT_signature *sig = lastnode->pkt->pkt.signature;
-
+
sig->flags.checked = 1;
sig->flags.valid = !!(pkt->pkt.ring_trust->sigcache & 2);
}
@@ -441,27 +441,27 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
keyblock = node;
else
add_kbnode (keyblock, node);
-
+
if ( pkt->pkttype == PKT_PUBLIC_KEY
|| pkt->pkttype == PKT_PUBLIC_SUBKEY
|| pkt->pkttype == PKT_SECRET_KEY
- || pkt->pkttype == PKT_SECRET_SUBKEY)
+ || pkt->pkttype == PKT_SECRET_SUBKEY)
{
if (++pk_no == hd->found.pk_no)
node->flag |= 1;
}
- else if ( pkt->pkttype == PKT_USER_ID)
+ else if ( pkt->pkttype == PKT_USER_ID)
{
if (++uid_no == hd->found.uid_no)
node->flag |= 2;
}
-
+
pkt = xmalloc (sizeof *pkt);
init_packet(pkt);
}
set_packet_list_mode(save_mode);
- if (rc == -1 && keyblock)
+ if (rc == -1 && keyblock)
rc = 0; /* got the entire keyblock */
if (rc || !ret_kb)
@@ -469,7 +469,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
else {
/*(duplicated form the loop body)*/
if ( pkt && pkt->pkttype == PKT_RING_TRUST
- && lastnode
+ && lastnode
&& lastnode->pkt->pkttype == PKT_SIGNATURE
&& (pkt->pkt.ring_trust->sigcache & 1) ) {
PKT_signature *sig = lastnode->pkt->pkt.signature;
@@ -483,7 +483,7 @@ keyring_get_keyblock (KEYRING_HANDLE hd, KBNODE *ret_kb)
iobuf_close(a);
/* Make sure that future search operations fail immediately when
- * we know that we are working on a invalid keyring
+ * we know that we are working on a invalid keyring
*/
if (rc == G10ERR_INV_KEYRING)
hd->current.error = rc;
@@ -543,11 +543,11 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
fname = hd->found.kr->fname;
else if (hd->current.kr)
fname = hd->current.kr->fname;
- else
+ else
fname = hd->resource? hd->resource->fname:NULL;
if (!fname)
- return G10ERR_GENERAL;
+ return G10ERR_GENERAL;
/* close this one otherwise we will lose the position for
* a next search. Fixme: it would be better to adjust the position
@@ -562,7 +562,7 @@ keyring_insert_keyblock (KEYRING_HANDLE hd, KBNODE kb)
{
update_offset_hash_table_from_kb (kr_offtbl, kb, 0);
}
-
+
return rc;
}
@@ -608,10 +608,10 @@ keyring_delete_keyblock (KEYRING_HANDLE hd)
-/*
+/*
* Start the next search on this handle right at the beginning
*/
-int
+int
keyring_search_reset (KEYRING_HANDLE hd)
{
assert (hd);
@@ -621,17 +621,17 @@ keyring_search_reset (KEYRING_HANDLE hd)
hd->current.iobuf = NULL;
hd->current.eof = 0;
hd->current.error = 0;
-
+
hd->found.kr = NULL;
hd->found.offset = 0;
- return 0;
+ return 0;
}
static int
prepare_search (KEYRING_HANDLE hd)
{
- if (hd->current.error)
+ if (hd->current.error)
return hd->current.error; /* still in error state */
if (hd->current.kr && !hd->current.eof) {
@@ -640,7 +640,7 @@ prepare_search (KEYRING_HANDLE hd)
return 0; /* okay */
}
- if (!hd->current.kr && hd->current.eof)
+ if (!hd->current.kr && hd->current.eof)
return -1; /* still EOF */
if (!hd->current.kr) { /* start search with first keyring */
@@ -652,7 +652,7 @@ prepare_search (KEYRING_HANDLE hd)
assert (!hd->current.iobuf);
}
else { /* EOF */
- iobuf_close (hd->current.iobuf);
+ iobuf_close (hd->current.iobuf);
hd->current.iobuf = NULL;
hd->current.kr = NULL;
hd->current.eof = 1;
@@ -809,7 +809,7 @@ compare_name (int mode, const char *name, const char *uid, size_t uidlen)
int i;
const char *s, *se;
- if (mode == KEYDB_SEARCH_MODE_EXACT) {
+ if (mode == KEYDB_SEARCH_MODE_EXACT) {
for (i=0; name[i] && uidlen; i++, uidlen--)
if (uid[i] != name[i])
break;
@@ -820,7 +820,7 @@ compare_name (int mode, const char *name, const char *uid, size_t uidlen)
if (ascii_memistr( uid, uidlen, name ))
return 0;
}
- else if ( mode == KEYDB_SEARCH_MODE_MAIL
+ else if ( mode == KEYDB_SEARCH_MODE_MAIL
|| mode == KEYDB_SEARCH_MODE_MAILSUB
|| mode == KEYDB_SEARCH_MODE_MAILEND) {
for (i=0, s= uid; i < uidlen && *s != '<'; s++, i++)
@@ -832,7 +832,7 @@ compare_name (int mode, const char *name, const char *uid, size_t uidlen)
;
if (i < uidlen) {
i = se - s;
- if (mode == KEYDB_SEARCH_MODE_MAIL) {
+ if (mode == KEYDB_SEARCH_MODE_MAIL) {
if( strlen(name)-2 == i
&& !ascii_memcasecmp( s, name+1, i) )
return 0;
@@ -856,11 +856,11 @@ compare_name (int mode, const char *name, const char *uid, size_t uidlen)
}
-/*
+/*
* Search through the keyring(s), starting at the current position,
* for a keyblock which contains one of the keys described in the DESC array.
*/
-int
+int
keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
size_t ndesc, size_t *descindex)
{
@@ -880,28 +880,28 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
/* figure out what information we need */
need_uid = need_words = need_keyid = need_fpr = any_skip = 0;
- for (n=0; n < ndesc; n++)
+ for (n=0; n < ndesc; n++)
{
- switch (desc[n].mode)
+ switch (desc[n].mode)
{
- case KEYDB_SEARCH_MODE_EXACT:
+ case KEYDB_SEARCH_MODE_EXACT:
case KEYDB_SEARCH_MODE_SUBSTR:
case KEYDB_SEARCH_MODE_MAIL:
case KEYDB_SEARCH_MODE_MAILSUB:
case KEYDB_SEARCH_MODE_MAILEND:
need_uid = 1;
break;
- case KEYDB_SEARCH_MODE_WORDS:
+ case KEYDB_SEARCH_MODE_WORDS:
need_uid = 1;
need_words = 1;
break;
- case KEYDB_SEARCH_MODE_SHORT_KID:
+ case KEYDB_SEARCH_MODE_SHORT_KID:
case KEYDB_SEARCH_MODE_LONG_KID:
need_keyid = 1;
break;
- case KEYDB_SEARCH_MODE_FPR16:
+ case KEYDB_SEARCH_MODE_FPR16:
case KEYDB_SEARCH_MODE_FPR20:
- case KEYDB_SEARCH_MODE_FPR:
+ case KEYDB_SEARCH_MODE_FPR:
need_fpr = 1;
break;
case KEYDB_SEARCH_MODE_FIRST:
@@ -910,7 +910,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
break;
default: break;
}
- if (desc[n].skipfnc)
+ if (desc[n].skipfnc)
{
any_skip = 1;
need_keyid = 1;
@@ -929,7 +929,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
else if (ndesc == 1 && desc[0].mode == KEYDB_SEARCH_MODE_LONG_KID)
{
struct off_item *oi;
-
+
oi = lookup_offset_hash_table (kr_offtbl, desc[0].u.kid);
if (!oi)
{ /* We know that we don't have this key */
@@ -938,9 +938,9 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
return -1;
}
/* We could now create a positive search status and return.
- * However the problem is that another instance of gpg may
+ * However the problem is that another instance of gpg may
* have changed the keyring so that the offsets are not valid
- * anymore - therefore we don't do it
+ * anymore - therefore we don't do it
*/
}
@@ -951,13 +951,13 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
log_debug ("word search mode does not yet work\n");
/* FIXME: here is a long standing bug in our function and in addition we
just use the first search description */
- for (n=0; n < ndesc && !name; n++)
+ for (n=0; n < ndesc && !name; n++)
{
- if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS)
+ if (desc[n].mode == KEYDB_SEARCH_MODE_WORDS)
name = desc[n].u.name;
}
assert (name);
- if ( !hd->word_match.name || strcmp (hd->word_match.name, name) )
+ if ( !hd->word_match.name || strcmp (hd->word_match.name, name) )
{
/* name changed */
xfree (hd->word_match.name);
@@ -975,23 +975,23 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
main_offset = 0;
pk_no = uid_no = 0;
initial_skip = 1; /* skip until we see the start of a keyblock */
- while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid)))
+ while (!(rc=search_packet (hd->current.iobuf, &pkt, &offset, need_uid)))
{
byte afp[MAX_FINGERPRINT_LEN];
size_t an;
- if (pkt.pkttype == PKT_PUBLIC_KEY || pkt.pkttype == PKT_SECRET_KEY)
+ if (pkt.pkttype == PKT_PUBLIC_KEY || pkt.pkttype == PKT_SECRET_KEY)
{
main_offset = offset;
pk_no = uid_no = 0;
initial_skip = 0;
}
- if (initial_skip)
+ if (initial_skip)
{
free_packet (&pkt);
continue;
}
-
+
pk = NULL;
sk = NULL;
uid = NULL;
@@ -1012,13 +1012,13 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
if (use_offtbl && !kr_offtbl_ready)
update_offset_hash_table (kr_offtbl, aki, main_offset);
}
- else if (pkt.pkttype == PKT_USER_ID)
+ else if (pkt.pkttype == PKT_USER_ID)
{
uid = pkt.pkt.user_id;
++uid_no;
}
else if ( pkt.pkttype == PKT_SECRET_KEY
- || pkt.pkttype == PKT_SECRET_SUBKEY)
+ || pkt.pkttype == PKT_SECRET_SUBKEY)
{
sk = pkt.pkt.secret_key;
++pk_no;
@@ -1030,28 +1030,28 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
}
if (need_keyid)
keyid_from_sk (sk, aki);
-
+
}
- for (n=0; n < ndesc; n++)
+ for (n=0; n < ndesc; n++)
{
switch (desc[n].mode) {
- case KEYDB_SEARCH_MODE_NONE:
+ case KEYDB_SEARCH_MODE_NONE:
BUG ();
break;
- case KEYDB_SEARCH_MODE_EXACT:
+ case KEYDB_SEARCH_MODE_EXACT:
case KEYDB_SEARCH_MODE_SUBSTR:
case KEYDB_SEARCH_MODE_MAIL:
case KEYDB_SEARCH_MODE_MAILSUB:
case KEYDB_SEARCH_MODE_MAILEND:
- case KEYDB_SEARCH_MODE_WORDS:
+ case KEYDB_SEARCH_MODE_WORDS:
if ( uid && !compare_name (desc[n].mode,
desc[n].u.name,
- uid->name, uid->len))
+ uid->name, uid->len))
goto found;
break;
-
- case KEYDB_SEARCH_MODE_SHORT_KID:
+
+ case KEYDB_SEARCH_MODE_SHORT_KID:
if ((pk||sk) && desc[n].u.kid[1] == aki[1])
goto found;
break;
@@ -1065,19 +1065,19 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
goto found;
break;
case KEYDB_SEARCH_MODE_FPR20:
- case KEYDB_SEARCH_MODE_FPR:
+ case KEYDB_SEARCH_MODE_FPR:
if ((pk||sk) && !memcmp (desc[n].u.fpr, afp, 20))
goto found;
break;
- case KEYDB_SEARCH_MODE_FIRST:
+ case KEYDB_SEARCH_MODE_FIRST:
if (pk||sk)
goto found;
break;
- case KEYDB_SEARCH_MODE_NEXT:
+ case KEYDB_SEARCH_MODE_NEXT:
if (pk||sk)
goto found;
break;
- default:
+ default:
rc = G10ERR_INV_ARG;
goto found;
}
@@ -1089,7 +1089,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
meaningful if this function returns with no errors. */
if(descindex)
*descindex=n;
- for (n=any_skip?0:ndesc; n < ndesc; n++)
+ for (n=any_skip?0:ndesc; n < ndesc; n++)
{
if (desc[n].skipfnc
&& desc[n].skipfnc (desc[n].skipfncvalue, aki, uid))
@@ -1115,12 +1115,12 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
if (use_offtbl && !kr_offtbl_ready)
{
KR_NAME kr;
-
+
/* First set the did_full_scan flag for this keyring (ignore
secret keyrings) */
for (kr=kr_names; kr; kr = kr->next)
{
- if (!kr->secret && hd->resource == kr)
+ if (!kr->secret && hd->resource == kr)
{
kr->did_full_scan = 1;
break;
@@ -1130,14 +1130,14 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
offtbl ready */
for (kr=kr_names; kr; kr = kr->next)
{
- if (!kr->secret && !kr->did_full_scan)
+ if (!kr->secret && !kr->did_full_scan)
break;
}
if (!kr)
kr_offtbl_ready = 1;
}
}
- else
+ else
hd->current.error = rc;
free_packet(&pkt);
@@ -1149,7 +1149,7 @@ keyring_search (KEYRING_HANDLE hd, KEYDB_SEARCH_DESC *desc,
static int
create_tmp_file (const char *template,
char **r_bakfname, char **r_tmpfname, IOBUF *r_fp)
-{
+{
char *bakfname, *tmpfname;
mode_t oldmask;
@@ -1173,7 +1173,7 @@ create_tmp_file (const char *template,
strcpy (tmpfname,template);
strcpy (tmpfname+strlen(template)-4, EXTSEP_S "tmp");
}
- else
+ else
{ /* file does not end with gpg; hmmm */
bakfname = xmalloc (strlen( template ) + 5);
strcpy (stpcpy(bakfname, template), EXTSEP_S "bak");
@@ -1206,7 +1206,7 @@ create_tmp_file (const char *template,
xfree (bakfname);
return G10ERR_OPEN_FILE;
}
-
+
*r_bakfname = bakfname;
*r_tmpfname = tmpfname;
return 0;
@@ -1233,7 +1233,7 @@ rename_tmp_file (const char *bakfname, const char *tmpfname,
/* first make a backup file except for secret keyrings */
if (!secret)
- {
+ {
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
remove (bakfname);
#endif
@@ -1244,7 +1244,7 @@ rename_tmp_file (const char *bakfname, const char *tmpfname,
return G10ERR_RENAME_FILE;
}
}
-
+
/* then rename the file */
#if defined(HAVE_DOSISH_SYSTEM) || defined(__riscos__)
remove( fname );
@@ -1298,10 +1298,10 @@ write_keyblock (IOBUF fp, KBNODE keyblock)
{
KBNODE kbctx = NULL, node;
int rc;
-
- while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
+
+ while ( (node = walk_kbnode (keyblock, &kbctx, 0)) )
{
- if (node->pkt->pkttype == PKT_RING_TRUST)
+ if (node->pkt->pkttype == PKT_RING_TRUST)
continue; /* we write it later on our own */
if ( (rc = build_packet (fp, node->pkt) ))
@@ -1310,12 +1310,12 @@ write_keyblock (IOBUF fp, KBNODE keyblock)
node->pkt->pkttype, g10_errstr(rc) );
return rc;
}
- if (node->pkt->pkttype == PKT_SIGNATURE)
+ if (node->pkt->pkttype == PKT_SIGNATURE)
{ /* always write a signature cache packet */
PKT_signature *sig = node->pkt->pkt.signature;
unsigned int cacheval = 0;
-
- if (sig->flags.checked)
+
+ if (sig->flags.checked)
{
cacheval |= 1;
if (sig->flags.valid)
@@ -1333,7 +1333,7 @@ write_keyblock (IOBUF fp, KBNODE keyblock)
return 0;
}
-/*
+/*
* Walk over all public keyrings, check the signatures and replace the
* keyring with a new one where the signature cache is then updated.
* This is only done for the public keyrings.
@@ -1378,7 +1378,7 @@ keyring_rebuild_cache (void *token,int noisy)
* the original file is closed */
tmpfp = NULL;
}
- rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
+ rc = lastresname? rename_tmp_file (bakfilename, tmpfilename,
lastresname, 0) : 0;
xfree (tmpfilename); tmpfilename = NULL;
xfree (bakfilename); bakfilename = NULL;
@@ -1391,10 +1391,10 @@ keyring_rebuild_cache (void *token,int noisy)
if (rc)
goto leave;
}
-
+
release_kbnode (keyblock);
rc = keyring_get_keyblock (hd, &keyblock);
- if (rc)
+ if (rc)
{
log_error ("keyring_get_keyblock failed: %s\n", g10_errstr(rc));
goto leave;
@@ -1438,7 +1438,7 @@ keyring_rebuild_cache (void *token,int noisy)
sigcount++;
}
}
-
+
/* write the keyblock to the temporary file */
rc = write_keyblock (tmpfp, keyblock);
if (rc)
@@ -1448,10 +1448,10 @@ keyring_rebuild_cache (void *token,int noisy)
log_info(_("%lu keys cached so far (%lu signatures)\n"),
count, sigcount );
- } /* end main loop */
+ } /* end main loop */
if (rc == -1)
rc = 0;
- if (rc)
+ if (rc)
{
log_error ("keyring_search failed: %s\n", g10_errstr(rc));
goto leave;
@@ -1479,8 +1479,8 @@ keyring_rebuild_cache (void *token,int noisy)
leave:
if (tmpfp)
iobuf_cancel (tmpfp);
- xfree (tmpfilename);
- xfree (bakfilename);
+ xfree (tmpfilename);
+ xfree (bakfilename);
release_kbnode (keyblock);
keyring_lock (hd, 0);
keyring_release (hd);
@@ -1503,13 +1503,13 @@ do_copy (int mode, const char *fname, KBNODE root, int secret,
char *bakfname = NULL;
char *tmpfname = NULL;
- /* Open the source file. Because we do a rename, we have to check the
+ /* Open the source file. Because we do a rename, we have to check the
permissions of the file */
if (access (fname, W_OK))
return G10ERR_WRITE_FILE;
fp = iobuf_open (fname);
- if (mode == 1 && !fp && errno == ENOENT) {
+ if (mode == 1 && !fp && errno == ENOENT) {
/* insert mode but file does not exist: create a new file */
KBNODE kbctx, node;
mode_t oldmask;
diff --git a/g10/signal.c b/g10/signal.c
index 4aaa11eaa..086bf51d3 100644
--- a/g10/signal.c
+++ b/g10/signal.c
@@ -66,7 +66,7 @@ init_one_signal (int sig, RETSIGTYPE (*handler)(int), int check_ign )
sigemptyset (&nact.sa_mask);
nact.sa_flags = 0;
sigaction ( sig, &nact, NULL);
-#else
+#else
RETSIGTYPE (*ohandler)(int);
ohandler = signal (sig, handler);
@@ -122,7 +122,7 @@ got_fatal_signal( int sig )
/* Reset action to default action and raise signal again. */
init_one_signal (sig, SIG_DFL, 0);
- remove_lockfiles ();
+ dotlock_remove_lockfiles ();
#ifdef __riscos__
riscos_close_fds ();
#endif /* __riscos__ */
@@ -165,7 +165,7 @@ pause_on_sigusr( int which )
sigsuspend( &oldmask );
caught_sigusr1 = 0;
sigprocmask( SIG_UNBLOCK, &mask, NULL );
-#else
+#else
assert (which == 1);
sighold (SIGUSR1);
while (!caught_sigusr1)
diff --git a/g10/tdbio.c b/g10/tdbio.c
index 282411e5d..2732b1b27 100644
--- a/g10/tdbio.c
+++ b/g10/tdbio.c
@@ -86,7 +86,7 @@ struct cmp_xdir_struct {
static char *db_name;
-static DOTLOCK lockhandle;
+static dotlock_t lockhandle;
static int is_locked;
static int db_fd = -1;
static int in_transaction;
@@ -248,7 +248,7 @@ put_record_into_cache( ulong recno, const char *data )
if( !n )
n = 1;
if( !is_locked ) {
- if( make_dotlock( lockhandle, -1 ) )
+ if (dotlock_take (lockhandle, -1))
log_fatal("can't acquire lock - giving up\n");
else
is_locked = 1;
@@ -267,7 +267,7 @@ put_record_into_cache( ulong recno, const char *data )
}
}
if( !opt.lock_once ) {
- if( !release_dotlock( lockhandle ) )
+ if (!dotlock_release (lockhandle))
is_locked = 0;
}
assert( unused );
@@ -309,7 +309,7 @@ tdbio_sync()
return 0;
if( !is_locked ) {
- if( make_dotlock( lockhandle, -1 ) )
+ if (dotlock_take (lockhandle, -1))
log_fatal("can't acquire lock - giving up\n");
else
is_locked = 1;
@@ -324,7 +324,7 @@ tdbio_sync()
}
cache_is_dirty = 0;
if( did_lock && !opt.lock_once ) {
- if( !release_dotlock( lockhandle ) )
+ if (!dotlock_release (lockhandle))
is_locked = 0;
}
@@ -364,7 +364,7 @@ tdbio_end_transaction()
if( !in_transaction )
log_bug("tdbio: no active transaction\n");
if( !is_locked ) {
- if( make_dotlock( lockhandle, -1 ) )
+ if (dotlock_take (lockhandle, -1))
log_fatal("can't acquire lock - giving up\n");
else
is_locked = 1;
@@ -374,7 +374,7 @@ tdbio_end_transaction()
rc = tdbio_sync();
unblock_all_signals();
if( !opt.lock_once ) {
- if( !release_dotlock( lockhandle ) )
+ if (!dotlock_release (lockhandle))
is_locked = 0;
}
return rc;
@@ -414,7 +414,7 @@ static void
cleanup(void)
{
if( is_locked ) {
- if( !release_dotlock(lockhandle) )
+ if (!dotlock_release (lockhandle))
is_locked = 0;
}
}
@@ -447,7 +447,7 @@ create_version_record (void)
{
TRUSTREC rec;
int rc;
-
+
memset( &rec, 0, sizeof rec );
rec.r.ver.version = 3;
rec.r.ver.created = make_timestamp();
@@ -517,10 +517,10 @@ tdbio_set_dbname( const char *new_dbname, int create )
db_name = fname;
#ifdef __riscos__
if( !lockhandle )
- lockhandle = create_dotlock( db_name );
+ lockhandle = dotlock_create (db_name, 0);
if( !lockhandle )
log_fatal( _("can't create lock for `%s'\n"), db_name );
- if( make_dotlock( lockhandle, -1 ) )
+ if (dotlock_take (lockhandle, -1))
log_fatal( _("can't lock `%s'\n"), db_name );
#endif /* __riscos__ */
oldmask=umask(077);
@@ -540,7 +540,7 @@ tdbio_set_dbname( const char *new_dbname, int create )
#ifndef __riscos__
if( !lockhandle )
- lockhandle = create_dotlock( db_name );
+ lockhandle = dotlock_create (db_name, 0);
if( !lockhandle )
log_fatal( _("can't create lock for `%s'\n"), db_name );
#endif /* !__riscos__ */
@@ -583,11 +583,11 @@ open_db()
assert( db_fd == -1 );
if (!lockhandle )
- lockhandle = create_dotlock( db_name );
+ lockhandle = dotlock_create (db_name, 0);
if (!lockhandle )
log_fatal( _("can't create lock for `%s'\n"), db_name );
#ifdef __riscos__
- if (make_dotlock( lockhandle, -1 ) )
+ if (dotlock_take (lockhandle, -1))
log_fatal( _("can't lock `%s'\n"), db_name );
#endif /* __riscos__ */
db_fd = open (db_name, O_RDWR | MY_O_BINARY );
@@ -613,7 +613,7 @@ open_db()
{
migrate_from_v2 ();
}
-
+
/* read the version record */
if (tdbio_read_record (0, &rec, RECTYPE_VER ) )
log_fatal( _("%s: invalid trustdb\n"), db_name );
@@ -690,7 +690,7 @@ tdbio_read_model(void)
{
TRUSTREC vr;
int rc;
-
+
rc = tdbio_read_record( 0, &vr, RECTYPE_VER );
if( rc )
log_fatal( _("%s: error reading version record: %s\n"),
@@ -1008,7 +1008,7 @@ drop_from_hashtable( ulong table, byte *key, int keylen, ulong recnum )
*/
static int
lookup_hashtable( ulong table, const byte *key, size_t keylen,
- int (*cmpfnc)(const void*, const TRUSTREC *),
+ int (*cmpfnc)(const void*, const TRUSTREC *),
const void *cmpdata, TRUSTREC *rec )
{
int rc;
@@ -1534,12 +1534,12 @@ migrate_from_v2 ()
/* We have some restrictions here. We can't use the version record
* and we can't use any of the old hashtables because we dropped the
* code. So we first collect all ownertrusts and then use a second
- * pass fo find the associated keys. We have to do this all without using
+ * pass fo find the associated keys. We have to do this all without using
* the regular record read functions.
*/
/* get all the ownertrusts */
- if (lseek (db_fd, 0, SEEK_SET ) == -1 )
+ if (lseek (db_fd, 0, SEEK_SET ) == -1 )
log_fatal ("migrate_from_v2: lseek failed: %s\n", strerror (errno));
for (recno=0;;recno++)
{
@@ -1553,7 +1553,7 @@ migrate_from_v2 ()
if (*oldbuf != 2)
continue;
-
+
/* v2 dir record */
if (ottable_used == ottable_size)
{
@@ -1570,7 +1570,7 @@ migrate_from_v2 ()
log_info ("found %d ownertrust records\n", ottable_used);
/* Read again and find the fingerprints */
- if (lseek (db_fd, 0, SEEK_SET ) == -1 )
+ if (lseek (db_fd, 0, SEEK_SET ) == -1 )
log_fatal ("migrate_from_v2: lseek failed: %s\n", strerror (errno));
for (recno=0;;recno++)
{
@@ -1582,7 +1582,7 @@ migrate_from_v2 ()
if (n != 40)
log_fatal ("migrate_from_v2: read error or short read\n");
- if (*oldbuf != 3)
+ if (*oldbuf != 3)
continue;
/* v2 key record */
@@ -1603,7 +1603,7 @@ migrate_from_v2 ()
if (create_version_record ())
log_fatal ("failed to recreate version record of `%s'\n", db_name);
- /* access the hash table, so it is store just after the version record,
+ /* access the hash table, so it is store just after the version record,
* this is not needed put a dump is more pretty */
get_trusthashrec ();
@@ -1613,7 +1613,7 @@ migrate_from_v2 ()
{
if (!ottable[i].okay)
continue;
-
+
memset (&rec, 0, sizeof rec);
rec.recnum = tdbio_new_recnum ();
rec.rectype = RECTYPE_TRUST;
diff --git a/include/dotlock.h b/include/dotlock.h
new file mode 100644
index 000000000..920a81a16
--- /dev/null
+++ b/include/dotlock.h
@@ -0,0 +1,112 @@
+/* dotlock.h - dotfile locking declarations
+ * Copyright (C) 2000, 2001, 2006, 2011 Free Software Foundation, Inc.
+ *
+ * This file is part of JNLIB, which is a subsystem of GnuPG.
+ *
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of either
+ *
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
+ *
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * JNLIB 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <http://www.gnu.org/licenses/>.
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU Lesser General License or the GNU
+ * General Public License. If you wish to allow use of your version of
+ * this file only under the terms of the GNU Lesser General License or
+ * the GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LIBJNLIB_DOTLOCK_H
+#define LIBJNLIB_DOTLOCK_H
+
+/* See dotlock.c for a description. */
+
+#ifdef DOTLOCK_EXT_SYM_PREFIX
+# ifndef _DOTLOCK_PREFIX
+# define _DOTLOCK_PREFIX1(x,y) x ## y
+# define _DOTLOCK_PREFIX2(x,y) _DOTLOCK_PREFIX1(x,y)
+# define _DOTLOCK_PREFIX(x) _DOTLOCK_PREFIX2(DOTLOCK_EXT_SYM_PREFIX,x)
+# endif /*_DOTLOCK_PREFIX*/
+# define dotlock_disable _DOTLOCK_PREFIX(dotlock_disable)
+# define dotlock_create _DOTLOCK_PREFIX(dotlock_create)
+# define dotlock_set_fd _DOTLOCK_PREFIX(dotlock_set_fd)
+# define dotlock_get_fd _DOTLOCK_PREFIX(dotlock_get_fd)
+# define dotlock_destroy _DOTLOCK_PREFIX(dotlock_destroy)
+# define dotlock_take _DOTLOCK_PREFIX(dotlock_take)
+# define dotlock_release _DOTLOCK_PREFIX(dotlock_release)
+# define dotlock_remove_lockfiles _DOTLOCK_PREFIX(dotlock_remove_lockfiles)
+#endif /*DOTLOCK_EXT_SYM_PREFIX*/
+
+#ifdef __cplusplus
+extern "C"
+{
+#if 0
+}
+#endif
+#endif
+
+
+struct dotlock_handle;
+typedef struct dotlock_handle *dotlock_t;
+
+void dotlock_disable (void);
+dotlock_t dotlock_create (const char *file_to_lock, unsigned int flags);
+void dotlock_set_fd (dotlock_t h, int fd);
+int dotlock_get_fd (dotlock_t h);
+void dotlock_destroy (dotlock_t h);
+int dotlock_take (dotlock_t h, long timeout);
+int dotlock_release (dotlock_t h);
+void dotlock_remove_lockfiles (void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /*LIBJNLIB_DOTLOCK_H*/
diff --git a/include/util.h b/include/util.h
index 4b3c40bbb..9303a50b1 100644
--- a/include/util.h
+++ b/include/util.h
@@ -124,15 +124,7 @@ const char *strusage( int level );
/*-- dotlock.c --*/
-struct dotlock_handle;
-typedef struct dotlock_handle *DOTLOCK;
-
-void disable_dotlock(void);
-DOTLOCK create_dotlock( const char *file_to_lock );
-void destroy_dotlock ( DOTLOCK h );
-int make_dotlock( DOTLOCK h, long timeout );
-int release_dotlock( DOTLOCK h );
-void remove_lockfiles (void);
+#include "../include/dotlock.h"
/*-- fileutil.c --*/
char * make_basename(const char *filepath, const char *inputpath);
@@ -217,10 +209,10 @@ int strncasecmp (const char *, const char *b, size_t n);
/* The definition of the structure is private, we only need it here,
so it can be allocated on the stack. */
struct private_membuf_s {
- size_t len;
- size_t size;
- char *buf;
- int out_of_core;
+ size_t len;
+ size_t size;
+ char *buf;
+ int out_of_core;
};
typedef struct private_membuf_s membuf_t;
diff --git a/util/dotlock.c b/util/dotlock.c
index ccbb6e89d..c5f3a784b 100644
--- a/util/dotlock.c
+++ b/util/dotlock.c
@@ -1,344 +1,511 @@
/* dotlock.c - dotfile locking
- * Copyright (C) 1998, 1999, 2000, 2001, 2004,
- * 2005, 2009 Free Software Foundation, Inc.
+ * Copyright (C) 1998, 2000, 2001, 2003, 2004,
+ * 2005, 2006, 2008, 2010, 2011 Free Software Foundation, Inc.
*
- * This file is part of GnuPG.
+ * This file is part of JNLIB, which is a subsystem of GnuPG.
*
- * GnuPG 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 of the License, or
- * (at your option) any later version.
+ * JNLIB is free software; you can redistribute it and/or modify it
+ * under the terms of either
*
- * GnuPG 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.
+ * - the GNU Lesser General Public License as published by the Free
+ * Software Foundation; either version 3 of the License, or (at
+ * your option) any later version.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, see <http://www.gnu.org/licenses/>.
+ * or
+ *
+ * - the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ *
+ * or both in parallel, as here.
+ *
+ * JNLIB 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 copies of the GNU General Public License
+ * and the GNU Lesser General Public License along with this program;
+ * if not, see <http://www.gnu.org/licenses/>.
+ *
+ * ALTERNATIVELY, this file may be distributed under the terms of the
+ * following license, in which case the provisions of this license are
+ * required INSTEAD OF the GNU Lesser General License or the GNU
+ * General Public License. If you wish to allow use of your version of
+ * this file only under the terms of the GNU Lesser General License or
+ * the GNU General Public License, and not to allow others to use your
+ * version of this file under the terms of the following license,
+ * indicate your decision by deleting this paragraph and the license
+ * below.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, and the entire permission notice in its entirety,
+ * including the disclaimer of warranties.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <config.h>
+/*
+ Overview:
+ =========
+
+ This module implements advisory file locking in a portable way.
+ Due to the problems with POSIX fcntl locking a separate lock file
+ is used. It would be possible to use fcntl locking on this lock
+ file and thus avoid the weird auto unlock bug of POSIX while still
+ having an unproved better performance of fcntl locking. However
+ there are still problems left, thus we resort to use a hardlink
+ which has the well defined property that a link call will fail if
+ the target file already exists.
+
+ Given that hardlinks are also available on NTFS file systems since
+ Windows XP; it will be possible to enhance this module to use
+ hardlinks even on Windows and thus allow Windows and Posix clients
+ to use locking on the same directory. This is not yet implemented;
+ instead we use a lockfile on Windows along with W32 style file
+ locking.
+
+ On FAT file systems hardlinks are not supported. Thus this method
+ does not work. Our solution is to use a O_EXCL locking instead.
+ Querying the type of the file system is not easy to do in a
+ portable way (e.g. Linux has a statfs, BSDs have a the same call
+ but using different structures and constants). What we do instead
+ is to check at runtime whether link(2) works for a specific lock
+ file.
+
+
+ How to use:
+ ===========
+
+ At program initialization time, the module should be explicitly
+ initialized:
+
+ dotlock_create (NULL, 0);
+
+ This installs an atexit handler and may also initialize mutex etc.
+ It is optional for non-threaded applications. Only the first call
+ has an effect. This needs to be done before any extra threads are
+ started.
+
+ To create a lock file (which prepares it but does not take the
+ lock) you do:
+
+ dotlock_t h
+
+ h = dotlock_create (fname, 0);
+ if (!h)
+ error ("error creating lock file: %s\n", strerror (errno));
+
+ It is important to handle the error. For example on a read-only
+ file system a lock can't be created (but is usually not needed).
+ FNAME is the file you want to lock; the actual lockfile is that
+ name with the suffix ".lock" appended. On success a handle to be
+ used with the other functions is returned or NULL on error. Note
+ that the handle shall only be used by one thread at a time. This
+ function creates a unique file temporary file (".#lk*") in the same
+ directory as FNAME and returns a handle for further operations.
+ The module keeps track of theses unique files so that they will be
+ unlinked using the atexit handler. If you don't need the lock file
+ anymore, you may also explicitly remove it with a call to:
+
+ dotlock_destroy (h);
+
+ To actually lock the file, you use:
+
+ if (dotlock_take (h, -1))
+ error ("error taking lock: %s\n", strerror (errno));
+
+ This function will wait until the lock is acquired. If an
+ unexpected error occurs if will return non-zero and set ERRNO. If
+ you pass (0) instead of (-1) the function does not wait in case the
+ file is already locked but returns -1 and sets ERRNO to EACCES.
+ Any other positive value for the second parameter is considered a
+ timeout valuie in milliseconds.
+
+ To release the lock you call:
+
+ if (dotlock_release (h))
+ error ("error releasing lock: %s\n", strerror (errno));
+
+ or, if the lock file is not anymore needed, you may just call
+ dotlock_destroy. However dotlock_release does some extra checks
+ before releasing the lock and prints diagnostics to help detecting
+ bugs.
+
+ If you want to explicitly destroy all lock files you may call
+
+ dotlock_remove_lockfiles ();
+
+ which is the core of the installed atexit handler. In case your
+ application wants to disable locking completely it may call
+
+ disable_locking ()
+
+ before any locks are created.
+
+ There are two convenience functions to store an integer (e.g. a
+ file descriptor) value with the handle:
+
+ void dotlock_set_fd (dotlock_t h, int fd);
+ int dotlock_get_fd (dotlock_t h);
+
+ If nothing has been stored dotlock_get_fd returns -1.
+
+
+
+ How to build:
+ =============
+
+ This module was originally developed for GnuPG but later changed to
+ allow its use without any GnuPG dependency. If you want to use it
+ with you application you may simply use it and it should figure out
+ most things automagically.
+
+ You may use the common config.h file to pass macros, but take care
+ to pass -DHAVE_CONFIG_H to the compiler. Macros used by this
+ module are:
+
+ DOTLOCK_USE_PTHREAD - Define if POSIX threads are in use.
+
+ DOTLOCK_GLIB_LOGGING - Define this to use Glib logging functions.
+
+ DOTLOCK_EXT_SYM_PREFIX - Prefix all external symbols with the
+ string to which this macro evaluates.
+
+ GNUPG_MAJOR_VERSION - Defined when used by GnuPG.
+
+ HAVE_DOSISH_SYSTEM - Defined for Windows etc. Will be
+ automatically defined if a the target is
+ Windows.
+
+ HAVE_POSIX_SYSTEM - Internally defined to !HAVE_DOSISH_SYSTEM.
+
+ HAVE_SIGNAL_H - Should be defined on Posix systems. If config.h
+ is not used defaults to defined.
+
+ DIRSEP_C - Separation character for file name parts.
+ Usually not redefined.
+
+ EXTSEP_S - Separation string for file name suffixes.
+ Usually not redefined.
+
+ HAVE_W32CE_SYSTEM - Currently only used by GnuPG.
+
+ Note that there is a test program t-dotlock which has compile
+ instructions at its end. At least for SMBFS and CIFS it is
+ important that 64 bit versions of stat are used; most programming
+ environments do this these days, just in case you want to compile
+ it on the command line, remember to pass -D_FILE_OFFSET_BITS=64
+
+
+ Bugs:
+ =====
+
+ On Windows this module is not yet thread-safe.
+
+
+ Miscellaneous notes:
+ ====================
+
+ On hardlinks:
+ - Hardlinks are supported under Windows with NTFS since XP/Server2003.
+ - In Linux 2.6.33 both SMBFS and CIFS seem to support hardlinks.
+ - NFS supports hard links. But there are solvable problems.
+ - FAT does not support links
+
+ On the file locking API:
+ - CIFS on Linux 2.6.33 supports several locking methods.
+ SMBFS seems not to support locking. No closer checks done.
+ - NFS supports Posix locks. flock is emulated in the server.
+ However there are a couple of problems; see below.
+ - FAT does not support locks.
+ - An advantage of fcntl locking is that R/W locks can be
+ implemented which is not easy with a straight lock file.
+
+ On O_EXCL:
+ - Does not work reliable on NFS
+ - Should work on CIFS and SMBFS but how can we delete lockfiles?
+
+ On NFS problems:
+ - Locks vanish if the server crashes and reboots.
+ - Client crashes keep the lock in the server until the client
+ re-connects.
+ - Communication problems may return unreliable error codes. The
+ MUA Postfix's workaround is to compare the link count after
+ seeing an error for link. However that gives a race. If using a
+ unique file to link to a lockfile and using stat to check the
+ link count instead of looking at the error return of link(2) is
+ the best solution.
+ - O_EXCL seems to have a race and may re-create a file anyway.
+
+*/
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+/* Some quick replacements for stuff we usually expect to be defined
+ in config.h. Define HAVE_POSIX_SYSTEM for better readability. */
+#if !defined (HAVE_DOSISH_SYSTEM) && defined(_WIN32)
+# define HAVE_DOSISH_SYSTEM 1
+#endif
+#if !defined (HAVE_DOSISH_SYSTEM) && !defined (HAVE_POSIX_SYSTEM)
+# define HAVE_POSIX_SYSTEM 1
+#endif
+
+/* With no config.h assume that we have sitgnal.h. */
+#if !defined (HAVE_CONFIG_H) && defined (HAVE_POSIX_SYSTEM)
+# define HAVE_SIGNAL_H 1
+#endif
+
+/* Standard headers. */
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <ctype.h>
#include <errno.h>
#include <unistd.h>
#ifdef HAVE_DOSISH_SYSTEM
-# define WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN /* We only need the OS core stuff. */
# include <windows.h>
#else
+# include <sys/types.h>
+# include <sys/stat.h>
# include <sys/utsname.h>
#endif
#include <sys/types.h>
-#ifndef _WIN32
#include <sys/time.h>
-#endif
#include <sys/stat.h>
#include <fcntl.h>
-#include <signal.h>
-#include "types.h"
-#include "util.h"
-#include "memory.h"
-#include "i18n.h"
-
-
-/* The object describing a lock. */
-struct dotlock_handle {
- struct dotlock_handle *next;
- char *tname; /* name of lockfile template */
- char *lockname; /* name of the real lockfile */
- int locked; /* lock status */
- int disable; /* locking */
-#ifdef HAVE_DOSISH_SYSTEM
- HANDLE lockhd; /* The W32 handle of the lock file. */
-#else
- size_t nodename_off; /* Offset in TNAME to the nodename part. */
- size_t nodename_len; /* Length of the nodename part. */
+#ifdef HAVE_SIGNAL_H
+# include <signal.h>
+#endif
+#ifdef DOTLOCK_USE_PTHREAD
+# include <pthread.h>
#endif
-};
+#ifdef DOTLOCK_GLIB_LOGGING
+# include <glib.h>
+#endif
-/* A list of of all lock handles. */
-static volatile DOTLOCK all_lockfiles;
+#ifdef GNUPG_MAJOR_VERSION
+# if GNUPG_MAJOR_VERSION > 1
+# include "libjnlib-config.h"
+# else
+# include "../include/util.h"
+# endif
+#endif
+#ifdef HAVE_W32CE_SYSTEM
+# include "utf8conv.h" /* WindowsCE requires filename conversion. */
+#endif
-/* If this has the value true all locking is disabled. */
-static int never_lock;
+#include "dotlock.h"
-#ifdef _REENTRANT
- /* fixme: acquire mutex on all_lockfiles */
-# define lock_all_lockfiles(h) do { } while (0)
-# define unlock_all_lockfiles(h) do { } while (0)
+/* Define constants for file name construction. */
+#if !defined(DIRSEP_C) && !defined(EXTSEP_S)
+# ifdef HAVE_DOSISH_SYSTEM
+# define DIRSEP_C '\\'
+# define EXTSEP_S "."
#else
-# define lock_all_lockfiles(h) do { } while (0)
-# define unlock_all_lockfiles(h) do { } while (0)
+# define DIRSEP_C '/'
+# define EXTSEP_S "."
+# endif
#endif
+/* In GnuPG we use wrappers around the malloc fucntions. If they are
+ not defined we assume that this code is used outside of GnuPG and
+ fall back to the regular malloc functions. */
+#ifndef jnlib_malloc
+# define jnlib_malloc(a) malloc ((a))
+# define jnlib_calloc(a,b) calloc ((a), (b))
+# define jnlib_free(a) free ((a))
+#endif
+/* Wrapper to set ERRNO. */
+#ifndef jnlib_set_errno
+# ifdef HAVE_W32CE_SYSTEM
+# define jnlib_set_errno(e) gpg_err_set_errno ((e))
+# else
+# define jnlib_set_errno(e) do { errno = (e); } while (0)
+# endif
+#endif
-void
-disable_dotlock(void)
-{
- never_lock = 1;
-}
-
-
-/****************
- * Create a lockfile with the given name and return an object of
- * type DOTLOCK which may be used later to actually do the lock.
- * A cleanup routine gets installed to cleanup left over locks
- * or other files used together with the lockmechanism.
- * Althoug the function is called dotlock, this does not necessarily
- * mean that real lockfiles are used - the function may decide to
- * use fcntl locking. Calling the function with NULL only install
- * the atexit handler and maybe used to assure that the cleanup
- * is called after all other atexit handlers.
- *
- * Notes: This function creates a lock file in the same directory
- * as file_to_lock with the name "file_to_lock.lock"
- * A temporary file ".#lk.<hostname>.pid[.threadid] is used.
- * This function does nothing for Windoze.
- */
-DOTLOCK
-create_dotlock( const char *file_to_lock )
-{
- static int initialized;
- DOTLOCK h;
-#ifndef HAVE_DOSISH_SYSTEM
- int fd = -1;
- char pidstr[16];
- struct utsname utsbuf;
- const char *nodename;
- const char *dirpart;
- int dirpartlen;
- size_t tnamelen;
- int n;
-#endif /*!HAVE_DOSISH_SYSTEM*/
+/* Gettext macro replacement. */
+#ifndef _
+# define _(a) (a)
+#endif
- if( !initialized ) {
- atexit( remove_lockfiles );
- initialized = 1;
- }
- if( !file_to_lock )
- return NULL;
+#ifdef GNUPG_MAJOR_VERSION
+# define my_info_0(a) log_info ((a))
+# define my_info_1(a,b) log_info ((a), (b))
+# define my_info_2(a,b,c) log_info ((a), (b), (c))
+# define my_info_3(a,b,c,d) log_info ((a), (b), (c), (d))
+# define my_error_0(a) log_error ((a))
+# define my_error_1(a,b) log_error ((a), (b))
+# define my_error_2(a,b,c) log_error ((a), (b), (c))
+# define my_debug_1(a,b) log_debug ((a), (b))
+# define my_fatal_0(a) log_fatal ((a))
+#elif defined (DOTLOCK_GLIB_LOGGING)
+# define my_info_0(a) g_message ((a))
+# define my_info_1(a,b) g_message ((a), (b))
+# define my_info_2(a,b,c) g_message ((a), (b), (c))
+# define my_info_3(a,b,c,d) g_message ((a), (b), (c), (d))
+# define my_error_0(a) g_warning ((a))
+# define my_error_1(a,b) g_warning ((a), (b))
+# define my_error_2(a,b,c) g_warning ((a), (b), (c))
+# define my_debug_1(a,b) g_debug ((a), (b))
+# define my_fatal_0(a) g_error ((a))
+#else
+# define my_info_0(a) fprintf (stderr, (a))
+# define my_info_1(a,b) fprintf (stderr, (a), (b))
+# define my_info_2(a,b,c) fprintf (stderr, (a), (b), (c))
+# define my_info_3(a,b,c,d) fprintf (stderr, (a), (b), (c), (d))
+# define my_error_0(a) fprintf (stderr, (a))
+# define my_error_1(a,b) fprintf (stderr, (a), (b))
+# define my_error_2(a,b,c) fprintf (stderr, (a), (b), (c))
+# define my_debug_1(a,b) fprintf (stderr, (a), (b))
+# define my_fatal_0(a) do { fprintf (stderr,(a)); fflush (stderr); \
+ abort (); } while (0)
+#endif
- h = xmalloc_clear( sizeof *h );
- if( never_lock ) {
- h->disable = 1;
- lock_all_lockfiles (h);
- h->next = all_lockfiles;
- all_lockfiles = h;
- return h;
- }
-#ifndef HAVE_DOSISH_SYSTEM
- snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
- /* create a temporary file */
- if( uname( &utsbuf ) )
- nodename = "unknown";
- else
- nodename = utsbuf.nodename;
-
-# ifdef __riscos__
- {
- char *iter = (char *) nodename;
- for (; iter[0]; iter++)
- if (iter[0] == '.')
- iter[0] = '/';
- }
-# endif /* __riscos__ */
-
- if( !(dirpart = strrchr( file_to_lock, DIRSEP_C )) ) {
- dirpart = EXTSEP_S;
- dirpartlen = 1;
- }
- else {
- dirpartlen = dirpart - file_to_lock;
- dirpart = file_to_lock;
- }
-
- lock_all_lockfiles (h);
- h->next = all_lockfiles;
- all_lockfiles = h;
-
- tnamelen = dirpartlen + 6+30+ strlen(nodename) + 10;
- h->tname = xmalloc (tnamelen + 1);
- h->nodename_len = strlen (nodename);
-
-# ifndef __riscos__
- snprintf (h->tname, tnamelen, "%.*s/.#lk%p.%n%s.%d",
- dirpartlen, dirpart, (void *)h, &n, nodename, (int)getpid ());
-# else /* __riscos__ */
- snprintf (h->tname, tnamelen, "%.*s.lk%p/%n%s/%d",
- dirpartlen, dirpart, (void *)h, &n, nodename, (int)getpid ());
-# endif /* __riscos__ */
- h->nodename_off = n;
-
- do {
- errno = 0;
- fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
- S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR);
- } while( fd == -1 && errno == EINTR );
- if( fd == -1 ) {
- all_lockfiles = h->next;
- log_error( "failed to create temporary file `%s': %s\n",
- h->tname, strerror(errno));
- xfree(h->tname);
- xfree(h);
- return NULL;
- }
- if (write (fd, pidstr, 11) != 11)
- goto write_failed;
- if (write (fd, nodename, strlen (nodename)) != strlen (nodename))
- goto write_failed;
- if (write (fd, "\n", 1 ) != 1)
- goto write_failed;
- if (close (fd))
- goto write_failed;
+
+/* The object describing a lock. */
+struct dotlock_handle
+{
+ struct dotlock_handle *next;
+ char *lockname; /* Name of the actual lockfile. */
+ unsigned int locked:1; /* Lock status. */
+ unsigned int disable:1; /* If true, locking is disabled. */
+ unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking. */
- unlock_all_lockfiles (h);
- h->lockname = xmalloc( strlen(file_to_lock) + 6 );
- strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
- return h;
+ int extra_fd; /* A place for the caller to store an FD. */
- write_failed:
- all_lockfiles = h->next;
- unlock_all_lockfiles (h);
- log_error ("error writing to `%s': %s\n", h->tname, strerror(errno));
- close (fd);
- unlink (h->tname);
- xfree (h->tname);
- xfree (h);
- return NULL;
+#ifdef HAVE_DOSISH_SYSTEM
+ HANDLE lockhd; /* The W32 handle of the lock file. */
+#else /*!HAVE_DOSISH_SYSTEM */
+ char *tname; /* Name of the lockfile template. */
+ size_t nodename_off; /* Offset in TNAME of the nodename part. */
+ size_t nodename_len; /* Length of the nodename part. */
+#endif /*!HAVE_DOSISH_SYSTEM */
+};
-#else /* HAVE_DOSISH_SYSTEM */
- /* The Windows version does not need a temporary file but uses the
- plain lock file along with record locking. We create this file
- here so that we later do only need to do the file locking. For
- error reporting it is useful to keep the name of the file in the
- handle. */
- h->next = all_lockfiles;
- all_lockfiles = h;
+/* A list of of all lock handles. The volatile attribute might help
+ if used in an atexit handler. */
+static volatile dotlock_t all_lockfiles;
+#ifdef DOTLOCK_USE_PTHREAD
+static pthread_mutex_t all_lockfiles_mutex = PTHREAD_MUTEX_INITIALIZER;
+# define LOCK_all_lockfiles() do { \
+ if (pthread_mutex_lock (&all_lockfiles_mutex)) \
+ my_fatal_0 ("locking all_lockfiles_mutex failed\n"); \
+ } while (0)
+# define UNLOCK_all_lockfiles() do { \
+ if (pthread_mutex_unlock (&all_lockfiles_mutex)) \
+ my_fatal_0 ("unlocking all_lockfiles_mutex failed\n"); \
+ } while (0)
+#else /*!DOTLOCK_USE_PTHREAD*/
+# define LOCK_all_lockfiles() do { } while (0)
+# define UNLOCK_all_lockfiles() do { } while (0)
+#endif /*!DOTLOCK_USE_PTHREAD*/
- h->lockname = xmalloc ( strlen (file_to_lock) + 6 );
- strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
+/* If this has the value true all locking is disabled. */
+static int never_lock;
- /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
- along with FILE_SHARE_DELETE but that does not work due to a race
- condition: Despite the OPEN_ALWAYS flag CreateFile may return an
- error and we can't reliable create/open the lock file unless we
- would wait here until it works - however there are other valid
- reasons why a lock file can't be created and thus the process
- would not stop as expected but spin until Windows crashes. Our
- solution is to keep the lock file open; that does not harm. */
- h->lockhd = CreateFile (h->lockname,
- GENERIC_READ|GENERIC_WRITE,
- FILE_SHARE_READ|FILE_SHARE_WRITE,
- NULL, OPEN_ALWAYS, 0, NULL);
- if (h->lockhd == INVALID_HANDLE_VALUE)
- {
- log_error (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
- all_lockfiles = h->next;
- xfree (h->lockname);
- xfree (h);
- return NULL;
- }
- return h;
-#endif /* HAVE_DOSISH_SYSTEM */
-}
+
+/* Entirely disable all locking. This function should be called
+ before any locking is done. It may be called right at startup of
+ the process as it only sets a global value. */
void
-destroy_dotlock ( DOTLOCK h )
+dotlock_disable (void)
{
- DOTLOCK hprev, htmp;
-
- if (!h)
- return;
-
- /* First remove the handle from our global list of all locks. */
- for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
- if (htmp == h)
- {
- if (hprev)
- hprev->next = htmp->next;
- else
- all_lockfiles = htmp->next;
- h->next = NULL;
- break;
- }
-
- /* Second destroy the lock. */
- if (!h->disable)
- {
-#ifdef HAVE_DOSISH_SYSTEM
- if (h->locked)
- UnlockFile (h->lockhd, 0, 0, 1, 0);
- CloseHandle (h->lockhd);
-#else
- if (h->locked && h->lockname)
- unlink (h->lockname);
- if (h->tname)
- unlink (h->tname);
- xfree (h->tname);
-#endif
- xfree (h->lockname);
- }
- xfree(h);
+ never_lock = 1;
}
-#ifndef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_POSIX_SYSTEM
static int
-maybe_deadlock( DOTLOCK h )
+maybe_deadlock (dotlock_t h)
{
- DOTLOCK r;
+ dotlock_t r;
+ int res = 0;
- for( r=all_lockfiles; r; r = r->next ) {
- if( r != h && r->locked )
- return 1;
+ LOCK_all_lockfiles ();
+ for (r=all_lockfiles; r; r = r->next)
+ {
+ if ( r != h && r->locked )
+ {
+ res = 1;
+ break;
+ }
}
- return 0;
+ UNLOCK_all_lockfiles ();
+ return res;
}
-#endif /* !HAVE_DOSISH_SYSTEM */
+#endif /*HAVE_POSIX_SYSTEM*/
/* Read the lock file and return the pid, returns -1 on error. True
will be stored in the integer at address SAME_NODE if the lock file
has been created on the same node. */
-#ifndef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_POSIX_SYSTEM
static int
-read_lockfile (DOTLOCK h, int *same_node )
+read_lockfile (dotlock_t h, int *same_node )
{
char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
- names are usually shorter. */
+ names are usually shorter. */
int fd;
int pid = -1;
char *buffer, *p;
size_t expected_len;
int res, nread;
-
+
*same_node = 0;
expected_len = 10 + 1 + h->nodename_len + 1;
if ( expected_len >= sizeof buffer_space)
- buffer = xmalloc (expected_len);
+ {
+ buffer = jnlib_malloc (expected_len);
+ if (!buffer)
+ return -1;
+ }
else
buffer = buffer_space;
if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
{
int e = errno;
- log_info ("error opening lockfile `%s': %s\n",
- h->lockname, strerror(errno) );
+ my_info_2 ("error opening lockfile `%s': %s\n",
+ h->lockname, strerror(errno) );
if (buffer != buffer_space)
- xfree (buffer);
- errno = e; /* Need to return ERRNO here. */
+ jnlib_free (buffer);
+ jnlib_set_errno (e); /* Need to return ERRNO here. */
return -1;
}
@@ -351,274 +518,790 @@ read_lockfile (DOTLOCK h, int *same_node )
continue;
if (res < 0)
{
- log_info ("error reading lockfile `%s'", h->lockname );
- close (fd);
+ my_info_1 ("error reading lockfile `%s'\n", h->lockname );
+ close (fd);
if (buffer != buffer_space)
- xfree (buffer);
- errno = 0; /* Do not return an inappropriate ERRNO. */
+ jnlib_free (buffer);
+ jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */
return -1;
}
p += res;
nread += res;
}
while (res && nread != expected_len);
- close (fd);
+ close(fd);
if (nread < 11)
{
- log_info ("invalid size of lockfile `%s'", h->lockname );
+ my_info_1 ("invalid size of lockfile `%s'\n", h->lockname);
if (buffer != buffer_space)
- xfree (buffer);
- errno = 0; /* Better don't return an inappropriate ERRNO. */
+ jnlib_free (buffer);
+ jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */
return -1;
}
if (buffer[10] != '\n'
|| (buffer[10] = 0, pid = atoi (buffer)) == -1
-#ifndef __riscos__
- || !pid
-#else /* __riscos__ */
- || (!pid && riscos_getpid())
-#endif /* __riscos__ */
- )
- {
- log_error ("invalid pid %d in lockfile `%s'", pid, h->lockname );
+ || !pid )
+ {
+ my_error_2 ("invalid pid %d in lockfile `%s'\n", pid, h->lockname);
if (buffer != buffer_space)
- xfree (buffer);
- errno = 0;
+ jnlib_free (buffer);
+ jnlib_set_errno (0);
return -1;
}
if (nread == expected_len
- && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
+ && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
&& buffer[11+h->nodename_len] == '\n')
*same_node = 1;
if (buffer != buffer_space)
- xfree (buffer);
+ jnlib_free (buffer);
return pid;
}
-#endif /* !HAVE_DOSISH_SYSTEM */
+#endif /*HAVE_POSIX_SYSTEM */
+
+
+/* Check whether the file system which stores TNAME supports
+ hardlinks. Instead of using the non-portable statsfs call which
+ differs between various Unix versions, we do a runtime test.
+ Returns: 0 supports hardlinks; 1 no hardlink support, -1 unknown
+ (test error). */
+#ifdef HAVE_POSIX_SYSTEM
+static int
+use_hardlinks_p (const char *tname)
+{
+ char *lname;
+ struct stat sb;
+ unsigned int nlink;
+ int res;
+
+ if (stat (tname, &sb))
+ return -1;
+ nlink = (unsigned int)sb.st_nlink;
+
+ lname = jnlib_malloc (strlen (tname) + 1 + 1);
+ if (!lname)
+ return -1;
+ strcpy (lname, tname);
+ strcat (lname, "x");
+
+ /* We ignore the return value of link() because it is unreliable. */
+ (void) link (tname, lname);
+
+ if (stat (tname, &sb))
+ res = -1; /* Ooops. */
+ else if (sb.st_nlink == nlink + 1)
+ res = 0; /* Yeah, hardlinks are supported. */
+ else
+ res = 1; /* No hardlink support. */
+
+ unlink (lname);
+ jnlib_free (lname);
+ return res;
+}
+#endif /*HAVE_POSIX_SYSTEM */
+
+
+
+#ifdef HAVE_POSIX_SYSTEM
+/* Locking core for Unix. It used a temporary file and the link
+ system call to make locking an atomic operation. */
+static dotlock_t
+dotlock_create_unix (dotlock_t h, const char *file_to_lock)
+{
+ int fd = -1;
+ char pidstr[16];
+ const char *nodename;
+ const char *dirpart;
+ int dirpartlen;
+ struct utsname utsbuf;
+ size_t tnamelen;
+
+ snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
+
+ /* Create a temporary file. */
+ if ( uname ( &utsbuf ) )
+ nodename = "unknown";
+ else
+ nodename = utsbuf.nodename;
+
+ if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
+ {
+ dirpart = EXTSEP_S;
+ dirpartlen = 1;
+ }
+ else
+ {
+ dirpartlen = dirpart - file_to_lock;
+ dirpart = file_to_lock;
+ }
+
+ LOCK_all_lockfiles ();
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+
+ tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
+ h->tname = jnlib_malloc (tnamelen + 1);
+ if (!h->tname)
+ {
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ jnlib_free (h);
+ return NULL;
+ }
+ h->nodename_len = strlen (nodename);
+
+ snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
+ h->nodename_off = strlen (h->tname);
+ snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
+ "%s.%d", nodename, (int)getpid ());
+
+ do
+ {
+ jnlib_set_errno (0);
+ fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
+ S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
+ }
+ while (fd == -1 && errno == EINTR);
+
+ if ( fd == -1 )
+ {
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ my_error_2 (_("failed to create temporary file `%s': %s\n"),
+ h->tname, strerror(errno));
+ jnlib_free (h->tname);
+ jnlib_free (h);
+ return NULL;
+ }
+ if ( write (fd, pidstr, 11 ) != 11 )
+ goto write_failed;
+ if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
+ goto write_failed;
+ if ( write (fd, "\n", 1 ) != 1 )
+ goto write_failed;
+ if ( close (fd) )
+ goto write_failed;
+
+ /* Check whether we support hard links. */
+ switch (use_hardlinks_p (h->tname))
+ {
+ case 0: /* Yes. */
+ break;
+ case 1: /* No. */
+ unlink (h->tname);
+ h->use_o_excl = 1;
+ break;
+ default:
+ my_error_2 ("can't check whether hardlinks are supported for `%s': %s\n",
+ h->tname, strerror(errno));
+ goto write_failed;
+ }
+
+ h->lockname = jnlib_malloc (strlen (file_to_lock) + 6 );
+ if (!h->lockname)
+ {
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ unlink (h->tname);
+ jnlib_free (h->tname);
+ jnlib_free (h);
+ return NULL;
+ }
+ strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
+ UNLOCK_all_lockfiles ();
+ if (h->use_o_excl)
+ my_debug_1 ("locking for `%s' done via O_EXCL\n", h->lockname);
+
+ return h;
+
+ write_failed:
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ my_error_2 (_("error writing to `%s': %s\n"), h->tname, strerror (errno));
+ close (fd);
+ unlink (h->tname);
+ jnlib_free (h->tname);
+ jnlib_free (h);
+ return NULL;
+}
+#endif /*HAVE_POSIX_SYSTEM*/
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* Locking core for Windows. This version does not need a temporary
+ file but uses the plain lock file along with record locking. We
+ create this file here so that we later only need to do the file
+ locking. For error reporting it is useful to keep the name of the
+ file in the handle. */
+static dotlock_t
+dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
+{
+ LOCK_all_lockfiles ();
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+
+ h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
+ if (!h->lockname)
+ {
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ jnlib_free (h);
+ return NULL;
+ }
+ strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
+
+ /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
+ along with FILE_SHARE_DELETE but that does not work due to a race
+ condition: Despite the OPEN_ALWAYS flag CreateFile may return an
+ error and we can't reliable create/open the lock file unless we
+ would wait here until it works - however there are other valid
+ reasons why a lock file can't be created and thus the process
+ would not stop as expected but spin until Windows crashes. Our
+ solution is to keep the lock file open; that does not harm. */
+ {
+#ifdef HAVE_W32CE_SYSTEM
+ wchar_t *wname = utf8_to_wchar (h->lockname);
+
+ if (wname)
+ h->lockhd = CreateFile (wname,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, OPEN_ALWAYS, 0, NULL);
+ else
+ h->lockhd = INVALID_HANDLE_VALUE;
+ jnlib_free (wname);
+#else
+ h->lockhd = CreateFile (h->lockname,
+ GENERIC_READ|GENERIC_WRITE,
+ FILE_SHARE_READ|FILE_SHARE_WRITE,
+ NULL, OPEN_ALWAYS, 0, NULL);
+#endif
+ }
+ if (h->lockhd == INVALID_HANDLE_VALUE)
+ {
+ all_lockfiles = h->next;
+ UNLOCK_all_lockfiles ();
+ my_error_2 (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
+ jnlib_free (h->lockname);
+ jnlib_free (h);
+ return NULL;
+ }
+ return h;
+}
+#endif /*HAVE_DOSISH_SYSTEM*/
+
+
+/* Create a lockfile for a file name FILE_TO_LOCK and returns an
+ object of type dotlock_t which may be used later to actually acquire
+ the lock. A cleanup routine gets installed to cleanup left over
+ locks or other files used internally by the lock mechanism.
+
+ Calling this function with NULL does only install the atexit
+ handler and may thus be used to assure that the cleanup is called
+ after all other atexit handlers.
+ This function creates a lock file in the same directory as
+ FILE_TO_LOCK using that name and a suffix of ".lock". Note that on
+ POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
+ used.
-/****************
- * Do a lock on H. A TIMEOUT of 0 returns immediately,
- * -1 waits forever (hopefully not), other
- * values are timeouts in milliseconds.
- * Returns: 0 on success
+ FLAGS must be 0.
+
+ The function returns an new handle which needs to be released using
+ destroy_dotlock but gets also released at the termination of the
+ process. On error NULL is returned.
*/
+
+dotlock_t
+dotlock_create (const char *file_to_lock, unsigned int flags)
+{
+ static int initialized;
+ dotlock_t h;
+
+ if ( !initialized )
+ {
+ atexit (dotlock_remove_lockfiles);
+ initialized = 1;
+ }
+
+ if ( !file_to_lock )
+ return NULL; /* Only initialization was requested. */
+
+ if (flags)
+ {
+ jnlib_set_errno (EINVAL);
+ return NULL;
+ }
+
+ h = jnlib_calloc (1, sizeof *h);
+ if (!h)
+ return NULL;
+ h->extra_fd = -1;
+
+ if (never_lock)
+ {
+ h->disable = 1;
+ LOCK_all_lockfiles ();
+ h->next = all_lockfiles;
+ all_lockfiles = h;
+ UNLOCK_all_lockfiles ();
+ return h;
+ }
+
+#ifdef HAVE_DOSISH_SYSTEM
+ return dotlock_create_w32 (h, file_to_lock);
+#else /*!HAVE_DOSISH_SYSTEM */
+ return dotlock_create_unix (h, file_to_lock);
+#endif /*!HAVE_DOSISH_SYSTEM*/
+}
+
+
+
+/* Convenience function to store a file descriptor (or any any other
+ integer value) in the context of handle H. */
+void
+dotlock_set_fd (dotlock_t h, int fd)
+{
+ h->extra_fd = fd;
+}
+
+/* Convenience function to retrieve a file descriptor (or any any other
+ integer value) stored in the context of handle H. */
int
-make_dotlock( DOTLOCK h, long timeout )
+dotlock_get_fd (dotlock_t h)
{
- int backoff=0;
-#ifndef HAVE_DOSISH_SYSTEM
- int pid;
- const char *maybe_dead="";
- int same_node;
-#endif
-
- if (h->disable)
- return 0;
+ return h->extra_fd;
+}
+
+
+
+#ifdef HAVE_POSIX_SYSTEM
+/* Unix specific code of destroy_dotlock. */
+static void
+dotlock_destroy_unix (dotlock_t h)
+{
+ if (h->locked && h->lockname)
+ unlink (h->lockname);
+ if (h->tname && !h->use_o_excl)
+ unlink (h->tname);
+ jnlib_free (h->tname);
+}
+#endif /*HAVE_POSIX_SYSTEM*/
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* Windows specific code of destroy_dotlock. */
+static void
+dotlock_destroy_w32 (dotlock_t h)
+{
if (h->locked)
{
-#ifndef __riscos__
- log_debug ("oops, `%s' is already locked\n", h->lockname);
-#endif /* !__riscos__ */
- return 0;
+ OVERLAPPED ovl;
+
+ memset (&ovl, 0, sizeof ovl);
+ UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
}
-
- for (;;)
+ CloseHandle (h->lockhd);
+}
+#endif /*HAVE_DOSISH_SYSTEM*/
+
+
+/* Destroy the locck handle H and release the lock. */
+void
+dotlock_destroy (dotlock_t h)
+{
+ dotlock_t hprev, htmp;
+
+ if ( !h )
+ return;
+
+ /* First remove the handle from our global list of all locks. */
+ LOCK_all_lockfiles ();
+ for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
+ if (htmp == h)
+ {
+ if (hprev)
+ hprev->next = htmp->next;
+ else
+ all_lockfiles = htmp->next;
+ h->next = NULL;
+ break;
+ }
+ UNLOCK_all_lockfiles ();
+
+ /* Then destroy the lock. */
+ if (!h->disable)
{
-#ifndef HAVE_DOSISH_SYSTEM
-# ifndef __riscos__
- if( !link(h->tname, h->lockname) )
+#ifdef HAVE_DOSISH_SYSTEM
+ dotlock_destroy_w32 (h);
+#else /* !HAVE_DOSISH_SYSTEM */
+ dotlock_destroy_unix (h);
+#endif /* HAVE_DOSISH_SYSTEM */
+ jnlib_free (h->lockname);
+ }
+ jnlib_free(h);
+}
+
+
+
+#ifdef HAVE_POSIX_SYSTEM
+/* Unix specific code of make_dotlock. Returns 0 on success and -1 on
+ error. */
+static int
+dotlock_take_unix (dotlock_t h, long timeout)
+{
+ int wtime = 0;
+ int sumtime = 0;
+ int pid;
+ int lastpid = -1;
+ int ownerchanged;
+ const char *maybe_dead="";
+ int same_node;
+
+ again:
+ if (h->use_o_excl)
+ {
+ /* No hardlink support - use open(O_EXCL). */
+ int fd;
+
+ do
{
- /* fixme: better use stat to check the link count */
- h->locked = 1;
- return 0; /* okay */
- }
- if (errno != EEXIST)
+ jnlib_set_errno (0);
+ fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
+ S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
+ }
+ while (fd == -1 && errno == EINTR);
+
+ if (fd == -1 && errno == EEXIST)
+ ; /* Lock held by another process. */
+ else if (fd == -1)
{
- log_error ("lock not made: link() failed: %s\n", strerror(errno));
+ my_error_2 ("lock not made: open(O_EXCL) of `%s' failed: %s\n",
+ h->lockname, strerror (errno));
return -1;
- }
-# else /* __riscos__ */
- if ( !riscos_renamefile(h->tname, h->lockname) )
- {
- h->locked = 1;
- return 0; /* okay */
}
- if (errno != EEXIST)
+ else
{
- log_error ("lock not made: rename() failed: %s\n", strerror(errno));
+ char pidstr[16];
+
+ snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
+ if (write (fd, pidstr, 11 ) == 11
+ && write (fd, h->tname + h->nodename_off,h->nodename_len)
+ == h->nodename_len
+ && write (fd, "\n", 1) == 1
+ && !close (fd))
+ {
+ h->locked = 1;
+ return 0;
+ }
+ /* Write error. */
+ my_error_2 ("lock not made: writing to `%s' failed: %s\n",
+ h->lockname, strerror (errno));
+ close (fd);
+ unlink (h->lockname);
return -1;
}
-# endif /* __riscos__ */
+ }
+ else /* Standard method: Use hardlinks. */
+ {
+ struct stat sb;
- if ((pid = read_lockfile (h, &same_node)) == -1 )
+ /* We ignore the return value of link() because it is unreliable. */
+ (void) link (h->tname, h->lockname);
+
+ if (stat (h->tname, &sb))
{
- if (errno != ENOENT)
- {
- log_info ("cannot read lockfile\n");
- return -1;
- }
- log_info ("lockfile disappeared\n");
- continue;
- }
- else if (pid == getpid ())
+ my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
+ strerror (errno));
+ /* In theory this might be a severe error: It is possible
+ that link succeeded but stat failed due to changed
+ permissions. We can't do anything about it, though. */
+ return -1;
+ }
+
+ if (sb.st_nlink == 2)
{
- log_info ("Oops: lock already held by us\n");
h->locked = 1;
- return 0; /* okay */
- }
- else if (same_node && kill(pid, 0) && errno == ESRCH)
- {
-# ifndef __riscos__
- log_info (_("removing stale lockfile (created by %d)\n"), pid );
- unlink (h->lockname);
- continue;
-# else /* __riscos__ */
- /* We are *pretty* sure that the other task is dead and
- therefore we remove the other lock file. */
- maybe_dead = " - probably dead - removing lock";
- unlink (h->lockname);
-# endif /* __riscos__ */
- }
+ return 0; /* Okay. */
+ }
+ }
- if (timeout == -1)
+ /* Check for stale lock files. */
+ if ( (pid = read_lockfile (h, &same_node)) == -1 )
+ {
+ if ( errno != ENOENT )
{
- struct timeval tv;
-
- log_info ("waiting for lock (held by %d%s) %s...\n",
- pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":"");
-
+ my_info_0 ("cannot read lockfile\n");
+ return -1;
+ }
+ my_info_0 ("lockfile disappeared\n");
+ goto again;
+ }
+ else if ( pid == getpid() && same_node )
+ {
+ my_info_0 ("Oops: lock already held by us\n");
+ h->locked = 1;
+ return 0; /* okay */
+ }
+ else if ( same_node && kill (pid, 0) && errno == ESRCH )
+ {
+ /* Note: It is unlikley that we get a race here unless a pid is
+ reused too fast or a new process with the same pid as the one
+ of the stale file tries to lock right at the same time as we. */
+ my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
+ unlink (h->lockname);
+ goto again;
+ }
- /* We can't use sleep, because signals may be blocked. */
- tv.tv_sec = 1 + backoff;
- tv.tv_usec = 0;
- select (0, NULL, NULL, NULL, &tv);
- if (backoff < 10)
- backoff++ ;
- }
- else
- return -1;
+ if (lastpid == -1)
+ lastpid = pid;
+ ownerchanged = (pid != lastpid);
-#else /*HAVE_DOSISH_SYSTEM*/
- int w32err;
-
- if (LockFile (h->lockhd, 0, 0, 1, 0))
+ if (timeout)
+ {
+ struct timeval tv;
+
+ /* Wait until lock has been released. We use increasing retry
+ intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
+ but reset it if the lock owner meanwhile changed. */
+ if (!wtime || ownerchanged)
+ wtime = 50;
+ else if (wtime < 800)
+ wtime *= 2;
+ else if (wtime == 800)
+ wtime = 2000;
+ else if (wtime < 8000)
+ wtime *= 2;
+
+ if (timeout > 0)
{
- h->locked = 1;
- return 0; /* okay */
+ if (wtime > timeout)
+ wtime = timeout;
+ timeout -= wtime;
}
- w32err = GetLastError ();
- if (w32err != ERROR_LOCK_VIOLATION)
+
+ sumtime += wtime;
+ if (sumtime >= 1500)
{
- log_error (_("lock `%s' not made: %s\n"),
- h->lockname, w32_strerror (w32err));
- return -1;
+ sumtime = 0;
+ my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
+ pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
}
-
- if (timeout == -1)
+
+
+ tv.tv_sec = wtime / 1000;
+ tv.tv_usec = (wtime % 1000) * 1000;
+ select (0, NULL, NULL, NULL, &tv);
+ goto again;
+ }
+
+ jnlib_set_errno (EACCES);
+ return -1;
+}
+#endif /*HAVE_POSIX_SYSTEM*/
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* Windows specific code of make_dotlock. Returns 0 on success and -1 on
+ error. */
+static int
+dotlock_take_w32 (dotlock_t h, long timeout)
+{
+ int wtime = 0;
+ int w32err;
+ OVERLAPPED ovl;
+
+ again:
+ /* Lock one byte at offset 0. The offset is given by OVL. */
+ memset (&ovl, 0, sizeof ovl);
+ if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
+ | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
+ {
+ h->locked = 1;
+ return 0; /* okay */
+ }
+
+ w32err = GetLastError ();
+ if (w32err != ERROR_LOCK_VIOLATION)
+ {
+ my_error_2 (_("lock `%s' not made: %s\n"),
+ h->lockname, w32_strerror (w32err));
+ return -1;
+ }
+
+ if (timeout)
+ {
+ /* Wait until lock has been released. We use retry intervals of
+ 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s. */
+ if (!wtime)
+ wtime = 50;
+ else if (wtime < 800)
+ wtime *= 2;
+ else if (wtime == 800)
+ wtime = 2000;
+ else if (wtime < 8000)
+ wtime *= 2;
+
+ if (timeout > 0)
{
- /* Wait until lock has been released. */
- log_info (_("waiting for lock %s...\n"), h->lockname);
- Sleep ((1 + backoff)*1000);
- if ( backoff < 10 )
- backoff++ ;
- }
- else
- return -1;
-#endif /*HAVE_DOSISH_SYSTEM*/
+ if (wtime > timeout)
+ wtime = timeout;
+ timeout -= wtime;
+ }
+
+ if (wtime >= 800)
+ my_info_1 (_("waiting for lock %s...\n"), h->lockname);
+
+ Sleep (wtime);
+ goto again;
}
- /*NOTREACHED */
+
+ return -1;
}
+#endif /*HAVE_DOSISH_SYSTEM*/
-/****************
- * release a lock
- * Returns: 0 := success
- */
+/* Take a lock on H. A value of 0 for TIMEOUT returns immediately if
+ the lock can't be taked, -1 waits forever (hopefully not), other
+ values wait for TIMEOUT milliseconds. Returns: 0 on success */
int
-release_dotlock (DOTLOCK h)
+dotlock_take (dotlock_t h, long timeout)
{
-#ifndef HAVE_DOSISH_SYSTEM
- int pid, same_node;
-#endif
-
- /* To avoid atexit race conditions we first check whether there are
- any locks left. It might happen that another atexit handler
- tries to release the lock while the atexit handler of this module
- already ran and thus H is undefined. */
- if (!all_lockfiles)
- return 0;
+ int ret;
- if (h->disable)
- return 0;
+ if ( h->disable )
+ return 0; /* Locks are completely disabled. Return success. */
- if (!h->locked)
+ if ( h->locked )
{
- log_debug("oops, `%s' is not locked\n", h->lockname );
+ my_debug_1 ("Oops, `%s' is already locked\n", h->lockname);
return 0;
}
-#ifndef HAVE_DOSISH_SYSTEM
+#ifdef HAVE_DOSISH_SYSTEM
+ ret = dotlock_take_w32 (h, timeout);
+#else /*!HAVE_DOSISH_SYSTEM*/
+ ret = dotlock_take_unix (h, timeout);
+#endif /*!HAVE_DOSISH_SYSTEM*/
+
+ return ret;
+}
+
+
+
+#ifdef HAVE_POSIX_SYSTEM
+/* Unix specific code of release_dotlock. */
+static int
+dotlock_release_unix (dotlock_t h)
+{
+ int pid, same_node;
+
pid = read_lockfile (h, &same_node);
- if (pid == -1)
+ if ( pid == -1 )
{
- log_error ("release_dotlock: lockfile error\n");
+ my_error_0 ("release_dotlock: lockfile error\n");
return -1;
}
- if (pid != getpid () || !same_node)
+ if ( pid != getpid() || !same_node )
{
- log_error ("release_dotlock: not our lock (pid=%d)\n", pid);
+ my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
return -1;
}
-# ifndef __riscos__
- if (unlink (h->lockname))
+
+ if ( unlink( h->lockname ) )
{
- log_error ("release_dotlock: error removing lockfile `%s'",
- h->lockname);
+ my_error_1 ("release_dotlock: error removing lockfile `%s'\n",
+ h->lockname);
return -1;
}
-# else /* __riscos__ */
- if( riscos_renamefile(h->lockname, h->tname) )
+ /* Fixme: As an extra check we could check whether the link count is
+ now really at 1. */
+ return 0;
+}
+#endif /*HAVE_POSIX_SYSTEM */
+
+
+#ifdef HAVE_DOSISH_SYSTEM
+/* Windows specific code of release_dotlock. */
+static int
+dotlock_release_w32 (dotlock_t h)
+{
+ OVERLAPPED ovl;
+
+ memset (&ovl, 0, sizeof ovl);
+ if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
{
- log_error( "release_dotlock: error renaming lockfile `%s' to `%s'",
- h->lockname, h->tname);
+ my_error_2 ("release_dotlock: error removing lockfile `%s': %s\n",
+ h->lockname, w32_strerror (-1));
return -1;
}
-# endif /* __riscos__ */
-#else /*HAVE_DOSISH_SYSTEM*/
+ return 0;
+}
+#endif /*HAVE_DOSISH_SYSTEM */
+
+
+/* Release a lock. Returns 0 on success. */
+int
+dotlock_release (dotlock_t h)
+{
+ int ret;
- if (!UnlockFile (h->lockhd, 0, 0, 1, 0))
+ /* To avoid atexit race conditions we first check whether there are
+ any locks left. It might happen that another atexit handler
+ tries to release the lock while the atexit handler of this module
+ already ran and thus H is undefined. */
+ LOCK_all_lockfiles ();
+ ret = !all_lockfiles;
+ UNLOCK_all_lockfiles ();
+ if (ret)
+ return 0;
+
+ if ( h->disable )
+ return 0;
+
+ if ( !h->locked )
{
- log_error ("release_dotlock: error removing lockfile `%s': %s\n",
- h->lockname, w32_strerror (-1));
- return -1;
+ my_debug_1 ("Oops, `%s' is not locked\n", h->lockname);
+ return 0;
}
-#endif /*HAVE_DOSISH_SYSTEM*/
- h->locked = 0;
- return 0;
+#ifdef HAVE_DOSISH_SYSTEM
+ ret = dotlock_release_w32 (h);
+#else
+ ret = dotlock_release_unix (h);
+#endif
+
+ if (!ret)
+ h->locked = 0;
+ return ret;
}
+
+/* Remove all lockfiles. This is called by the atexit handler
+ installed by this module but may also be called by other
+ termination handlers. */
void
-remove_lockfiles()
+dotlock_remove_lockfiles (void)
{
-#if !defined (HAVE_DOSISH_SYSTEM)
- DOTLOCK h, h2;
+ dotlock_t h, h2;
- h = all_lockfiles;
- all_lockfiles = NULL;
+ /* First set the lockfiles list to NULL so that for example
+ dotlock_release is ware that this fucntion is currently
+ running. */
+ LOCK_all_lockfiles ();
+ h = all_lockfiles;
+ all_lockfiles = NULL;
+ UNLOCK_all_lockfiles ();
- while( h ) {
- h2 = h->next;
- destroy_dotlock (h);
- h = h2;
+ while ( h )
+ {
+ h2 = h->next;
+ dotlock_destroy (h);
+ h = h2;
}
-#endif
}