Coverage Report

Created: 2022-12-08 06:09

/src/gnupg/common/dotlock.c
Line
Count
Source (jump to first uncovered line)
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 and/or modify this
8
 * part of GnuPG 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 these 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 value 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
   Note that there is a test program t-dotlock which has compile
213
   instructions at its end.  At least for SMBFS and CIFS it is
214
   important that 64 bit versions of stat are used; most programming
215
   environments do this these days, just in case you want to compile
216
   it on the command line, remember to pass -D_FILE_OFFSET_BITS=64
217
218
219
   Bugs:
220
   =====
221
222
   On Windows this module is not yet thread-safe.
223
224
225
   Miscellaneous notes:
226
   ====================
227
228
   On hardlinks:
229
   - Hardlinks are supported under Windows with NTFS since XP/Server2003.
230
   - In Linux 2.6.33 both SMBFS and CIFS seem to support hardlinks.
231
   - NFS supports hard links.  But there are solvable problems.
232
   - FAT does not support links
233
234
   On the file locking API:
235
   - CIFS on Linux 2.6.33 supports several locking methods.
236
     SMBFS seems not to support locking.  No closer checks done.
237
   - NFS supports Posix locks.  flock is emulated in the server.
238
     However there are a couple of problems; see below.
239
   - FAT does not support locks.
240
   - An advantage of fcntl locking is that R/W locks can be
241
     implemented which is not easy with a straight lock file.
242
243
   On O_EXCL:
244
   - Does not work reliable on NFS
245
   - Should work on CIFS and SMBFS but how can we delete lockfiles?
246
247
   On NFS problems:
248
   - Locks vanish if the server crashes and reboots.
249
   - Client crashes keep the lock in the server until the client
250
     re-connects.
251
   - Communication problems may return unreliable error codes.  The
252
     MUA Postfix's workaround is to compare the link count after
253
     seeing an error for link.  However that gives a race.  If using a
254
     unique file to link to a lockfile and using stat to check the
255
     link count instead of looking at the error return of link(2) is
256
     the best solution.
257
   - O_EXCL seems to have a race and may re-create a file anyway.
258
259
*/
260
261
#ifdef HAVE_CONFIG_H
262
# include <config.h>
263
#endif
264
265
/* Some quick replacements for stuff we usually expect to be defined
266
   in config.h.  Define HAVE_POSIX_SYSTEM for better readability. */
267
#if !defined (HAVE_DOSISH_SYSTEM) && defined(_WIN32)
268
# define HAVE_DOSISH_SYSTEM 1
269
#endif
270
#if !defined (HAVE_DOSISH_SYSTEM) && !defined (HAVE_POSIX_SYSTEM)
271
# define HAVE_POSIX_SYSTEM 1
272
#endif
273
274
/* With no config.h assume that we have sitgnal.h.  */
275
#if !defined (HAVE_CONFIG_H) && defined (HAVE_POSIX_SYSTEM)
276
# define HAVE_SIGNAL_H 1
277
#endif
278
279
/* Standard headers.  */
280
#include <stdlib.h>
281
#include <stdio.h>
282
#include <string.h>
283
#include <errno.h>
284
#include <ctype.h>
285
#include <errno.h>
286
#include <unistd.h>
287
#ifdef  HAVE_DOSISH_SYSTEM
288
# define WIN32_LEAN_AND_MEAN  /* We only need the OS core stuff.  */
289
# include <windows.h>
290
#else
291
# include <sys/types.h>
292
# include <sys/stat.h>
293
# include <sys/utsname.h>
294
#endif
295
#include <sys/types.h>
296
#include <sys/time.h>
297
#include <sys/stat.h>
298
#include <fcntl.h>
299
#ifdef HAVE_SIGNAL_H
300
# include <signal.h>
301
#endif
302
#ifdef DOTLOCK_USE_PTHREAD
303
# include <pthread.h>
304
#endif
305
306
#ifdef DOTLOCK_GLIB_LOGGING
307
# include <glib.h>
308
#endif
309
310
#ifdef GNUPG_MAJOR_VERSION
311
# include "util.h"
312
# include "common-defs.h"
313
# include "stringhelp.h"  /* For stpcpy and w32_strerror. */
314
#endif
315
316
#include "dotlock.h"
317
318
319
/* Define constants for file name construction.  */
320
#if !defined(DIRSEP_C) && !defined(EXTSEP_S)
321
# ifdef HAVE_DOSISH_SYSTEM
322
#  define DIRSEP_C '\\'
323
#  define EXTSEP_S "."
324
#else
325
#  define DIRSEP_C '/'
326
#  define EXTSEP_S "."
327
# endif
328
#endif
329
330
/* In GnuPG we use wrappers around the malloc functions.  If they are
331
   not defined we assume that this code is used outside of GnuPG and
332
   fall back to the regular malloc functions.  */
