Replace file locking by the new portable dotlock code.
authorWerner Koch <wk@gnupg.org>
Tue, 10 Jan 2012 14:16:44 +0000 (15:16 +0100)
committerWerner Koch <wk@gnupg.org>
Tue, 10 Jan 2012 14:16:44 +0000 (15:16 +0100)
* 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.

configure.ac
g10/gpg.c
g10/gpgv.c
g10/keydb.c
g10/keyring.c
g10/signal.c
g10/tdbio.c
include/dotlock.h [new file with mode: 0644]
include/util.h
util/dotlock.c

index 8570daa..181c07b 100644 (file)
@@ -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
index 3106d29..438da52 100644 (file)
--- 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:
index dfeaa85..8d2a8e6 100644 (file)
@@ -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) {}
index 5a62f18..d6d83e2 100644 (file)
@@ -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;
 }
index fb399d4..108e107 100644 (file)
@@ -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;
 }
-    
+
 
 \f
 /* 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)
 
 
 \f
-/* 
+/*
  * 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)
 }
 
 \f
-/* 
+/*
  * 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;
index 4aaa11e..086bf51 100644 (file)
@@ -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)
index 282411e..2732b1b 100644 (file)
@@ -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 (file)
index 0000000..920a81a
--- /dev/null
@@ -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*/
index 4b3c40b..9303a50 100644 (file)
@@ -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;
index ccbb6e8..c5f3a78 100644 (file)
 /* 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;
+\f
+/* 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 */
-}
 
 
+\f
+/* 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 */
+
+
+\f
+#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*/
+}
+
+
+\f
+/* 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;
+}
+
+
+\f
+#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);
+}
+
+
+\f
+#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;
+}
+
+
+\f
+#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;
 }
 
 
+\f
+/* 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
 }