Re-indent code and use test macros for betetr readability
[gnupg.git] / common / iobuf.c
index ae35d30..04b17ff 100644 (file)
@@ -1,6 +1,6 @@
 /* iobuf.c  -  File Handling for OpenPGP.
  * Copyright (C) 1998, 1999, 2000, 2001, 2003, 2004, 2006,
- *               2007  Free Software Foundation, Inc.
+ *               2007, 2008, 2009  Free Software Foundation, Inc.
  *
  * This file is part of GnuPG.
  *
@@ -48,7 +48,8 @@
    test "armored_key_8192" in armor.test! */
 #define IOBUF_BUFFER_SIZE  8192
 
-/* We don't want to use the STDIO based backend.  */
+/* We don't want to use the STDIO based backend.  If you change this
+   be aware that there is no fsync support for the stdio backend.  */
 #undef FILE_FILTER_USES_STDIO
 
 /*-- End configurable part.  --*/
@@ -78,7 +79,7 @@
      we are using the low-evel backend.
 
    fp_or_fd_t
-     Is the type we use for the backend stream or fiel descriptor.
+     Is the type we use for the backend stream or file descriptor.
 
    INVALID_FP, FILEP_OR_FD_FOR_STDIN, FILEP_OR_FD_FOR_STDOUT
      Are macros defined depending on the used backend.
@@ -187,13 +188,32 @@ static int translate_file_handle (int fd, int for_write);
 
 \f
 #ifndef FILE_FILTER_USES_STDIO
+/* This is a replacement for strcmp.  Under W32 it does not
+   distinguish between backslash and slash.  */
+static int
+fd_cache_strcmp (const char *a, const char *b)
+{
+#ifdef HAVE_DOSISH_SYSTEM
+  for (; *a && *b; a++, b++)
+    {
+      if (*a != *b && !((*a == '/' && *b == '\\') 
+                        || (*a == '\\' && *b == '/')) )
+        break;
+    }
+  return *(const unsigned char *)a - *(const unsigned char *)b;
+#else
+  return strcmp (a, b);
+#endif
+}
+
 /*
  * Invalidate (i.e. close) a cached iobuf
  */
-static void
+static int
 fd_cache_invalidate (const char *fname)
 {
   close_cache_t cc;
+  int rc = 0;
 
   assert (fname);
   if (DBG_IOBUF)
@@ -201,18 +221,52 @@ fd_cache_invalidate (const char *fname)
 
   for (cc = close_cache; cc; cc = cc->next)
     {
-      if (cc->fp != INVALID_FP && !strcmp (cc->fname, fname))
+      if (cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname))
        {
          if (DBG_IOBUF)
            log_debug ("                did (%s)\n", cc->fname);
 #ifdef HAVE_W32_SYSTEM
-         CloseHandle (cc->fp);
+         if (!CloseHandle (cc->fp))
+            rc = -1;
 #else
-         close (cc->fp);
+         rc = close (cc->fp);
 #endif
          cc->fp = INVALID_FP;
        }
     }
+  return rc;
+}
+
+
+/* Try to sync changes to the disk.  This is to avoid data loss during
+   a system crash in write/close/rename cycle on some file
+   systems.  */
+static int
+fd_cache_synchronize (const char *fname)
+{
+  int err = 0;
+
+#ifdef HAVE_FSYNC
+  close_cache_t cc;
+
+  if (DBG_IOBUF)
+    log_debug ("fd_cache_synchronize (%s)\n", fname);
+
+  for (cc=close_cache; cc; cc = cc->next )
+    {
+      if (cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname))
+       {
+         if (DBG_IOBUF)
+           log_debug ("                 did (%s)\n", cc->fname);
+
+         err = fsync (cc->fp);
+       }
+    }
+#else
+  (void)fname;
+#endif /*HAVE_FSYNC*/
+
+  return err;
 }
 
 