333
#ifndef xtrymalloc
334
# define xtrymalloc(a)     malloc ((a))
335
# define xtrycalloc(a,b)   calloc ((a), (b))
336
# define xfree(a)    free ((a))
337
#endif
338
339
/* Wrapper to set ERRNO (required for W32CE).  */
340
#ifdef GPG_ERROR_VERSION
341
3
#  define my_set_errno(e)  gpg_err_set_errno ((e))
342
#else
343
#  define my_set_errno(e)  do { errno = (e); } while (0)
344
#endif
345
346
/* Gettext macro replacement.  */
347
#ifndef _
348
# define _(a) (a)
349
#endif
350
351
#ifdef GNUPG_MAJOR_VERSION
352
0
# define my_info_0(a)       log_info ((a))
353
0
# define my_info_1(a,b)     log_info ((a), (b))
354
0
# define my_info_2(a,b,c)   log_info ((a), (b), (c))
355
0
# define my_info_3(a,b,c,d) log_info ((a), (b), (c), (d))
356
0
# define my_error_0(a)      log_error ((a))
357
0
# define my_error_1(a,b)    log_error ((a), (b))
358
0
# define my_error_2(a,b,c)  log_error ((a), (b), (c))
359
0
# define my_debug_1(a,b)    log_debug ((a), (b))
360
# define my_fatal_0(a)      log_fatal ((a))
361
#elif defined (DOTLOCK_GLIB_LOGGING)
362
# define my_info_0(a)       g_message ((a))
363
# define my_info_1(a,b)     g_message ((a), (b))
364
# define my_info_2(a,b,c)   g_message ((a), (b), (c))
365
# define my_info_3(a,b,c,d) g_message ((a), (b), (c), (d))
366
# define my_error_0(a)      g_warning ((a))
367
# define my_error_1(a,b)    g_warning ((a), (b))
368
# define my_error_2(a,b,c)  g_warning ((a), (b), (c))
369
# define my_debug_1(a,b)    g_debug ((a), (b))
370
# define my_fatal_0(a)      g_error ((a))
371
#else
372
# define my_info_0(a)       fprintf (stderr, (a))
373
# define my_info_1(a,b)     fprintf (stderr, (a), (b))
374
# define my_info_2(a,b,c)   fprintf (stderr, (a), (b), (c))
375
# define my_info_3(a,b,c,d) fprintf (stderr, (a), (b), (c), (d))
376
# define my_error_0(a)      fprintf (stderr, (a))
377
# define my_error_1(a,b)    fprintf (stderr, (a), (b))
378
# define my_error_2(a,b,c)  fprintf (stderr, (a), (b), (c))
379
# define my_debug_1(a,b)    fprintf (stderr, (a), (b))
380
# define my_fatal_0(a)      do { fprintf (stderr,(a)); fflush (stderr); \
381
                                 abort (); } while (0)
382
#endif
383
384
385
386
387

388
/* The object describing a lock.  */
389
struct dotlock_handle
390
{
391
  struct dotlock_handle *next;
392
  char *lockname;            /* Name of the actual lockfile.          */
393
  unsigned int locked:1;     /* Lock status.                          */
394
  unsigned int disable:1;    /* If true, locking is disabled.         */
395
  unsigned int use_o_excl:1; /* Use open (O_EXCL) for locking.        */
396
397
  int extra_fd;              /* A place for the caller to store an FD.  */
398
399
#ifdef HAVE_DOSISH_SYSTEM
400
  HANDLE lockhd;       /* The W32 handle of the lock file.      */
401
#else /*!HAVE_DOSISH_SYSTEM */
402
  char *tname;         /* Name of the lockfile template.        */
403
  size_t nodename_off; /* Offset in TNAME of the nodename part. */
404
  size_t nodename_len; /* Length of the nodename part.          */
405
#endif /*!HAVE_DOSISH_SYSTEM */
406
};
407
408
409
/* A list of all lock handles.  The volatile attribute might help
410
   if used in an atexit handler.  Note that [UN]LOCK_all_lockfiles
411
   must not change ERRNO. */
412
static volatile dotlock_t all_lockfiles;
413
#ifdef DOTLOCK_USE_PTHREAD
414
static pthread_mutex_t all_lockfiles_mutex = PTHREAD_MUTEX_INITIALIZER;
415
# define LOCK_all_lockfiles() do {                               \
416
        if (pthread_mutex_lock (&all_lockfiles_mutex))           \
417
          my_fatal_0 ("locking all_lockfiles_mutex failed\n");   \
418
      } while (0)
419
# define UNLOCK_all_lockfiles() do {                             \
420
        if (pthread_mutex_unlock (&all_lockfiles_mutex))         \
421
          my_fatal_0 ("unlocking all_lockfiles_mutex failed\n"); \
422
      } while (0)
423
#else  /*!DOTLOCK_USE_PTHREAD*/
424
10
# define LOCK_all_lockfiles()   do { } while (0)
425
10
# define UNLOCK_all_lockfiles() do { } while (0)
426
#endif /*!DOTLOCK_USE_PTHREAD*/
427
428
/* If this has the value true all locking is disabled.  */
429
static int never_lock;
430
431
432
433

434
#ifdef HAVE_DOSISH_SYSTEM
435
/* FIXME: For use in GnuPG this can be replaced by
436
 *        gnupg_w32_set_errno.  */
437
static int
438
map_w32_to_errno (DWORD w32_err)
439
{
440
  switch (w32_err)
441
    {
442
    case 0:
443
      return 0;
444
445
    case ERROR_FILE_NOT_FOUND:
446
      return ENOENT;
447
448
    case ERROR_PATH_NOT_FOUND:
449
      return ENOENT;
450
451
    case ERROR_ACCESS_DENIED:
452
      return EPERM;
453
454
    case ERROR_INVALID_HANDLE:
455
    case ERROR_INVALID_BLOCK:
456
      return EINVAL;
457
458
    case ERROR_NOT_ENOUGH_MEMORY:
459
      return ENOMEM;
460
461
    case ERROR_NO_DATA:
462
    case ERROR_BROKEN_PIPE:
463
      return EPIPE;
464
465
    default:
466
      return EIO;
467
    }
468
}
469
#endif /*HAVE_DOSISH_SYSTEM*/
470
471
472
#ifdef HAVE_W32_SYSTEM
473
static int
474
any8bitchar (const char *string)
475
{
476
  if (string)
477
    for ( ; *string; string++)
478
      if ((*string & 0x80))
479
        return 1;
480
  return 0;
481
}
482
#endif /*HAVE_W32_SYSTEM*/
483
484
485
486

