common: Prepare for parsing mail sub-addresses.
[gnupg.git] / common / dotlock.c
index b4734b9..1bc31d8 100644 (file)
@@ -2,10 +2,10 @@
  * Copyright (C) 1998, 2000, 2001, 2003, 2004,
  *               2005, 2006, 2008, 2010, 2011 Free Software Foundation, Inc.
  *
- * This file is part of JNLIB, which is a subsystem of GnuPG.
+ * This file is part of GnuPG.
  *
- * JNLIB is free software; you can redistribute it and/or modify it
- * under the terms of either
+ * GnuPG is free software; you can redistribute and/or modify this
+ * part of GnuPG under the terms of either
  *
  *   - the GNU Lesser General Public License as published by the Free
  *     Software Foundation; either version 3 of the License, or (at
  *
  * or both in parallel, as here.
  *
- * JNLIB is distributed in the hope that it will be useful, but
+ * GnuPG is distributed in the hope that it will be useful, but
  * WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  * General Public License for more details.
  *
  * You should have received a copies of the GNU General Public License
  * and the GNU Lesser General Public License along with this program;
- * if not, see <http://www.gnu.org/licenses/>.
+ * if not, see <https://www.gnu.org/licenses/>.
  *
  * ALTERNATIVELY, this file may be distributed under the terms of the
  * following license, in which case the provisions of this license are
@@ -52,7 +52,7 @@
  *    products derived from this software without specific prior
  *    written permission.
  *
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
    you pass (0) instead of (-1) the function does not wait in case the
    file is already locked but returns -1 and sets ERRNO to EACCES.
    Any other positive value for the second parameter is considered a
-   timeout valuie in milliseconds.
+   timeout value in milliseconds.
 
    To release the lock you call:
 
 #endif
 
 #ifdef GNUPG_MAJOR_VERSION
-# include "libjnlib-config.h"
+# include "util.h"
+# include "common-defs.h"
+# include "stringhelp.h"  /* For stpcpy and w32_strerror. */
 #endif
 #ifdef HAVE_W32CE_SYSTEM
 # include "utf8conv.h"  /* WindowsCE requires filename conversion.  */
 # endif
 #endif
 
-/* In GnuPG we use wrappers around the malloc fucntions.  If they are
+/* In GnuPG we use wrappers around the malloc functions.  If they are
    not defined we assume that this code is used outside of GnuPG and
    fall back to the regular malloc functions.  */
-#ifndef jnlib_malloc
-# define jnlib_malloc(a)     malloc ((a))
-# define jnlib_calloc(a,b)   calloc ((a), (b))
-# define jnlib_free(a)      free ((a))
+#ifndef xtrymalloc
+# define xtrymalloc(a)     malloc ((a))
+# define xtrycalloc(a,b)   calloc ((a), (b))
+# define xfree(a)         free ((a))
 #endif
 
-/* Wrapper to set ERRNO.  */
-#ifndef jnlib_set_errno
-# ifdef HAVE_W32CE_SYSTEM
-#  define jnlib_set_errno(e)  gpg_err_set_errno ((e))
-# else
-#  define jnlib_set_errno(e)  do { errno = (e); } while (0)
-# endif
+/* Wrapper to set ERRNO (required for W32CE).  */
+#ifdef GPG_ERROR_VERSION
+#  define my_set_errno(e)  gpg_err_set_errno ((e))
+#else
+#  define my_set_errno(e)  do { errno = (e); } while (0)
 #endif
 
 /* Gettext macro replacement.  */
@@ -411,8 +411,9 @@ struct dotlock_handle
 };
 
 
-/* A list of of all lock handles.  The volatile attribute might help
-   if used in an atexit handler.  */
+/* A list of all lock handles.  The volatile attribute might help
+   if used in an atexit handler.  Note that [UN]LOCK_all_lockfiles
+   must not change ERRNO. */
 static volatile dotlock_t all_lockfiles;
 #ifdef DOTLOCK_USE_PTHREAD
 static pthread_mutex_t all_lockfiles_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -434,6 +435,41 @@ static int never_lock;
 
 
 
