1
0
mirror of git://git.gnupg.org/gnupg.git synced 2025-02-07 17:33:02 +01:00

Improve dotlocking.

Implement locking for W32.
This commit is contained in:
Werner Koch 2009-05-05 15:32:16 +00:00
parent 631a0de335
commit 418e61a824
4 changed files with 401 additions and 224 deletions

2
NEWS
View File

@ -4,6 +4,8 @@ Noteworthy changes in version 1.4.10 (unreleased)
* The algorithm to compute the SIG_ID status has been changed to * The algorithm to compute the SIG_ID status has been changed to
match the one from 2.0.10. match the one from 2.0.10.
* Improved file locking. Implemented it for W32.
Noteworthy changes in version 1.4.9 (2008-03-26) Noteworthy changes in version 1.4.9 (2008-03-26)
------------------------------------------------ ------------------------------------------------

View File

@ -1,12 +1,12 @@
2009-05-05 Werner Koch <wk@g10code.com> 2009-05-05 Werner Koch <wk@g10code.com>
* keygen.c (output_control_s): s/create/creation/. * keygen.c (read_parameter_file): Add keyword "Creation-Date".
(output_control_s): s/create/creation/.
(enum para_name): Add pCREATIONDATE, pKEYCREATIONDATE. Remove (enum para_name): Add pCREATIONDATE, pKEYCREATIONDATE. Remove
pCREATETIME. pCREATETIME.
(generate_keypair): Do not set old pCREATETIME. (generate_keypair): Do not set old pCREATETIME.
(parse_creation_string): New. (parse_creation_string): New.
(proc_parameter_file): Set pCREATIONDATE. (proc_parameter_file): Set pCREATIONDATE.
(read_parameter_file): Add keyword "Creation-Date".
(do_generate_keypair): Remove arg TIMESTAMP. Set it using (do_generate_keypair): Remove arg TIMESTAMP. Set it using
pKEYCREATIONDATE. pKEYCREATIONDATE.
(get_parameter_u32): Set a default pKEYCREATIONDATE. (get_parameter_u32): Set a default pKEYCREATIONDATE.

View File

@ -1,5 +1,8 @@
2009-05-05 Werner Koch <wk@g10code.com> 2009-05-05 Werner Koch <wk@g10code.com>
* dotlock.c: Merged changes from GnuPG-2. Better detection of
stale lockfiles and actual locking support on W32. Fixes bug#1028.
* miscutil.c (isotime2seconds): New. * miscutil.c (isotime2seconds): New.
2009-04-05 David Shaw <dshaw@jabberwocky.com> 2009-04-05 David Shaw <dshaw@jabberwocky.com>

View File

