]> cygwin.com Git - cygwin-apps/setup.git/blobdiff - download.cc
2002-07-15 Robert Collins <rbtcollins@hotmail.com>
[cygwin-apps/setup.git] / download.cc
index daabe1d0755c9d70b388c74bece025fac58eef04..6a375a9c84172106369d039e1c58ee41388bfefb 100644 (file)
 /* The purpose of this file is to download all the files we need to
    do the installation. */
 
-static char *cvsid = "\n%%% $Id$\n";
+#if 0
+static const char *cvsid =
+  "\n%%% $Id$\n";
+#endif
 
+#include "download.h"
+  
 #include "win32.h"
 
 #include <stdio.h>
 #include <unistd.h>
+#include <process.h>
 
 #include "resource.h"
 #include "msg.h"
-#include "ini.h"
 #include "dialog.h"
-#include "concat.h"
+#include "String++.h"
 #include "geturl.h"
 #include "state.h"
-#include "mkdir.h"
-#include "log.h"
-#include "port.h"
+#include "LogSingleton.h"
+#include "filemanip.h"
 
-#define pi (package[i].info[package[i].trust])
+#include "io_stream.h"
 
-DWORD
-get_file_size (char *name)
-{
-  HANDLE h;
-  WIN32_FIND_DATA buf;
-  DWORD ret = 0;
+#include "package_db.h"
+#include "package_meta.h"
+#include "package_version.h"
+#include "package_source.h"
+
+#include "rfc1738.h"
+
+#include "threebar.h"
+
+#include "md5.h"
 
-  h = FindFirstFileA (name, &buf);
-  if (h != INVALID_HANDLE_VALUE)
+#include "Exception.h"
+
+extern ThreeBarProgressPage Progress;
+
+
+bool
+validateCachedPackage (String const &fullname, packagesource & pkgsource)
+{
+  if (pkgsource.md5.isSet())
     {
-      if (buf.nFileSizeHigh == 0)
-       ret = buf.nFileSizeLow;
-      FindClose (h);
+      // check the MD5 sum of the cached file here
+      io_stream *thefile = io_stream::open (fullname, "rb");
+      if (!thefile)
+       return 0;
+      md5_state_t pns;
+      md5_init (&pns);
+
+      log (LOG_BABBLE) << "Checking MD5 for " << fullname << endLog;
+
+      Progress.SetText1 ((String ("Checking MD5 for ") + pkgsource.Base()).cstr_oneuse());
+      Progress.SetText4 ("Progress:");
+      Progress.SetBar1 (0);
+      
+      unsigned char buffer[16384];
+      ssize_t count;
+      while ((count = thefile->read (buffer, 16384)) > 0)
+       {
+         md5_append (&pns, buffer, count);
+         Progress.SetBar1 (thefile->tell(), thefile->get_size());
+       }
+      delete thefile;
+      if (count < 0)
+       throw new Exception ("__LINE__ __FILE__", (String ("IO Error reading ") + pkgsource.Cached()).cstr_oneuse(), APPERR_IO_ERROR);
+      
+      md5_byte_t tempdigest[16];
+      md5_finish(&pns, tempdigest);
+      md5 tempMD5;
+      tempMD5.set (tempdigest);
+      
+      log (LOG_BABBLE) << "For file '" << fullname << 
+          " ini digest is " << pkgsource.md5.print() <<
+          " file digest is " << tempMD5.print() << endLog;
+      
+      if (pkgsource.md5 != tempMD5)
+       return false;
     }
-  return ret;
+  return true;
 }
 
-static int
-download_one (char *name, int expected_size, int action)
+/* 0 on failure
+ */
+int
+check_for_cached (packagesource & pkgsource)
 {
-  char *local = name;
-  int errors = 0;
+  /* search algo:
+     1) is there a legacy version in the cache dir available.
+     (Note that the cache dir is represented by a mirror site of
+     file://local_dir
+   */
 
+  // Already found one.
+  if (pkgsource.Cached())
+    return 1;
+  
+  String prefix = String ("file://") + local_dir +  "/";
   DWORD size;
-  if ((size = get_file_size (local)) > 0)
-    if (size == expected_size && action != ACTION_SRC_ONLY
-  && action != ACTION_REDO )
-      return 0;
+  if ((size = get_file_size (prefix + pkgsource.Canonical ())) > 0)
+    if (size == pkgsource.size)
+      {
+       if (validateCachedPackage (prefix + pkgsource.Canonical (), pkgsource))
+         pkgsource.set_cached (prefix + pkgsource.Canonical ());
+       else
+         throw new Exception ("__LINE__ __FILE__", (String ("Package validation failure for ") + prefix + pkgsource.Canonical ()).cstr_oneuse(), APPERR_CORRUPT_PACKAGE);
+       return 1;
+      }
 
-  mkdir_p (0, local);
+  /*
+     2) is there a version from one of the selected mirror sites available ?
+   */
+  for (packagesource::sitestype::const_iterator n = pkgsource.sites.begin();
+       n != pkgsource.sites.end(); ++n)
+    {
+      String fullname = prefix + rfc1738_escape_part (n->key) + "/" +
+       pkgsource.Canonical ();
+    if ((size = get_file_size (fullname)) > 0)
+      if (size == pkgsource.size)
+       {
+         if (validateCachedPackage (fullname, pkgsource))
+           pkgsource.set_cached (fullname );
+         else
+           throw new Exception ("__LINE__ __FILE__", (String ("Package validation failure for ") + fullname).cstr_oneuse(), APPERR_CORRUPT_PACKAGE);
+         return 1;
+       }
+    }
+  return 0;
+}
 
-  if (get_url_to_file (concat (MIRROR_SITE, "/", name, 0),
-                      concat (local, ".tmp", 0),
-                      expected_size))
+/* download a file from a mirror site to the local cache. */
+static int
+download_one (packagesource & pkgsource, HWND owner)
+{
+  try
     {
-      note (IDS_DOWNLOAD_FAILED, name);
-      return 1;
+      if (check_for_cached (pkgsource))
+        return 0;
     }
-  else
+  catch (Exception * e)
+    {
+      // We know what to do with these..
+      if (e->errNo() == APPERR_CORRUPT_PACKAGE)
+       {
+         fatal (owner, IDS_CORRUPT_PACKAGE, pkgsource.Canonical());
+         return 1;
+       }
+      // Unexpected exception.
+      throw e;
+    }
+  /* try the download sites one after another */
+
+  int success = 0;
+  for (packagesource::sitestype::const_iterator n = pkgsource.sites.begin();
+       n != pkgsource.sites.end() && !success; ++n)
     {
-      size = get_file_size (concat (local, ".tmp", 0));
-      if (size == expected_size)
+      String const local = local_dir + "/" +
+                                 rfc1738_escape_part (n->key) + "/" +
+                                 pkgsource.Canonical ();
+      io_stream::mkpath_p (PATH_TO_FILE, String ("file://") + local);
+
+      if (get_url_to_file(n->key +  "/" + pkgsource.Canonical (),
+                         local + ".tmp", pkgsource.size, owner))
        {
-         log (0, "Downloaded %s", local);
-    if ( _access (local , 0) == 0)
-       remove ( local );
-         rename (concat (local, ".tmp", 0), local);
+         /* FIXME: note new source ? */
+         continue;
        }
       else
        {
-         log (0, "Download %s wrong size (%d actual vs %d expected)",
-              local, size, expected_size);
-         note (IDS_DOWNLOAD_SHORT, local, size, expected_size);
-         return 1;
+         size_t size = get_file_size (String("file://") + local + ".tmp");
+         if (size == pkgsource.size)
+           {
+             log (LOG_PLAIN) << "Downloaded " << local << endLog;
+             if (_access (local.cstr_oneuse(), 0) == 0)
+               remove (local.cstr_oneuse());
+             rename ((local + ".tmp").cstr_oneuse(), local.cstr_oneuse());
+             success = 1;
+             pkgsource.set_cached (String ("file://") + local);
+             // FIXME: move the downloaded file to the 
+             //  original locations - without the mirror site dir in the way
+             continue;
+           }
+         else
+           {
+             log (LOG_PLAIN) << "Download " << local << " wrong size (" <<
+               size << " actual vs " << pkgsource.size << " expected)" << 
+               endLog;
+             remove ((local + ".tmp").cstr_oneuse());
+             continue;
+           }
        }
     }
-
-  return 0;
+  if (success)
+    return 0;
+  /* FIXME: Do we want to note this? if so how? */
+  return 1;
 }
 
-void
-do_download (HINSTANCE h)
+static void
+do_download_thread (HINSTANCE h, HWND owner)
 {
-  int i;
   int errors = 0;
   total_download_bytes = 0;
   total_download_bytes_sofar = 0;
 
-  for (i=0; i<npackages; i++)
-    if (package[i].action == ACTION_NEW || package[i].action == ACTION_UPGRADE
-  || package[i].action == ACTION_REDO
-  || package[i].action == ACTION_SRC_ONLY)
-      {
-       DWORD size = get_file_size (pi.install);
-  char *local = pi.install;
-       if (package[i].action != ACTION_SRC_ONLY &&
-     (package[i].action == ACTION_REDO ||
-     size != pi.install_size))
-    total_download_bytes += pi.install_size;
-  local = pi.source;
-  size = get_file_size (pi.source);
-       if (package[i].srcaction == SRCACTION_YES &&
-     (package[i].action == ACTION_SRC_ONLY ||
-     size != pi.source_size))
-         total_download_bytes += pi.source_size;
-      }
-
-  for (i=0; i<npackages; i++)
-    if (package[i].action == ACTION_NEW || package[i].action == ACTION_UPGRADE
-  || package[i].action == ACTION_REDO
-  || package[i].action == ACTION_SRC_ONLY)
-      {
-  int e = 0;
-       if (package[i].action != ACTION_SRC_ONLY)
-    e += download_one (pi.install, pi.install_size, package[i].action);
-       if (package[i].srcaction == SRCACTION_YES && pi.source)
-    e += download_one (pi.source, pi.source_size, package[i].action);
-       errors += e;
-       if (e)
-         package[i].action = ACTION_ERROR;
-      }
+  packagedb db;
+  /* calculate the amount needed */
+  for (vector <packagemeta *>::iterator i = db.packages.begin ();
+       i != db.packages.end (); ++i)
+    {
+      packagemeta & pkg = **i;
+      if (pkg.desired.changeRequested())
+       {
+         packageversion version = pkg.desired;
+         packageversion sourceversion = version.sourcePackage();
+         try 
+           {
+             if (version.picked())
+               {
+                 for (vector<packagesource>::iterator i = 
+                      version.sources ()->begin(); 
+                      i != version.sources ()->end(); ++i)
+                   if (!check_for_cached (*i))
+                     total_download_bytes += i->size;
+               }
+             if (sourceversion.picked ())
+               {
+                 for (vector<packagesource>::iterator i =
+                      sourceversion.sources ()->begin();
+                      i != sourceversion.sources ()->end(); ++i)
+                   if (!check_for_cached (*i))
+                     total_download_bytes += i->size;
+               }
+           }
+         catch (Exception * e)
+           {
+             // We know what to do with these..
+             if (e->errNo() == APPERR_CORRUPT_PACKAGE)
+               fatal (owner, IDS_CORRUPT_PACKAGE, pkg.name.cstr_oneuse());
+             // Unexpected exception.
+             throw e;
+           }
+       }
+    }
 
-  dismiss_url_status_dialog ();
+  /* and do the download. FIXME: This here we assign a new name for the cached version
+   * and check that above.
+   */
+  for (vector <packagemeta *>::iterator i = db.packages.begin ();
+       i != db.packages.end (); ++i)
+    {
+      packagemeta & pkg = **i;
+      if (pkg.desired.changeRequested())
+       {
+         int e = 0;
+         packageversion version = pkg.desired;
+         packageversion sourceversion = version.sourcePackage();
+         if (version.picked())
+           {
+             for (vector<packagesource>::iterator i =
+                  version.sources ()->begin();
+                  i != version.sources ()->end(); ++i)
+               e += download_one (*i, owner);
+           }
+         if (sourceversion && sourceversion.picked())
+           {
+             for (vector<packagesource>::iterator i =
+                  sourceversion.sources ()->begin();
+                  i != sourceversion.sources ()->end(); ++i)
+               e += download_one (*i, owner);
+           }
+         errors += e;
+#if 0
+         if (e)
+           pkg->action = ACTION_ERROR;
+#endif
+       }
+    }
 
   if (errors)
     {
-      if (yesno (IDS_DOWNLOAD_INCOMPLETE) == IDYES)
+      if (yesno (owner, IDS_DOWNLOAD_INCOMPLETE) == IDYES)
        {
          next_dialog = IDD_SITE;
          return;
@@ -160,3 +317,29 @@ do_download (HINSTANCE h)
   else
     next_dialog = IDD_S_INSTALL;
 }
+
+static DWORD WINAPI
+do_download_reflector (void *p)
+{
+  HANDLE *context;
+  context = (HANDLE *) p;
+
+  do_download_thread ((HINSTANCE) context[0], (HWND) context[1]);
+
+  // Tell the progress page that we're done downloading
+  Progress.PostMessage (WM_APP_DOWNLOAD_THREAD_COMPLETE, 0, next_dialog);
+
+  ExitThread(0);
+}
+
+static HANDLE context[2];
+
+void
+do_download (HINSTANCE h, HWND owner)
+{
+  context[0] = h;
+  context[1] = owner;
+
+  DWORD threadID;
+  CreateThread (NULL, 0, do_download_reflector, context, 0, &threadID);
+}
This page took 0.03246 seconds and 5 git commands to generate.