@@ -226,19 +280,21 @@ direct_open (const char *fname, const char *mode)
   /* Note, that we do not handle all mode combinations */
 
   /* According to the ReactOS source it seems that open() of the
-   * standard MSW32 crt does open the file in share mode which is
+   * standard MSW32 crt does open the file in shared mode which is
    * something new for MS applications ;-)
    */
   if (strchr (mode, '+'))
     {
-      fd_cache_invalidate (fname);
+      if (fd_cache_invalidate (fname))
+        return INVALID_FP;
       da = GENERIC_READ | GENERIC_WRITE;
       cd = OPEN_EXISTING;
       sm = FILE_SHARE_READ | FILE_SHARE_WRITE;
     }
   else if (strchr (mode, 'w'))
     {
-      fd_cache_invalidate (fname);
+      if (fd_cache_invalidate (fname))
+        return INVALID_FP;
       da = GENERIC_WRITE;
       cd = CREATE_ALWAYS;
       sm = FILE_SHARE_WRITE;
@@ -259,12 +315,14 @@ direct_open (const char *fname, const char *mode)
   /* Note, that we do not handle all mode combinations */
   if (strchr (mode, '+'))
     {
-      fd_cache_invalidate (fname);
+      if (fd_cache_invalidate (fname))
+        return INVALID_FP;
       oflag = O_RDWR;
     }
   else if (strchr (mode, 'w'))
     {
-      fd_cache_invalidate (fname);
+      if (fd_cache_invalidate (fname))
+        return INVALID_FP;
       oflag = O_WRONLY | O_CREAT | O_TRUNC;
     }
   else
@@ -318,7 +376,7 @@ fd_cache_close (const char *fname, fp_or_fd_t fp)
   /* try to reuse a slot */
   for (cc = close_cache; cc; cc = cc->next)
     {
-      if (cc->fp == INVALID_FP && !strcmp (cc->fname, fname))
+      if (cc->fp == INVALID_FP && !fd_cache_strcmp (cc->fname, fname))
        {
          cc->fp = fp;
          if (DBG_IOBUF)
@@ -347,7 +405,7 @@ fd_cache_open (const char *fname, const char *mode)
   assert (fname);
   for (cc = close_cache; cc; cc = cc->next)
     {
-      if (cc->fp != INVALID_FP && !strcmp (cc->fname, fname))
+      if (cc->fp != INVALID_FP && !fd_cache_strcmp (cc->fname, fname))
        {
          fp_or_fd_t fp = cc->fp;
          cc->fp = INVALID_FP;
@@ -412,14 +470,20 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
   size_t nbytes = 0;
   int rc = 0;
 
+  (void)chain; /* Not used.  */
+
 #ifdef FILE_FILTER_USES_STDIO
   if (control == IOBUFCTRL_UNDERFLOW)
     {
-      assert (size);           /* need a buffer */
+      assert (size);  /* We need a buffer. */
       if (feof (f))
-       {                       /* On terminals you could easiely read as many EOFs as you call         */
-         rc = -1;              /* fread() or fgetc() repeatly. Every call will block until you press   */
-         *ret_len = 0;         /* CTRL-D. So we catch this case before we call fread() again.          */
+       { 
+          /* On terminals you could easily read as many EOFs as you
+             call fread() or fgetc() repeatly.  Every call will block
+             until you press CTRL-D. So we catch this case before we
+             call fread() again.  */
+         rc = -1;              
+         *ret_len = 0;         
        }
       else
        {
@@ -427,7 +491,7 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
          nbytes = fread (buf, 1, size, f);
          if (feof (f) && !nbytes)
            {
-             rc = -1;          /* okay: we can return EOF now. */
+             rc = -1;  /* Okay: we can return EOF now. */
            }
          else if (ferror (f) && errno != EPIPE)
            {
@@ -469,13 +533,13 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
            fclose (f);
        }
       f = NULL;
-      xfree (a);               /* we can free our context now */
+      xfree (a); /* We can free our context now. */
     }
 #else /* !stdio implementation */
 
   if (control == IOBUFCTRL_UNDERFLOW)
     {
-      assert (size);           /* need a buffer */
+      assert (size); /* We need a buffer.  */
       if (a->eof_seen)
        {
          rc = -1;
@@ -620,9 +684,9 @@ file_filter (void *opaque, int control, iobuf_t chain, byte * buf,
        }
       f = INVALID_FP;
 #endif
-      xfree (a);               /* we can free our context now */
+      xfree (a); /* We can free our context now. */
     }
-#endif /* !stdio implementation */
+#endif /* !stdio implementation. */
   return rc;
 }
 
@@ -639,6 +703,8 @@ sock_filter (void *opaque, int control, iobuf_t chain, byte * buf,
   size_t nbytes = 0;
   int rc = 0;
 
+  (void)chain;
+
   if (control == IOBUFCTRL_UNDERFLOW)
     {
       assert (size);           /* need a buffer */
@@ -1012,7 +1078,7 @@ print_chain (iobuf_t a)
                   (byte *) & desc, &dummy_len);
 
       log_debug ("iobuf chain: %d.%d `%s' filter_eof=%d start=%d len=%d\n",
-                a->no, a->subno, desc, a->filter_eof,
+                a->no, a->subno, desc?desc:"?", a->filter_eof,
                 (int) a->d.start, (int) a->d.len);
     }
 }
@@ -1069,7 +1135,8 @@ iobuf_close (iobuf_t a)
        log_error ("iobuf_flush failed on close: %s\n", gpg_strerror (rc));
 
       if (DBG_IOBUF)
-       log_debug ("iobuf-%d.%d: close `%s'\n", a->no, a->subno, a->desc);
+       log_debug ("iobuf-%d.%d: close `%s'\n", a->no, a->subno,
+                   a->desc?a->desc:"?");
       if (a->filter && (rc = a->filter (a->filter_ov, IOBUFCTRL_FREE,
                                        a->chain, NULL, &dummy_len)))
        log_error ("IOBUFCTRL_FREE failed on close: %s\n", gpg_strerror (rc));
@@ -1193,6 +1260,32 @@ iobuf_is_pipe_filename (const char *fname)
   return check_special_filename (fname) != -1;
 }
 
+
+/* Either open the file specified by the file descriptor FD or - if FD
+   is -1, the file with name FNAME.  As of now MODE is assumed to be
+   "rb" if FNAME is used.  In contrast to iobuf_fdopen the file
+   descriptor FD will not be closed during an iobuf_close.  */
+iobuf_t
+iobuf_open_fd_or_name (gnupg_fd_t fd, const char *fname, const char *mode)
+{
+  iobuf_t a;
+
+  if (fd == -1)
+    a = iobuf_open (fname);
+  else
+    {
+      int fd2;
+
+      fd2 = dup (fd);
+      if (fd2 == -1)
+        a = NULL;
+      else
+        a = iobuf_fdopen (fd2, mode);
+    }
+  return a;
+}
+
+
 /****************
  * Create a head iobuf for reading from a file
  * returns: NULL if an error occures and sets errno
@@ -1336,7 +1429,8 @@ iobuf_create (const char *fname)
   file_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: create `%s'\n", a->no, a->subno, a->desc);
+    log_debug ("iobuf-%d.%d: create `%s'\n", a->no, a->subno,
+               a->desc?a->desc:"?");
 
   return a;
 }
@@ -1369,7 +1463,8 @@ iobuf_append (const char *fname)
   file_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: append `%s'\n", a->no, a->subno, a->desc);
+    log_debug ("iobuf-%d.%d: append `%s'\n", a->no, a->subno,
+               a->desc?a->desc:"?");
 
   return a;
 }
@@ -1397,7 +1492,8 @@ iobuf_openrw (const char *fname)
   file_filter (fcx, IOBUFCTRL_DESC, NULL, (byte *) & a->desc, &len);
   file_filter (fcx, IOBUFCTRL_INIT, NULL, NULL, &len);
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: openrw `%s'\n", a->no, a->subno, a->desc);
+    log_debug ("iobuf-%d.%d: openrw `%s'\n", a->no, a->subno,
+               a->desc?a->desc:"?");
 
   return a;
 }
@@ -1410,7 +1506,8 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
     {                          /* keep system filepointer/descriptor open */
       if (DBG_IOBUF)
        log_debug ("iobuf-%d.%d: ioctl `%s' keep=%d\n",
-                  a ? a->no : -1, a ? a->subno : -1, a ? a->desc : "?",
+                  a ? a->no : -1, a ? a->subno : -1, 
+                   a && a->desc ? a->desc : "?",
                   intval);
       for (; a; a = a->chain)
        if (!a->chain && a->filter == file_filter)
@@ -1436,7 +1533,8 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
       if (!a && !intval && ptrval)
        {
 #ifndef FILE_FILTER_USES_STDIO
-         fd_cache_invalidate (ptrval);
+         if (fd_cache_invalidate (ptrval))
+            return -1;
 #endif
          return 0;
        }
@@ -1445,7 +1543,8 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
     {                          /* disallow/allow caching */
       if (DBG_IOBUF)
        log_debug ("iobuf-%d.%d: ioctl `%s' no_cache=%d\n",
-                  a ? a->no : -1, a ? a->subno : -1, a ? a->desc : "?",
+                  a ? a->no : -1, a ? a->subno : -1, 
+                   a && a->desc? a->desc : "?",
                   intval);
       for (; a; a = a->chain)
        if (!a->chain && a->filter == file_filter)
@@ -1463,6 +1562,24 @@ iobuf_ioctl (iobuf_t a, int cmd, int intval, void *ptrval)
          }
 #endif
     }
+  else if (cmd == 4)
+    {
+      /* Do a fsync on the open fd and return any errors to the caller
+         of iobuf_ioctl.  Note that we work on a file name here. */
+      if (DBG_IOBUF)
+        log_debug ("iobuf-*.*: ioctl `%s' fsync\n",
+                   ptrval? (const char*)ptrval:"<null>");
+
+       if (!a && !intval && ptrval)
+         {
+#ifndef FILE_FILTER_USES_STDIO
+           return fd_cache_synchronize (ptrval);
+#else
+           return 0;
+#endif
+         }
+      }
+
 
   return -1;
 }
@@ -1546,7 +1663,8 @@ iobuf_push_filter2 (iobuf_t a,
 
   if (DBG_IOBUF)
     {
-      log_debug ("iobuf-%d.%d: push `%s'\n", a->no, a->subno, a->desc);
+      log_debug ("iobuf-%d.%d: push `%s'\n", a->no, a->subno, 
+                 a->desc?a->desc:"?");
       print_chain (a);
     }
 
@@ -1573,7 +1691,8 @@ pop_filter (iobuf_t a, int (*f) (void *opaque, int control,
     BUG ();
 
   if (DBG_IOBUF)
-    log_debug ("iobuf-%d.%d: pop `%s'\n", a->no, a->subno, a->desc);
+    log_debug ("iobuf-%d.%d: pop `%s'\n", a->no, a->subno,
+               a->desc?a->desc:"?");
   if (!a->filter)
     {                          /* this is simple */
       b = a->chain;
@@ -1660,7 +1779,7 @@ underflow (iobuf_t a)
          iobuf_t b = a->chain;
          if (DBG_IOBUF)
            log_debug ("iobuf-%d.%d: pop `%s' in underflow\n",
-                      a->no, a->subno, a->desc);
+                      a->no, a->subno, a->desc?a->desc:"?");
          xfree (a->d.buf);
          xfree (a->real_fname);
          memcpy (a, b, sizeof *a);
@@ -1733,8 +1852,8 @@ underflow (iobuf_t a)
            {
              iobuf_t b = a->chain;
              if (DBG_IOBUF)
-               log_debug ("iobuf-%d.%d: pop `%s' in underflow (!len)\n",
-                          a->no, a->subno, a->desc);
+               log_debug ("iobuf-%d.%d: pop in underflow (!len)\n",
+                          a->no, a->subno);
              xfree (a->d.buf);
              xfree (a->real_fname);
              memcpy (a, b, sizeof *a);
@@ -2294,7 +2413,6 @@ iobuf_get_fname (iobuf_t a)
        file_filter_ctx_t *b = a->filter_ov;
        return b->fname;
       }
-
   return NULL;
 }
 
@@ -2400,6 +2518,8 @@ translate_file_handle (int fd, int for_write)
 # else
   {
     int x;
+    
+    (void)for_write;
 
     if (fd == 0)
       x = (int) GetStdHandle (STD_INPUT_HANDLE);
@@ -2417,6 +2537,8 @@ translate_file_handle (int fd, int for_write)
     fd = x;
   }
 # endif
+#else
+  (void)for_write;
 #endif
   return fd;
 }