+\f
+#ifdef HAVE_DOSISH_SYSTEM
+static int
+map_w32_to_errno (DWORD w32_err)
+{
+  switch (w32_err)
+    {
+    case 0:
+      return 0;
+
+    case ERROR_FILE_NOT_FOUND:
+      return ENOENT;
+
+    case ERROR_PATH_NOT_FOUND:
+      return ENOENT;
+
+    case ERROR_ACCESS_DENIED:
+      return EPERM;
+
+    case ERROR_INVALID_HANDLE:
+    case ERROR_INVALID_BLOCK:
+      return EINVAL;
+
+    case ERROR_NOT_ENOUGH_MEMORY:
+      return ENOMEM;
+
+    case ERROR_NO_DATA:
+    case ERROR_BROKEN_PIPE:
+      return EPIPE;
+
+    default:
+      return EIO;
+    }
+}
+#endif /*HAVE_DOSISH_SYSTEM*/
 
 \f
 /* Entirely disable all locking.  This function should be called
@@ -487,7 +523,7 @@ read_lockfile (dotlock_t h, int *same_node )
   expected_len = 10 + 1 + h->nodename_len + 1;
   if ( expected_len >= sizeof buffer_space)
     {
-      buffer = jnlib_malloc (expected_len);
+      buffer = xtrymalloc (expected_len);
       if (!buffer)
         return -1;
     }
@@ -497,11 +533,11 @@ read_lockfile (dotlock_t h, int *same_node )
   if ( (fd = open (h->lockname, O_RDONLY)) == -1 )
     {
       int e = errno;
-      my_info_2 ("error opening lockfile `%s': %s\n",
+      my_info_2 ("error opening lockfile '%s': %s\n",
                  h->lockname, strerror(errno) );
       if (buffer != buffer_space)
-        jnlib_free (buffer);
-      jnlib_set_errno (e); /* Need to return ERRNO here. */
+        xfree (buffer);
+      my_set_errno (e); /* Need to return ERRNO here. */
       return -1;
     }
 
@@ -514,11 +550,12 @@ read_lockfile (dotlock_t h, int *same_node )
         continue;
       if (res < 0)
         {
-          my_info_1 ("error reading lockfile `%s'\n", h->lockname );
+          int e = errno;
+          my_info_1 ("error reading lockfile '%s'\n", h->lockname );
           close (fd);
           if (buffer != buffer_space)
-            jnlib_free (buffer);
-          jnlib_set_errno (0); /* Do not return an inappropriate ERRNO. */
+            xfree (buffer);
+          my_set_errno (e);
           return -1;
         }
       p += res;
@@ -529,10 +566,10 @@ read_lockfile (dotlock_t h, int *same_node )
 
   if (nread < 11)
     {
-      my_info_1 ("invalid size of lockfile `%s'\n", h->lockname);
+      my_info_1 ("invalid size of lockfile '%s'\n", h->lockname);
       if (buffer != buffer_space)
-        jnlib_free (buffer);
-      jnlib_set_errno (0); /* Better don't return an inappropriate ERRNO. */
+        xfree (buffer);
+      my_set_errno (EINVAL);
       return -1;
     }
 
@@ -540,10 +577,10 @@ read_lockfile (dotlock_t h, int *same_node )
       || (buffer[10] = 0, pid = atoi (buffer)) == -1
       || !pid )
     {
-      my_error_2 ("invalid pid %d in lockfile `%s'\n", pid, h->lockname);
+      my_error_2 ("invalid pid %d in lockfile '%s'\n", pid, h->lockname);
       if (buffer != buffer_space)
-        jnlib_free (buffer);
-      jnlib_set_errno (0);
+        xfree (buffer);
+      my_set_errno (EINVAL);
       return -1;
     }
 