487
/* Entirely disable all locking.  This function should be called
488
   before any locking is done.  It may be called right at startup of
489
   the process as it only sets a global value.  */
490
void
491
dotlock_disable (void)
492
0
{
493
0
  never_lock = 1;
494
0
}
495
496
497
#ifdef HAVE_POSIX_SYSTEM
498
static int
499
maybe_deadlock (dotlock_t h)
500
0
{
501
0
  dotlock_t r;
502
0
  int res = 0;
503
504
0
  LOCK_all_lockfiles ();
505
0
  for (r=all_lockfiles; r; r = r->next)
506
0
    {
507
0
      if ( r != h && r->locked )
508
0
        {
509
0
          res = 1;
510
0
          break;
511
0
        }
512
0
    }
513
0
  UNLOCK_all_lockfiles ();
514
0
  return res;
515
0
}
516
#endif /*HAVE_POSIX_SYSTEM*/
517
518
519
/* Read the lock file and return the pid, returns -1 on error.  True
520
   will be stored in the integer at address SAME_NODE if the lock file
521
   has been created on the same node. */
522
#ifdef HAVE_POSIX_SYSTEM
523
static int
524
read_lockfile (dotlock_t h, int *same_node, int *r_fd)
525
3
{
526
3
  char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
527
                                   names are usually shorter. */
528
3
  int fd;
529
3
  int pid = -1;
530
3
  char *buffer, *p;
531
3
  size_t expected_len;
532
3
  int res, nread;
533
534
3
  *same_node = 0;
535
3
  expected_len = 10 + 1 + h->nodename_len + 1;
536
3
  if ( expected_len >= sizeof buffer_space)
537
0
    {
538
0
      buffer = xtrymalloc (expected_len);
539
0
      if (!buffer)
540
0
        return -1;
541
0
    }
542
3
  else
543
3
    buffer = buffer_space;
544
545
3
  if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
546
0
    {
547
0
      int e = errno;
548
0
      my_info_2 ("error opening lockfile '%s': %s\n",
549
0
                 h->lockname, strerror(errno) );
550
0
      if (buffer != buffer_space)
551
0
        xfree (buffer);
552
0
      my_set_errno (e); /* Need to return ERRNO here. */
553
0
      return -1;
554
0
    }
555
556
3
  p = buffer;
557
3
  nread = 0;
558
3
  do
559
3
    {
560
3
      res = read (fd, p, expected_len - nread);
561
3
      if (res == -1 && errno == EINTR)
562
0
        continue;
563
3
      if (res < 0)
564
0
        {
565
0
          int e = errno;
566
0
          my_info_1 ("error reading lockfile '%s'\n", h->lockname );
567
0
          close (fd);
568
0
          if (buffer != buffer_space)
569
0
            xfree (buffer);
570
0
          my_set_errno (e);
571
0
          return -1;
572
0
        }
573
3
      p += res;
574
3
      nread += res;
575
3
    }
576
3
  while (res && nread != expected_len);
577
578
3
  if (r_fd)
579
0
    *r_fd = fd;
580
3
  else
581
3
    close(fd);
582
583
3
  if (nread < 11)
584
0
    {
585
0
      my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
586
0
      if (buffer != buffer_space)
587
0
        xfree (buffer);
588
0
      my_set_errno (EINVAL);
589
0
      return -1;
590
0
    }
591
592
3
  if (buffer[10] != '\n'
593
3
      || (buffer[10] = 0, pid = atoi (buffer)) == -1
594
3
      || !pid )
595
0
    {
596
0
      my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
597
0
      if (buffer != buffer_space)
598
0
        xfree (buffer);
599
0
      my_set_errno (EINVAL);
600
0
      return -1;
601
0
    }
602
603
3
  if (nread == expected_len
604
3
      && !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
605
3
      && buffer[11+h->nodename_len] == '\n')
606
3
    *same_node = 1;
607
608
3
  if (buffer != buffer_space)
609
0
    xfree (buffer);
610
3
  return pid;
611
3
}
612
#endif /*HAVE_POSIX_SYSTEM */
613
614
615
/* Check whether the file system which stores TNAME supports
616
   hardlinks.  Instead of using the non-portable statsfs call which
617
   differs between various Unix versions, we do a runtime test.
618
   Returns: 0 supports hardlinks; 1 no hardlink support, -1 unknown
619
   (test error).  */
620
#ifdef HAVE_POSIX_SYSTEM
621
static int
622
use_hardlinks_p (const char *tname)
623
3
{
624
3
  char *lname;
625
3
  struct stat sb;
626
3
  unsigned int nlink;
627
3
  int res;
628
629
3
  if (stat (tname, &sb))
630
0
    return -1;
631
3
  nlink = (unsigned int)sb.st_nlink;
632
633
3
  lname = xtrymalloc (strlen (tname) + 1 + 1);
634
3
  if (!lname)
635
0
    return -1;
636
3
  strcpy (lname, tname);
637
3
  strcat (lname, "x");
638
639
  /* We ignore the return value of link() because it is unreliable.  */
640
3
  (void) link (tname, lname);
641
642
3
  if (stat (tname, &sb))
643
0
    res = -1;  /* Ooops.  */
644
3
  else if (sb.st_nlink == nlink + 1)
645
3
    res = 0;   /* Yeah, hardlinks are supported.  */
646
0
  else
647
0
    res = 1;   /* No hardlink support.  */
648
649
3
  unlink (lname);
650
3
  xfree (lname);
651
3
  return res;
652
3
}
653
#endif /*HAVE_POSIX_SYSTEM */
654
655
656

