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