]> cygwin.com Git - cygwin-apps/setup.git/blobdiff - ini.cc
Merged across diffs between setup_crypto_branch_branchpoint and
[cygwin-apps/setup.git] / ini.cc
diff --git a/ini.cc b/ini.cc
index ea035d0fe49bb0a7a77e63c1e25e9094a9b83cbc..5ba481eb5a02deb3a58280a956778be32350f87d 100644 (file)
--- a/ini.cc
+++ b/ini.cc
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, Red Hat, Inc.
+ * Copyright (c) 2000,2007 Red Hat, Inc.
  *
  *     This program is free software; you can redistribute it and/or modify
  *     it under the terms of the GNU General Public License as published by
    flex parsers are provided also.  We check to see if this setup.ini
    is older than the one we used last time, and if so, warn the user. */
 
-static char *cvsid = "\n%%% $Id$\n";
+#if 0
+static const char *cvsid =
+  "\n%%% $Id$\n";
+#endif
 
+#include "ini.h"
+
+#include "csu_util/rfc1738.h"
+#include "csu_util/version_compare.h"
+
+#include "setup_version.h"
 #include "win32.h"
+#include "LogSingleton.h"
 
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <process.h>
 
-#include "ini.h"
 #include "resource.h"
-#include "concat.h"
 #include "state.h"
 #include "geturl.h"
 #include "dialog.h"
 #include "msg.h"
-#include "mkdir.h"
-#include "log.h"
-#include "version.h"
 #include "mount.h"
+#include "site.h"
+#include "find.h"
+#include "IniParseFindVisitor.h"
+#include "IniParseFeedback.h"
+
+#include "io_stream.h"
+#include "io_stream_memory.h"
+
+#include "threebar.h"
+
+#include "getopt++/BoolOption.h"
+#include "IniDBBuilderPackage.h"
+#include "compress.h"
+#include "Exception.h"
+#include "crypto.h"
+  
+extern ThreeBarProgressPage Progress;
 
 unsigned int setup_timestamp = 0;
-char *setup_version = 0;
+std::string ini_setup_version;
+std::string current_ini_sig_name;
 
-extern "C" int yyparse ();
-/*extern int yydebug;*/
+static BoolOption NoVerifyOption (false, 'X', "no-verify", "Don't verify setup.ini signatures");
 
-static char *error_buf = 0;
-static int error_count = 0;
+extern int yyparse ();
+/*extern int yydebug;*/
 
-void
-do_ini (HINSTANCE h)
+class GuiParseFeedback : public IniParseFeedback
 {
-  char *ini_file = get_url_to_string (concat (MIRROR_SITE, "/setup.ini", 0));
-  dismiss_url_status_dialog ();
-
-  if (!ini_file)
+public:
+  GuiParseFeedback () : lastpct (0) 
+    {
+      Progress.SetText2 ("");
+      Progress.SetText3 ("");
+      Progress.SetText4 ("Progress:");
+    }
+  virtual void progress(unsigned long const pos, unsigned long const max)
+    {
+      if (!max)
+       /* length not known or eof */
+       return;
+      if (lastpct == 100)
+       /* rounding down should mean this only ever fires once */
+       lastpct = 0;
+      if (pos * 100 / max > lastpct)
+       {
+         lastpct = pos * 100 / max;
+         /* log (LOG_BABBLE) << lastpct << "% (" << pos << " of " << max
+            << " bytes of ini file read)" << endLog; */
+       }
+      Progress.SetBar1(pos, max);
+    }
+  virtual void iniName (const std::string& name)
+    {
+      Progress.SetText1 (("Parsing ini file \"" + name + "\"").c_str());
+    }
+  virtual void babble(const std::string& message)const
+    {
+      log (LOG_BABBLE) << message << endLog;
+    }
+  virtual void warning (const std::string& message)const
     {
-      note (IDS_SETUPINI_MISSING, MIRROR_SITE);
-      next_dialog = IDD_SITE;
-      return;
+      MessageBox (0, message.c_str(), "Warning", 0);
     }
+  virtual void error(const std::string& message)const
+    {
+      MessageBox (0, message.c_str(), "Parse Errors", 0);
+    }
+  virtual ~ GuiParseFeedback ()
+    {
+      Progress.SetText4("Package:");
+    }
+private:
+  unsigned int lastpct;
+};
 