657
#ifdef  HAVE_POSIX_SYSTEM
658
/* Locking core for Unix.  It used a temporary file and the link
659
   system call to make locking an atomic operation. */
660
static dotlock_t
661
dotlock_create_unix (dotlock_t h, const char *file_to_lock)
662
3
{
663
3
  int  fd = -1;
664
3
  char pidstr[16];
665
3
  const char *nodename;
666
3
  const char *dirpart;
667
3
  int dirpartlen;
668
3
  struct utsname utsbuf;
669
3
  size_t tnamelen;
670
671
3
  snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
672
673
  /* Create a temporary file. */
674
3
  if ( uname ( &utsbuf ) )
675
0
    nodename = "unknown";
676
3
  else
677
3
    nodename = utsbuf.nodename;
678
679
3
  if ( !(dirpart = strrchr (file_to_lock, DIRSEP_C)) )
680
0
    {
681
0
      dirpart = EXTSEP_S;
682
0
      dirpartlen = 1;
683
0
    }
684
3
  else
685
3
    {
686
3
      dirpartlen = dirpart - file_to_lock;
687
3
      dirpart = file_to_lock;
688
3
    }
689
690
3
  LOCK_all_lockfiles ();
691
3
  h->next = all_lockfiles;
692
3
  all_lockfiles = h;
693
694
3
  tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
695
3
  h->tname = xtrymalloc (tnamelen + 1);
696
3
  if (!h->tname)
697
0
    {
698
0
      all_lockfiles = h->next;
699
0
      UNLOCK_all_lockfiles ();
700
0
      xfree (h);
701
0
      return NULL;
702
0
    }
703
3
  h->nodename_len = strlen (nodename);
704
705
3
  snprintf (h->tname, tnamelen, "%.*s/.#lk%p.", dirpartlen, dirpart, h );
706
3
  h->nodename_off = strlen (h->tname);
707
3
  snprintf (h->tname+h->nodename_off, tnamelen - h->nodename_off,
708
3
           "%s.%d", nodename, (int)getpid ());
709
710
3
  do
711
3
    {
712
3
      my_set_errno (0);
713
3
      fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
714
3
                 S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
715
3
    }
716
3
  while (fd == -1 && errno == EINTR);
717
718
3
  if ( fd == -1 )
719
0
    {
720
0
      int saveerrno = errno;
721
0
      all_lockfiles = h->next;
722
0
      UNLOCK_all_lockfiles ();
723
0
      my_error_2 (_("failed to create temporary file '%s': %s\n"),
724
0
                  h->tname, strerror (errno));
725
0
      xfree (h->tname);
726
0
      xfree (h);
727
0
      my_set_errno (saveerrno);
728
0
      return NULL;
729
0
    }
730
3
  if ( write (fd, pidstr, 11 ) != 11 )
731
0
    goto write_failed;
732
3
  if ( write (fd, nodename, strlen (nodename) ) != strlen (nodename) )
733
0
    goto write_failed;
734
3
  if ( write (fd, "\n", 1 ) != 1 )
735
0
    goto write_failed;
736
3
  if ( close (fd) )
737
0
    {
738
0
      if ( errno == EINTR )
739
0
        fd = -1;
740
0
      goto write_failed;
741
0
    }
742
3
  fd = -1;
743
744
  /* Check whether we support hard links.  */
745
3
  switch (use_hardlinks_p (h->tname))
746
3
    {
747
3
    case 0: /* Yes.  */
748
3
      break;
749
0
    case 1: /* No.  */
750
0
      unlink (h->tname);
751
0
      h->use_o_excl = 1;
752
0
      break;
753
0
    default:
754
0
      {
755
0
        int saveerrno = errno;
756
0
        my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
757
0
                    , h->tname, strerror (saveerrno));
758
0
        my_set_errno (saveerrno);
759
0
      }
760
0
      goto write_failed;
761
3
    }
762
763
3
  h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
764
3
  if (!h->lockname)
765
0
    {
766
0
      int saveerrno = errno;
767
0
      all_lockfiles = h->next;
768
0
      UNLOCK_all_lockfiles ();
769
0
      unlink (h->tname);
770
0
      xfree (h->tname);
771
0
      xfree (h);
772
0
      my_set_errno (saveerrno);
773
0
      return NULL;
774
0
    }
775
3
  strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
776
3
  UNLOCK_all_lockfiles ();
777
778
3
  return h;
779
780
0
 write_failed:
781
0
  {
782
0
    int saveerrno = errno;
783
0
    all_lockfiles = h->next;
784
0
    UNLOCK_all_lockfiles ();
785
0
    my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
786
0
    if ( fd != -1 )
787
0
      close (fd);
788
0
    unlink (h->tname);
789
0
    xfree (h->tname);
790
0
    xfree (h);
791
0
    my_set_errno (saveerrno);
792
0
  }
793
0
  return NULL;
794
3
}
795
#endif /*HAVE_POSIX_SYSTEM*/
796
797
798
#ifdef HAVE_DOSISH_SYSTEM
799
/* Locking core for Windows.  This version does not need a temporary
800
   file but uses the plain lock file along with record locking.  We
801
   create this file here so that we later only need to do the file
802
   locking.  For error reporting it is useful to keep the name of the
803
   file in the handle.  */