@@ -553,7 +590,7 @@ read_lockfile (dotlock_t h, int *same_node )
     *same_node = 1;
 
   if (buffer != buffer_space)
-    jnlib_free (buffer);
+    xfree (buffer);
   return pid;
 }
 #endif /*HAVE_POSIX_SYSTEM */
@@ -577,13 +614,14 @@ use_hardlinks_p (const char *tname)
     return -1;
   nlink = (unsigned int)sb.st_nlink;
 
-  lname = jnlib_malloc (strlen (tname) + 1 + 1);
+  lname = xtrymalloc (strlen (tname) + 1 + 1);
   if (!lname)
     return -1;
   strcpy (lname, tname);
   strcat (lname, "x");
 
-  link (tname, lname);
+  /* We ignore the return value of link() because it is unreliable.  */
+  (void) link (tname, lname);
 
   if (stat (tname, &sb))
     res = -1;  /* Ooops.  */
@@ -593,7 +631,7 @@ use_hardlinks_p (const char *tname)
     res = 1;   /* No hardlink support.  */
 
   unlink (lname);
-  jnlib_free (lname);
+  xfree (lname);
   return res;
 }
 #endif /*HAVE_POSIX_SYSTEM */
@@ -638,12 +676,12 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
   all_lockfiles = h;
 
   tnamelen = dirpartlen + 6 + 30 + strlen(nodename) + 10 + 1;
-  h->tname = jnlib_malloc (tnamelen + 1);
+  h->tname = xtrymalloc (tnamelen + 1);
   if (!h->tname)
     {
       all_lockfiles = h->next;
       UNLOCK_all_lockfiles ();
-      jnlib_free (h);
+      xfree (h);
       return NULL;
     }
   h->nodename_len = strlen (nodename);
@@ -655,7 +693,7 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
 
   do
     {
-      jnlib_set_errno (0);
+      my_set_errno (0);
       fd = open (h->tname, O_WRONLY|O_CREAT|O_EXCL,
                  S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
     }
@@ -663,12 +701,14 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
 
   if ( fd == -1 )
     {
+      int saveerrno = errno;
       all_lockfiles = h->next;
       UNLOCK_all_lockfiles ();
-      my_error_2 (_("failed to create temporary file `%s': %s\n"),
-                  h->tname, strerror(errno));
-      jnlib_free (h->tname);
-      jnlib_free (h);
+      my_error_2 (_("failed to create temporary file '%s': %s\n"),
+                  h->tname, strerror (errno));
+      xfree (h->tname);
+      xfree (h);
+      my_set_errno (saveerrno);
       return NULL;
     }
   if ( write (fd, pidstr, 11 ) != 11 )
@@ -678,7 +718,12 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
   if ( write (fd, "\n", 1 ) != 1 )
     goto write_failed;
   if ( close (fd) )
-    goto write_failed;
+    {
+      if ( errno == EINTR )
+        fd = -1;
+      goto write_failed;
+    }
+  fd = -1;
 
   /* Check whether we support hard links.  */
   switch (use_hardlinks_p (h->tname))
@@ -690,36 +735,47 @@ dotlock_create_unix (dotlock_t h, const char *file_to_lock)
       h->use_o_excl = 1;
       break;
     default:
-      my_error_2 ("can't check whether hardlinks are supported for `%s': %s\n",
-                  h->tname, strerror(errno));
+      {
+        int saveerrno = errno;
+        my_error_2 ("can't check whether hardlinks are supported for '%s': %s\n"
+                    , h->tname, strerror (saveerrno));
+        my_set_errno (saveerrno);
+      }
       goto write_failed;
     }
 