-  package = 0;
-  npackages = 0;
-  setup_timestamp = 0;
-  setup_version = 0;
+static int
+do_local_ini (HWND owner)
+{
+  GuiParseFeedback myFeedback;
+  IniDBBuilderPackage findBuilder(myFeedback);
+  IniParseFindVisitor myVisitor (findBuilder, local_dir, myFeedback);
+  Find (local_dir).accept(myVisitor);
+  setup_timestamp = myVisitor.timeStamp();
+  ini_setup_version = myVisitor.version();
+  return myVisitor.iniCount(); 
+}
 
-  ini_init (ini_file);
+static int
+do_remote_ini (HWND owner)
+{
+  size_t ini_count = 0;
+  GuiParseFeedback myFeedback;
+  IniDBBuilderPackage aBuilder(myFeedback);
+  io_stream *ini_file, *ini_sig_file;
 
-  setup_timestamp = 0;
-  /*yydebug = 1;*/
+  /* FIXME: Get rid of this io_stream pointer travesty.  The need to
+     explicitly delete these things is ridiculous.  Note that the
+     decompress io_stream "owns" the underlying compressed io_stream
+     instance, so it should not be deleted explicitly.  */
 
-  if (yyparse () || error_count > 0)
+  for (SiteList::const_iterator n = site_list.begin();
+       n != site_list.end(); ++n)
     {
-      if (error_count == 1)
-       MessageBox (0, error_buf, "Parse Error", 0);
+      bool sig_fail = false;
+      /* First try to fetch the .bz2 compressed ini file.  */
+      current_ini_name = n->url + "/" + SETUP_BZ2_FILENAME;
+      current_ini_sig_name = n->url + "/" + SETUP_BZ2_FILENAME + ".sig";
+      ini_file = get_url_to_membuf (current_ini_name, owner);
+      if (!NoVerifyOption)
+        ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
+      if (!NoVerifyOption && ini_file && !ini_sig_file)
+       {
+         note (owner, IDS_SETUPINI_MISSING, current_ini_sig_name.c_str(), n->url.c_str());
+         delete ini_file;
+         ini_file = NULL;
+         sig_fail = true;
+       }
+      else if (!NoVerifyOption && ini_file && !verify_ini_file_sig (ini_file, ini_sig_file, owner))
+       {
+         note (owner, IDS_SIG_INVALID, current_ini_sig_name.c_str(), n->url.c_str());
+         delete ini_file;
+         ini_file = NULL;
+         delete ini_sig_file;
+         ini_sig_file = NULL;
+         sig_fail = true;
+       }
+      if (ini_file)
+       {
+          /* Decompress the entire file in memory right now.  This has the
+             advantage that input_stream->get_size() will work during parsing
+             and we'll have an accurate status bar.  Also, we can't seek 
+             bz2 streams, so when it comes time to write out a local cached
+             copy of the .ini file below, we'd otherwise have to delete this
+             stream and uncompress it again from the start, which is wasteful.
+             The current uncompresed size of the .ini file as of 2007 is less
+             than 600 kB, so this is not a great deal of memory.  */
+         io_stream *bz2_stream = compress::decompress (ini_file);
+         if (!bz2_stream)
+           {
+             /* This isn't a valid bz2 file.  */
+             delete ini_file;
+             ini_file = NULL;
+           }
+         else
+            {
+             io_stream *uncompressed = new io_stream_memory ();
+
+              if (io_stream::copy (bz2_stream, uncompressed) != 0 ||
+                  bz2_stream->error () == EIO)
+                {
+                  /* There was a problem decompressing bz2.  */
+                  delete bz2_stream;
+                  delete uncompressed;
+                  ini_file = NULL;
+                  log (LOG_PLAIN) << 
+                    "Warning: Problem encountered while uncompressing " <<
+                    current_ini_name << " - possibly truncated or corrupt bzip2"
+                    " file.  Retrying with uncompressed version." << endLog;
+                }
+              else
+                {
+                  delete bz2_stream;
+                  ini_file = uncompressed;
+                  ini_file->seek (0, IO_SEEK_SET);
+                }
+            }
+       }
+      
+      if (!ini_file)
+        {
+          /* Try to look for a plain .ini file because one of the following
+             happened above:
+               - there was no .bz2 file found on the mirror.
+               - the .bz2 file didn't look like a valid bzip2 file.
+               - there was an error during bzip2 decompression.  */
+          current_ini_name = n->url + "/" + SETUP_INI_FILENAME;
+          current_ini_sig_name = n->url + "/" + SETUP_INI_FILENAME + ".sig";
+         ini_file = get_url_to_membuf (current_ini_name, owner);
+         if (!NoVerifyOption)
+           ini_sig_file = get_url_to_membuf (current_ini_sig_name, owner);
+
+         if (!NoVerifyOption && ini_file && !ini_sig_file)
+           {
+             note (owner, IDS_SETUPINI_MISSING, current_ini_sig_name.c_str(), n->url.c_str());
+             delete ini_file;
+             ini_file = NULL;
+             sig_fail = true;
+           }
+         else if (!NoVerifyOption && ini_file && !verify_ini_file_sig (ini_file, ini_sig_file, owner))
+           {
+             note (owner, IDS_SIG_INVALID, current_ini_sig_name.c_str(), n->url.c_str());
+             delete ini_file;
+             ini_file = NULL;
+             delete ini_sig_file;
+             ini_sig_file = NULL;
+             sig_fail = true;
+           }
+       }
+
+      if (!ini_file)
+       {
+         if (!sig_fail)
+           note (owner, IDS_SETUPINI_MISSING, SETUP_INI_FILENAME, n->url.c_str());
+         continue;
+       }
+
+      myFeedback.iniName (current_ini_name);
+      aBuilder.parse_mirror = n->url;
+      ini_init (ini_file, &aBuilder, myFeedback);
+
+      /*yydebug = 1; */
+
+      if (yyparse () || yyerror_count > 0)
+        myFeedback.error (yyerror_messages);
       else
-       MessageBox (0, error_buf, "Parse Errors", 0);
-    }
-  else
-    {
-      /* save known-good setup.ini locally */
-      FILE *inif = fopen ("setup.ini", "wb");
-      if (inif)
        {
-         fwrite (ini_file, 1, strlen (ini_file), inif);
-         fclose (inif);
+         /* save known-good setup.ini locally */
+         const std::string fp = "file://" + local_dir + "/" +
+                                  rfc1738_escape_part (n->url) +
+                                  "/" + SETUP_INI_FILENAME;
+         io_stream::mkpath_p (PATH_TO_FILE, fp);
+         if (io_stream *out = io_stream::open (fp, "wb"))
+           {
+              ini_file->seek (0, IO_SEEK_SET);
+             if (io_stream::copy (ini_file, out) != 0)
+               io_stream::remove (fp);
+             delete out;
+           }
+         ++ini_count;
+       }
+      if (aBuilder.timestamp > setup_timestamp)
+       {
+         setup_timestamp = aBuilder.timestamp;
+         ini_setup_version = aBuilder.version;
        }
+      delete ini_file;
     }
+  return ini_count;
+}
+
+static bool
+do_ini_thread (HINSTANCE h, HWND owner)
+{
+  size_t ini_count = 0;
+  if (source == IDC_SOURCE_CWD)
+    ini_count = do_local_ini (owner);
+  else
+    ini_count = do_remote_ini (owner);
+
+  if (ini_count == 0)
+    return false;
 
-  if (get_root_dir ())
+  if (get_root_dir ().c_str())
     {
-      mkdir_p (1, cygpath ("/etc/setup", 0));
+      io_stream::mkpath_p (PATH_TO_DIR, "cygfile:///etc/setup");
 
       unsigned int old_timestamp = 0;
-      FILE *ots = fopen (cygpath ("/etc/setup/timestamp", 0), "rt");
+      io_stream *ots =
+       io_stream::open ("cygfile:///etc/setup/timestamp", "rt");
       if (ots)
        {
-         fscanf (ots, "%u", &old_timestamp);
-         fclose (ots);
+         char temp[20];
+         memset (temp, '\0', 20);
+         if (ots->read (temp, 19))
+           sscanf (temp, "%u", &old_timestamp);
+         delete ots;
          if (old_timestamp && setup_timestamp
              && (old_timestamp > setup_timestamp))
            {
-             int yn = yesno (IDS_OLD_SETUPINI);
+             int yn = yesno (owner, IDS_OLD_SETUPINI);
              if (yn == IDNO)
-               exit_setup (1);
+               LogSingleton::GetInstance().exit (1);
            }
        }
       if (setup_timestamp)
        {
-         FILE *nts = fopen (cygpath ("/etc/setup/timestamp", 0), "wt");
+         io_stream *nts =
+           io_stream::open ("cygfile:///etc/setup/timestamp", "wt");
          if (nts)
            {
-             fprintf (nts, "%u", setup_timestamp);
-             fclose (nts);
+             char temp[20];
+             sprintf (temp, "%u", setup_timestamp);
+             nts->write (temp, strlen (temp));
+             delete nts;
            }
        }
     }
 
-  msg ("setup_version is %s, our_version is %s", setup_version?:"(null)", version);
-  if (setup_version)
+  msg (".ini setup_version is %s, our setup_version is %s", ini_setup_version.size() ? 
+       ini_setup_version.c_str() : "(null)",
+       setup_version);
+  if (ini_setup_version.size())
     {
-      char *ini_version = canonicalize_version (setup_version);
-      char *our_version = canonicalize_version (version);
-      if (strcmp (our_version, ini_version) < 0)
-       note (IDS_OLD_SETUP_VERSION, version, setup_version);
+      if (version_compare(setup_version, ini_setup_version) < 0)
+       note (owner, IDS_OLD_SETUP_VERSION, setup_version,
+              ini_setup_version.c_str());
     }
 
-  next_dialog = IDD_CHOOSE;
+  return true;
 }
 