804
static dotlock_t
805
dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
806
{
807
  LOCK_all_lockfiles ();
808
  h->next = all_lockfiles;
809
  all_lockfiles = h;
810
811
  h->lockname = strconcat (file_to_lock, EXTSEP_S "lock", NULL);
812
  if (!h->lockname)
813
    {
814
      all_lockfiles = h->next;
815
      UNLOCK_all_lockfiles ();
816
      xfree (h);
817
      return NULL;
818
    }
819
820
  /* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
821
     along with FILE_SHARE_DELETE but that does not work due to a race
822
     condition: Despite the OPEN_ALWAYS flag CreateFile may return an
823
     error and we can't reliable create/open the lock file unless we
824
     would wait here until it works - however there are other valid
825
     reasons why a lock file can't be created and thus the process
826
     would not stop as expected but spin until Windows crashes.  Our
827
     solution is to keep the lock file open; that does not harm. */
828
  if (any8bitchar (h->lockname))
829
    {
830
      wchar_t *wname = utf8_to_wchar (h->lockname);
831
832
      if (wname)
833
        h->lockhd = CreateFileW (wname,
834
                                 GENERIC_READ|GENERIC_WRITE,
835
                                 FILE_SHARE_READ|FILE_SHARE_WRITE,
836
                                 NULL, OPEN_ALWAYS, 0, NULL);
837
      else
838
        h->lockhd = INVALID_HANDLE_VALUE;
839
      xfree (wname);
840
    }
841
  else
842
    h->lockhd = CreateFileA (h->lockname,
843
                             GENERIC_READ|GENERIC_WRITE,
844
                             FILE_SHARE_READ|FILE_SHARE_WRITE,
845
                             NULL, OPEN_ALWAYS, 0, NULL);
846
  if (h->lockhd == INVALID_HANDLE_VALUE)
847
    {
848
      int saveerrno = map_w32_to_errno (GetLastError ());
849
      all_lockfiles = h->next;
850
      UNLOCK_all_lockfiles ();
851
      my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
852
      xfree (h->lockname);
853
      xfree (h);
854
      my_set_errno (saveerrno);
855
      return NULL;
856
    }
857
  return h;
858
}
859
#endif /*HAVE_DOSISH_SYSTEM*/
860
861
862
/* Create a lockfile for a file name FILE_TO_LOCK and returns an
863
   object of type dotlock_t which may be used later to actually acquire
864
   the lock.  A cleanup routine gets installed to cleanup left over
865
   locks or other files used internally by the lock mechanism.
866
867
   Calling this function with NULL does only install the atexit
868
   handler and may thus be used to assure that the cleanup is called
869
   after all other atexit handlers.
870
871
   This function creates a lock file in the same directory as
872
   FILE_TO_LOCK using that name and a suffix of ".lock".  Note that on
873
   POSIX systems a temporary file ".#lk.<hostname>.pid[.threadid] is
874
   used.
875
876
   FLAGS must be 0.
877
878
   The function returns an new handle which needs to be released using
879
   destroy_dotlock but gets also released at the termination of the
880
   process.  On error NULL is returned.
881
 */
882
883
dotlock_t
884
dotlock_create (const char *file_to_lock, unsigned int flags)
885
3
{
886
3
  static int initialized;
887
3
  dotlock_t h;
888
889
3
  if ( !initialized )
890
1
    {
891
1
      atexit (dotlock_remove_lockfiles);
892
1
      initialized = 1;
893
1
    }
894
895
3
  if ( !file_to_lock )
896
0
    return NULL;  /* Only initialization was requested.  */
897
898
3
  if (flags)
899
0
    {
900
0
      my_set_errno (EINVAL);
901
0
      return NULL;
902
0
    }
903
904
3
  h = xtrycalloc (1, sizeof *h);
905
3
  if (!h)
906
0
    return NULL;
907
3
  h->extra_fd = -1;
908
909
3
  if (never_lock)
910
0
    {
911
0
      h->disable = 1;
912
0
      LOCK_all_lockfiles ();
913
0
      h->next = all_lockfiles;
914
0
      all_lockfiles = h;
915
0
      UNLOCK_all_lockfiles ();
916
0
      return h;
917
0
    }
918
919
#ifdef HAVE_DOSISH_SYSTEM
920
  return dotlock_create_w32 (h, file_to_lock);
921
#else /*!HAVE_DOSISH_SYSTEM */
922
3
  return dotlock_create_unix (h, file_to_lock);
923
3
#endif /*!HAVE_DOSISH_SYSTEM*/
924
3
}
925
926
927

928
/* Convenience function to store a file descriptor (or any other
929
   integer value) in the context of handle H.  */
930
void
931
dotlock_set_fd (dotlock_t h, int fd)
932
0
{
933
0
  h->extra_fd = fd;
934
0
}
935
936
/* Convenience function to retrieve a file descriptor (or any other
937
   integer value) stored in the context of handle H.  */
938
int
939
dotlock_get_fd (dotlock_t h)
940
0
{
941
0
  return h->extra_fd;
942
0
}
943
944
945