-  h->lockname = jnlib_malloc (strlen (file_to_lock) + 6 );
+  h->lockname = xtrymalloc (strlen (file_to_lock) + 6 );
   if (!h->lockname)
     {
+      int saveerrno = errno;
       all_lockfiles = h->next;
       UNLOCK_all_lockfiles ();
       unlink (h->tname);
-      jnlib_free (h->tname);
-      jnlib_free (h);
+      xfree (h->tname);
+      xfree (h);
+      my_set_errno (saveerrno);
       return NULL;
     }
   strcpy (stpcpy (h->lockname, file_to_lock), EXTSEP_S "lock");
   UNLOCK_all_lockfiles ();
   if (h->use_o_excl)
-    my_debug_1 ("locking for `%s' done via O_EXCL\n", h->lockname);
+    my_debug_1 ("locking for '%s' done via O_EXCL\n", h->lockname);
 
   return h;
 
  write_failed:
-  all_lockfiles = h->next;
-  UNLOCK_all_lockfiles ();
-  my_error_2 (_("error writing to `%s': %s\n"), h->tname, strerror (errno));
-  close (fd);
-  unlink (h->tname);
-  jnlib_free (h->tname);
-  jnlib_free (h);
+  {
+    int saveerrno = errno;
+    all_lockfiles = h->next;
+    UNLOCK_all_lockfiles ();
+    my_error_2 (_("error writing to '%s': %s\n"), h->tname, strerror (errno));
+    if ( fd != -1 )
+      close (fd);
+    unlink (h->tname);
+    xfree (h->tname);
+    xfree (h);
+    my_set_errno (saveerrno);
+  }
   return NULL;
 }
 #endif /*HAVE_POSIX_SYSTEM*/
@@ -738,12 +794,12 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
   h->next = all_lockfiles;
   all_lockfiles = h;
 
-  h->lockname = jnlib_malloc ( strlen (file_to_lock) + 6 );
+  h->lockname = xtrymalloc ( strlen (file_to_lock) + 6 );
   if (!h->lockname)
     {
       all_lockfiles = h->next;
       UNLOCK_all_lockfiles ();
-      jnlib_free (h);
+      xfree (h);
       return NULL;
     }
   strcpy (stpcpy(h->lockname, file_to_lock), EXTSEP_S "lock");
@@ -767,7 +823,7 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
                               NULL, OPEN_ALWAYS, 0, NULL);
     else
       h->lockhd = INVALID_HANDLE_VALUE;
-    jnlib_free (wname);
+    xfree (wname);
 #else
     h->lockhd = CreateFile (h->lockname,
                             GENERIC_READ|GENERIC_WRITE,
@@ -777,11 +833,13 @@ dotlock_create_w32 (dotlock_t h, const char *file_to_lock)
   }
   if (h->lockhd == INVALID_HANDLE_VALUE)
     {
+      int saveerrno = map_w32_to_errno (GetLastError ());
       all_lockfiles = h->next;
       UNLOCK_all_lockfiles ();
-      my_error_2 (_("can't create `%s': %s\n"), h->lockname, w32_strerror (-1));
-      jnlib_free (h->lockname);
-      jnlib_free (h);
+      my_error_2 (_("can't create '%s': %s\n"), h->lockname, w32_strerror (-1));
+      xfree (h->lockname);
+      xfree (h);
+      my_set_errno (saveerrno);
       return NULL;
     }
   return h;
@@ -827,11 +885,11 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
 
   if (flags)
     {
-      jnlib_set_errno (EINVAL);
+      my_set_errno (EINVAL);
       return NULL;
     }
 
-  h = jnlib_calloc (1, sizeof *h);
+  h = xtrycalloc (1, sizeof *h);
   if (!h)
     return NULL;
   h->extra_fd = -1;
@@ -855,7 +913,7 @@ dotlock_create (const char *file_to_lock, unsigned int flags)
 
 
 \f
-/* Convenience function to store a file descriptor (or any any other
+/* Convenience function to store a file descriptor (or any other
    integer value) in the context of handle H.  */
 void
 dotlock_set_fd (dotlock_t h, int fd)
