dirmngr: Allow command VERSIONCHECK to handle 3 part version numbers.
authorWerner Koch <wk@gnupg.org>
Tue, 25 Oct 2016 07:38:01 +0000 (09:38 +0200)
committerWerner Koch <wk@gnupg.org>
Tue, 25 Oct 2016 07:38:01 +0000 (09:38 +0200)
* dirmngr/server.c (parse_version_string): Add arg MICRO and set it.
(cmp_version): Extend to handle the MICRO part.
(confucius_mktmpdir): Rename to my_mktmpdir.
(my_mktmpdir): xstrconcat does not fail; use strconcat.
(fetch_into_tmpdir): Improve error checking.

Signed-off-by: Werner Koch <wk@gnupg.org>
dirmngr/server.c

index 496ee2d..0ad2713 100644 (file)
@@ -2342,6 +2342,10 @@ cmd_reloaddirmngr (assuan_context_t ctx, char *line)
 
 
 \f
+/* This function parses the first portion of the version number S and
+ * stores it in *NUMBER.  On success, this function returns a pointer
+ * into S starting with the first character, which is not part of the
+ * initial number portion; on failure, NULL is returned.  */
 static const char*
 parse_version_number (const char *s, int *number)
 {
@@ -2359,8 +2363,16 @@ parse_version_number (const char *s, int *number)
 }
 
 
+/* This function breaks up the complete string-representation of the
+ * version number S, which is of the following struture: <major
+ * number>.<minor number>[.<micro number>]<patch level>.  The major,
+ * minor and micro number components will be stored in *MAJOR, *MINOR
+ * and *MICRO.  If MICRO is not given 0 is used instead.
+ *
+ * On success, the last component, the patch level, will be returned;
+ * on failure, NULL will be returned.  */
 static const char *
-parse_version_string (const char *s, int *major, int *minor)
+parse_version_string (const char *s, int *major, int *minor, int *micro)
 {
   s = parse_version_number (s, major);
   if (!s || *s != '.')
@@ -2369,18 +2381,23 @@ parse_version_string (const char *s, int *major, int *minor)
   s = parse_version_number (s, minor);
   if (!s)
     return NULL;
+  if (*s == '.')
+    {
+      s++;
+      s = parse_version_number (s, micro);
+      if (!s)
+        return NULL;
+    }
+  else
+    micro = 0;
   return s;  /* Patchlevel.  */
 }
 
-/* Class Confucius.
-
-   "Don't worry that other people don't know you;
-   worry that you don't know other people."            Analects--1.16.  */
 
 /* Create temporary directory with mode 0700.  Returns a dynamically
  allocated string with the filename of the directory.  */
* allocated string with the filename of the directory.  */
 static char *
-confucius_mktmpdir (void)
+my_mktmpdir (void)
 {
   char *name, *p;
 
@@ -2388,19 +2405,22 @@ confucius_mktmpdir (void)
   if (!p || !*p)
     p = "/tmp";
   if (p[strlen (p) - 1] == '/')
-    name = xstrconcat (p, "gpg-XXXXXX", NULL);
+    name = strconcat (p, "gpg-XXXXXX", NULL);
   else
-    name = xstrconcat (p, "/", "gpg-XXXXXX", NULL);
+    name = strconcat (p, "/", "gpg-XXXXXX", NULL);
   if (!name || !gnupg_mkdtemp (name))
     {
+      int saveerr = errno;
       log_error (_("can't create temporary directory '%s': %s\n"),
-                 name?name:"", strerror (errno));
+                 name, strerror (saveerr));
+      gpg_err_set_errno (saveerr);
       return NULL;
     }
 
   return name;
 }
 
+
 /* Sets result to -1 if version a is less than b, 0 if the versions are equal
  * and 1 otherwise. Patch levels are compared as strings.  */
 static gpg_error_t
