LCOV - code coverage report
Current view: top level - common - dotlock.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 145 308 47.1 %
Date: 2015-11-05 17:10:59 Functions: 11 15 73.3 %

          Line data    Source code
       1             : /* dotlock.c - dotfile locking
       2             :  * Copyright (C) 1998, 2000, 2001, 2003, 2004,
       3             :  *               2005, 2006, 2008, 2010, 2011 Free Software Foundation, Inc.
       4             :  *
       5             :  * This file is part of GnuPG.
       6             :  *
       7             :  * GnuPG is free software; you can redistribute it and/or modify it
       8             :  * under the terms of either
       9             :  *
      10             :  *   - the GNU Lesser General Public License as published by the Free
      11             :  *     Software Foundation; either version 3 of the License, or (at
      12             :  *     your option) any later version.
      13             :  *
      14             :  * or
      15             :  *
      16             :  *   - the GNU General Public License as published by the Free
      17             :  *     Software Foundation; either version 2 of the License, or (at
      18             :  *     your option) any later version.
      19             :  *
      20             :  * or both in parallel, as here.
      21             :  *
      22             :  * GnuPG is distributed in the hope that it will be useful, but
      23             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      24             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      25             :  * General Public License for more details.
      26             :  *
      27             :  * You should have received a copies of the GNU General Public License
      28             :  * and the GNU Lesser General Public License along with this program;
      29             :  * if not, see <http://www.gnu.org/licenses/>.
      30             :  *
      31             :  * ALTERNATIVELY, this file may be distributed under the terms of the
      32             :  * following license, in which case the provisions of this license are
      33             :  * required INSTEAD OF the GNU Lesser General License or the GNU
      34             :  * General Public License. If you wish to allow use of your version of
      35             :  * this file only under the terms of the GNU Lesser General License or
      36             :  * the GNU General Public License, and not to allow others to use your
      37             :  * version of this file under the terms of the following license,
      38             :  * indicate your decision by deleting this paragraph and the license
      39             :  * below.
      40             :  *
      41             :  * Redistribution and use in source and binary forms, with or without
      42             :  * modification, are permitted provided that the following conditions
      43             :  * are met:
      44             :  *
      45             :  * 1. Redistributions of source code must retain the above copyright
      46             :  *    notice, and the entire permission notice in its entirety,
      47             :  *    including the disclaimer of warranties.
      48             :  * 2. Redistributions in binary form must reproduce the above copyright
      49             :  *    notice, this list of conditions and the following disclaimer in the
      50             :  *    documentation and/or other materials provided with the distribution.
      51             :  * 3. The name of the author may not be used to endorse or promote
      52             :  *    products derived from this software without specific prior
      53             :  *    written permission.
      54             :  *
      55             :  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
      56             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      57             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      58             :  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      59             :  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      60             :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      61             :  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      62             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      63             :  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      64             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
      65             :  * OF THE POSSIBILITY OF SUCH DAMAGE.
      66             :  */
      67             : 
      68             : /*
      69             :    Overview:
      70             :    =========
      71             : 
      72             :    This module implements advisory file locking in a portable way.
      73             :    Due to the problems with POSIX fcntl locking a separate lock file
      74             :    is used.  It would be possible to use fcntl locking on this lock
      75             :    file and thus avoid the weird auto unlock bug of POSIX while still
      76             :    having an unproved better performance of fcntl locking.  However
      77             :    there are still problems left, thus we resort to use a hardlink
      78             :    which has the well defined property that a link call will fail if
      79             :    the target file already exists.
      80             : 
      81             :    Given that hardlinks are also available on NTFS file systems since
      82             :    Windows XP; it will be possible to enhance this module to use
      83             :    hardlinks even on Windows and thus allow Windows and Posix clients
      84             :    to use locking on the same directory.  This is not yet implemented;
      85             :    instead we use a lockfile on Windows along with W32 style file
      86             :    locking.
      87             : 
      88             :    On FAT file systems hardlinks are not supported.  Thus this method
      89             :    does not work.  Our solution is to use a O_EXCL locking instead.
      90             :    Querying the type of the file system is not easy to do in a
      91             :    portable way (e.g. Linux has a statfs, BSDs have a the same call
      92             :    but using different structures and constants).  What we do instead
      93             :    is to check at runtime whether link(2) works for a specific lock
      94             :    file.
      95             : 
      96             : 
      97             :    How to use:
      98             :    ===========
      99             : 
     100             :    At program initialization time, the module should be explicitly
     101             :    initialized:
     102             : 
     103             :       dotlock_create (NULL, 0);
     104             : 
     105             :    This installs an atexit handler and may also initialize mutex etc.
     106             :    It is optional for non-threaded applications.  Only the first call
     107             :    has an effect.  This needs to be done before any extra threads are
     108             :    started.
     109             : 
     110             :    To create a lock file (which  prepares it but does not take the
     111             :    lock) you do:
     112             : 
     113             :      dotlock_t h
     114             : 
     115             :      h = dotlock_create (fname, 0);
     116             :      if (!h)
     117             :        error ("error creating lock file: %s\n", strerror (errno));
     118             : 
     119             :    It is important to handle the error.  For example on a read-only
     120             :    file system a lock can't be created (but is usually not needed).
     121             :    FNAME is the file you want to lock; the actual lockfile is that
     122             :    name with the suffix ".lock" appended.  On success a handle to be
     123             :    used with the other functions is returned or NULL on error.  Note
     124             :    that the handle shall only be used by one thread at a time.  This
     125             :    function creates a unique file temporary file (".#lk*") in the same
     126             :    directory as FNAME and returns a handle for further operations.
     127             :    The module keeps track of theses unique files so that they will be
     128             :    unlinked using the atexit handler.  If you don't need the lock file
     129             :    anymore, you may also explicitly remove it with a call to:
     130             : 
     131             :      dotlock_destroy (h);
     132             : 
     133             :    To actually lock the file, you use:
     134             : 
     135             :      if (dotlock_take (h, -1))
     136             :        error ("error taking lock: %s\n", strerror (errno));
     137             : 
     138             :    This function will wait until the lock is acquired.  If an
     139             :    unexpected error occurs if will return non-zero and set ERRNO.  If
     140             :    you pass (0) instead of (-1) the function does not wait in case the
     141             :    file is already locked but returns -1 and sets ERRNO to EACCES.
     142             :    Any other positive value for the second parameter is considered a
     143             :    timeout valuie in milliseconds.
     144             : 
     145             :    To release the lock you call:
     146             : 
     147             :      if (dotlock_release (h))
     148             :        error ("error releasing lock: %s\n", strerror (errno));
     149             : 
     150             :    or, if the lock file is not anymore needed, you may just call
     151             :    dotlock_destroy.  However dotlock_release does some extra checks
     152             :    before releasing the lock and prints diagnostics to help detecting
     153             :    bugs.
     154             : 
     155             :    If you want to explicitly destroy all lock files you may call
     156             : 
     157             :      dotlock_remove_lockfiles ();
     158             : 
     159             :    which is the core of the installed atexit handler.  In case your
     160             :    application wants to disable locking completely it may call
     161             : 
     162             :      disable_locking ()
     163             : 
     164             :    before any locks are created.
     165             : 
     166             :    There are two convenience functions to store an integer (e.g. a
     167             :    file descriptor) value with the handle:
     168             : 
     169             :      void dotlock_set_fd (dotlock_t h, int fd);
     170             :      int  dotlock_get_fd (dotlock_t h);
     171             : 
     172             :    If nothing has been stored dotlock_get_fd returns -1.
     173             : 
     174             : 
     175             : 
     176             :    How to build:
     177             :    =============
     178             : 
     179             :    This module was originally developed for GnuPG but later changed to
     180             :    allow its use without any GnuPG dependency.  If you want to use it
     181             :    with you application you may simply use it and it should figure out
     182             :    most things automagically.
     183             : 
     184             :    You may use the common config.h file to pass macros, but take care
     185             :    to pass -DHAVE_CONFIG_H to the compiler.  Macros used by this
     186             :    module are:
     187             : 
     188             :      DOTLOCK_USE_PTHREAD  - Define if POSIX threads are in use.
     189             : 
     190             :      DOTLOCK_GLIB_LOGGING - Define this to use Glib logging functions.
     191             : 
     192             :      DOTLOCK_EXT_SYM_PREFIX - Prefix all external symbols with the
     193             :                               string to which this macro evaluates.
     194             : 
     195             :      GNUPG_MAJOR_VERSION - Defined when used by GnuPG.
     196             : 
     197             :      HAVE_DOSISH_SYSTEM  - Defined for Windows etc.  Will be
     198             :                            automatically defined if a the target is
     199             :                            Windows.
     200             : 
     201             :      HAVE_POSIX_SYSTEM   - Internally defined to !HAVE_DOSISH_SYSTEM.
     202             : 
     203             :      HAVE_SIGNAL_H       - Should be defined on Posix systems.  If config.h
     204             :                            is not used defaults to defined.
     205             : 
     206             :      DIRSEP_C            - Separation character for file name parts.
     207             :                            Usually not redefined.
     208             : 
     209             :      EXTSEP_S            - Separation string for file name suffixes.
     210             :                            Usually not redefined.
     211             : 
     212             :      HAVE_W32CE_SYSTEM   - Currently only used by GnuPG.
     213             : 
     214             :    Note that there is a test program t-dotlock which has compile
     215             :    instructions at its end.  At least for SMBFS and CIFS it is
     216             :    important that 64 bit versions of stat are used; most programming
     217             :    environments do this these days, just in case you want to compile
     218             :    it on the command line, remember to pass -D_FILE_OFFSET_BITS=64
     219             : 
     220             : 
     221             :    Bugs:
     222             :    =====
     223             : 
     224             :    On Windows this module is not yet thread-safe.
     225             : 
     226             : 
     227             :    Miscellaneous notes:
     228             :    ====================
     229             : 
     230             :    On hardlinks:
     231             :    - Hardlinks are supported under Windows with NTFS since XP/Server2003.
     232             :    - In Linux 2.6.33 both SMBFS and CIFS seem to support hardlinks.
     233             :    - NFS supports hard links.  But there are solvable problems.
     234             :    - FAT does not support links
     235             : 
     236             :    On the file locking API:
     237             :    - CIFS on Linux 2.6.33 supports several locking methods.
     238             :      SMBFS seems not to support locking.  No closer checks done.
     239             :    - NFS supports Posix locks.  flock is emulated in the server.
     240             :      However there are a couple of problems; see below.
     241             :    - FAT does not support locks.
     242             :    - An advantage of fcntl locking is that R/W locks can be
     243             :      implemented which is not easy with a straight lock file.
     244             : 
     245             :    On O_EXCL:
     246             :    - Does not work reliable on NFS
     247             :    - Should work on CIFS and SMBFS but how can we delete lockfiles?
     248             : 
     249             :    On NFS problems:
     250             :    - Locks vanish if the server crashes and reboots.
     251             :    - Client crashes keep the lock in the server until the client
     252             :      re-connects.
     253             :    - Communication problems may return unreliable error codes.  The
     254             :      MUA Postfix's workaround is to compare the link count after
     255             :      seeing an error for link.  However that gives a race.  If using a
     256             :      unique file to link to a lockfile and using stat to check the
     257             :      link count instead of looking at the error return of link(2) is
     258             :      the best solution.
     259             :    - O_EXCL seems to have a race and may re-create a file anyway.
     260             : 
     261             : */
     262             : 
     263             : #ifdef HAVE_CONFIG_H
     264             : # include <config.h>
     265             : #endif
     266             : 
     267             : /* Some quick replacements for stuff we usually expect to be defined
     268             :    in config.h.  Define HAVE_POSIX_SYSTEM for better readability. */
     269             : #if !defined (HAVE_DOSISH_SYSTEM) && defined(_WIN32)
     270             : # define HAVE_DOSISH_SYSTEM 1
     271             : #endif
     272             : #if !defined (HAVE_DOSISH_SYSTEM) && !defined (HAVE_POSIX_SYSTEM)
     273             : # define HAVE_POSIX_SYSTEM 1
     274             : #endif
     275             : 
     276             : /* With no config.h assume that we have sitgnal.h.  */
     277             : #if !defined (HAVE_CONFIG_H) && defined (HAVE_POSIX_SYSTEM)
     278             : # define HAVE_SIGNAL_H 1
     279             : #endif
     280             : 
     281             : /* Standard headers.  */
     282             : #include <stdlib.h>
     283             : #include <stdio.h>
     284             : #include <string.h>
     285             : #include <errno.h>
     286             : #include <ctype.h>
     287             : #include <errno.h>
     288             : #include <unistd.h>
     289             : #ifdef  HAVE_DOSISH_SYSTEM
     290             : # define WIN32_LEAN_AND_MEAN  /* We only need the OS core stuff.  */
     291             : # include <windows.h>
     292             : #else
     293             : # include <sys/types.h>
     294             : # include <sys/stat.h>
     295             : # include <sys/utsname.h>
     296             : #endif
     297             : #include <sys/types.h>
     298             : #include <sys/time.h>
     299             : #include <sys/stat.h>
     300             : #include <fcntl.h>
     301             : #ifdef HAVE_SIGNAL_H
     302             : # include <signal.h>
     303             : #endif
     304             : #ifdef DOTLOCK_USE_PTHREAD
     305             : # include <pthread.h>
     306             : #endif
     307             : 
     308             : #ifdef DOTLOCK_GLIB_LOGGING
     309             : # include <glib.h>
     310             : #endif
     311             : 
     312             : #ifdef GNUPG_MAJOR_VERSION
     313             : # include "util.h"
     314             : # include "common-defs.h"
     315             : # include "stringhelp.h"  /* For stpcpy and w32_strerror. */
     316             : #endif
     317             : #ifdef HAVE_W32CE_SYSTEM
     318             : # include "utf8conv.h"  /* WindowsCE requires filename conversion.  */
     319             : #endif
     320             : 
     321             : #include "dotlock.h"
     322             : 
     323             : 
     324             : /* Define constants for file name construction.  */
     325             : #if !defined(DIRSEP_C) && !defined(EXTSEP_S)
     326             : # ifdef HAVE_DOSISH_SYSTEM
     327             : #  define DIRSEP_C '\\'
     328             : #  define EXTSEP_S "."
     329             : #else
     330             : #  define DIRSEP_C '/'
     331             : #  define EXTSEP_S "."
     332             : # endif
     333             : #endif
     334             : 
     335             : /* In GnuPG we use wrappers around the malloc fucntions.  If they are
     336             :    not defined we assume that this code is used outside of GnuPG and
     337             :    fall back to the regular malloc functions.  */
     338             : #ifndef xtrymalloc
     339             : # define xtrymalloc(a)     malloc ((a))
     340             : # define xtrycalloc(a,b)   calloc ((a), (b))
     341             : # define xfree(a)          free ((a))
     342             : #endif
     343             : 
     344             : /* Wrapper to set ERRNO (required for W32CE).  */
     345             : #ifdef GPG_ERROR_VERSION
     346             : #  define my_set_errno(e)  gpg_err_set_errno ((e))
     347             : #else
     348             : #  define my_set_errno(e)  do { errno = (e); } while (0)
     349             : #endif
     350             : 
     351             : /* Gettext macro replacement.  */
     352             : #ifndef _
     353             : # define _(a) (a)
     354             : #endif
     355             : 
     356             : #ifdef GNUPG_MAJOR_VERSION
     357             : # define my_info_0(a)       log_info ((a))
     358             : # define my_info_1(a,b)     log_info ((a), (b))
     359             : # define my_info_2(a,b,c)   log_info ((a), (b), (c))
     360             : # define my_info_3(a,b,c,d) log_info ((a), (b), (c), (d))
     361             : # define my_error_0(a)      log_error ((a))
     362             : # define my_error_1(a,b)    log_error ((a), (b))
     363             : # define my_error_2(a,b,c)  log_error ((a), (b), (c))
     364             : # define my_debug_1(a,b)    log_debug ((a), (b))
     365             : # define my_fatal_0(a)      log_fatal ((a))
     366             : #elif defined (DOTLOCK_GLIB_LOGGING)
     367             : # define my_info_0(a)       g_message ((a))
     368             : # define my_info_1(a,b)     g_message ((a), (b))
     369             : # define my_info_2(a,b,c)   g_message ((a), (b), (c))
     370             : # define my_info_3(a,b,c,d) g_message ((a), (b), (c), (d))
     371             : # define my_error_0(a)      g_warning ((a))
     372             : # define my_error_1(a,b)    g_warning ((a), (b))
     373             : # define my_error_2(a,b,c)  g_warning ((a), (b), (c))
     374             : # define my_debug_1(a,b)    g_debug ((a), (b))
     375             : # define my_fatal_0(a)      g_error ((a))
     376             : #else
     377             : # define my_info_0(a)       fprintf (stderr, (a))
     378             : # define my_info_1(a,b)     fprintf (stderr, (a), (b))
     379             : # define my_info_2(a,b,c)   fprintf (stderr, (a), (b), (c))
     380             : # define my_info_3(a,b,c,d) fprintf (stderr, (a), (b), (c), (d))
     381             : # define my_error_0(a)      fprintf (stderr, (a))
     382             : # define my_error_1(a,b)    fprintf (stderr, (a), (b))
     383             : # define my_error_2(a,b,c)  fprintf (stderr, (a), (b), (c))
     384             : # define my_debug_1(a,b)    fprintf (stderr, (a), (b))
     385             : # define my_fatal_0(a)      do { fprintf (stderr,(a)); fflush (stderr); \
     386             :                                  abort (); } while (0)
     387             : #endif
     388             : 
     389             : 
     390             : 
     391             : 
     392             : 
     393             : /* The object describing a lock.  */
     394             : struct dotlock_handle
     395             : {
     396             :   struct dotlock_handle *next;
     397             :   char *lockname;            /* Name of the actual lockfile.          */
     398             :   unsigned int locked:1;     /* Lock status.                          */
     399             :   unsigned int disable:1;    /* If true, locking is disabled.         */
     400             :   unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking.        */
     401             : 
     402             :   int extra_fd;              /* A place for the caller to store an FD.  */
     403             : 
     404             : #ifdef HAVE_DOSISH_SYSTEM
     405             :   HANDLE lockhd;       /* The W32 handle of the lock file.      */
     406             : #else /*!HAVE_DOSISH_SYSTEM */
     407             :   char *tname;         /* Name of the lockfile template.        */
     408             :   size_t nodename_off; /* Offset in TNAME of the nodename part. */
     409             :   size_t nodename_len; /* Length of the nodename part.          */
     410             : #endif /*!HAVE_DOSISH_SYSTEM */
     411             : };
     412             : 
     413             : 
     414             : /* A list of of all lock handles.  The volatile attribute might help
     415             :    if used in an atexit handler.  */
     416             : static volatile dotlock_t all_lockfiles;
     417             : #ifdef DOTLOCK_USE_PTHREAD
     418             : static pthread_mutex_t all_lockfiles_mutex = PTHREAD_MUTEX_INITIALIZER;
     419             : # define LOCK_all_lockfiles() do {                               \
     420             :         if (pthread_mutex_lock (&all_lockfiles_mutex))           \
     421             :           my_fatal_0 ("locking all_lockfiles_mutex failed\n");   \
     422             :       } while (0)
     423             : # define UNLOCK_all_lockfiles() do {                             \
     424             :         if (pthread_mutex_unlock (&all_lockfiles_mutex))         \
     425             :           my_fatal_0 ("unlocking all_lockfiles_mutex failed\n"); \
     426             :       } while (0)
     427             : #else  /*!DOTLOCK_USE_PTHREAD*/
     428             : # define LOCK_all_lockfiles()   do { } while (0)
     429             : # define UNLOCK_all_lockfiles() do { } while (0)
     430             : #endif /*!DOTLOCK_USE_PTHREAD*/
     431             : 
     432             : /* If this has the value true all locking is disabled.  */
     433             : static int never_lock;
     434             : 
     435             : 
     436             : 
     437             : 
     438             : 
     439             : /* Entirely disable all locking.  This function should be called
     440             :    before any locking is done.  It may be called right at startup of
     441             :    the process as it only sets a global value.  */
     442             : void
     443           0 : dotlock_disable (void)
     444             : {
     445           0 :   never_lock = 1;
     446           0 : }
     447             : 
     448             : 
     449             : #ifdef HAVE_POSIX_SYSTEM
     450             : static int
     451           0 : maybe_deadlock (dotlock_t h)
     452             : {
     453             :   dotlock_t r;
     454           0 :   int res = 0;
     455             : 
     456             :   LOCK_all_lockfiles ();
     457           0 :   for (r=all_lockfiles; r; r = r->next)
     458             :     {
     459           0 :       if ( r != h && r->locked )
     460             :         {
     461           0 :           res = 1;
     462           0 :           break;
     463             :         }
     464             :     }
     465             :   UNLOCK_all_lockfiles ();
     466           0 :   return res;
     467             : }
     468             : #endif /*HAVE_POSIX_SYSTEM*/
     469             : 
     470             : 
     471             : /* Read the lock file and return the pid, returns -1 on error.  True
     472             :    will be stored in the integer at address SAME_NODE if the lock file
     473             :    has been created on the same node. */
     474             : #ifdef HAVE_POSIX_SYSTEM
     475             : static int
     476          12 : read_lockfile (dotlock_t h, int *same_node )
     477             : {
     478             :   char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
     479             :                                    names are usually shorter. */
     480             :   int fd;
     481          12 :   int pid = -1;
     482             :   char *buffer, *p;
     483             :   size_t expected_len;
     484             :   int res, nread;
     485             : 
     486          12 :   *same_node = 0;
     487          12 :   expected_len = 10 + 1 + h->nodename_len + 1;
     488          12 :   if ( expected_len >= sizeof buffer_space)
     489             :     {
     490           0 :       buffer = xtrymalloc (expected_len);
     491           0 :       if (!buffer)
     492           0 :         return -1;
     493             :     }
     494             :   else
     495          12 :     buffer = buffer_space;
     496             : 
     497          12 :   if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
     498             :     {
     499           0 :       int e = errno;
     500           0 :       my_info_2 ("error opening lockfile '%s': %s\n",
     501             :                  h->lockname, strerror(errno) );
     502           0 :       if (buffer != buffer_space)
     503           0 :         xfree (buffer);
     504           0 :       my_set_errno (e); /* Need to return ERRNO here. */
     505           0 :       return -1;
     506             :     }
     507             : 
     508          12 :   p = buffer;
     509          12 :   nread = 0;
     510             :   do
     511             :     {
     512          12 :       res = read (fd, p, expected_len - nread);
     513          12 :       if (res == -1 && errno == EINTR)
     514           0 :         continue;
     515          12 :       if (res < 0)
     516             :         {
     517           0 :           my_info_1 ("error reading lockfile '%s'\n", h->lockname );
     518           0 :           close (fd);
     519           0 :           if (buffer != buffer_space)
     520           0 :             xfree (buffer);
     521           0 :           my_set_errno (0); /* Do not return an inappropriate ERRNO. */
     522           0 :           return -1;
     523             :         }
     524          12 :       p += res;
     525          12 :       nread += res;
     526             :     }
     527          12 :   while (res && nread != expected_len);
     528          12 :   close(fd);
     529             : 
     530          12 :   if (nread < 11)
     531             :     {
     532           0 :       my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
     533           0 :       if (buffer != buffer_space)
     534           0 :         xfree (buffer);
     535           0 :       my_set_errno (0); /* Better don't return an inappropriate ERRNO. */
     536           0 :       return -1;
     537             :     }
     538             : 
     539          12 :   if (buffer[10] != '\n'
     540          12 :       || (buffer[10] = 0, pid = atoi (buffer)) == -1
     541          12 :       || !pid )
     542             :     {
     543           0 :       my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
     544           0 :       if (buffer != buffer_space)
     545           0 :         xfree (buffer);
     546           0 :       my_set_errno (0);
     547           0 :       return -1;
     548             :     }
     549             : 
     550          12 :   if (nread == expected_len
     551          12 :       && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
     552          12 :       && buffer[11+h->nodename_len] == '\n')
     553          12 :     *same_node = 1;
     554             : 
     555          12 :   if (buffer != buffer_space)
     556           0 :     xfree (buffer);
     557          12 :   return pid;
     558             : }
     559             : #endif /*HAVE_POSIX_SYSTEM */
     560             : 
     561             : 
     562             : /* Check whether the file system which stores TNAME supports
     563             :    hardlinks.  Instead of using the non-portable statsfs call which
     564             :    differs between various Unix versions, we do a runtime test.
     565             :    Returns: 0 supports hardlinks; 1 no hardlink support, -1 unknown
     566             :    (test error).  */
     567             : #ifdef HAVE_POSIX_SYSTEM
     568             : static int
     569           9 : use_hardlinks_p (const char *tname)
     570             : {
     571             :   char *lname;
     572             :   struct stat sb;
     573             :   unsigned int nlink;
     574             :   int res;
     575             : 
     576           9 :   if (stat (tname, &sb))
     577           0 :     return -1;
     578           9 :   nlink = (unsigned int)sb.st_nlink;
     579             : 
     580           9 :   lname = xtrymalloc (strlen (tname) + 1 + 1);
     581           9 :   if (!lname)
     582           0 :     return -1;
     583           9 :   strcpy (lname, tname);
     584           9 :   strcat (lname, "x");
     585             : 
     586             :   /* We ignore the return value of link() because it is unreliable.  */
     587           9 :   (void) link (tname, lname);
     588             : 
     589           9 :   if (stat (tname, &sb))
     590           0 :     res = -1;  /* Ooops.  */
     591           9 :   else if (sb.st_nlink == nlink + 1)
     592           9 :     res = 0;   /* Yeah, hardlinks are supported.  */
     593             :   else
     594           0 :     res = 1;   /* No hardlink support.  */
     595             : 
     596           9 :   unlink (lname);
     597           9 :   xfree (lname);
     598           9 :   return res;
     599             : }
     600             : #endif /*HAVE_POSIX_SYSTEM */
     601             : 
     602             : 
     603             : 
     604             : #ifdef  HAVE_POSIX_SYSTEM
     605             : /* Locking core for Unix.  It used a temporary file and the link
     606             :    system call to make locking an atomic operation. */
     607             : static dotlock_t
     608           9 : dotlock_create_unix (dotlock_t h, const char *file_to_lock)
     609             : {
     610           9 :   int  fd = -1;
     611             :   char pidstr[16];
     612             :   const char *nodename;
     613             :   const char *dirpart;
     614             :   int dirpartlen;
     615             :   struct utsname utsbuf;
     616             :   size_t tnamelen;
     617             : 
     618           9 :   snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
     619             : 
     620             :   /* Create a temporary file. */
     621           9 :   if ( uname ( &utsbuf ) )
     622           0 :     nodename = "unknown";
     623             :   else
     624           9 :     nodename = utsbuf.nodename;
     625             : 
     626           9 :   if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
     627             :     {
     628           0 :       dirpart = EXTSEP_S;
     629           0 :       dirpartlen = 1;
     630             :     }
     631             :   else
     632             :     {
     633           9 :       dirpartlen = dirpart - file_to_lock;
     634           9 :       dirpart = file_to_lock;
     635             :     }
     636             : 
     637             :   LOCK_all_lockfiles ();
     638           9 :   h->next = all_lockfiles;
     639           9 :   all_lockfiles = h;
     640             : 
     641           9 :   tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
     642           9 :   h->tname = xtrymalloc (tnamelen + 1);
     643           9 :   if (!h->tname)
     644             :     {
     645           0 :       all_lockfiles = h->next;
     646             :       UNLOCK_all_lockfiles ();
     647           0 :       xfree (h);
     648           0 :       return NULL;
     649             :     }
     650           9 :   h->nodename_len = strlen (nodename);
     651             : 
     652           9 :   snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
     653           9 :   h->nodename_off = strlen (h->tname);
     654           9 :   snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
     655             :            "%s.%d", nodename, (int)getpid ());
     656             : 
     657             :   do
     658             :     {
     659           9 :       my_set_errno (0);
     660           9 :       fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
     661             :                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
     662             :     }
     663           9 :   while (fd == -1 && errno == EINTR);
     664             : 
     665           9 :   if ( fd == -1 )
     666             :     {
     667           0 :       all_lockfiles = h->next;
     668             :       UNLOCK_all_lockfiles ();
     669           0 :       my_error_2 (_("failed to create temporary file '%s': %s\n"),
     670             :                   h->tname, strerror(errno));
     671           0 :       xfree (h->tname);
     672           0 :       xfree (h);
     673           0 :       return NULL;
     674             :     }
     675           9 :   if ( write (fd, pidstr, 11 ) != 11 )
     676           0 :     goto write_failed;
     677           9 :   if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
     678           0 :     goto write_failed;
     679           9 :   if ( write (fd, "\n", 1 ) != 1 )
     680           0 :     goto write_failed;
     681           9 :   if ( close (fd) )
     682             :     {
     683           0 :       if ( errno == EINTR )
     684           0 :         fd = -1;
     685           0 :       goto write_failed;
     686             :     }
     687           9 :   fd = -1;
     688             : 
     689             :   /* Check whether we support hard links.  */
     690           9 :   switch (use_hardlinks_p (h->tname))
     691             :     {
     692             :     case 0: /* Yes.  */
     693           9 :       break;
     694             :     case 1: /* No.  */
     695           0 :       unlink (h->tname);
     696           0 :       h->use_o_excl = 1;
     697           0 :       break;
     698             :     default:
     699           0 :       my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n",
     700             :                   h->tname, strerror(errno));
     701           0 :       goto write_failed;
     702             :     }
     703             : 
     704           9 :   h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
     705           9 :   if (!h->lockname)
     706             :     {
     707           0 :       all_lockfiles = h->next;
     708             :       UNLOCK_all_lockfiles ();
     709           0 :       unlink (h->tname);
     710           0 :       xfree (h->tname);
     711           0 :       xfree (h);
     712           0 :       return NULL;
     713             :     }
     714           9 :   strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
     715             :   UNLOCK_all_lockfiles ();
     716           9 :   if (h->use_o_excl)
     717           0 :     my_debug_1 ("locking for '%s' done via O_EXCL\n", h->lockname);
     718             : 
     719           9 :   return h;
     720             : 
     721             :  write_failed:
     722           0 :   all_lockfiles = h->next;
     723             :   UNLOCK_all_lockfiles ();
     724           0 :   my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
     725           0 :   if ( fd != -1 )
     726           0 :     close (fd);
     727           0 :   unlink (h->tname);
     728           0 :   xfree (h->tname);
     729           0 :   xfree (h);
     730           0 :   return NULL;
     731             : }
     732             : #endif /*HAVE_POSIX_SYSTEM*/
     733             : 
     734             : 
     735             : #ifdef HAVE_DOSISH_SYSTEM
     736             : /* Locking core for Windows.  This version does not need a temporary
     737             :    file but uses the plain lock file along with record locking.  We
     738             :    create this file here so that we later only need to do the file
     739             :    locking.  For error reporting it is useful to keep the name of the
     740             :    file in the handle.  */
     741             : static dotlock_t
     742             : dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
     743             : {
     744             :   LOCK_all_lockfiles ();
     745             :   h->next = all_lockfiles;
     746             :   all_lockfiles = h;
     747             : 
     748             :   h->lockname = xtrymalloc ( strlen (file_to_lock) + 6 );
     749             :   if (!h->lockname)
     750             :     {
     751             :       all_lockfiles = h->next;
     752             :       UNLOCK_all_lockfiles ();
     753             :       xfree (h);
     754             :       return NULL;
     755             :     }
     756             :   strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
     757             : 
     758             :   /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
     759             :      along with FILE_SHARE_DELETE but that does not work due to a race
     760             :      condition: Despite the OPEN_ALWAYS flag CreateFile may return an
     761             :      error and we can't reliable create/open the lock file unless we
     762             :      would wait here until it works - however there are other valid
     763             :      reasons why a lock file can't be created and thus the process
     764             :      would not stop as expected but spin until Windows crashes.  Our
     765             :      solution is to keep the lock file open; that does not harm. */
     766             :   {
     767             : #ifdef HAVE_W32CE_SYSTEM
     768             :     wchar_t *wname = utf8_to_wchar (h->lockname);
     769             : 
     770             :     if (wname)
     771             :       h->lockhd = CreateFile (wname,
     772             :                               GENERIC_READ|GENERIC_WRITE,
     773             :                               FILE_SHARE_READ|FILE_SHARE_WRITE,
     774             :                               NULL, OPEN_ALWAYS, 0, NULL);
     775             :     else
     776             :       h->lockhd = INVALID_HANDLE_VALUE;
     777             :     xfree (wname);
     778             : #else
     779             :     h->lockhd = CreateFile (h->lockname,
     780             :                             GENERIC_READ|GENERIC_WRITE,
     781             :                             FILE_SHARE_READ|FILE_SHARE_WRITE,
     782             :                             NULL, OPEN_ALWAYS, 0, NULL);
     783             : #endif
     784             :   }
     785             :   if (h->lockhd == INVALID_HANDLE_VALUE)
     786             :     {
     787             :       all_lockfiles = h->next;
     788             :       UNLOCK_all_lockfiles ();
     789             :       my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
     790             :       xfree (h->lockname);
     791             :       xfree (h);
     792             :       return NULL;
     793             :     }
     794             :   return h;
     795             : }
     796             : #endif /*HAVE_DOSISH_SYSTEM*/
     797             : 
     798             : 
     799             : /* Create a lockfile for a file name FILE_TO_LOCK and returns an
     800             :    object of type dotlock_t which may be used later to actually acquire
     801             :    the lock.  A cleanup routine gets installed to cleanup left over
     802             :    locks or other files used internally by the lock mechanism.
     803             : 
     804             :    Calling this function with NULL does only install the atexit
     805             :    handler and may thus be used to assure that the cleanup is called
     806             :    after all other atexit handlers.
     807             : 
     808             :    This function creates a lock file in the same directory as
     809             :    FILE_TO_LOCK using that name and a suffix of ".lock".  Note that on
     810             :    POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
     811             :    used.
     812             : 
     813             :    FLAGS must be 0.
     814             : 
     815             :    The function returns an new handle which needs to be released using
     816             :    destroy_dotlock but gets also released at the termination of the
     817             :    process.  On error NULL is returned.
     818             :  */
     819             : 
     820             : dotlock_t
     821        1343 : dotlock_create (const char *file_to_lock, unsigned int flags)
     822             : {
     823             :   static int initialized;
     824             :   dotlock_t h;
     825             : 
     826        1343 :   if ( !initialized )
     827             :     {
     828        1335 :       atexit (dotlock_remove_lockfiles);
     829        1335 :       initialized = 1;
     830             :     }
     831             : 
     832        1343 :   if ( !file_to_lock )
     833        1334 :     return NULL;  /* Only initialization was requested.  */
     834             : 
     835           9 :   if (flags)
     836             :     {
     837           0 :       my_set_errno (EINVAL);
     838           0 :       return NULL;
     839             :     }
     840             : 
     841           9 :   h = xtrycalloc (1, sizeof *h);
     842           9 :   if (!h)
     843           0 :     return NULL;
     844           9 :   h->extra_fd = -1;
     845             : 
     846           9 :   if (never_lock)
     847             :     {
     848           0 :       h->disable = 1;
     849             :       LOCK_all_lockfiles ();
     850           0 :       h->next = all_lockfiles;
     851           0 :       all_lockfiles = h;
     852             :       UNLOCK_all_lockfiles ();
     853           0 :       return h;
     854             :     }
     855             : 
     856             : #ifdef HAVE_DOSISH_SYSTEM
     857             :   return dotlock_create_w32 (h, file_to_lock);
     858             : #else /*!HAVE_DOSISH_SYSTEM */
     859           9 :   return dotlock_create_unix (h, file_to_lock);
     860             : #endif /*!HAVE_DOSISH_SYSTEM*/
     861             : }
     862             : 
     863             : 
     864             : 
     865             : /* Convenience function to store a file descriptor (or any any other
     866             :    integer value) in the context of handle H.  */
     867             : void
     868           0 : dotlock_set_fd (dotlock_t h, int fd)
     869             : {
     870           0 :   h->extra_fd = fd;
     871           0 : }
     872             : 
     873             : /* Convenience function to retrieve a file descriptor (or any any other
     874             :    integer value) stored in the context of handle H.  */
     875             : int
     876           0 : dotlock_get_fd (dotlock_t h)
     877             : {
     878           0 :   return h->extra_fd;
     879             : }
     880             : 
     881             : 
     882             : 
     883             : #ifdef HAVE_POSIX_SYSTEM
     884             : /* Unix specific code of destroy_dotlock.  */
     885             : static void
     886           9 : dotlock_destroy_unix (dotlock_t h)
     887             : {
     888           9 :   if (h->locked && h->lockname)
     889           1 :     unlink (h->lockname);
     890           9 :   if (h->tname && !h->use_o_excl)
     891           9 :     unlink (h->tname);
     892           9 :   xfree (h->tname);
     893           9 : }
     894             : #endif /*HAVE_POSIX_SYSTEM*/
     895             : 
     896             : 
     897             : #ifdef HAVE_DOSISH_SYSTEM
     898             : /* Windows specific code of destroy_dotlock.  */
     899             : static void
     900             : dotlock_destroy_w32 (dotlock_t h)
     901             : {
     902             :   if (h->locked)
     903             :     {
     904             :       OVERLAPPED ovl;
     905             : 
     906             :       memset (&ovl, 0, sizeof ovl);
     907             :       UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
     908             :     }
     909             :   CloseHandle (h->lockhd);
     910             : }
     911             : #endif /*HAVE_DOSISH_SYSTEM*/
     912             : 
     913             : 
     914             : /* Destroy the locck handle H and release the lock.  */
     915             : void
     916           9 : dotlock_destroy (dotlock_t h)
     917             : {
     918             :   dotlock_t hprev, htmp;
     919             : 
     920           9 :   if ( !h )
     921           9 :     return;
     922             : 
     923             :   /* First remove the handle from our global list of all locks. */
     924             :   LOCK_all_lockfiles ();
     925           9 :   for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
     926           3 :     if (htmp == h)
     927             :       {
     928           3 :         if (hprev)
     929           0 :           hprev->next = htmp->next;
     930             :         else
     931           3 :           all_lockfiles = htmp->next;
     932           3 :         h->next = NULL;
     933           3 :         break;
     934             :       }
     935             :   UNLOCK_all_lockfiles ();
     936             : 
     937             :   /* Then destroy the lock. */
     938           9 :   if (!h->disable)
     939             :     {
     940             : #ifdef HAVE_DOSISH_SYSTEM
     941             :       dotlock_destroy_w32 (h);
     942             : #else /* !HAVE_DOSISH_SYSTEM */
     943           9 :       dotlock_destroy_unix (h);
     944             : #endif /* HAVE_DOSISH_SYSTEM */
     945           9 :       xfree (h->lockname);
     946             :     }
     947           9 :   xfree(h);
     948             : }
     949             : 
     950             : 
     951             : 
     952             : #ifdef HAVE_POSIX_SYSTEM
     953             : /* Unix specific code of make_dotlock.  Returns 0 on success and -1 on
     954             :    error.  */
     955             : static int
     956          13 : dotlock_take_unix (dotlock_t h, long timeout)
     957             : {
     958          13 :   int wtime = 0;
     959          13 :   int sumtime = 0;
     960             :   int pid;
     961          13 :   int lastpid = -1;
     962             :   int ownerchanged;
     963          13 :   const char *maybe_dead="";
     964             :   int same_node;
     965             : 
     966             :  again:
     967          13 :   if (h->use_o_excl)
     968             :     {
     969             :       /* No hardlink support - use open(O_EXCL).  */
     970             :       int fd;
     971             : 
     972             :       do
     973             :         {
     974           0 :           my_set_errno (0);
     975           0 :           fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
     976             :                      S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
     977             :         }
     978           0 :       while (fd == -1 && errno == EINTR);
     979             : 
     980           0 :       if (fd == -1 && errno == EEXIST)
     981             :         ; /* Lock held by another process.  */
     982           0 :       else if (fd == -1)
     983             :         {
     984           0 :           my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
     985             :                       h->lockname, strerror (errno));
     986           0 :           return -1;
     987             :         }
     988             :       else
     989             :         {
     990             :           char pidstr[16];
     991             : 
     992           0 :           snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
     993           0 :           if (write (fd, pidstr, 11 ) == 11
     994           0 :               && write (fd, h->tname + h->nodename_off,h->nodename_len)
     995           0 :               == h->nodename_len
     996           0 :               && write (fd, "\n", 1) == 1
     997           0 :               && !close (fd))
     998             :             {
     999           0 :               h->locked = 1;
    1000           0 :               return 0;
    1001             :             }
    1002             :           /* Write error.  */
    1003           0 :           my_error_2 ("lock not made: writing to '%s' failed: %s\n",
    1004             :                       h->lockname, strerror (errno));
    1005           0 :           close (fd);
    1006           0 :           unlink (h->lockname);
    1007           0 :           return -1;
    1008             :         }
    1009             :     }
    1010             :   else /* Standard method:  Use hardlinks.  */
    1011             :     {
    1012             :       struct stat sb;
    1013             : 
    1014             :       /* We ignore the return value of link() because it is unreliable.  */
    1015          13 :       (void) link (h->tname, h->lockname);
    1016             : 
    1017          13 :       if (stat (h->tname, &sb))
    1018             :         {
    1019           0 :           my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
    1020             :                       strerror (errno));
    1021             :           /* In theory this might be a severe error: It is possible
    1022             :              that link succeeded but stat failed due to changed
    1023             :              permissions.  We can't do anything about it, though.  */
    1024          13 :           return -1;
    1025             :         }
    1026             : 
    1027          13 :       if (sb.st_nlink == 2)
    1028             :         {
    1029          13 :           h->locked = 1;
    1030          13 :           return 0; /* Okay.  */
    1031             :         }
    1032             :     }
    1033             : 
    1034             :   /* Check for stale lock files.  */
    1035           0 :   if ( (pid = read_lockfile (h, &same_node)) == -1 )
    1036             :     {
    1037           0 :       if ( errno != ENOENT )
    1038             :         {
    1039           0 :           my_info_0 ("cannot read lockfile\n");
    1040           0 :           return -1;
    1041             :         }
    1042           0 :       my_info_0 ("lockfile disappeared\n");
    1043           0 :       goto again;
    1044             :     }
    1045           0 :   else if ( pid == getpid() && same_node )
    1046             :     {
    1047           0 :       my_info_0 ("Oops: lock already held by us\n");
    1048           0 :       h->locked = 1;
    1049           0 :       return 0; /* okay */
    1050             :     }
    1051           0 :   else if ( same_node && kill (pid, 0) && errno == ESRCH )
    1052             :     {
    1053             :       /* Note: It is unlikley that we get a race here unless a pid is
    1054             :          reused too fast or a new process with the same pid as the one
    1055             :          of the stale file tries to lock right at the same time as we.  */
    1056           0 :       my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
    1057           0 :       unlink (h->lockname);
    1058           0 :       goto again;
    1059             :     }
    1060             : 
    1061           0 :   if (lastpid == -1)
    1062           0 :     lastpid = pid;
    1063           0 :   ownerchanged = (pid != lastpid);
    1064             : 
    1065           0 :   if (timeout)
    1066             :     {
    1067             :       struct timeval tv;
    1068             : 
    1069             :       /* Wait until lock has been released.  We use increasing retry
    1070             :          intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
    1071             :          but reset it if the lock owner meanwhile changed.  */
    1072           0 :       if (!wtime || ownerchanged)
    1073           0 :         wtime = 50;
    1074           0 :       else if (wtime < 800)
    1075           0 :         wtime *= 2;
    1076           0 :       else if (wtime == 800)
    1077           0 :         wtime = 2000;
    1078           0 :       else if (wtime < 8000)
    1079           0 :         wtime *= 2;
    1080             : 
    1081           0 :       if (timeout > 0)
    1082             :         {
    1083           0 :           if (wtime > timeout)
    1084           0 :             wtime = timeout;
    1085           0 :           timeout -= wtime;
    1086             :         }
    1087             : 
    1088           0 :       sumtime += wtime;
    1089           0 :       if (sumtime >= 1500)
    1090             :         {
    1091           0 :           sumtime = 0;
    1092           0 :           my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
    1093             :                      pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
    1094             :         }
    1095             : 
    1096             : 
    1097           0 :       tv.tv_sec = wtime / 1000;
    1098           0 :       tv.tv_usec = (wtime % 1000) * 1000;
    1099           0 :       select (0, NULL, NULL, NULL, &tv);
    1100           0 :       goto again;
    1101             :     }
    1102             : 
    1103           0 :   my_set_errno (EACCES);
    1104           0 :   return -1;
    1105             : }
    1106             : #endif /*HAVE_POSIX_SYSTEM*/
    1107             : 
    1108             : 
    1109             : #ifdef HAVE_DOSISH_SYSTEM
    1110             : /* Windows specific code of make_dotlock.  Returns 0 on success and -1 on
    1111             :    error.  */
    1112             : static int
    1113             : dotlock_take_w32 (dotlock_t h, long timeout)
    1114             : {
    1115             :   int wtime = 0;
    1116             :   int w32err;
    1117             :   OVERLAPPED ovl;
    1118             : 
    1119             :  again:
    1120             :   /* Lock one byte at offset 0.  The offset is given by OVL.  */
    1121             :   memset (&ovl, 0, sizeof ovl);
    1122             :   if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
    1123             :                               | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
    1124             :     {
    1125             :       h->locked = 1;
    1126             :       return 0; /* okay */
    1127             :     }
    1128             : 
    1129             :   w32err = GetLastError ();
    1130             :   if (w32err != ERROR_LOCK_VIOLATION)
    1131             :     {
    1132             :       my_error_2 (_("lock '%s' not made: %s\n"),
    1133             :                   h->lockname, w32_strerror (w32err));
    1134             :       return -1;
    1135             :     }
    1136             : 
    1137             :   if (timeout)
    1138             :     {
    1139             :       /* Wait until lock has been released.  We use retry intervals of
    1140             :          50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s.  */
    1141             :       if (!wtime)
    1142             :         wtime = 50;
    1143             :       else if (wtime < 800)
    1144             :         wtime *= 2;
    1145             :       else if (wtime == 800)
    1146             :         wtime = 2000;
    1147             :       else if (wtime < 8000)
    1148             :         wtime *= 2;
    1149             : 
    1150             :       if (timeout > 0)
    1151             :         {
    1152             :           if (wtime > timeout)
    1153             :             wtime = timeout;
    1154             :           timeout -= wtime;
    1155             :         }
    1156             : 
    1157             :       if (wtime >= 800)
    1158             :         my_info_1 (_("waiting for lock %s...\n"), h->lockname);
    1159             : 
    1160             :       Sleep (wtime);
    1161             :       goto again;
    1162             :     }
    1163             : 
    1164             :   return -1;
    1165             : }
    1166             : #endif /*HAVE_DOSISH_SYSTEM*/
    1167             : 
    1168             : 
    1169             : /* Take a lock on H.  A value of 0 for TIMEOUT returns immediately if
    1170             :    the lock can't be taked, -1 waits forever (hopefully not), other
    1171             :    values wait for TIMEOUT milliseconds.  Returns: 0 on success  */
    1172             : int
    1173          13 : dotlock_take (dotlock_t h, long timeout)
    1174             : {
    1175             :   int ret;
    1176             : 
    1177          13 :   if ( h->disable )
    1178           0 :     return 0; /* Locks are completely disabled.  Return success. */
    1179             : 
    1180          13 :   if ( h->locked )
    1181             :     {
    1182           0 :       my_debug_1 ("Oops, '%s' is already locked\n", h->lockname);
    1183           0 :       return 0;
    1184             :     }
    1185             : 
    1186             : #ifdef HAVE_DOSISH_SYSTEM
    1187             :   ret = dotlock_take_w32 (h, timeout);
    1188             : #else /*!HAVE_DOSISH_SYSTEM*/
    1189          13 :   ret = dotlock_take_unix (h, timeout);
    1190             : #endif /*!HAVE_DOSISH_SYSTEM*/
    1191             : 
    1192          13 :   return ret;
    1193             : }
    1194             : 
    1195             : 
    1196             : 
    1197             : #ifdef HAVE_POSIX_SYSTEM
    1198             : /* Unix specific code of release_dotlock.  */
    1199             : static int
    1200          12 : dotlock_release_unix (dotlock_t h)
    1201             : {
    1202             :   int pid, same_node;
    1203             : 
    1204          12 :   pid = read_lockfile (h, &same_node);
    1205          12 :   if ( pid == -1 )
    1206             :     {
    1207           0 :       my_error_0 ("release_dotlock: lockfile error\n");
    1208           0 :       return -1;
    1209             :     }
    1210          12 :   if ( pid != getpid() || !same_node )
    1211             :     {
    1212           0 :       my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
    1213           0 :       return -1;
    1214             :     }
    1215             : 
    1216          12 :   if ( unlink( h->lockname ) )
    1217             :     {
    1218           0 :       my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
    1219             :                   h->lockname);
    1220           0 :       return -1;
    1221             :     }
    1222             :   /* Fixme: As an extra check we could check whether the link count is
    1223             :      now really at 1. */
    1224          12 :   return 0;
    1225             : }
    1226             : #endif /*HAVE_POSIX_SYSTEM */
    1227             : 
    1228             : 
    1229             : #ifdef HAVE_DOSISH_SYSTEM
    1230             : /* Windows specific code of release_dotlock.  */
    1231             : static int
    1232             : dotlock_release_w32 (dotlock_t h)
    1233             : {
    1234             :   OVERLAPPED ovl;
    1235             : 
    1236             :   memset (&ovl, 0, sizeof ovl);
    1237             :   if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
    1238             :     {
    1239             :       my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
    1240             :                   h->lockname, w32_strerror (-1));
    1241             :       return -1;
    1242             :     }
    1243             : 
    1244             :   return 0;
    1245             : }
    1246             : #endif /*HAVE_DOSISH_SYSTEM */
    1247             : 
    1248             : 
    1249             : /* Release a lock.  Returns 0 on success.  */
    1250             : int
    1251          12 : dotlock_release (dotlock_t h)
    1252             : {
    1253             :   int ret;
    1254             : 
    1255             :   /* To avoid atexit race conditions we first check whether there are
    1256             :      any locks left.  It might happen that another atexit handler
    1257             :      tries to release the lock while the atexit handler of this module
    1258             :      already ran and thus H is undefined.  */
    1259             :   LOCK_all_lockfiles ();
    1260          12 :   ret = !all_lockfiles;
    1261             :   UNLOCK_all_lockfiles ();
    1262          12 :   if (ret)
    1263           0 :     return 0;
    1264             : 
    1265          12 :   if ( h->disable )
    1266           0 :     return 0;
    1267             : 
    1268          12 :   if ( !h->locked )
    1269             :     {
    1270           0 :       my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
    1271           0 :       return 0;
    1272             :     }
    1273             : 
    1274             : #ifdef HAVE_DOSISH_SYSTEM
    1275             :   ret = dotlock_release_w32 (h);
    1276             : #else
    1277          12 :   ret = dotlock_release_unix (h);
    1278             : #endif
    1279             : 
    1280          12 :   if (!ret)
    1281          12 :     h->locked = 0;
    1282          12 :   return ret;
    1283             : }
    1284             : 
    1285             : 
    1286             : 
    1287             : /* Remove all lockfiles.  This is called by the atexit handler
    1288             :    installed by this module but may also be called by other
    1289             :    termination handlers.  */
    1290             : void
    1291        1335 : dotlock_remove_lockfiles (void)
    1292             : {
    1293             :   dotlock_t h, h2;
    1294             : 
    1295             :   /* First set the lockfiles list to NULL so that for example
    1296             :      dotlock_release is ware that this fucntion is currently
    1297             :      running.  */
    1298             :   LOCK_all_lockfiles ();
    1299        1335 :   h = all_lockfiles;
    1300        1335 :   all_lockfiles = NULL;
    1301             :   UNLOCK_all_lockfiles ();
    1302             : 
    1303        2676 :   while ( h )
    1304             :     {
    1305           6 :       h2 = h->next;
    1306           6 :       dotlock_destroy (h);
    1307           6 :       h = h2;
    1308             :     }
    1309        1335 : }

Generated by: LCOV version 1.11