X-Git-Url: https://cygwin.com/git/?a=blobdiff_plain;f=download.cc;h=6a375a9c84172106369d039e1c58ee41388bfefb;hb=ec13f13ca57fba24a53d873e9aa80527fc0b8134;hp=872eb64ca5fe5e906f6ca86e298af0be837bdb4c;hpb=d4a4527da0ec223a015fc7335f4f6cc51b20fd24;p=cygwin-apps%2Fsetup.git diff --git a/download.cc b/download.cc index 872eb64c..6a375a9c 100644 --- a/download.cc +++ b/download.cc @@ -21,121 +21,285 @@ static const char *cvsid = "\n%%% $Id$\n"; #endif +#include "download.h" + #include "win32.h" #include #include +#include #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" + +#include "io_stream.h" + +#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" + +#include "Exception.h" + +extern ThreeBarProgressPage Progress; -DWORD get_file_size (const char *name) -{ - HANDLE h; - WIN32_FIND_DATA buf; - DWORD ret = 0; - h = FindFirstFileA (name, &buf); - if (h != INVALID_HANDLE_VALUE) +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, unsigned int expected_size, int action) +/* 0 on failure + */ +int +check_for_cached (packagesource & pkgsource) { - char *local = name; + /* 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 (%ld 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 errors = 0; total_download_bytes = 0; total_download_bytes_sofar = 0; - for (Package * pkg = package; pkg->name; pkg++) - if (is_download_action (pkg)) - { - Info *pi = pkg->info + pkg->trust; - DWORD size = get_file_size (pi->install); - char *local = pi->install; - if (pkg->action != ACTION_SRC_ONLY && - (pkg->action == ACTION_REDO || size != pi->install_size)) - total_download_bytes += pi->install_size; - local = pi->source; - size = get_file_size (pi->source); - if (pkg->srcpicked && - (pkg->action == ACTION_SRC_ONLY || size != pi->source_size)) - total_download_bytes += pi->source_size; - } - - for (Package * pkg = package; pkg->name; pkg++) - if (is_download_action (pkg)) - { - int e = 0; - Info *pi = pkg->info + pkg->trust; - if (pkg->action != ACTION_SRC_ONLY) - e += download_one (pi->install, pi->install_size, pkg->action); - if (pkg->srcpicked && pi->source) - e += download_one (pi->source, pi->source_size, pkg->action); - errors += e; - if (e) - pkg->action = ACTION_ERROR; - } + packagedb db; + /* calculate the amount needed */ + for (vector ::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::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::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 ::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::iterator i = + version.sources ()->begin(); + i != version.sources ()->end(); ++i) + e += download_one (*i, owner); + } + if (sourceversion && sourceversion.picked()) + { + for (vector::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; @@ -153,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); +}