LCOV - code coverage report
Current view: top level - egg - dotlock.c (source / functions) Coverage Total Hit
Test: coverage.info Lines: 46.9 % 326 153
Test Date: 2024-02-13 21:56:33 Functions: 86.7 % 15 13

            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 JNLIB, which is a subsystem of GnuPG.
       6              :  *
       7              :  * JNLIB 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              :  * JNLIB 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 "libjnlib-config.h"
     314              : #endif
     315              : #ifdef HAVE_W32CE_SYSTEM
     316              : # include "utf8conv.h"  /* WindowsCE requires filename conversion.  */
     317              : #endif
     318              : 
     319              : #include "dotlock.h"
     320              : 
     321              : 
     322              : /* Define constants for file name construction.  */
     323              : #if !defined(DIRSEP_C) && !defined(EXTSEP_S)
     324              : # ifdef HAVE_DOSISH_SYSTEM
     325              : #  define DIRSEP_C '\\'
     326              : #  define EXTSEP_S "."
     327              : #else
     328              : #  define DIRSEP_C '/'
     329              : #  define EXTSEP_S "."
     330              : # endif
     331              : #endif
     332              : 
     333              : /* In GnuPG we use wrappers around the malloc fucntions.  If they are
     334              :    not defined we assume that this code is used outside of GnuPG and
     335              :    fall back to the regular malloc functions.  */
     336              : #ifndef jnlib_malloc
     337              : # define jnlib_malloc(a)     malloc ((a))
     338              : # define jnlib_calloc(a,b)   calloc ((a), (b))
     339              : # define jnlib_free(a)       free ((a))
     340              : #endif
     341              : 
     342              : /* Wrapper to set ERRNO.  */
     343              : #ifndef jnlib_set_errno
     344              : # ifdef HAVE_W32CE_SYSTEM
     345              : #  define jnlib_set_errno(e)  gpg_err_set_errno ((e))
     346              : # else
     347              : #  define jnlib_set_errno(e)  do { errno = (e); } while (0)
     348              : # endif
     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            0 :   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            0 :   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           38 : 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           38 :   int pid = -1;
     482              :   char *buffer, *p;
     483              :   size_t expected_len;
     484              :   int res, nread;
     485              : 
     486           38 :   *same_node = 0;
     487           38 :   expected_len = 10 + 1 + h->nodename_len + 1;
     488           38 :   if ( expected_len >= sizeof buffer_space)
     489              :     {
     490            0 :       buffer = jnlib_malloc (expected_len);
     491            0 :       if (!buffer)
     492            0 :         return -1;
     493              :     }
     494              :   else
     495           38 :     buffer = buffer_space;
     496              : 
     497           38 :   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 :         jnlib_free (buffer);
     504            0 :       jnlib_set_errno (e); /* Need to return ERRNO here. */
     505            0 :       return -1;
     506              :     }
     507              : 
     508           38 :   p = buffer;
     509           38 :   nread = 0;
     510              :   do
     511              :     {
     512           38 :       res = read (fd, p, expected_len - nread);
     513           38 :       if (res == -1 && errno == EINTR)
     514            0 :         continue;
     515           38 :       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 :             jnlib_free (buffer);
     521            0 :           jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */
     522            0 :           return -1;
     523              :         }
     524           38 :       p += res;
     525           38 :       nread += res;
     526              :     }
     527           38 :   while (res && nread != expected_len);
     528           38 :   close(fd);
     529              : 
     530           38 :   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 :         jnlib_free (buffer);
     535            0 :       jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */
     536            0 :       return -1;
     537              :     }
     538              : 
     539           38 :   if (buffer[10] != '\n'
     540           38 :       || (buffer[10] = 0, pid = atoi (buffer)) == -1
     541           38 :       || !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 :         jnlib_free (buffer);
     546            0 :       jnlib_set_errno (0);
     547            0 :       return -1;
     548              :     }
     549              : 
     550           38 :   if (nread == expected_len
     551           38 :       && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
     552           38 :       && buffer[11+h->nodename_len] == '\n')
     553           38 :     *same_node = 1;
     554              : 
     555           38 :   if (buffer != buffer_space)
     556            0 :     jnlib_free (buffer);
     557           38 :   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           38 : use_hardlinks_p (const char *tname)
     570              : {
     571              :   char *lname;
     572              :   struct stat sb;
     573              :   unsigned int nlink;
     574              :   int res;
     575              : 
     576           38 :   if (stat (tname, &sb))
     577            0 :     return -1;
     578           38 :   nlink = (unsigned int)sb.st_nlink;
     579              : 
     580           38 :   lname = jnlib_malloc (strlen (tname) + 1 + 1);
     581           38 :   if (!lname)
     582            0 :     return -1;
     583           38 :   strcpy (lname, tname);
     584           38 :   strcat (lname, "x");
     585              : 
     586           38 :   link (tname, lname);
     587              : 
     588           38 :   if (stat (tname, &sb))
     589            0 :     res = -1;  /* Ooops.  */
     590           38 :   else if (sb.st_nlink == nlink + 1)
     591           38 :     res = 0;   /* Yeah, hardlinks are supported.  */
     592              :   else
     593            0 :     res = 1;   /* No hardlink support.  */
     594              : 
     595           38 :   unlink (lname);
     596           38 :   jnlib_free (lname);
     597           38 :   return res;
     598              : }
     599              : #endif /*HAVE_POSIX_SYSTEM */
     600              : 
     601              : 
     602              : 
     603              : #ifdef  HAVE_POSIX_SYSTEM
     604              : /* Locking core for Unix.  It used a temporary file and the link
     605              :    system call to make locking an atomic operation. */
     606              : static dotlock_t
     607           38 : dotlock_create_unix (dotlock_t h, const char *file_to_lock)
     608              : {
     609           38 :   int  fd = -1;
     610              :   char pidstr[16];
     611              :   const char *nodename;
     612              :   const char *dirpart;
     613              :   int dirpartlen;
     614              :   struct utsname utsbuf;
     615              :   size_t tnamelen;
     616              : 
     617           38 :   snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
     618              : 
     619              :   /* Create a temporary file. */
     620           38 :   if ( uname ( &utsbuf ) )
     621            0 :     nodename = "unknown";
     622              :   else
     623           38 :     nodename = utsbuf.nodename;
     624              : 
     625           38 :   if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
     626              :     {
     627            0 :       dirpart = EXTSEP_S;
     628            0 :       dirpartlen = 1;
     629              :     }
     630              :   else
     631              :     {
     632           38 :       dirpartlen = dirpart - file_to_lock;
     633           38 :       dirpart = file_to_lock;
     634              :     }
     635              : 
     636           38 :   LOCK_all_lockfiles ();
     637           38 :   h->next = all_lockfiles;
     638           38 :   all_lockfiles = h;
     639              : 
     640           38 :   tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
     641           38 :   h->tname = jnlib_malloc (tnamelen + 1);
     642           38 :   if (!h->tname)
     643              :     {
     644            0 :       all_lockfiles = h->next;
     645            0 :       UNLOCK_all_lockfiles ();
     646            0 :       jnlib_free (h);
     647            0 :       return NULL;
     648              :     }
     649           38 :   h->nodename_len = strlen (nodename);
     650              : 
     651           38 :   snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
     652           38 :   h->nodename_off = strlen (h->tname);
     653           38 :   snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
     654           38 :            "%s.%d", nodename, (int)getpid ());
     655              : 
     656              :   do
     657              :     {
     658           38 :       jnlib_set_errno (0);
     659           38 :       fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
     660              :                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
     661              :     }
     662           38 :   while (fd == -1 && errno == EINTR);
     663              : 
     664           38 :   if ( fd == -1 )
     665              :     {
     666            0 :       all_lockfiles = h->next;
     667            0 :       UNLOCK_all_lockfiles ();
     668            0 :       my_error_2 (_("failed to create temporary file `%s': %s\n"),
     669              :                   h->tname, strerror(errno));
     670            0 :       jnlib_free (h->tname);
     671            0 :       jnlib_free (h);
     672            0 :       return NULL;
     673              :     }
     674           38 :   if ( write (fd, pidstr, 11 ) != 11 )
     675            0 :     goto write_failed;
     676           38 :   if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
     677            0 :     goto write_failed;
     678           38 :   if ( write (fd, "\n", 1 ) != 1 )
     679            0 :     goto write_failed;
     680           38 :   if ( close (fd) )
     681            0 :     goto write_failed;
     682              : 
     683              :   /* Check whether we support hard links.  */
     684           38 :   switch (use_hardlinks_p (h->tname))
     685              :     {
     686           38 :     case 0: /* Yes.  */
     687           38 :       break;
     688            0 :     case 1: /* No.  */
     689            0 :       unlink (h->tname);
     690            0 :       h->use_o_excl = 1;
     691            0 :       break;
     692            0 :     default:
     693            0 :       my_error_2 ("can't check whether hardlinks are supported for `%s': %s\n",
     694              :                   h->tname, strerror(errno));
     695            0 :       goto write_failed;
     696              :     }
     697              : 
     698           38 :   h->lockname = jnlib_malloc (strlen (file_to_lock) + 6 );
     699           38 :   if (!h->lockname)
     700              :     {
     701            0 :       all_lockfiles = h->next;
     702            0 :       UNLOCK_all_lockfiles ();
     703            0 :       unlink (h->tname);
     704            0 :       jnlib_free (h->tname);
     705            0 :       jnlib_free (h);
     706            0 :       return NULL;
     707              :     }
     708           38 :   strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
     709           38 :   UNLOCK_all_lockfiles ();
     710           38 :   if (h->use_o_excl)
     711            0 :     my_debug_1 ("locking for `%s' done via O_EXCL\n", h->lockname);
     712              : 
     713           38 :   return h;
     714              : 
     715            0 :  write_failed:
     716            0 :   all_lockfiles = h->next;
     717            0 :   UNLOCK_all_lockfiles ();
     718            0 :   my_error_2 (_("error writing to `%s': %s\n"), h->tname, strerror (errno));
     719            0 :   close (fd);
     720            0 :   unlink (h->tname);
     721            0 :   jnlib_free (h->tname);
     722            0 :   jnlib_free (h);
     723            0 :   return NULL;
     724              : }
     725              : #endif /*HAVE_POSIX_SYSTEM*/
     726              : 
     727              : 
     728              : #ifdef HAVE_DOSISH_SYSTEM
     729              : /* Locking core for Windows.  This version does not need a temporary
     730              :    file but uses the plain lock file along with record locking.  We
     731              :    create this file here so that we later only need to do the file
     732              :    locking.  For error reporting it is useful to keep the name of the
     733              :    file in the handle.  */
     734              : static dotlock_t
     735              : dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
     736              : {
     737              :   LOCK_all_lockfiles ();
     738              :   h->next = all_lockfiles;
     739              :   all_lockfiles = h;
     740              : 
     741              :   h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
     742              :   if (!h->lockname)
     743              :     {
     744              :       all_lockfiles = h->next;
     745              :       UNLOCK_all_lockfiles ();
     746              :       jnlib_free (h);
     747              :       return NULL;
     748              :     }
     749              :   strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
     750              : 
     751              :   /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
     752              :      along with FILE_SHARE_DELETE but that does not work due to a race
     753              :      condition: Despite the OPEN_ALWAYS flag CreateFile may return an
     754              :      error and we can't reliable create/open the lock file unless we
     755              :      would wait here until it works - however there are other valid
     756              :      reasons why a lock file can't be created and thus the process
     757              :      would not stop as expected but spin until Windows crashes.  Our
     758              :      solution is to keep the lock file open; that does not harm. */
     759              :   {
     760              : #ifdef HAVE_W32CE_SYSTEM
     761              :     wchar_t *wname = utf8_to_wchar (h->lockname);
     762              : 
     763              :     if (wname)
     764              :       h->lockhd = CreateFile (wname,
     765              :                               GENERIC_READ|GENERIC_WRITE,
     766              :                               FILE_SHARE_READ|FILE_SHARE_WRITE,
     767              :                               NULL, OPEN_ALWAYS, 0, NULL);
     768              :     else
     769              :       h->lockhd = INVALID_HANDLE_VALUE;
     770              :     jnlib_free (wname);
     771              : #else
     772              :     h->lockhd = CreateFile (h->lockname,
     773              :                             GENERIC_READ|GENERIC_WRITE,
     774              :                             FILE_SHARE_READ|FILE_SHARE_WRITE,
     775              :                             NULL, OPEN_ALWAYS, 0, NULL);
     776              : #endif
     777              :   }
     778              :   if (h->lockhd == INVALID_HANDLE_VALUE)
     779              :     {
     780              :       all_lockfiles = h->next;
     781              :       UNLOCK_all_lockfiles ();
     782              :       my_error_2 (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
     783              :       jnlib_free (h->lockname);
     784              :       jnlib_free (h);
     785              :       return NULL;
     786              :     }
     787              :   return h;
     788              : }
     789              : #endif /*HAVE_DOSISH_SYSTEM*/
     790              : 
     791              : 
     792              : /* Create a lockfile for a file name FILE_TO_LOCK and returns an
     793              :    object of type dotlock_t which may be used later to actually acquire
     794              :    the lock.  A cleanup routine gets installed to cleanup left over
     795              :    locks or other files used internally by the lock mechanism.
     796              : 
     797              :    Calling this function with NULL does only install the atexit
     798              :    handler and may thus be used to assure that the cleanup is called
     799              :    after all other atexit handlers.
     800              : 
     801              :    This function creates a lock file in the same directory as
     802              :    FILE_TO_LOCK using that name and a suffix of ".lock".  Note that on
     803              :    POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
     804              :    used.
     805              : 
     806              :    FLAGS must be 0.
     807              : 
     808              :    The function returns an new handle which needs to be released using
     809              :    destroy_dotlock but gets also released at the termination of the
     810              :    process.  On error NULL is returned.
     811              :  */
     812              : 
     813              : dotlock_t
     814           38 : dotlock_create (const char *file_to_lock, unsigned int flags)
     815              : {
     816              :   static int initialized;
     817              :   dotlock_t h;
     818              : 
     819           38 :   if ( !initialized )
     820              :     {
     821            6 :       atexit (dotlock_remove_lockfiles);
     822            6 :       initialized = 1;
     823              :     }
     824              : 
     825           38 :   if ( !file_to_lock )
     826            0 :     return NULL;  /* Only initialization was requested.  */
     827              : 
     828           38 :   if (flags)
     829              :     {
     830            0 :       jnlib_set_errno (EINVAL);
     831            0 :       return NULL;
     832              :     }
     833              : 
     834           38 :   h = jnlib_calloc (1, sizeof *h);
     835           38 :   if (!h)
     836            0 :     return NULL;
     837           38 :   h->extra_fd = -1;
     838              : 
     839           38 :   if (never_lock)
     840              :     {
     841            0 :       h->disable = 1;
     842            0 :       LOCK_all_lockfiles ();
     843            0 :       h->next = all_lockfiles;
     844            0 :       all_lockfiles = h;
     845            0 :       UNLOCK_all_lockfiles ();
     846            0 :       return h;
     847              :     }
     848              : 
     849              : #ifdef HAVE_DOSISH_SYSTEM
     850              :   return dotlock_create_w32 (h, file_to_lock);
     851              : #else /*!HAVE_DOSISH_SYSTEM */
     852           38 :   return dotlock_create_unix (h, file_to_lock);
     853              : #endif /*!HAVE_DOSISH_SYSTEM*/
     854              : }
     855              : 
     856              : 
     857              : 
     858              : /* Convenience function to store a file descriptor (or any any other
     859              :    integer value) in the context of handle H.  */
     860              : void
     861           38 : dotlock_set_fd (dotlock_t h, int fd)
     862              : {
     863           38 :   h->extra_fd = fd;
     864           38 : }
     865              : 
     866              : /* Convenience function to retrieve a file descriptor (or any any other
     867              :    integer value) stored in the context of handle H.  */
     868              : int
     869           48 : dotlock_get_fd (dotlock_t h)
     870              : {
     871           48 :   return h->extra_fd;
     872              : }
     873              : 
     874              : 
     875              : 
     876              : #ifdef HAVE_POSIX_SYSTEM
     877              : /* Unix specific code of destroy_dotlock.  */
     878              : static void
     879           38 : dotlock_destroy_unix (dotlock_t h)
     880              : {
     881           38 :   if (h->locked && h->lockname)
     882            0 :     unlink (h->lockname);
     883           38 :   if (h->tname && !h->use_o_excl)
     884           38 :     unlink (h->tname);
     885           38 :   jnlib_free (h->tname);
     886           38 : }
     887              : #endif /*HAVE_POSIX_SYSTEM*/
     888              : 
     889              : 
     890              : #ifdef HAVE_DOSISH_SYSTEM
     891              : /* Windows specific code of destroy_dotlock.  */
     892              : static void
     893              : dotlock_destroy_w32 (dotlock_t h)
     894              : {
     895              :   if (h->locked)
     896              :     {
     897              :       OVERLAPPED ovl;
     898              : 
     899              :       memset (&ovl, 0, sizeof ovl);
     900              :       UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
     901              :     }
     902              :   CloseHandle (h->lockhd);
     903              : }
     904              : #endif /*HAVE_DOSISH_SYSTEM*/
     905              : 
     906              : 
     907              : /* Destroy the locck handle H and release the lock.  */
     908              : void
     909           38 : dotlock_destroy (dotlock_t h)
     910              : {
     911              :   dotlock_t hprev, htmp;
     912              : 
     913           38 :   if ( !h )
     914            0 :     return;
     915              : 
     916              :   /* First remove the handle from our global list of all locks. */
     917           38 :   LOCK_all_lockfiles ();
     918           38 :   for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
     919           38 :     if (htmp == h)
     920              :       {
     921           38 :         if (hprev)
     922            0 :           hprev->next = htmp->next;
     923              :         else
     924           38 :           all_lockfiles = htmp->next;
     925           38 :         h->next = NULL;
     926           38 :         break;
     927              :       }
     928           38 :   UNLOCK_all_lockfiles ();
     929              : 
     930              :   /* Then destroy the lock. */
     931           38 :   if (!h->disable)
     932              :     {
     933              : #ifdef HAVE_DOSISH_SYSTEM
     934              :       dotlock_destroy_w32 (h);
     935              : #else /* !HAVE_DOSISH_SYSTEM */
     936           38 :       dotlock_destroy_unix (h);
     937              : #endif /* HAVE_DOSISH_SYSTEM */
     938           38 :       jnlib_free (h->lockname);
     939              :     }
     940           38 :   jnlib_free(h);
     941              : }
     942              : 
     943              : 
     944              : 
     945              : #ifdef HAVE_POSIX_SYSTEM
     946              : /* Unix specific code of make_dotlock.  Returns 0 on success and -1 on
     947              :    error.  */
     948              : static int
     949           38 : dotlock_take_unix (dotlock_t h, long timeout)
     950              : {
     951           38 :   int wtime = 0;
     952           38 :   int sumtime = 0;
     953              :   int pid;
     954           38 :   int lastpid = -1;
     955              :   int ownerchanged;
     956           38 :   const char *maybe_dead="";
     957              :   int same_node;
     958              : 
     959            0 :  again:
     960           38 :   if (h->use_o_excl)
     961              :     {
     962              :       /* No hardlink support - use open(O_EXCL).  */
     963              :       int fd;
     964              : 
     965              :       do
     966              :         {
     967            0 :           jnlib_set_errno (0);
     968            0 :           fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
     969              :                      S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
     970              :         }
     971            0 :       while (fd == -1 && errno == EINTR);
     972              : 
     973            0 :       if (fd == -1 && errno == EEXIST)
     974              :         ; /* Lock held by another process.  */
     975            0 :       else if (fd == -1)
     976              :         {
     977            0 :           my_error_2 ("lock not made: open(O_EXCL) of `%s' failed: %s\n",
     978              :                       h->lockname, strerror (errno));
     979            0 :           return -1;
     980              :         }
     981              :       else
     982              :         {
     983              :           char pidstr[16];
     984              : 
     985            0 :           snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
     986            0 :           if (write (fd, pidstr, 11 ) == 11
     987            0 :               && write (fd, h->tname + h->nodename_off,h->nodename_len)
     988            0 :               == h->nodename_len
     989            0 :               && write (fd, "\n", 1) == 1
     990            0 :               && !close (fd))
     991              :             {
     992            0 :               h->locked = 1;
     993            0 :               return 0;
     994              :             }
     995              :           /* Write error.  */
     996            0 :           my_error_2 ("lock not made: writing to `%s' failed: %s\n",
     997              :                       h->lockname, strerror (errno));
     998            0 :           close (fd);
     999            0 :           unlink (h->lockname);
    1000            0 :           return -1;
    1001              :         }
    1002              :     }
    1003              :   else /* Standard method:  Use hardlinks.  */
    1004              :     {
    1005              :       struct stat sb;
    1006              : 
    1007           38 :       link (h->tname, h->lockname);
    1008              : 
    1009           38 :       if (stat (h->tname, &sb))
    1010              :         {
    1011            0 :           my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
    1012              :                       strerror (errno));
    1013              :           /* In theory this might be a severe error: It is possible
    1014              :              that link succeeded but stat failed due to changed
    1015              :              permissions.  We can't do anything about it, though.  */
    1016           38 :           return -1;
    1017              :         }
    1018              : 
    1019           38 :       if (sb.st_nlink == 2)
    1020              :         {
    1021           38 :           h->locked = 1;
    1022           38 :           return 0; /* Okay.  */
    1023              :         }
    1024              :     }
    1025              : 
    1026              :   /* Check for stale lock files.  */
    1027            0 :   if ( (pid = read_lockfile (h, &same_node)) == -1 )
    1028              :     {
    1029            0 :       if ( errno != ENOENT )
    1030              :         {
    1031            0 :           my_info_0 ("cannot read lockfile\n");
    1032            0 :           return -1;
    1033              :         }
    1034            0 :       my_info_0 ("lockfile disappeared\n");
    1035            0 :       goto again;
    1036              :     }
    1037            0 :   else if ( pid == getpid() && same_node )
    1038              :     {
    1039            0 :       my_info_0 ("Oops: lock already held by us\n");
    1040            0 :       h->locked = 1;
    1041            0 :       return 0; /* okay */
    1042              :     }
    1043            0 :   else if ( same_node && kill (pid, 0) && errno == ESRCH )
    1044              :     {
    1045              :       /* Note: It is unlikley that we get a race here unless a pid is
    1046              :          reused too fast or a new process with the same pid as the one
    1047              :          of the stale file tries to lock right at the same time as we.  */
    1048            0 :       my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
    1049            0 :       unlink (h->lockname);
    1050            0 :       goto again;
    1051              :     }
    1052              : 
    1053            0 :   if (lastpid == -1)
    1054            0 :     lastpid = pid;
    1055            0 :   ownerchanged = (pid != lastpid);
    1056              : 
    1057            0 :   if (timeout)
    1058              :     {
    1059              :       struct timeval tv;
    1060              : 
    1061              :       /* Wait until lock has been released.  We use increasing retry
    1062              :          intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
    1063              :          but reset it if the lock owner meanwhile changed.  */
    1064            0 :       if (!wtime || ownerchanged)
    1065            0 :         wtime = 50;
    1066            0 :       else if (wtime < 800)
    1067            0 :         wtime *= 2;
    1068            0 :       else if (wtime == 800)
    1069            0 :         wtime = 2000;
    1070            0 :       else if (wtime < 8000)
    1071            0 :         wtime *= 2;
    1072              : 
    1073            0 :       if (timeout > 0)
    1074              :         {
    1075            0 :           if (wtime > timeout)
    1076            0 :             wtime = timeout;
    1077            0 :           timeout -= wtime;
    1078              :         }
    1079              : 
    1080            0 :       sumtime += wtime;
    1081            0 :       if (sumtime >= 1500)
    1082              :         {
    1083            0 :           sumtime = 0;
    1084            0 :           my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
    1085              :                      pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
    1086              :         }
    1087              : 
    1088              : 
    1089            0 :       tv.tv_sec = wtime / 1000;
    1090            0 :       tv.tv_usec = (wtime % 1000) * 1000;
    1091            0 :       select (0, NULL, NULL, NULL, &tv);
    1092            0 :       goto again;
    1093              :     }
    1094              : 
    1095            0 :   jnlib_set_errno (EACCES);
    1096            0 :   return -1;
    1097              : }
    1098              : #endif /*HAVE_POSIX_SYSTEM*/
    1099              : 
    1100              : 
    1101              : #ifdef HAVE_DOSISH_SYSTEM
    1102              : /* Windows specific code of make_dotlock.  Returns 0 on success and -1 on
    1103              :    error.  */
    1104              : static int
    1105              : dotlock_take_w32 (dotlock_t h, long timeout)
    1106              : {
    1107              :   int wtime = 0;
    1108              :   int w32err;
    1109              :   OVERLAPPED ovl;
    1110              : 
    1111              :  again:
    1112              :   /* Lock one byte at offset 0.  The offset is given by OVL.  */
    1113              :   memset (&ovl, 0, sizeof ovl);
    1114              :   if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
    1115              :                               | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
    1116              :     {
    1117              :       h->locked = 1;
    1118              :       return 0; /* okay */
    1119              :     }
    1120              : 
    1121              :   w32err = GetLastError ();
    1122              :   if (w32err != ERROR_LOCK_VIOLATION)
    1123              :     {
    1124              :       my_error_2 (_("lock `%s' not made: %s\n"),
    1125              :                   h->lockname, w32_strerror (w32err));
    1126              :       return -1;
    1127              :     }
    1128              : 
    1129              :   if (timeout)
    1130              :     {
    1131              :       /* Wait until lock has been released.  We use retry intervals of
    1132              :          50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s.  */
    1133              :       if (!wtime)
    1134              :         wtime = 50;
    1135              :       else if (wtime < 800)
    1136              :         wtime *= 2;
    1137              :       else if (wtime == 800)
    1138              :         wtime = 2000;
    1139              :       else if (wtime < 8000)
    1140              :         wtime *= 2;
    1141              : 
    1142              :       if (timeout > 0)
    1143              :         {
    1144              :           if (wtime > timeout)
    1145              :             wtime = timeout;
    1146              :           timeout -= wtime;
    1147              :         }
    1148              : 
    1149              :       if (wtime >= 800)
    1150              :         my_info_1 (_("waiting for lock %s...\n"), h->lockname);
    1151              : 
    1152              :       Sleep (wtime);
    1153              :       goto again;
    1154              :     }
    1155              : 
    1156              :   return -1;
    1157              : }
    1158              : #endif /*HAVE_DOSISH_SYSTEM*/
    1159              : 
    1160              : 
    1161              : /* Take a lock on H.  A value of 0 for TIMEOUT returns immediately if
    1162              :    the lock can't be taked, -1 waits forever (hopefully not), other
    1163              :    values wait for TIMEOUT milliseconds.  Returns: 0 on success  */
    1164              : int
    1165           38 : dotlock_take (dotlock_t h, long timeout)
    1166              : {
    1167              :   int ret;
    1168              : 
    1169           38 :   if ( h->disable )
    1170            0 :     return 0; /* Locks are completely disabled.  Return success. */
    1171              : 
    1172           38 :   if ( h->locked )
    1173              :     {
    1174            0 :       my_debug_1 ("Oops, `%s' is already locked\n", h->lockname);
    1175            0 :       return 0;
    1176              :     }
    1177              : 
    1178              : #ifdef HAVE_DOSISH_SYSTEM
    1179              :   ret = dotlock_take_w32 (h, timeout);
    1180              : #else /*!HAVE_DOSISH_SYSTEM*/
    1181           38 :   ret = dotlock_take_unix (h, timeout);
    1182              : #endif /*!HAVE_DOSISH_SYSTEM*/
    1183              : 
    1184           38 :   return ret;
    1185              : }
    1186              : 
    1187              : 
    1188              : 
    1189              : #ifdef HAVE_POSIX_SYSTEM
    1190              : /* Unix specific code of release_dotlock.  */
    1191              : static int
    1192           38 : dotlock_release_unix (dotlock_t h)
    1193              : {
    1194              :   int pid, same_node;
    1195              : 
    1196           38 :   pid = read_lockfile (h, &same_node);
    1197           38 :   if ( pid == -1 )
    1198              :     {
    1199            0 :       my_error_0 ("release_dotlock: lockfile error\n");
    1200            0 :       return -1;
    1201              :     }
    1202           38 :   if ( pid != getpid() || !same_node )
    1203              :     {
    1204            0 :       my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
    1205            0 :       return -1;
    1206              :     }
    1207              : 
    1208           38 :   if ( unlink( h->lockname ) )
    1209              :     {
    1210            0 :       my_error_1 ("release_dotlock: error removing lockfile `%s'\n",
    1211              :                   h->lockname);
    1212            0 :       return -1;
    1213              :     }
    1214              :   /* Fixme: As an extra check we could check whether the link count is
    1215              :      now really at 1. */
    1216           38 :   return 0;
    1217              : }
    1218              : #endif /*HAVE_POSIX_SYSTEM */
    1219              : 
    1220              : 
    1221              : #ifdef HAVE_DOSISH_SYSTEM
    1222              : /* Windows specific code of release_dotlock.  */
    1223              : static int
    1224              : dotlock_release_w32 (dotlock_t h)
    1225              : {
    1226              :   OVERLAPPED ovl;
    1227              : 
    1228              :   memset (&ovl, 0, sizeof ovl);
    1229              :   if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
    1230              :     {
    1231              :       my_error_2 ("release_dotlock: error removing lockfile `%s': %s\n",
    1232              :                   h->lockname, w32_strerror (-1));
    1233              :       return -1;
    1234              :     }
    1235              : 
    1236              :   return 0;
    1237              : }
    1238              : #endif /*HAVE_DOSISH_SYSTEM */
    1239              : 
    1240              : 
    1241              : /* Release a lock.  Returns 0 on success.  */
    1242              : int
    1243           38 : dotlock_release (dotlock_t h)
    1244              : {
    1245              :   int ret;
    1246              : 
    1247              :   /* To avoid atexit race conditions we first check whether there are
    1248              :      any locks left.  It might happen that another atexit handler
    1249              :      tries to release the lock while the atexit handler of this module
    1250              :      already ran and thus H is undefined.  */
    1251           38 :   LOCK_all_lockfiles ();
    1252           38 :   ret = !all_lockfiles;
    1253           38 :   UNLOCK_all_lockfiles ();
    1254           38 :   if (ret)
    1255            0 :     return 0;
    1256              : 
    1257           38 :   if ( h->disable )
    1258            0 :     return 0;
    1259              : 
    1260           38 :   if ( !h->locked )
    1261              :     {
    1262            0 :       my_debug_1 ("Oops, `%s' is not locked\n", h->lockname);
    1263            0 :       return 0;
    1264              :     }
    1265              : 
    1266              : #ifdef HAVE_DOSISH_SYSTEM
    1267              :   ret = dotlock_release_w32 (h);
    1268              : #else
    1269           38 :   ret = dotlock_release_unix (h);
    1270              : #endif
    1271              : 
    1272           38 :   if (!ret)
    1273           38 :     h->locked = 0;
    1274           38 :   return ret;
    1275              : }
    1276              : 
    1277              : 
    1278              : 
    1279              : /* Remove all lockfiles.  This is called by the atexit handler
    1280              :    installed by this module but may also be called by other
    1281              :    termination handlers.  */
    1282              : void
    1283            6 : dotlock_remove_lockfiles (void)
    1284              : {
    1285              :   dotlock_t h, h2;
    1286              : 
    1287              :   /* First set the lockfiles list to NULL so that for example
    1288              :      dotlock_release is ware that this fucntion is currently
    1289              :      running.  */
    1290            6 :   LOCK_all_lockfiles ();
    1291            6 :   h = all_lockfiles;
    1292            6 :   all_lockfiles = NULL;
    1293            6 :   UNLOCK_all_lockfiles ();
    1294              : 
    1295            6 :   while ( h )
    1296              :     {
    1297            0 :       h2 = h->next;
    1298            0 :       dotlock_destroy (h);
    1299            0 :       h = h2;
    1300              :     }
    1301            6 : }
        

Generated by: LCOV version 2.0-1