@@ -2408,21 +2428,27 @@ cmp_version (const char *a, const char *b, int *result)
 {
   int a_major, b_major;
   int a_minor, b_minor;
+  int a_micro, b_micro;
   const char *a_patch, *b_patch;
 
   if (!a || !b || !result)
-    return GPG_ERR_EINVAL;
+    return gpg_error (GPG_ERR_EINVAL);
 
-  a_patch = parse_version_string (a, &a_major, &a_minor);
-  b_patch = parse_version_string (b, &b_major, &b_minor);
+  a_patch = parse_version_string (a, &a_major, &a_minor, &a_micro);
+  b_patch = parse_version_string (b, &b_major, &b_minor, &b_micro);
 
   if (!a_patch || !b_patch)
-    return GPG_ERR_EINVAL;
+    return gpg_error (GPG_ERR_EINVAL);
 
   if (a_major == b_major)
     {
       if (a_minor == b_minor)
-        *result = strcmp (a_patch, b_patch);
+        {
+          if (a_micro == b_micro)
+            *result = strcmp (a_patch, b_patch);
+          else
+            *result = a_micro - b_minor;
+        }
       else
         *result = a_minor - b_minor;
     }
@@ -2432,25 +2458,26 @@ cmp_version (const char *a, const char *b, int *result)
   return 0;
 }
 
+
 static gpg_error_t
-fetch_into_tmpdir (ctrl_t ctrl, const char* url, estream_t* strm_out,
-                   char** path)
+fetch_into_tmpdir (ctrl_t ctrl, const char *url, estream_t *strm_out,
+                   char **path)
 {
   gpg_error_t err;
-  charfilename = NULL;
-  chardirname = NULL;
-  estream_t file;
-  estream_t strm;
-  size_t len = 0;
+  char *filename = NULL;
+  char *dirname = NULL;
+  estream_t file = NULL;
+  estream_t strm = NULL;
+  size_t len, nwritten;
   char buf[1024];
 
   if (!strm_out || !path || !url)
     {
-      err = (GPG_ERR_INV_ARG);
+      err = gpg_error (GPG_ERR_INV_ARG);
       goto leave;
     }
 
-  dirname = confucius_mktmpdir ();
+  dirname = my_mktmpdir ();
   if (!dirname)
     {
       err = gpg_error_from_syserror ();
@@ -2465,39 +2492,60 @@ fetch_into_tmpdir (ctrl_t ctrl, const char* url, estream_t* strm_out,
     }
 
   file = es_fopen (filename, "w+");
+  if (!file)
+    {
+      err = gpg_error_from_syserror ();
+      goto leave;
+    }
 
   if ((err = ks_http_fetch (ctrl, url, &strm)))
     goto leave;
 
-  while (!es_read (strm, buf, sizeof buf, &len))
+  for (;;)
     {
+      if (es_read (strm, buf, sizeof buf, &len))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error reading '%s': %s\n",
+                     es_fname_get (strm), gpg_strerror (err));
+          goto leave;
+        }
+
       if (!len)
         break;
-      if ((err = es_write (file, buf, len, NULL)))
+      if (es_write (file, buf, len, &nwritten))
+        {
+          err = gpg_error_from_syserror ();
+          log_error ("error writing '%s': %s\n", filename, gpg_strerror (err));
+          goto leave;
+        }
+      else if (len != nwritten)
         {
-          log_error ("error writing message to pipe: %s\n", gpg_strerror (err));
-          es_free (strm);
+          err = gpg_error (GPG_ERR_EIO);
+          log_error ("error writing '%s': %s\n", filename, "short write");
           goto leave;
         }
     }
 
   es_rewind (file);
-  es_fclose (strm);
   *strm_out = file;
-  err = 0;
+  file = NULL;
 
   if (path)
     {
-    *path = dirname;
-    dirname = NULL;
+      *path = dirname;
+      dirname = NULL;
     }
 
-leave:
+ leave:
+  es_fclose (file);
+  es_fclose (strm);
   xfree (dirname);
   xfree (filename);
   return err;
 }
 
+
 static const char hlp_versioncheck[] =
   "VERSIONCHECK <name> <version>"
   "\n"
@@ -2510,8 +2558,8 @@ cmd_versioncheck (assuan_context_t ctx, char *line)
 {
   gpg_error_t err;
 
-  charname;
-  charversion;
+  char *name;
+  char *version;
   size_t name_len;
   char *cmd_fields[2];