946
#ifdef HAVE_POSIX_SYSTEM
947
/* Unix specific code of destroy_dotlock.  */
948
static void
949
dotlock_destroy_unix (dotlock_t h)
950
3
{
951
3
  if (h->locked && h->lockname)
952
0
    unlink (h->lockname);
953
3
  if (h->tname && !h->use_o_excl)
954
3
    unlink (h->tname);
955
3
  xfree (h->tname);
956
3
}
957
#endif /*HAVE_POSIX_SYSTEM*/
958
959
960
#ifdef HAVE_DOSISH_SYSTEM
961
/* Windows specific code of destroy_dotlock.  */
962
static void
963
dotlock_destroy_w32 (dotlock_t h)
964
{
965
  if (h->locked)
966
    {
967
      OVERLAPPED ovl;
968
969
      memset (&ovl, 0, sizeof ovl);
970
      UnlockFileEx (h->lockhd, 0, 1, 0, &ovl);
971
    }
972
  CloseHandle (h->lockhd);
973
}
974
#endif /*HAVE_DOSISH_SYSTEM*/
975
976
977
/* Destroy the lock handle H and release the lock.  */
978
void
979
dotlock_destroy (dotlock_t h)
980
3
{
981
3
  dotlock_t hprev, htmp;
982
983
3
  if ( !h )
984
0
    return;
985
986
  /* First remove the handle from our global list of all locks. */
987
3
  LOCK_all_lockfiles ();
988
3
  for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
989
1
    if (htmp == h)
990
1
      {
991
1
        if (hprev)
992
0
          hprev->next = htmp->next;
993
1
        else
994
1
          all_lockfiles = htmp->next;
995
1
        h->next = NULL;
996
1
        break;
997
1
      }
998
3
  UNLOCK_all_lockfiles ();
999
1000
  /* Then destroy the lock. */
1001
3
  if (!h->disable)
1002
3
    {
1003
#ifdef HAVE_DOSISH_SYSTEM
1004
      dotlock_destroy_w32 (h);
1005
#else /* !HAVE_DOSISH_SYSTEM */
1006
3
      dotlock_destroy_unix (h);
1007
3
#endif /* HAVE_DOSISH_SYSTEM */
1008
3
      xfree (h->lockname);
1009
3
    }
1010
3
  xfree(h);
1011
3
}
1012
1013
1014

1015
#ifdef HAVE_POSIX_SYSTEM
1016
/* Unix specific code of make_dotlock.  Returns 0 on success and -1 on
1017
   error.  */
1018
static int
1019
dotlock_take_unix (dotlock_t h, long timeout)
1020
3
{
1021
3
  int wtime = 0;
1022
3
  int sumtime = 0;
1023
3
  int pid;
1024
3
  int lastpid = -1;
1025
3
  int ownerchanged;
1026
3
  const char *maybe_dead="";
1027
3
  int same_node;
1028
3
  int saveerrno;
1029
3
  int fd;
1030
1031
3
 again:
1032
3
  if (h->use_o_excl)
1033
0
    {
1034
      /* No hardlink support - use open(O_EXCL).  */
1035
0
      do
1036
0
        {
1037
0
          my_set_errno (0);
1038
0
          fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
1039
0
                     S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
1040
0
        }
1041
0
      while (fd == -1 && errno == EINTR);
1042
1043
0
      if (fd == -1 && errno == EEXIST)
1044
0
        ; /* Lock held by another process.  */
1045
0
      else if (fd == -1)
1046
0
        {
1047
0
          saveerrno = errno;
1048
0
          my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
1049
0
                      h->lockname, strerror (saveerrno));
1050
0
          my_set_errno (saveerrno);
1051
0
          return -1;
1052
0
        }
1053
0
      else
1054
0
        {
1055
0
          char pidstr[16];
1056
1057
0
          snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid());
1058
0
          if (write (fd, pidstr, 11 ) == 11
1059
0
              && write (fd, h->tname + h->nodename_off,h->nodename_len)
1060
0
              == h->nodename_len
1061
0
              && write (fd, "\n", 1) == 1
1062
0
              && !close (fd))
1063
0
            {
1064
0
              h->locked = 1;
1065
0
              return 0;
1066
0
            }
1067
          /* Write error.  */
1068
0
          saveerrno = errno;
1069
0
          my_error_2 ("lock not made: writing to '%s' failed: %s\n",
1070
0
                      h->lockname, strerror (errno));
1071
0
          close (fd);
1072
0
          unlink (h->lockname);
1073
0
          my_set_errno (saveerrno);
1074
0
          return -1;
1075
0
        }
1076
0
    }
1077
3
  else /* Standard method:  Use hardlinks.  */
1078
3
    {
1079
3
      struct stat sb;
1080
1081
      /* We ignore the return value of link() because it is unreliable.  */
1082
3
      (void) link (h->tname, h->lockname);
1083
1084
3
      if (stat (h->tname, &sb))
1085
0
        {
1086
0
          saveerrno = errno;
1087
0
          my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
1088
0
                      strerror (errno));
1089
          /* In theory this might be a severe error: It is possible
1090
             that link succeeded but stat failed due to changed
1091
             permissions.  We can't do anything about it, though.  */
1092
0
          my_set_errno (saveerrno);
1093
0
          return -1;
1094
0
        }
1095
1096
3
      if (sb.st_nlink == 2)
1097
3
        {
1098
3
          h->locked = 1;
1099
3
          return 0; /* Okay.  */
1100
3
        }
1101
3
    }
1102
1103
  /* Check for stale lock files.  */
1104
0
  if ( (pid = read_lockfile (h, &same_node, &fd)) == -1 )
1105
0
    {
1106
0
      if ( errno != ENOENT )
1107
0
        {
1108
0
          saveerrno = errno;
1109
0
          my_info_0 ("cannot read lockfile\n");
1110
0
          my_set_errno (saveerrno);
1111
0
          return -1;
1112
0
        }
1113
0
      my_info_0 ("lockfile disappeared\n");
1114
0
      goto again;
1115
0
    }