@@ -863,7 +921,7 @@ dotlock_set_fd (dotlock_t h, int fd)
   h->extra_fd = fd;
 }
 
-/* Convenience function to retrieve a file descriptor (or any any other
+/* Convenience function to retrieve a file descriptor (or any other
    integer value) stored in the context of handle H.  */
 int
 dotlock_get_fd (dotlock_t h)
@@ -882,7 +940,7 @@ dotlock_destroy_unix (dotlock_t h)
     unlink (h->lockname);
   if (h->tname && !h->use_o_excl)
     unlink (h->tname);
-  jnlib_free (h->tname);
+  xfree (h->tname);
 }
 #endif /*HAVE_POSIX_SYSTEM*/
 
@@ -904,7 +962,7 @@ dotlock_destroy_w32 (dotlock_t h)
 #endif /*HAVE_DOSISH_SYSTEM*/
 
 
-/* Destroy the locck handle H and release the lock.  */
+/* Destroy the lock handle H and release the lock.  */
 void
 dotlock_destroy (dotlock_t h)
 {
@@ -935,9 +993,9 @@ dotlock_destroy (dotlock_t h)
 #else /* !HAVE_DOSISH_SYSTEM */
       dotlock_destroy_unix (h);
 #endif /* HAVE_DOSISH_SYSTEM */
-      jnlib_free (h->lockname);
+      xfree (h->lockname);
     }
-  jnlib_free(h);
+  xfree(h);
 }
 
 
@@ -955,6 +1013,7 @@ dotlock_take_unix (dotlock_t h, long timeout)
   int ownerchanged;
   const char *maybe_dead="";
   int same_node;
+  int saveerrno;
 
  again:
   if (h->use_o_excl)
@@ -964,7 +1023,7 @@ dotlock_take_unix (dotlock_t h, long timeout)
 
       do
         {
-          jnlib_set_errno (0);
+          my_set_errno (0);
           fd = open (h->lockname, O_WRONLY|O_CREAT|O_EXCL,
                      S_IRUSR|S_IRGRP|S_IROTH|S_IWUSR );
         }
@@ -974,8 +1033,10 @@ dotlock_take_unix (dotlock_t h, long timeout)
         ; /* Lock held by another process.  */
       else if (fd == -1)
         {
-          my_error_2 ("lock not made: open(O_EXCL) of `%s' failed: %s\n",
-                      h->lockname, strerror (errno));
+          saveerrno = errno;
+          my_error_2 ("lock not made: open(O_EXCL) of '%s' failed: %s\n",
+                      h->lockname, strerror (saveerrno));
+          my_set_errno (saveerrno);
           return -1;
         }
       else
@@ -993,10 +1054,12 @@ dotlock_take_unix (dotlock_t h, long timeout)
               return 0;
             }
           /* Write error.  */
-          my_error_2 ("lock not made: writing to `%s' failed: %s\n",
+          saveerrno = errno;
+          my_error_2 ("lock not made: writing to '%s' failed: %s\n",
                       h->lockname, strerror (errno));
           close (fd);
           unlink (h->lockname);
+          my_set_errno (saveerrno);
           return -1;
         }
     }
@@ -1004,15 +1067,18 @@ dotlock_take_unix (dotlock_t h, long timeout)
     {
       struct stat sb;
 
-      link (h->tname, h->lockname);
+      /* We ignore the return value of link() because it is unreliable.  */
+      (void) link (h->tname, h->lockname);
 
       if (stat (h->tname, &sb))
         {
+          saveerrno = errno;
           my_error_1 ("lock not made: Oops: stat of tmp file failed: %s\n",
                       strerror (errno));
           /* In theory this might be a severe error: It is possible
              that link succeeded but stat failed due to changed
              permissions.  We can't do anything about it, though.  */
+          my_set_errno (saveerrno);
           return -1;
         }
 
@@ -1028,7 +1094,9 @@ dotlock_take_unix (dotlock_t h, long timeout)
     {
       if ( errno != ENOENT )
         {
+          saveerrno = errno;
           my_info_0 ("cannot read lockfile\n");
+          my_set_errno (saveerrno);
           return -1;
         }
       my_info_0 ("lockfile disappeared\n");
@@ -1092,7 +1160,7 @@ dotlock_take_unix (dotlock_t h, long timeout)
       goto again;
     }
 
-  jnlib_set_errno (EACCES);
+  my_set_errno (EACCES);
   return -1;
 }
 #endif /*HAVE_POSIX_SYSTEM*/