@ -1,6 +1,6 @@
/* dotlock.c - dotfile locking /* dotlock.c - dotfile locking
* Copyright (C) 1998, 1999, 2000, 2001, 2004, * Copyright (C) 1998, 1999, 2000, 2001, 2004,
* 2005 Free Software Foundation, Inc. * 2005, 2009 Free Software Foundation, Inc.
* *
* This file is part of GnuPG. * This file is part of GnuPG.
* *
@ -25,8 +25,11 @@
#include <ctype.h> #include <ctype.h>
#include <errno.h> #include <errno.h>
#include <unistd.h> #include <unistd.h>
#if !defined (HAVE_DOSISH_SYSTEM) #ifdef HAVE_DOSISH_SYSTEM
#include <sys/utsname.h> # define WIN32_LEAN_AND_MEAN
# include <windows.h>
#else
# include <sys/utsname.h>
#endif #endif
#include <sys/types.h> #include <sys/types.h>
#ifndef _WIN32 #ifndef _WIN32
@ -38,25 +41,50 @@
#include "types.h" #include "types.h"
#include "util.h" #include "util.h"
#include "memory.h" #include "memory.h"
#include "i18n.h"
/* The object describing a lock. */
struct dotlock_handle { struct dotlock_handle {
struct dotlock_handle *next; struct dotlock_handle *next;
char *tname; /* name of lockfile template */ char *tname; /* name of lockfile template */
char *lockname; /* name of the real lockfile */ char *lockname; /* name of the real lockfile */
int locked; /* lock status */ int locked; /* lock status */
int disable; /* locking */ int disable; /* locking */
#ifdef HAVE_DOSISH_SYSTEM
HANDLE lockhd; /* The W32 handle of the lock file. */
#else
size_t nodename_off; /* Offset in TNAME to the nodename part. */
size_t nodename_len; /* Length of the nodename part. */
#endif
}; };
/* A list of of all lock handles. */
static volatile DOTLOCK all_lockfiles; static volatile DOTLOCK all_lockfiles;
/* If this has the value true all locking is disabled. */
static int never_lock; static int never_lock;
#ifdef _REENTRANT
/* fixme: acquire mutex on all_lockfiles */
# define lock_all_lockfiles(h) do { } while (0)
# define unlock_all_lockfiles(h) do { } while (0)
#else
# define lock_all_lockfiles(h) do { } while (0)
# define unlock_all_lockfiles(h) do { } while (0)
#endif
void void
disable_dotlock(void) disable_dotlock(void)
{ {
never_lock = 1; never_lock = 1;
} }
/**************** /****************
* Create a lockfile with the given name and return an object of * Create a lockfile with the given name and return an object of
* type DOTLOCK which may be used later to actually do the lock. * type DOTLOCK which may be used later to actually do the lock.
@ -78,14 +106,16 @@ create_dotlock( const char *file_to_lock )
{ {
static int initialized; static int initialized;
DOTLOCK h; DOTLOCK h;
#if !defined (HAVE_DOSISH_SYSTEM) #ifndef HAVE_DOSISH_SYSTEM
int fd = -1; int fd = -1;
char pidstr[16]; char pidstr[16];
struct utsname utsbuf; struct utsname utsbuf;
const char *nodename; const char *nodename;
const char *dirpart; const char *dirpart;
int dirpartlen; int dirpartlen;
#endif size_t tnamelen;
int n;
#endif /*!HAVE_DOSISH_SYSTEM*/
if( !initialized ) { if( !initialized ) {
atexit( remove_lockfiles ); atexit( remove_lockfiles );
@ -97,18 +127,15 @@ create_dotlock( const char *file_to_lock )
h = xmalloc_clear( sizeof *h ); h = xmalloc_clear( sizeof *h );
if( never_lock ) { if( never_lock ) {
h->disable = 1; h->disable = 1;
#ifdef _REENTRANT lock_all_lockfiles (h);
/* fixme: aquire mutex on all_lockfiles */
#endif
h->next = all_lockfiles; h->next = all_lockfiles;
all_lockfiles = h; all_lockfiles = h;
return h; return h;
} }
#if !defined (HAVE_DOSISH_SYSTEM) #ifndef HAVE_DOSISH_SYSTEM
sprintf( pidstr, "%10d\n", (int)getpid() ); snprintf (pidstr, sizeof pidstr, "%10d\n", (int)getpid() );
/* fixme: add the hostname to the second line (FQDN or IP addr?) */
/* create a temporary file */ /* create a temporary file */
if( uname( &utsbuf ) ) if( uname( &utsbuf ) )
@ -116,14 +143,14 @@ create_dotlock( const char *file_to_lock )
else else
nodename = utsbuf.nodename; nodename = utsbuf.nodename;
#ifdef __riscos__ # ifdef __riscos__
{ {
char *iter = (char *) nodename; char *iter = (char *) nodename;
for (; iter[0]; iter++) for (; iter[0]; iter++)
if (iter[0] == '.') if (iter[0] == '.')
iter[0] = '/'; iter[0] = '/';
} }
#endif /* __riscos__ */ # endif /* __riscos__ */
if( !(dirpart = strrchr( file_to_lock, DIRSEP_C )) ) { if( !(dirpart = strrchr( file_to_lock, DIRSEP_C )) ) {
dirpart = EXTSEP_S; dirpart = EXTSEP_S;
@ -134,25 +161,27 @@ create_dotlock( const char *file_to_lock )
dirpart = file_to_lock; dirpart = file_to_lock;
} }
#ifdef _REENTRANT lock_all_lockfiles (h);
/* fixme: aquire mutex on all_lockfiles */
#endif
h->next = all_lockfiles; h->next = all_lockfiles;
all_lockfiles = h; all_lockfiles = h;
h->tname = xmalloc( dirpartlen + 6+30+ strlen(nodename) + 11 ); tnamelen = dirpartlen + 6+30+ strlen(nodename) + 10;
#ifndef __riscos__ h->tname = xmalloc (tnamelen + 1);
sprintf( h->tname, "%.*s/.#lk%p.%s.%d", h->nodename_len = strlen (nodename);
dirpartlen, dirpart, (void *)h, nodename, (int)getpid() );
#else /* __riscos__ */ # ifndef __riscos__
sprintf( h->tname, "%.*s.lk%p/%s/%d", snprintf (h->tname, tnamelen, "%.*s/.#lk%p.%n%s.%d",
dirpartlen, dirpart, (void *)h, nodename, (int)getpid() ); dirpartlen, dirpart, (void *)h, &n, nodename, (int)getpid ());
#endif /* __riscos__ */ # else /* __riscos__ */
snprintf (h->tname, tnamelen, "%.*s.lk%p/%n%s/%d",
dirpartlen, dirpart, (void *)h, &n, nodename, (int)getpid ());
# endif /* __riscos__ */
h->nodename_off = n;
do { do {
errno = 0; errno = 0;
fd = open( h->tname, O_WRONLY|O_CREAT|O_EXCL, fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR ); S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR);
} while( fd == -1 && errno == EINTR ); } while( fd == -1 && errno == EINTR );
if( fd == -1 ) { if( fd == -1 ) {
all_lockfiles = h->next; all_lockfiles = h->next;
@ -162,78 +191,110 @@ create_dotlock( const char *file_to_lock )
xfree(h); xfree(h);
return NULL; return NULL;
} }
if( write(fd, pidstr, 11 ) != 11 ) { if (write (fd, pidstr, 11) != 11)
all_lockfiles = h->next; goto write_failed;
#ifdef _REENTRANT if (write (fd, nodename, strlen (nodename)) != strlen (nodename))
/* release mutex */ goto write_failed;
#endif if (write (fd, "\n", 1 ) != 1)
log_fatal( "error writing to `%s': %s\n", h->tname, strerror(errno) ); goto write_failed;
close(fd); if (close (fd))
unlink(h->tname); goto write_failed;
xfree(h->tname);
xfree(h);
return NULL;
}
if( close(fd) ) {
all_lockfiles = h->next;
#ifdef _REENTRANT
/* release mutex */
#endif
log_error( "error closing `%s': %s\n", h->tname, strerror(errno));
unlink(h->tname);
xfree(h->tname);
xfree(h);
return NULL;
}
#ifdef _REENTRANT unlock_all_lockfiles (h);
/* release mutex */
#endif
#endif
h->lockname = xmalloc( strlen(file_to_lock) + 6 ); h->lockname = xmalloc( strlen(file_to_lock) + 6 );
strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock"); strcpy(stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
return h; return h;
write_failed:
all_lockfiles = h->next;
unlock_all_lockfiles (h);
log_error ("error writing to `%s': %s\n", h->tname, strerror(errno));
close (fd);
unlink (h->tname);
xfree (h->tname);
xfree (h);
return NULL;
#else /* HAVE_DOSISH_SYSTEM */
/* The Windows version does not need a temporary file but uses the
plain lock file along with record locking. We create this file
here so that we later do only need to do the file locking. For
error reporting it is useful to keep the name of the file in the
handle. */
h->next = all_lockfiles;
all_lockfiles = h;
h->lockname = xmalloc ( strlen (file_to_lock) + 6 );
strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
/* If would be nice if we would use the FILE_FLAG_DELETE_ON_CLOSE
along with FILE_SHARE_DELETE but that does not work due to a race
condition: Despite the OPEN_ALWAYS flag CreateFile may return an
error and we can't reliable create/open the lock file unless we
would wait here until it works - however there are other valid
reasons why a lock file can't be created and thus the process
would not stop as expected but spin until Windows crashes. Our
solution is to keep the lock file open; that does not harm. */
h->lockhd = CreateFile (h->lockname,
GENERIC_READ|GENERIC_WRITE,
FILE_SHARE_READ|FILE_SHARE_WRITE,
NULL, OPEN_ALWAYS, 0, NULL);
if (h->lockhd == INVALID_HANDLE_VALUE)
{
log_error (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
all_lockfiles = h->next;
xfree (h->lockname);
xfree (h);
return NULL;
}
return h;
#endif /* HAVE_DOSISH_SYSTEM */
} }
void void
destroy_dotlock ( DOTLOCK h ) destroy_dotlock ( DOTLOCK h )
{ {
#if !defined (HAVE_DOSISH_SYSTEM) DOTLOCK hprev, htmp;
if ( h )
if (!h)
return;
/* First remove the handle from our global list of all locks. */
for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next)
if (htmp == h)
{ {
DOTLOCK hprev, htmp; if (hprev)
hprev->next = htmp->next;
/* First remove the handle from our global list of all locks. */ else
for (hprev=NULL, htmp=all_lockfiles; htmp; hprev=htmp, htmp=htmp->next) all_lockfiles = htmp->next;
if (htmp == h) h->next = NULL;
{ break;
if (hprev)
hprev->next = htmp->next;
else
all_lockfiles = htmp->next;
h->next = NULL;
break;
}
/* Second destroy the lock. */
if (!h->disable)
{
if (h->locked && h->lockname)
unlink (h->lockname);
if (h->tname)
unlink (h->tname);
xfree (h->tname);
xfree (h->lockname);
}
xfree(h);
} }
/* Second destroy the lock. */
if (!h->disable)
{
#ifdef HAVE_DOSISH_SYSTEM
if (h->locked)
UnlockFile (h->lockhd, 0, 0, 1, 0);
CloseHandle (h->lockhd);
#else
if (h->locked && h->lockname)
unlink (h->lockname);
if (h->tname)
unlink (h->tname);
xfree (h->tname);
#endif #endif
xfree (h->lockname);
}
xfree(h);
} }
#ifndef HAVE_DOSISH_SYSTEM
#ifndef HAVE_DOSISH_SYSTEM
static int static int
maybe_deadlock( DOTLOCK h ) maybe_deadlock( DOTLOCK h )
{ {
@ -245,44 +306,101 @@ maybe_deadlock( DOTLOCK h )
} }
return 0; return 0;
} }
#endif /* !HAVE_DOSISH_SYSTEM */
/****************
* Read the lock file and return the pid, returns -1 on error. /* Read the lock file and return the pid, returns -1 on error. True
*/ will be stored in the integer at address SAME_NODE if the lock file
has been created on the same node. */
#ifndef HAVE_DOSISH_SYSTEM
static int static int
read_lockfile( const char *name ) read_lockfile (DOTLOCK h, int *same_node )
{ {
int fd, pid; char buffer_space[10+1+70+1]; /* 70 is just an estimated value; node
char pidstr[16]; names are usually shorter. */
int fd;
int pid = -1;
char *buffer, *p;
size_t expected_len;
int res, nread;
*same_node = 0;
expected_len = 10 + 1 + h->nodename_len + 1;
if ( expected_len >= sizeof buffer_space)
buffer = xmalloc (expected_len);
else
buffer = buffer_space;
if( (fd = open(name, O_RDONLY)) == -1 ) { if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
int e = errno; {
log_debug("error opening lockfile `%s': %s\n", name, strerror(errno) ); int e = errno;
errno = e; log_info ("error opening lockfile `%s': %s\n",
return -1; h->lockname, strerror(errno) );
if (buffer != buffer_space)
xfree (buffer);
errno = e; /* Need to return ERRNO here. */
return -1;
} }
if( read(fd, pidstr, 10 ) != 10 ) { /* Read 10 digits w/o newline */
log_debug("error reading lockfile `%s'", name ); p = buffer;
close(fd); nread = 0;
errno = 0; do
return -1; {
res = read (fd, p, expected_len - nread);
if (res == -1 && errno == EINTR)
continue;
if (res < 0)
{
log_info ("error reading lockfile `%s'", h->lockname );
close (fd);
if (buffer != buffer_space)
xfree (buffer);
errno = 0; /* Do not return an inappropriate ERRNO. */
return -1;
}
p += res;
nread += res;
} }
pidstr[10] = 0; /* terminate pid string */ while (res && nread != expected_len);
close(fd); close (fd);
pid = atoi(pidstr);
if (nread < 11)
{
log_info ("invalid size of lockfile `%s'", h->lockname );
if (buffer != buffer_space)
xfree (buffer);
errno = 0; /* Better don't return an inappropriate ERRNO. */
return -1;
}
if (buffer[10] != '\n'
|| (buffer[10] = 0, pid = atoi (buffer)) == -1
#ifndef __riscos__ #ifndef __riscos__
if( !pid || pid == -1 ) { || !pid
#else /* __riscos__ */ #else /* __riscos__ */
if( (!pid && riscos_getpid()) || pid == -1 ) { || (!pid && riscos_getpid())
#endif /* __riscos__ */ #endif /* __riscos__ */
log_error("invalid pid %d in lockfile `%s'", pid, name ); )
errno = 0; {
return -1; log_error ("invalid pid %d in lockfile `%s'", pid, h->lockname );
if (buffer != buffer_space)
xfree (buffer);
errno = 0;
return -1;
} }
return pid;
if (nread == expected_len
&& !memcmp (h->tname+h->nodename_off, buffer+11, h->nodename_len)
&& buffer[11+h->nodename_len] == '\n')
*same_node = 1;
if (buffer != buffer_space)
xfree (buffer);
return pid;
} }
#endif /* !HAVE_DOSISH_SYSTEM */ #endif /* !HAVE_DOSISH_SYSTEM */
/**************** /****************
* Do a lock on H. A TIMEOUT of 0 returns immediately, * Do a lock on H. A TIMEOUT of 0 returns immediately,
* -1 waits forever (hopefully not), other * -1 waits forever (hopefully not), other
@ -292,90 +410,129 @@ read_lockfile( const char *name )
int int
make_dotlock( DOTLOCK h, long timeout ) make_dotlock( DOTLOCK h, long timeout )
{ {
#if defined (HAVE_DOSISH_SYSTEM) int backoff=0;
#ifndef HAVE_DOSISH_SYSTEM
int pid;
const char *maybe_dead="";
int same_node;
#endif
if (h->disable)
return 0; return 0;
#else
int pid;
const char *maybe_dead="";
int backoff=0;
if( h->disable ) { if (h->locked)
return 0; {
}
if( h->locked ) {
#ifndef __riscos__ #ifndef __riscos__
log_debug("oops, `%s' is already locked\n", h->lockname ); log_debug ("oops, `%s' is already locked\n", h->lockname);
#endif /* !__riscos__ */ #endif /* !__riscos__ */
return 0; return 0;
} }
for (;;)
{
#ifndef HAVE_DOSISH_SYSTEM
# ifndef __riscos__
if( !link(h->tname, h->lockname) )
{
/* fixme: better use stat to check the link count */
h->locked = 1;
return 0; /* okay */
}
if (errno != EEXIST)
{
log_error ("lock not made: link() failed: %s\n", strerror(errno));
return -1;
}
# else /* __riscos__ */
if ( !riscos_renamefile(h->tname, h->lockname) )
{
h->locked = 1;
return 0; /* okay */
}
if (errno != EEXIST)
{
log_error ("lock not made: rename() failed: %s\n", strerror(errno));
return -1;
}
# endif /* __riscos__ */
for(;;) { if ((pid = read_lockfile (h, &same_node)) == -1 )
#ifndef __riscos__ {
if( !link(h->tname, h->lockname) ) { if (errno != ENOENT)
/* fixme: better use stat to check the link count */ {
h->locked = 1; log_info ("cannot read lockfile\n");
return 0; /* okay */ return -1;
}
if( errno != EEXIST ) {
log_error( "lock not made: link() failed: %s\n", strerror(errno) );
return -1;
}
#else /* __riscos__ */
if( !riscos_renamefile(h->tname, h->lockname) ) {
h->locked = 1;
return 0; /* okay */
}
if( errno != EEXIST ) {
log_error( "lock not made: rename() failed: %s\n", strerror(errno) );
return -1;
}
#endif /* __riscos__ */
if( (pid = read_lockfile(h->lockname)) == -1 ) {
if( errno != ENOENT ) {
log_info("cannot read lockfile\n");
return -1;
} }
log_info( "lockfile disappeared\n"); log_info ("lockfile disappeared\n");
continue; continue;
} }
else if( pid == getpid() ) { else if (pid == getpid ())
log_info( "Oops: lock already held by us\n"); {
h->locked = 1; log_info ("Oops: lock already held by us\n");
return 0; /* okay */ h->locked = 1;
return 0; /* okay */
} }
else if( kill(pid, 0) && errno == ESRCH ) { else if (same_node && kill(pid, 0) && errno == ESRCH)
#ifndef __riscos__ {
maybe_dead = " - probably dead"; # ifndef __riscos__
#if 0 /* we should not do this without checking the permissions */ log_info (_("removing stale lockfile (created by %d)\n"), pid );
/* and the hostname */ unlink (h->lockname);
log_info( "removing stale lockfile (created by %d)", pid ); continue;
#endif # else /* __riscos__ */
#else /* __riscos__ */ /* We are *pretty* sure that the other task is dead and
/* we are *pretty* sure that the other task is dead and therefore therefore we remove the other lock file. */
we remove the other lock file */ maybe_dead = " - probably dead - removing lock";
maybe_dead = " - probably dead - removing lock"; unlink (h->lockname);
unlink(h->lockname); # endif /* __riscos__ */
#endif /* __riscos__ */
} }
if( timeout == -1 ) {
struct timeval tv; if (timeout == -1)
log_info( "waiting for lock (held by %d%s) %s...\n", {
pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":""); struct timeval tv;
log_info ("waiting for lock (held by %d%s) %s...\n",
pid, maybe_dead, maybe_deadlock(h)? "(deadlock?) ":"");
/* can't use sleep, cause signals may be blocked */ /* We can't use sleep, because signals may be blocked. */
tv.tv_sec = 1 + backoff; tv.tv_sec = 1 + backoff;
tv.tv_usec = 0; tv.tv_usec = 0;
select(0, NULL, NULL, NULL, &tv); select (0, NULL, NULL, NULL, &tv);
if( backoff < 10 ) if (backoff < 10)
backoff++ ; backoff++ ;
} }
else else
return -1; return -1;
#else /*HAVE_DOSISH_SYSTEM*/
int w32err;
if (LockFile (h->lockhd, 0, 0, 1, 0))
{
h->locked = 1;
return 0; /* okay */
}
w32err = GetLastError ();
if (w32err != ERROR_LOCK_VIOLATION)
{
log_error (_("lock `%s' not made: %s\n"),
h->lockname, w32_strerror (w32err));
return -1;
}
if (timeout == -1)
{
/* Wait until lock has been released. */
log_info (_("waiting for lock %s...\n"), h->lockname);
Sleep ((1 + backoff)*1000);
if ( backoff < 10 )
backoff++ ;
}
else
return -1;
#endif /*HAVE_DOSISH_SYSTEM*/
} }
/*not reached */ /*NOTREACHED */
#endif
} }
@ -384,56 +541,71 @@ make_dotlock( DOTLOCK h, long timeout )
* Returns: 0 := success * Returns: 0 := success
*/ */
int int
release_dotlock( DOTLOCK h ) release_dotlock (DOTLOCK h)
{ {
#if defined (HAVE_DOSISH_SYSTEM) #ifndef HAVE_DOSISH_SYSTEM
return 0; int pid, same_node;
#else
int pid;
/* To avoid atexit race conditions we first check whether there
are any locks left. It might happen that another atexit
handler tries to release the lock while the atexit handler of
this module already ran and thus H is undefined. */
if(!all_lockfiles)
return 0;
if( h->disable )
return 0;
if( !h->locked ) {
log_debug("oops, `%s' is not locked\n", h->lockname );
return 0;
}
pid = read_lockfile( h->lockname );
if( pid == -1 ) {
log_error( "release_dotlock: lockfile error\n");
return -1;
}
if( pid != getpid() ) {
log_error( "release_dotlock: not our lock (pid=%d)\n", pid);
return -1;
}
#ifndef __riscos__
if( unlink( h->lockname ) ) {
log_error( "release_dotlock: error removing lockfile `%s'",
h->lockname);
return -1;
}
#else /* __riscos__ */
if( riscos_renamefile(h->lockname, h->tname) ) {
log_error( "release_dotlock: error renaming lockfile `%s' to `%s'",
h->lockname, h->tname);
return -1;
}
#endif /* __riscos__ */
/* fixme: check that the link count is now 1 */
h->locked = 0;
return 0;
#endif #endif
/* To avoid atexit race conditions we first check whether there are
any locks left. It might happen that another atexit handler
tries to release the lock while the atexit handler of this module
already ran and thus H is undefined. */
if (!all_lockfiles)
return 0;
if (h->disable)
return 0;
if (!h->locked)
{
log_debug("oops, `%s' is not locked\n", h->lockname );
return 0;
}
#ifndef HAVE_DOSISH_SYSTEM
pid = read_lockfile (h, &same_node);
if (pid == -1)
{
log_error ("release_dotlock: lockfile error\n");
return -1;
}
if (pid != getpid () || !same_node)
{
log_error ("release_dotlock: not our lock (pid=%d)\n", pid);
return -1;
}
# ifndef __riscos__
if (unlink (h->lockname))
{
log_error ("release_dotlock: error removing lockfile `%s'",
h->lockname);
return -1;
}
# else /* __riscos__ */
if( riscos_renamefile(h->lockname, h->tname) )
{
log_error( "release_dotlock: error renaming lockfile `%s' to `%s'",
h->lockname, h->tname);
return -1;
}
# endif /* __riscos__ */
#else /*HAVE_DOSISH_SYSTEM*/
if (!UnlockFile (h->lockhd, 0, 0, 1, 0))
{
log_error ("release_dotlock: error removing lockfile `%s': %s\n",
h->lockname, w32_strerror (-1));
return -1;
}
#endif /*HAVE_DOSISH_SYSTEM*/
h->locked = 0;
return 0;
} }
void void
remove_lockfiles() remove_lockfiles()
{ {