1116
0
  else if ( (pid == getpid() && same_node)
1117
0
            || (same_node && kill (pid, 0) && errno == ESRCH) )
1118
    /* Stale lockfile is detected. */
1119
0
    {
1120
0
      struct stat sb;
1121
1122
      /* Check if it's unlocked during examining the lockfile.  */
1123
0
      if (fstat (fd, &sb) || sb.st_nlink == 0)
1124
0
        {
1125
          /* It's gone already by another process.  */
1126
0
          close (fd);
1127
0
          goto again;
1128
0
        }
1129
1130
      /*
1131
       * Here, although it's quite _rare_, we have a race condition.
1132
       *
1133
       * When multiple processes race on a stale lockfile, detecting
1134
       * AND removing should be done atomically.  That is, to work
1135
       * correctly, the file to be removed should be the one which is
1136
       * examined for detection.
1137
       *
1138
       * But, when it's not atomic, consider the case for us where it
1139
       * takes some time between the detection and the removal of the
1140
       * lockfile.
1141
       *
1142
       * In this situation, it is possible that the file which was
1143
       * detected as stale is already removed by another process and
1144
       * then new lockfile is created (by that process or other one).
1145
       *
1146
       * And it is newly created valid lockfile which is going to be
1147
       * removed by us.
1148
       *
1149
       * Consider this long comment as it expresses possible (long)
1150
       * time between fstat above and unlink below; Meanwhile, the
1151
       * lockfile in question may be removed and there may be new
1152
       * valid one.
1153
       *
1154
       * In short, when you see the message of removing stale lockfile
1155
       * when there are multiple processes for the work, there is
1156
       * (very) little possibility something went wrong.
1157
       */
1158
1159
0
      unlink (h->lockname);
1160
0
      my_info_1 (_("removing stale lockfile (created by %d)\n"), pid);
1161
0
      close (fd);
1162
0
      goto again;
1163
0
    }
1164
1165
0
  close (fd);
1166
0
  if (lastpid == -1)
1167
0
    lastpid = pid;
1168
0
  ownerchanged = (pid != lastpid);
1169
1170
0
  if (timeout)
1171
0
    {
1172
0
      struct timeval tv;
1173
1174
      /* Wait until lock has been released.  We use increasing retry
1175
         intervals of 50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s
1176
         but reset it if the lock owner meanwhile changed.  */
1177
0
      if (!wtime || ownerchanged)
1178
0
        wtime = 50;
1179
0
      else if (wtime < 800)
1180
0
        wtime *= 2;
1181
0
      else if (wtime == 800)
1182
0
        wtime = 2000;
1183
0
      else if (wtime < 8000)
1184
0
        wtime *= 2;
1185
1186
0
      if (timeout > 0)
1187
0
        {
1188
0
          if (wtime > timeout)
1189
0
            wtime = timeout;
1190
0
          timeout -= wtime;
1191
0
        }
1192
1193
0
      sumtime += wtime;
1194
0
      if (sumtime >= 1500)
1195
0
        {
1196
0
          sumtime = 0;
1197
0
          my_info_3 (_("waiting for lock (held by %d%s) %s...\n"),
1198
0
                     pid, maybe_dead, maybe_deadlock(h)? _("(deadlock?) "):"");
1199
0
        }
1200
1201
1202
0
      tv.tv_sec = wtime / 1000;
1203
0
      tv.tv_usec = (wtime % 1000) * 1000;
1204
0
      select (0, NULL, NULL, NULL, &tv);
1205
0
      goto again;
1206
0
    }
1207
1208
0
  my_set_errno (EACCES);
1209
0
  return -1;
1210
0
}
1211
#endif /*HAVE_POSIX_SYSTEM*/
1212
1213
1214
#ifdef HAVE_DOSISH_SYSTEM
1215
/* Windows specific code of make_dotlock.  Returns 0 on success and -1 on
1216
   error.  */
1217
static int
1218
dotlock_take_w32 (dotlock_t h, long timeout)
1219
{
1220
  int wtime = 0;
1221
  int w32err;
1222
  OVERLAPPED ovl;
1223
1224
 again:
1225
  /* Lock one byte at offset 0.  The offset is given by OVL.  */
1226
  memset (&ovl, 0, sizeof ovl);
1227
  if (LockFileEx (h->lockhd, (LOCKFILE_EXCLUSIVE_LOCK
1228
                              | LOCKFILE_FAIL_IMMEDIATELY), 0, 1, 0, &ovl))
1229
    {
1230
      h->locked = 1;
1231
      return 0; /* okay */
1232
    }
1233
1234
  w32err = GetLastError ();
1235
  if (w32err != ERROR_LOCK_VIOLATION)
1236
    {
1237
      my_error_2 (_("lock '%s' not made: %s\n"),
1238
                  h->lockname, w32_strerror (w32err));
1239
      my_set_errno (map_w32_to_errno (w32err));
1240
      return -1;
1241
    }
1242
1243
  if (timeout)
1244
    {
1245
      /* Wait until lock has been released.  We use retry intervals of
1246
         50ms, 100ms, 200ms, 400ms, 800ms, 2s, 4s and 8s.  */
1247
      if (!wtime)
1248
        wtime = 50;
1249
      else if (wtime < 800)
1250
        wtime *= 2;
1251
      else if (wtime == 800)
1252
        wtime = 2000;
1253
      else if (wtime < 8000)
1254
        wtime *= 2;
1255
1256
      if (timeout > 0)
1257
        {
1258
          if (wtime > timeout)
1259
            wtime = timeout;
1260
          timeout -= wtime;
1261
        }
1262
1263
      if (wtime >= 800)
1264
        my_info_1 (_("waiting for lock %s...\n"), h->lockname);
1265
1266
      Sleep (wtime);
1267
      goto again;
1268
    }
1269
1270
  my_set_errno (EACCES);
1271
  return -1;
1272
}
1273
#endif /*HAVE_DOSISH_SYSTEM*/
1274
1275
1276
/* Take a lock on H.  A value of 0 for TIMEOUT returns immediately if
1277
   the lock can't be taken, -1 waits forever (hopefully not), other
1278
   values wait for TIMEOUT milliseconds.  Returns: 0 on success  */
