LCOV - code coverage report
Current view: top level - common - dotlock.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 145 330 43.9 %
Date: 2016-11-29 15:00:56 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 <https://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.  Note that [UN]LOCK_all_lockfiles
     416             :    must not change ERRNO. */
     417             : static volatile dotlock_t all_lockfiles;
     418             : #ifdef DOTLOCK_USE_PTHREAD
     419             : static pthread_mutex_t all_lockfiles_mutex = PTHREAD_MUTEX_INITIALIZER;
     420             : # define LOCK_all_lockfiles() do {                               \
     421             :         if (pthread_mutex_lock (&all_lockfiles_mutex))           \
     422             :           my_fatal_0 ("locking all_lockfiles_mutex failed\n");   \
     423             :       } while (0)
     424             : # define UNLOCK_all_lockfiles() do {                             \
     425             :         if (pthread_mutex_unlock (&all_lockfiles_mutex))         \
     426             :           my_fatal_0 ("unlocking all_lockfiles_mutex failed\n"); \
     427             :       } while (0)
     428             : #else  /*!DOTLOCK_USE_PTHREAD*/
     429             : # define LOCK_all_lockfiles()   do { } while (0)
     430             : # define UNLOCK_all_lockfiles() do { } while (0)
     431             : #endif /*!DOTLOCK_USE_PTHREAD*/
     432             : 
     433             : /* If this has the value true all locking is disabled.  */
     434             : static int never_lock;
     435             : 
     436             : 
     437             : 
     438             : 
     439             : #ifdef HAVE_DOSISH_SYSTEM
     440             : static int
     441             : map_w32_to_errno (DWORD w32_err)
     442             : {
     443             :   switch (w32_err)
     444             :     {
     445             :     case 0:
     446             :       return 0;
     447             : 
     448             :     case ERROR_FILE_NOT_FOUND:
     449             :       return ENOENT;
     450             : 
     451             :     case ERROR_PATH_NOT_FOUND:
     452             :       return ENOENT;
     453             : 
     454             :     case ERROR_ACCESS_DENIED:
     455             :       return EPERM;
     456             : 
     457             :     case ERROR_INVALID_HANDLE:
     458             :     case ERROR_INVALID_BLOCK:
     459             :       return EINVAL;
     460             : 
     461             :     case ERROR_NOT_ENOUGH_MEMORY:
     462             :       return ENOMEM;
     463             : 
     464             :     case ERROR_NO_DATA:
     465             :     case ERROR_BROKEN_PIPE:
     466             :       return EPIPE;
     467             : 
     468             :     default:
     469             :       return EIO;
     470             :     }
     471             : }
     472             : #endif /*HAVE_DOSISH_SYSTEM*/
     473             : 
     474             : 
     475             : /* Entirely disable all locking.  This function should be called
     476             :    before any locking is done.  It may be called right at startup of
     477             :    the process as it only sets a global value.  */
     478             : void
     479           0 : dotlock_disable (void)
     480             : {
     481           0 :   never_lock = 1;
     482           0 : }
     483             : 
     484             : 
     485             : #ifdef HAVE_POSIX_SYSTEM
     486             : static int
     487           0 : maybe_deadlock (dotlock_t h)
     488             : {
     489             :   dotlock_t r;
     490           0 :   int res = 0;
     491             : 
     492             :   LOCK_all_lockfiles ();
     493           0 :   for (r=all_lockfiles; r; r = r->next)
     494             :     {
     495           0 :       if ( r != h && r->locked )
     496             :         {
     497           0 :           res = 1;
     498           0 :           break;
     499             :         }
     500             :     }
     501             :   UNLOCK_all_lockfiles ();
     502           0 :   return res;
     503             : }
     504             : #endif /*HAVE_POSIX_SYSTEM*/
     505             : 
     506             : 
     507             : /* Read the lock file and return the pid, returns -1 on error.  True
     508             :    will be stored in the integer at address SAME_NODE if the lock file
     509             :    has been created on the same node. */
     510             : #ifdef HAVE_POSIX_SYSTEM
     511             : static int
     512         292 : read_lockfile (dotlock_t h, int *same_node )
     513             : {
     514             :   char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
     515             :                                    names are usually shorter. */
     516             :   int fd;
     517         292 :   int pid = -1;
     518             :   char *buffer, *p;
     519             :   size_t expected_len;
     520             :   int res, nread;
     521             : 
     522         292 :   *same_node = 0;
     523         292 :   expected_len = 10 + 1 + h->nodename_len + 1;
     524         292 :   if ( expected_len >= sizeof buffer_space)
     525             :     {
     526           0 :       buffer = xtrymalloc (expected_len);
     527           0 :       if (!buffer)
     528           0 :         return -1;
     529             :     }
     530             :   else
     531         292 :     buffer = buffer_space;
     532             : 
     533         292 :   if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
     534             :     {
     535           0 :       int e = errno;
     536           0 :       my_info_2 ("error opening lockfile '%s': %s\n",
     537             :                  h->lockname, strerror(errno) );
     538           0 :       if (buffer != buffer_space)
     539           0 :         xfree (buffer);
     540           0 :       my_set_errno (e); /* Need to return ERRNO here. */
     541           0 :       return -1;
     542             :     }
     543             : 
     544         292 :   p = buffer;
     545         292 :   nread = 0;
     546             :   do
     547             :     {
     548         292 :       res = read (fd, p, expected_len - nread);
     549         292 :       if (res == -1 && errno == EINTR)
     550           0 :         continue;
     551         292 :       if (res < 0)
     552             :         {
     553           0 :           int e = errno;
     554           0 :           my_info_1 ("error reading lockfile '%s'\n", h->lockname );
     555           0 :           close (fd);
     556           0 :           if (buffer != buffer_space)
     557           0 :             xfree (buffer);
     558           0 :           my_set_errno (e);
     559           0 :           return -1;
     560             :         }
     561         292 :       p += res;
     562         292 :       nread += res;
     563             :     }
     564         292 :   while (res && nread != expected_len);
     565         292 :   close(fd);
     566             : 
     567         292 :   if (nread < 11)
     568             :     {
     569           0 :       my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
     570           0 :       if (buffer != buffer_space)
     571           0 :         xfree (buffer);
     572           0 :       my_set_errno (EINVAL);
     573           0 :       return -1;
     574             :     }
     575             : 
     576         292 :   if (buffer[10] != '\n'
     577         292 :       || (buffer[10] = 0, pid = atoi (buffer)) == -1
     578         292 :       || !pid )
     579             :     {
     580           0 :       my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
     581           0 :       if (buffer != buffer_space)
     582           0 :         xfree (buffer);
     583           0 :       my_set_errno (EINVAL);
     584           0 :       return -1;
     585             :     }
     586             : 
     587         292 :   if (nread == expected_len
     588         292 :       && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
     589         292 :       && buffer[11+h->nodename_len] == '\n')
     590         292 :     *same_node = 1;
     591             : 
     592         292 :   if (buffer != buffer_space)
     593           0 :     xfree (buffer);
     594         292 :   return pid;
     595             : }
     596             : #endif /*HAVE_POSIX_SYSTEM */
     597             : 
     598             : 
     599             : /* Check whether the file system which stores TNAME supports
     600             :    hardlinks.  Instead of using the non-portable statsfs call which
     601             :    differs between various Unix versions, we do a runtime test.
     602             :    Returns: 0 supports hardlinks; 1 no hardlink support, -1 unknown
     603             :    (test error).  */
     604             : #ifdef HAVE_POSIX_SYSTEM
     605             : static int
     606         194 : use_hardlinks_p (const char *tname)
     607             : {
     608             :   char *lname;
     609             :   struct stat sb;
     610             :   unsigned int nlink;
     611             :   int res;
     612             : 
     613         194 :   if (stat (tname, &sb))
     614           0 :     return -1;
     615         194 :   nlink = (unsigned int)sb.st_nlink;
     616             : 
     617         194 :   lname = xtrymalloc (strlen (tname) + 1 + 1);
     618         194 :   if (!lname)
     619           0 :     return -1;
     620         194 :   strcpy (lname, tname);
     621         194 :   strcat (lname, "x");
     622             : 
     623             :   /* We ignore the return value of link() because it is unreliable.  */
     624         194 :   (void) link (tname, lname);
     625             : 
     626         194 :   if (stat (tname, &sb))
     627           0 :     res = -1;  /* Ooops.  */
     628         194 :   else if (sb.st_nlink == nlink + 1)
     629         194 :     res = 0;   /* Yeah, hardlinks are supported.  */
     630             :   else
     631           0 :     res = 1;   /* No hardlink support.  */
     632             : 
     633         194 :   unlink (lname);
     634         194 :   xfree (lname);
     635         194 :   return res;
     636             : }
     637             : #endif /*HAVE_POSIX_SYSTEM */
     638             : 
     639             : 
     640             : 
     641             : #ifdef  HAVE_POSIX_SYSTEM
     642             : /* Locking core for Unix.  It used a temporary file and the link
     643             :    system call to make locking an atomic operation. */
     644             : static dotlock_t
     645         194 : dotlock_create_unix (dotlock_t h, const char *file_to_lock)
     646             : {
     647         194 :   int  fd = -1;
     648             :   char pidstr[16];
     649             :   const char *nodename;
     650             :   const char *dirpart;
     651             :   int dirpartlen;
     652             :   struct utsname utsbuf;
     653             :   size_t tnamelen;
     654             : 
     655         194 :   snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
     656             : 
     657             :   /* Create a temporary file. */
     658         194 :   if ( uname ( &utsbuf ) )
     659           0 :     nodename = "unknown";
     660             :   else
     661         194 :     nodename = utsbuf.nodename;
     662             : 
     663         194 :   if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
     664             :     {
     665           0 :       dirpart = EXTSEP_S;
     666           0 :       dirpartlen = 1;
     667             :     }
     668             :   else
     669             :     {
     670         194 :       dirpartlen = dirpart - file_to_lock;
     671         194 :       dirpart = file_to_lock;
     672             :     }
     673             : 
     674             :   LOCK_all_lockfiles ();
     675         194 :   h->next = all_lockfiles;
     676         194 :   all_lockfiles = h;
     677             : 
     678         194 :   tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
     679         194 :   h->tname = xtrymalloc (tnamelen + 1);
     680         194 :   if (!h->tname)
     681             :     {
     682           0 :       all_lockfiles = h->next;
     683             :       UNLOCK_all_lockfiles ();
     684           0 :       xfree (h);
     685           0 :       return NULL;
     686             :     }
     687         194 :   h->nodename_len = strlen (nodename);
     688             : 
     689         194 :   snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
     690         194 :   h->nodename_off = strlen (h->tname);
     691         194 :   snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
     692             :            "%s.%d", nodename, (int)getpid ());
     693             : 
     694             :   do
     695             :     {
     696         194 :       my_set_errno (0);
     697         194 :       fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
     698             :                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
     699             :     }
     700         194 :   while (fd == -1 && errno == EINTR);
     701             : 
     702         194 :   if ( fd == -1 )
     703             :     {
     704           0 :       int saveerrno = errno;
     705           0 :       all_lockfiles = h->next;
     706             :       UNLOCK_all_lockfiles ();
     707           0 :       my_error_2 (_("failed to create temporary file '%s': %s\n"),
     708             :                   h->tname, strerror (errno));
     709           0 :       xfree (h->tname);
     710           0 :       xfree (h);
     711           0 :       my_set_errno (saveerrno);
     712           0 :       return NULL;
     713             :     }
     714         194 :   if ( write (fd, pidstr, 11 ) != 11 )
     715           0 :     goto write_failed;
     716         194 :   if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
     717           0 :     goto write_failed;
     718         194 :   if ( write (fd, "\n", 1 ) != 1 )
     719           0 :     goto write_failed;
     720         194 :   if ( close (fd) )
     721             :     {
     722           0 :       if ( errno == EINTR )
     723           0 :         fd = -1;
     724           0 :       goto write_failed;
     725             :     }
     726         194 :   fd = -1;
     727             : 
     728             :   /* Check whether we support hard links.  */
     729         194 :   switch (use_hardlinks_p (h->tname))
     730             :     {
     731             :     case 0: /* Yes.  */
     732         194 :       break;
     733             :     case 1: /* No.  */
     734           0 :       unlink (h->tname);
     735           0 :       h->use_o_excl = 1;
     736           0 :       break;
     737             :     default:
     738             :       {
     739           0 :         int saveerrno = errno;
     740           0 :         my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
     741             :                     , h->tname, strerror (saveerrno));
     742           0 :         my_set_errno (saveerrno);
     743             :       }
     744           0 :       goto write_failed;
     745             :     }
     746             : 
     747         194 :   h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
     748         194 :   if (!h->lockname)
     749             :     {
     750           0 :       int saveerrno = errno;
     751           0 :       all_lockfiles = h->next;
     752             :       UNLOCK_all_lockfiles ();
     753           0 :       unlink (h->tname);
     754           0 :       xfree (h->tname);
     755           0 :       xfree (h);
     756           0 :       my_set_errno (saveerrno);
     757           0 :       return NULL;
     758             :     }
     759         194 :   strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
     760             :   UNLOCK_all_lockfiles ();
     761         194 :   if (h->use_o_excl)
     762           0 :     my_debug_1 ("locking for '%s' done via O_EXCL\n", h->lockname);
     763             : 
     764         194 :   return h;
     765             : 
     766             :  write_failed:
     767             :   {
     768           0 :     int saveerrno = errno;
     769           0 :     all_lockfiles = h->next;
     770             :     UNLOCK_all_lockfiles ();
     771           0 :     my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
     772           0 :     if ( fd != -1 )
     773           0 :       close (fd);
     774           0 :     unlink (h->tname);
     775           0 :     xfree (h->tname);
     776           0 :     xfree (h);
     777           0 :     my_set_errno (saveerrno);
     778             :   }
     779           0 :   return NULL;
     780             : }
     781             : #endif /*HAVE_POSIX_SYSTEM*/
     782             : 
     783             : 
     784             : #ifdef HAVE_DOSISH_SYSTEM
     785             : /* Locking core for Windows.  This version does not need a temporary
     786             :    file but uses the plain lock file along with record locking.  We
     787             :    create this file here so that we later only need to do the file
     788             :    locking.  For error reporting it is useful to keep the name of the
     789             :    file in the handle.  */
     790             : static dotlock_t
     791             : dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
     792             : {
     793             :   LOCK_all_lockfiles ();
     794             :   h->next = all_lockfiles;
     795             :   all_lockfiles = h;
     796             : 
     797             :   h->lockname = xtrymalloc ( strlen (file_to_lock) + 6 );
     798             :   if (!h->lockname)
     799             :     {
     800             :       all_lockfiles = h->next;
     801             :       UNLOCK_all_lockfiles ();
     802             :       xfree (h);
     803             :       return NULL;
     804             :     }
     805             :   strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
     806             : 
     807             :   /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
     808             :      along with FILE_SHARE_DELETE but that does not work due to a race
     809             :      condition: Despite the OPEN_ALWAYS flag CreateFile may return an
     810             :      error and we can't reliable create/open the lock file unless we
     811             :      would wait here until it works - however there are other valid
     812             :      reasons why a lock file can't be created and thus the process
     813             :      would not stop as expected but spin until Windows crashes.  Our
     814             :      solution is to keep the lock file open; that does not harm. */
     815             :   {
     816             : #ifdef HAVE_W32CE_SYSTEM
     817             :     wchar_t *wname = utf8_to_wchar (h->lockname);
     818             : 
     819             :     if (wname)
     820             :       h->lockhd = CreateFile (wname,
     821             :                               GENERIC_READ|GENERIC_WRITE,
     822             :                               FILE_SHARE_READ|FILE_SHARE_WRITE,
     823             :                               NULL, OPEN_ALWAYS, 0, NULL);
     824             :     else
     825             :       h->lockhd = INVALID_HANDLE_VALUE;
     826             :     xfree (wname);
     827             : #else
     828             :     h->lockhd = CreateFile (h->lockname,
     829             :                             GENERIC_READ|GENERIC_WRITE,
     830             :                             FILE_SHARE_READ|FILE_SHARE_WRITE,
     831             :                             NULL, OPEN_ALWAYS, 0, NULL);
     832             : #endif
     833             :   }
     834             :   if (h->lockhd == INVALID_HANDLE_VALUE)
     835             :     {
     836             :       int saveerrno = map_w32_to_errno (GetLastError ());
     837             :       all_lockfiles = h->next;
     838             :       UNLOCK_all_lockfiles ();
     839             :       my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
     840             :       xfree (h->lockname);
     841             :       xfree (h);
     842             :       my_set_errno (saveerrno);
     843             :       return NULL;
     844             :     }
     845             :   return h;
     846             : }
     847             : #endif /*HAVE_DOSISH_SYSTEM*/
     848             : 
     849             : 
     850             : /* Create a lockfile for a file name FILE_TO_LOCK and returns an
     851             :    object of type dotlock_t which may be used later to actually acquire
     852             :    the lock.  A cleanup routine gets installed to cleanup left over
     853             :    locks or other files used internally by the lock mechanism.
     854             : 
     855             :    Calling this function with NULL does only install the atexit
     856             :    handler and may thus be used to assure that the cleanup is called
     857             :    after all other atexit handlers.
     858             : 
     859             :    This function creates a lock file in the same directory as
     860             :    FILE_TO_LOCK using that name and a suffix of ".lock".  Note that on
     861             :    POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
     862             :    used.
     863             : 
     864             :    FLAGS must be 0.
     865             : 
     866             :    The function returns an new handle which needs to be released using
     867             :    destroy_dotlock but gets also released at the termination of the
     868             :    process.  On error NULL is returned.
     869             :  */
     870             : 
     871             : dotlock_t
     872        1424 : dotlock_create (const char *file_to_lock, unsigned int flags)
     873             : {
     874             :   static int initialized;
     875             :   dotlock_t h;
     876             : 
     877        1424 :   if ( !initialized )
     878             :     {
     879        1275 :       atexit (dotlock_remove_lockfiles);
     880        1275 :       initialized = 1;
     881             :     }
     882             : 
     883        1424 :   if ( !file_to_lock )
     884        1230 :     return NULL;  /* Only initialization was requested.  */
     885             : 
     886         194 :   if (flags)
     887             :     {
     888           0 :       my_set_errno (EINVAL);
     889           0 :       return NULL;
     890             :     }
     891             : 
     892         194 :   h = xtrycalloc (1, sizeof *h);
     893         194 :   if (!h)
     894           0 :     return NULL;
     895         194 :   h->extra_fd = -1;
     896             : 
     897         194 :   if (never_lock)
     898             :     {
     899           0 :       h->disable = 1;
     900             :       LOCK_all_lockfiles ();
     901           0 :       h->next = all_lockfiles;
     902           0 :       all_lockfiles = h;
     903             :       UNLOCK_all_lockfiles ();
     904           0 :       return h;
     905             :     }
     906             : 
     907             : #ifdef HAVE_DOSISH_SYSTEM
     908             :   return dotlock_create_w32 (h, file_to_lock);
     909             : #else /*!HAVE_DOSISH_SYSTEM */
     910         194 :   return dotlock_create_unix (h, file_to_lock);
     911             : #endif /*!HAVE_DOSISH_SYSTEM*/
     912             : }
     913             : 
     914             : 
     915             : 
     916             : /* Convenience function to store a file descriptor (or any any other
     917             :    integer value) in the context of handle H.  */
     918             : void
     919           0 : dotlock_set_fd (dotlock_t h, int fd)
     920             : {
     921           0 :   h->extra_fd = fd;
     922           0 : }
     923             : 
     924             : /* Convenience function to retrieve a file descriptor (or any any other
     925             :    integer value) stored in the context of handle H.  */
     926             : int
     927           0 : dotlock_get_fd (dotlock_t h)
     928             : {
     929           0 :   return h->extra_fd;
     930             : }
     931             : 
     932             : 
     933             : 
     934             : #ifdef HAVE_POSIX_SYSTEM
     935             : /* Unix specific code of destroy_dotlock.  */
     936             : static void
     937         194 : dotlock_destroy_unix (dotlock_t h)
     938             : {
     939         194 :   if (h->locked && h->lockname)
     940          50 :     unlink (h->lockname);
     941         194 :   if (h->tname && !h->use_o_excl)
     942         194 :     unlink (h->tname);
     943         194 :   xfree (h->tname);
     944         194 : }
     945             : #endif /*HAVE_POSIX_SYSTEM*/
     946             : 
     947             : 
     948             : #ifdef HAVE_DOSISH_SYSTEM
     949             : /* Windows specific code of destroy_dotlock.  */
     950             : static void
     951             : dotlock_destroy_w32 (dotlock_t h)
     952             : {
     953             :   if (h->locked)
     954             :     {
     955             :       OVERLAPPED ovl;
     956             : 
     957             :       memset (&ovl, 0, sizeof ovl);
     958             :       UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
     959             :     }
     960             :   CloseHandle (h->lockhd);
     961             : }
     962             : #endif /*HAVE_DOSISH_SYSTEM*/
     963             : 
     964             : 
     965             : /* Destroy the lock handle H and release the lock.  */
     966             : void
     967         194 : dotlock_destroy (dotlock_t h)
     968             : {
     969             :   dotlock_t hprev, htmp;
     970             : 
     971         194 :   if ( !h )
     972         194 :     return;
     973             : 
     974             :   /* First remove the handle from our global list of all locks. */
     975             :   LOCK_all_lockfiles ();
     976         194 :   for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
     977          64 :     if (htmp == h)
     978             :       {
     979          64 :         if (hprev)
     980           0 :           hprev->next = htmp->next;
     981             :         else
     982          64 :           all_lockfiles = htmp->next;
     983          64 :         h->next = NULL;
     984          64 :         break;
     985             :       }
     986             :   UNLOCK_all_lockfiles ();
     987             : 
     988             :   /* Then destroy the lock. */
     989         194 :   if (!h->disable)
     990             :     {
     991             : #ifdef HAVE_DOSISH_SYSTEM
     992             :       dotlock_destroy_w32 (h);
     993             : #else /* !HAVE_DOSISH_SYSTEM */
     994         194 :       dotlock_destroy_unix (h);
     995             : #endif /* HAVE_DOSISH_SYSTEM */
     996         194 :       xfree (h->lockname);
     997             :     }
     998         194 :   xfree(h);
     999             : }
    1000             : 
    1001             : 
    1002             : 
    1003             : #ifdef HAVE_POSIX_SYSTEM
    1004             : /* Unix specific code of make_dotlock.  Returns 0 on success and -1 on
    1005             :    error.  */
    1006             : static int
    1007         342 : dotlock_take_unix (dotlock_t h, long timeout)
    1008             : {
    1009         342 :   int wtime = 0;
    1010         342 :   int sumtime = 0;
    1011             :   int pid;
    1012         342 :   int lastpid = -1;
    1013             :   int ownerchanged;
    1014         342 :   const char *maybe_dead="";
    1015             :   int same_node;
    1016             :   int saveerrno;
    1017             : 
    1018             :  again:
    1019         342 :   if (h->use_o_excl)
    1020             :     {
    1021             :       /* No hardlink support - use open(O_EXCL).  */
    1022             :       int fd;
    1023             : 
    1024             :       do
    1025             :         {
    1026           0 :           my_set_errno (0);
    1027           0 :           fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
    1028             :                      S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
    1029             :         }
    1030           0 :       while (fd == -1 && errno == EINTR);
    1031             : 
    1032           0 :       if (fd == -1 && errno == EEXIST)
    1033             :         ; /* Lock held by another process.  */
    1034           0 :       else if (fd == -1)
    1035             :         {
    1036           0 :           saveerrno = errno;
    1037           0 :           my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
    1038             :                       h->lockname, strerror (saveerrno));
    1039           0 :           my_set_errno (saveerrno);
    1040           0 :           return -1;
    1041             :         }
    1042             :       else
    1043             :         {
    1044             :           char pidstr[16];
    1045             : 
    1046           0 :           snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
    1047           0 :           if (write (fd, pidstr, 11 ) == 11
    1048           0 :               && write (fd, h->tname + h->nodename_off,h->nodename_len)
    1049           0 :               == h->nodename_len
    1050           0 :               && write (fd, "\n", 1) == 1
    1051           0 :               && !close (fd))
    1052             :             {
    1053           0 :               h->locked = 1;
    1054           0 :               return 0;
    1055             :             }
    1056             :           /* Write error.  */
    1057           0 :           saveerrno = errno;
    1058           0 :           my_error_2 ("lock not made: writing to '%s' failed: %s\n",
    1059             :                       h->lockname, strerror (errno));
    1060           0 :           close (fd);
    1061           0 :           unlink (h->lockname);
    1062           0 :           my_set_errno (saveerrno);
    1063           0 :           return -1;
    1064             :         }
    1065             :     }
    1066             :   else /* Standard method:  Use hardlinks.  */
    1067             :     {
    1068             :       struct stat sb;
    1069             : 
    1070             :       /* We ignore the return value of link() because it is unreliable.  */
    1071         342 :       (void) link (h->tname, h->lockname);
    1072             : 
    1073         342 :       if (stat (h->tname, &sb))
    1074             :         {
    1075           0 :           saveerrno = errno;
    1076           0 :           my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
    1077             :                       strerror (errno));
    1078             :           /* In theory this might be a severe error: It is possible
    1079             :              that link succeeded but stat failed due to changed
    1080             :              permissions.  We can't do anything about it, though.  */
    1081           0 :           my_set_errno (saveerrno);
    1082         342 :           return -1;
    1083             :         }
    1084             : 
    1085         342 :       if (sb.st_nlink == 2)
    1086             :         {
    1087         342 :           h->locked = 1;
    1088         342 :           return 0; /* Okay.  */
    1089             :         }
    1090             :     }
    1091             : 
    1092             :   /* Check for stale lock files.  */
    1093           0 :   if ( (pid = read_lockfile (h, &same_node)) == -1 )
    1094             :     {
    1095           0 :       if ( errno != ENOENT )
    1096             :         {
    1097           0 :           saveerrno = errno;
    1098           0 :           my_info_0 ("cannot read lockfile\n");
    1099           0 :           my_set_errno (saveerrno);
    1100           0 :           return -1;
    1101             :         }
    1102           0 :       my_info_0 ("lockfile disappeared\n");
    1103           0 :       goto again;
    1104             :     }
    1105           0 :   else if ( pid == getpid() && same_node )
    1106             :     {
    1107           0 :       my_info_0 ("Oops: lock already held by us\n");
    1108           0 :       h->locked = 1;
    1109           0 :       return 0; /* okay */
    1110             :     }
    1111           0 :   else if ( same_node && kill (pid, 0) && errno == ESRCH )
    1112             :     {
    1113             :       /* Note: It is unlikley that we get a race here unless a pid is
    1114             :          reused too fast or a new process with the same pid as the one
    1115             :          of the stale file tries to lock right at the same time as we.  */
    1116           0 :       my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
    1117           0 :       unlink (h->lockname);
    1118           0 :       goto again;
    1119             :     }
    1120             : 
    1121           0 :   if (lastpid == -1)
    1122           0 :     lastpid = pid;
    1123           0 :   ownerchanged = (pid != lastpid);
    1124             : 
    1125           0 :   if (timeout)
    1126             :     {
    1127             :       struct timeval tv;
    1128             : 
    1129             :       /* Wait until lock has been released.  We use increasing retry
    1130             :          intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
    1131             :          but reset it if the lock owner meanwhile changed.  */
    1132           0 :       if (!wtime || ownerchanged)
    1133           0 :         wtime = 50;
    1134           0 :       else if (wtime < 800)
    1135           0 :         wtime *= 2;
    1136           0 :       else if (wtime == 800)
    1137           0 :         wtime = 2000;
    1138           0 :       else if (wtime < 8000)
    1139           0 :         wtime *= 2;
    1140             : 
    1141           0 :       if (timeout > 0)
    1142             :         {
    1143           0 :           if (wtime > timeout)
    1144           0 :             wtime = timeout;
    1145           0 :           timeout -= wtime;
    1146             :         }
    1147             : 
    1148           0 :       sumtime += wtime;
    1149           0 :       if (sumtime >= 1500)
    1150             :         {
    1151           0 :           sumtime = 0;
    1152           0 :           my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
    1153             :                      pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
    1154             :         }
    1155             : 
    1156             : 
    1157           0 :       tv.tv_sec = wtime / 1000;
    1158           0 :       tv.tv_usec = (wtime % 1000) * 1000;
    1159           0 :       select (0, NULL, NULL, NULL, &tv);
    1160           0 :       goto again;
    1161             :     }
    1162             : 
    1163           0 :   my_set_errno (EACCES);
    1164           0 :   return -1;
    1165             : }
    1166             : #endif /*HAVE_POSIX_SYSTEM*/
    1167             : 
    1168             : 
    1169             : #ifdef HAVE_DOSISH_SYSTEM
    1170             : /* Windows specific code of make_dotlock.  Returns 0 on success and -1 on
    1171             :    error.  */
    1172             : static int
    1173             : dotlock_take_w32 (dotlock_t h, long timeout)
    1174             : {
    1175             :   int wtime = 0;
    1176             :   int w32err;
    1177             :   OVERLAPPED ovl;
    1178             : 
    1179             :  again:
    1180             :   /* Lock one byte at offset 0.  The offset is given by OVL.  */
    1181             :   memset (&ovl, 0, sizeof ovl);
    1182             :   if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
    1183             :                               | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
    1184             :     {
    1185             :       h->locked = 1;
    1186             :       return 0; /* okay */
    1187             :     }
    1188             : 
    1189             :   w32err = GetLastError ();
    1190             :   if (w32err != ERROR_LOCK_VIOLATION)
    1191             :     {
    1192             :       my_error_2 (_("lock '%s' not made: %s\n"),
    1193             :                   h->lockname, w32_strerror (w32err));
    1194             :       my_set_errno (map_w32_to_errno (w32err));
    1195             :       return -1;
    1196             :     }
    1197             : 
    1198             :   if (timeout)
    1199             :     {
    1200             :       /* Wait until lock has been released.  We use retry intervals of
    1201             :          50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s.  */
    1202             :       if (!wtime)
    1203             :         wtime = 50;
    1204             :       else if (wtime < 800)
    1205             :         wtime *= 2;
    1206             :       else if (wtime == 800)
    1207             :         wtime = 2000;
    1208             :       else if (wtime < 8000)
    1209             :         wtime *= 2;
    1210             : 
    1211             :       if (timeout > 0)
    1212             :         {
    1213             :           if (wtime > timeout)
    1214             :             wtime = timeout;
    1215             :           timeout -= wtime;
    1216             :         }
    1217             : 
    1218             :       if (wtime >= 800)
    1219             :         my_info_1 (_("waiting for lock %s...\n"), h->lockname);
    1220             : 
    1221             :       Sleep (wtime);
    1222             :       goto again;
    1223             :     }
    1224             : 
    1225             :   my_set_errno (EACCES);
    1226             :   return -1;
    1227             : }
    1228             : #endif /*HAVE_DOSISH_SYSTEM*/
    1229             : 
    1230             : 
    1231             : /* Take a lock on H.  A value of 0 for TIMEOUT returns immediately if
    1232             :    the lock can't be taked, -1 waits forever (hopefully not), other
    1233             :    values wait for TIMEOUT milliseconds.  Returns: 0 on success  */
    1234             : int
    1235         342 : dotlock_take (dotlock_t h, long timeout)
    1236             : {
    1237             :   int ret;
    1238             : 
    1239         342 :   if ( h->disable )
    1240           0 :     return 0; /* Locks are completely disabled.  Return success. */
    1241             : 
    1242         342 :   if ( h->locked )
    1243             :     {
    1244           0 :       my_debug_1 ("Oops, '%s' is already locked\n", h->lockname);
    1245           0 :       return 0;
    1246             :     }
    1247             : 
    1248             : #ifdef HAVE_DOSISH_SYSTEM
    1249             :   ret = dotlock_take_w32 (h, timeout);
    1250             : #else /*!HAVE_DOSISH_SYSTEM*/
    1251         342 :   ret = dotlock_take_unix (h, timeout);
    1252             : #endif /*!HAVE_DOSISH_SYSTEM*/
    1253             : 
    1254         342 :   return ret;
    1255             : }
    1256             : 
    1257             : 
    1258             : 
    1259             : #ifdef HAVE_POSIX_SYSTEM
    1260             : /* Unix specific code of release_dotlock.  */
    1261             : static int
    1262         292 : dotlock_release_unix (dotlock_t h)
    1263             : {
    1264             :   int pid, same_node;
    1265             :   int saveerrno;
    1266             : 
    1267         292 :   pid = read_lockfile (h, &same_node);
    1268         292 :   if ( pid == -1 )
    1269             :     {
    1270           0 :       saveerrno = errno;
    1271           0 :       my_error_0 ("release_dotlock: lockfile error\n");
    1272           0 :       my_set_errno (saveerrno);
    1273           0 :       return -1;
    1274             :     }
    1275         292 :   if ( pid != getpid() || !same_node )
    1276             :     {
    1277           0 :       my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
    1278           0 :       my_set_errno (EACCES);
    1279           0 :       return -1;
    1280             :     }
    1281             : 
    1282         292 :   if ( unlink( h->lockname ) )
    1283             :     {
    1284           0 :       saveerrno = errno;
    1285           0 :       my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
    1286             :                   h->lockname);
    1287           0 :       my_set_errno (saveerrno);
    1288           0 :       return -1;
    1289             :     }
    1290             :   /* Fixme: As an extra check we could check whether the link count is
    1291             :      now really at 1. */
    1292         292 :   return 0;
    1293             : }
    1294             : #endif /*HAVE_POSIX_SYSTEM */
    1295             : 
    1296             : 
    1297             : #ifdef HAVE_DOSISH_SYSTEM
    1298             : /* Windows specific code of release_dotlock.  */
    1299             : static int
    1300             : dotlock_release_w32 (dotlock_t h)
    1301             : {
    1302             :   OVERLAPPED ovl;
    1303             : 
    1304             :   memset (&ovl, 0, sizeof ovl);
    1305             :   if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
    1306             :     {
    1307             :       int saveerrno = map_w32_to_errno (GetLastError ());
    1308             :       my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
    1309             :                   h->lockname, w32_strerror (-1));
    1310             :       my_set_errno (saveerrno);
    1311             :       return -1;
    1312             :     }
    1313             : 
    1314             :   return 0;
    1315             : }
    1316             : #endif /*HAVE_DOSISH_SYSTEM */
    1317             : 
    1318             : 
    1319             : /* Release a lock.  Returns 0 on success.  */
    1320             : int
    1321         292 : dotlock_release (dotlock_t h)
    1322             : {
    1323             :   int ret;
    1324             : 
    1325             :   /* To avoid atexit race conditions we first check whether there are
    1326             :      any locks left.  It might happen that another atexit handler
    1327             :      tries to release the lock while the atexit handler of this module
    1328             :      already ran and thus H is undefined.  */
    1329             :   LOCK_all_lockfiles ();
    1330         292 :   ret = !all_lockfiles;
    1331             :   UNLOCK_all_lockfiles ();
    1332         292 :   if (ret)
    1333           0 :     return 0;
    1334             : 
    1335         292 :   if ( h->disable )
    1336           0 :     return 0;
    1337             : 
    1338         292 :   if ( !h->locked )
    1339             :     {
    1340           0 :       my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
    1341           0 :       return 0;
    1342             :     }
    1343             : 
    1344             : #ifdef HAVE_DOSISH_SYSTEM
    1345             :   ret = dotlock_release_w32 (h);
    1346             : #else
    1347         292 :   ret = dotlock_release_unix (h);
    1348             : #endif
    1349             : 
    1350         292 :   if (!ret)
    1351         292 :     h->locked = 0;
    1352         292 :   return ret;
    1353             : }
    1354             : 
    1355             : 
    1356             : 
    1357             : /* Remove all lockfiles.  This is called by the atexit handler
    1358             :    installed by this module but may also be called by other
    1359             :    termination handlers.  */
    1360             : void
    1361        1275 : dotlock_remove_lockfiles (void)
    1362             : {
    1363             :   dotlock_t h, h2;
    1364             : 
    1365             :   /* First set the lockfiles list to NULL so that for example
    1366             :      dotlock_release is aware that this function is currently
    1367             :      running.  */
    1368             :   LOCK_all_lockfiles ();
    1369        1275 :   h = all_lockfiles;
    1370        1275 :   all_lockfiles = NULL;
    1371             :   UNLOCK_all_lockfiles ();
    1372             : 
    1373        2680 :   while ( h )
    1374             :     {
    1375         130 :       h2 = h->next;
    1376         130 :       dotlock_destroy (h);
    1377         130 :       h = h2;
    1378             :     }
    1379        1275 : }

Generated by: LCOV version 1.11