-extern int yylineno;
-
-extern "C" int yyerror (char *s, ...)
+static DWORD WINAPI
+do_ini_thread_reflector(void* p)
 {
-  char buf[1000];
-  int len;
-  sprintf (buf, "setup.ini line %d: ", yylineno);
-  va_list args;
-  va_start (args, s);
-  vsprintf (buf + strlen (buf), s, args);
-  OutputDebugString (buf);
-  if (error_buf)
-    {
-      strcat (error_buf, "\n");
-      len = strlen (error_buf) + strlen (buf) + 5;
-      error_buf = (char *) realloc (error_buf, len);
-      strcat (error_buf, buf);
-    }
-  else
-    {
-      len = strlen (buf) + 5;
-      error_buf = (char *) malloc (len);
-      strcpy (error_buf, buf);
-    }
-  error_count++;
-}
+  HANDLE *context;
+  context = (HANDLE*)p;
 
-extern "C" int fprintf (FILE *f, const char *s, ...);
+  try
+  {
+    bool succeeded = do_ini_thread((HINSTANCE)context[0], (HWND)context[1]);
 
-static char stderrbuf[1000];
+    // Tell the progress page that we're done downloading
+    Progress.PostMessage(WM_APP_SETUP_INI_DOWNLOAD_COMPLETE, 0, succeeded);
+  }
+  TOPLEVEL_CATCH("ini");
 
-int
-fprintf (FILE *f, const char *fmt, ...)
-{
-  char buf[1000];
-  int rv;
-  va_list args;
-  va_start (args, fmt);
-  if (f == stderr)
-    {
-      rv = vsprintf (buf, fmt, args);
-      strcat (stderrbuf, buf);
-      if (char *nl = strchr (stderrbuf, '\n'))
-       {
-         *nl = 0;
-         /*OutputDebugString (stderrbuf);*/
-         MessageBox (0, buf, "Cygwin Setup", 0);
-         stderrbuf[0] = 0;
-       }
+  ExitThread(0);
+}
 
-    }
-  else
-    {
-      rv = vfprintf (f, fmt, args);
-    }
-  return rv;
+static HANDLE context[2];
+
+void
+do_ini (HINSTANCE h, HWND owner)
+{
+  context[0] = h;
+  context[1] = owner;
+       
+  DWORD threadID;      
+  CreateThread (NULL, 0, do_ini_thread_reflector, context, 0, &threadID);
 }
+
This page took 0.031055 seconds and 5 git commands to generate.