@@ -1121,8 +1189,9 @@ dotlock_take_w32 (dotlock_t h, long timeout)
   w32err = GetLastError ();
   if (w32err != ERROR_LOCK_VIOLATION)
     {
-      my_error_2 (_("lock `%s' not made: %s\n"),
+      my_error_2 (_("lock '%s' not made: %s\n"),
                   h->lockname, w32_strerror (w32err));
+      my_set_errno (map_w32_to_errno (w32err));
       return -1;
     }
 
@@ -1153,6 +1222,7 @@ dotlock_take_w32 (dotlock_t h, long timeout)
       goto again;
     }
 
+  my_set_errno (EACCES);
   return -1;
 }
 #endif /*HAVE_DOSISH_SYSTEM*/
@@ -1171,7 +1241,7 @@ dotlock_take (dotlock_t h, long timeout)
 
   if ( h->locked )
     {
-      my_debug_1 ("Oops, `%s' is already locked\n", h->lockname);
+      my_debug_1 ("Oops, '%s' is already locked\n", h->lockname);
       return 0;
     }
 
@@ -1192,23 +1262,29 @@ static int
 dotlock_release_unix (dotlock_t h)
 {
   int pid, same_node;
+  int saveerrno;
 
   pid = read_lockfile (h, &same_node);
   if ( pid == -1 )
     {
+      saveerrno = errno;
       my_error_0 ("release_dotlock: lockfile error\n");
+      my_set_errno (saveerrno);
       return -1;
     }
   if ( pid != getpid() || !same_node )
     {
       my_error_1 ("release_dotlock: not our lock (pid=%d)\n", pid);
+      my_set_errno (EACCES);
       return -1;
     }
 
   if ( unlink( h->lockname ) )
     {
-      my_error_1 ("release_dotlock: error removing lockfile `%s'\n",
+      saveerrno = errno;
+      my_error_1 ("release_dotlock: error removing lockfile '%s'\n",
                   h->lockname);
+      my_set_errno (saveerrno);
       return -1;
     }
   /* Fixme: As an extra check we could check whether the link count is
@@ -1228,8 +1304,10 @@ dotlock_release_w32 (dotlock_t h)
   memset (&ovl, 0, sizeof ovl);
   if (!UnlockFileEx (h->lockhd, 0, 1, 0, &ovl))
     {
-      my_error_2 ("release_dotlock: error removing lockfile `%s': %s\n",
+      int saveerrno = map_w32_to_errno (GetLastError ());
+      my_error_2 ("release_dotlock: error removing lockfile '%s': %s\n",
                   h->lockname, w32_strerror (-1));
+      my_set_errno (saveerrno);
       return -1;
     }
 
@@ -1259,7 +1337,7 @@ dotlock_release (dotlock_t h)
 
   if ( !h->locked )
     {
-      my_debug_1 ("Oops, `%s' is not locked\n", h->lockname);
+      my_debug_1 ("Oops, '%s' is not locked\n", h->lockname);
       return 0;
     }
 
@@ -1285,7 +1363,7 @@ dotlock_remove_lockfiles (void)
   dotlock_t h, h2;
 
   /* First set the lockfiles list to NULL so that for example
-     dotlock_release is ware that this fucntion is currently
+     dotlock_release is aware that this function is currently
      running.  */
   LOCK_all_lockfiles ();
   h = all_lockfiles;