1279
int
1280
dotlock_take (dotlock_t h, long timeout)
1281
3
{
1282
3
  int ret;
1283
1284
3
  if ( h->disable )
1285
0
    return 0; /* Locks are completely disabled.  Return success. */
1286
1287
3
  if ( h->locked )
1288
0
    {
1289
0
      my_debug_1 ("Oops, '%s' is already locked\n", h->lockname);
1290
0
      return 0;
1291
0
    }
1292
1293
#ifdef HAVE_DOSISH_SYSTEM
1294
  ret = dotlock_take_w32 (h, timeout);
1295
#else /*!HAVE_DOSISH_SYSTEM*/
1296
3
  ret = dotlock_take_unix (h, timeout);
1297
3
#endif /*!HAVE_DOSISH_SYSTEM*/
1298
1299
3
  return ret;
1300
3
}
1301
1302
1303

1304
#ifdef HAVE_POSIX_SYSTEM
1305
/* Unix specific code of release_dotlock.  */
1306
static int
1307
dotlock_release_unix (dotlock_t h)
1308
3
{
1309
3
  int pid, same_node;
1310
3
  int saveerrno;
1311
1312
3
  pid = read_lockfile (h, &same_node, NULL);
1313
3
  if ( pid == -1 )
1314
0
    {
1315
0
      saveerrno = errno;
1316
0
      my_error_0 ("release_dotlock: lockfile error\n");
1317
0
      my_set_errno (saveerrno);
1318
0
      return -1;
1319
0
    }
1320
3
  if ( pid != getpid() || !same_node )
1321
0
    {
1322
0
      my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
1323
0
      my_set_errno (EACCES);
1324
0
      return -1;
1325
0
    }
1326
1327
3
  if ( unlink( h->lockname ) )
1328
0
    {
1329
0
      saveerrno = errno;
1330
0
      my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
1331
0
                  h->lockname);
1332
0
      my_set_errno (saveerrno);
1333
0
      return -1;
1334
0
    }
1335
  /* Fixme: As an extra check we could check whether the link count is
1336
     now really at 1. */
1337
3
  return 0;
1338
3
}
1339
#endif /*HAVE_POSIX_SYSTEM */
1340
1341
1342
#ifdef HAVE_DOSISH_SYSTEM
1343
/* Windows specific code of release_dotlock.  */
1344
static int
1345
dotlock_release_w32 (dotlock_t h)
1346
{
1347
  OVERLAPPED ovl;
1348
1349
  memset (&ovl, 0, sizeof ovl);
1350
  if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
1351
    {
1352
      int saveerrno = map_w32_to_errno (GetLastError ());
1353
      my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
1354
                  h->lockname, w32_strerror (-1));
1355
      my_set_errno (saveerrno);
1356
      return -1;
1357
    }
1358
1359
  return 0;
1360
}
1361
#endif /*HAVE_DOSISH_SYSTEM */
1362
1363
1364
/* Release a lock.  Returns 0 on success.  */
1365
int
1366
dotlock_release (dotlock_t h)
1367
3
{
1368
3
  int ret;
1369
1370
  /* To avoid atexit race conditions we first check whether there are
1371
     any locks left.  It might happen that another atexit handler
1372
     tries to release the lock while the atexit handler of this module
1373
     already ran and thus H is undefined.  */
1374
3
  LOCK_all_lockfiles ();
1375
3
  ret = !all_lockfiles;
1376
3
  UNLOCK_all_lockfiles ();
1377
3
  if (ret)
1378
0
    return 0;
1379
1380
3
  if ( h->disable )
1381
0
    return 0;
1382
1383
3
  if ( !h->locked )
1384
0
    {
1385
0
      my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
1386
0
      return 0;
1387
0
    }
1388
1389
#ifdef HAVE_DOSISH_SYSTEM
1390
  ret = dotlock_release_w32 (h);
1391
#else
1392
3
  ret = dotlock_release_unix (h);
1393
3
#endif
1394
1395
3
  if (!ret)
1396
3
    h->locked = 0;
1397
3
  return ret;
1398
3
}
1399
1400
1401

1402
/* Remove all lockfiles.  This is called by the atexit handler
1403
   installed by this module but may also be called by other
1404
   termination handlers.  */
1405
void
1406
dotlock_remove_lockfiles (void)
1407
1
{
1408
1
  dotlock_t h, h2;
1409
1410
  /* First set the lockfiles list to NULL so that for example
1411
     dotlock_release is aware that this function is currently
1412
     running.  */
1413
1
  LOCK_all_lockfiles ();
1414
1
  h = all_lockfiles;
1415
1
  all_lockfiles = NULL;
1416
1
  UNLOCK_all_lockfiles ();
1417
1418
3
  while ( h )
1419
2
    {
1420
2
      h2 = h->next;
1421
2
      dotlock_destroy (h);
1422
2
      h = h2;
1423
2
    }
1424
1
}