]> cygwin.com Git - cygwin-apps/setup.git/blame - download.cc
2004-11-22 Max Bowsher <maxb@ukf.net>
[cygwin-apps/setup.git] / download.cc
CommitLineData
23c9e63c 1/*
9fe1181b 2 * Copyright (c) 2000, 2001, Red Hat, Inc.
23c9e63c
DD
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * A copy of the GNU General Public License can be found at
10 * http://www.gnu.org/
11 *
12 * Written by DJ Delorie <dj@cygnus.com>
13 *
14 */
15
16/* The purpose of this file is to download all the files we need to
17 do the installation. */
18
b24c88b3
RC
19#if 0
20static const char *cvsid =
21 "\n%%% $Id$\n";
22#endif
8507f105 23
aa1e3b4d
RC
24#include "download.h"
25
23c9e63c
DD
26#include "win32.h"
27
28#include <stdio.h>
42bf5b92 29#include <unistd.h>
ab57ceaa 30#include <process.h>
23c9e63c
DD
31
32#include "resource.h"
33#include "msg.h"
23c9e63c 34#include "dialog.h"
3c054baf 35#include "String++.h"
23c9e63c
DD
36#include "geturl.h"
37#include "state.h"
aa1e3b4d 38#include "LogSingleton.h"
341988b9 39#include "filemanip.h"
23c9e63c 40
bb849dbd
RC
41#include "io_stream.h"
42
43#include "package_db.h"
44#include "package_meta.h"
45#include "package_version.h"
46#include "package_source.h"
47
48#include "rfc1738.h"
49
ab57ceaa 50#include "threebar.h"
58ee6135 51
58ee6135
RC
52#include "Exception.h"
53
5f4b0e57 54#include "getopt++/BoolOption.h"
0229b1d7 55#include "csu_util/MD5Sum.h"
5f4b0e57 56
6625e635
RC
57using namespace std;
58
ab57ceaa
RC
59extern ThreeBarProgressPage Progress;
60
5f4b0e57 61static BoolOption NoMD5Option (false, '5', "no-md5", "Suppress MD5 checksum verification");
aa1e3b4d 62
6beebaa3 63static bool
aa1e3b4d
RC
64validateCachedPackage (String const &fullname, packagesource & pkgsource)
65{
6beebaa3
MB
66 DWORD size = get_file_size(fullname);
67 if (size != pkgsource.size)
68 {
69 log (LOG_BABBLE) << "INVALID PACKAGE: " << fullname
70 << " - Size mismatch: Ini-file: " << pkgsource.size
71 << " != On-disk: " << size << endLog;
72 return false;
73 }
5f4b0e57 74 if (pkgsource.md5.isSet() && !NoMD5Option)
aa1e3b4d
RC
75 {
76 // check the MD5 sum of the cached file here
77 io_stream *thefile = io_stream::open (fullname, "rb");
78 if (!thefile)
79 return 0;
0229b1d7
MB
80 MD5Sum tempMD5;
81 tempMD5.begin();
aa1e3b4d
RC
82
83 log (LOG_BABBLE) << "Checking MD5 for " << fullname << endLog;
84
85 Progress.SetText1 ((String ("Checking MD5 for ") + pkgsource.Base()).cstr_oneuse());
86 Progress.SetText4 ("Progress:");
87 Progress.SetBar1 (0);
88
89 unsigned char buffer[16384];
90 ssize_t count;
91 while ((count = thefile->read (buffer, 16384)) > 0)
92 {
0229b1d7 93 tempMD5.append(buffer, count);
aa1e3b4d
RC
94 Progress.SetBar1 (thefile->tell(), thefile->get_size());
95 }
96 delete thefile;
97 if (count < 0)
6beebaa3
MB
98 throw new Exception (TOSTRING(__LINE__) " " __FILE__,
99 String ("IO Error reading ") + fullname,
100 APPERR_IO_ERROR);
aa1e3b4d 101
0229b1d7 102 tempMD5.finish();
aa1e3b4d 103
aa1e3b4d 104 if (pkgsource.md5 != tempMD5)
6beebaa3
MB
105 {
106 log (LOG_BABBLE) << "INVALID PACKAGE: " << fullname
0229b1d7
MB
107 << " - MD5 mismatch: Ini-file: " << pkgsource.md5.str()
108 << " != On-disk: " << tempMD5.str() << endLog;
6beebaa3
MB
109 return false;
110 }
111
0229b1d7
MB
112 log (LOG_BABBLE) << "MD5 verified OK: " << fullname << " "
113 << pkgsource.md5.str() << endLog;
aa1e3b4d
RC
114 }
115 return true;
116}
117
bb849dbd
RC
118/* 0 on failure
119 */
58ee6135 120int
bb849dbd 121check_for_cached (packagesource & pkgsource)
3b9077d4 122{
bb849dbd
RC
123 /* search algo:
124 1) is there a legacy version in the cache dir available.
125 (Note that the cache dir is represented by a mirror site of
126 file://local_dir
127 */
3b9077d4 128
58ee6135
RC
129 // Already found one.
130 if (pkgsource.Cached())
131 return 1;
e0a4db64
RC
132
133 String prefix = String ("file://") + local_dir + "/";
6beebaa3
MB
134 String fullname = prefix + pkgsource.Canonical();
135 if (io_stream::exists(fullname))
136 {
137 if (validateCachedPackage (fullname, pkgsource))
138 pkgsource.set_cached (fullname);
139 else
140 throw new Exception (TOSTRING(__LINE__) " " __FILE__,
141 String ("Package validation failure for ") + fullname,
142 APPERR_CORRUPT_PACKAGE);
143 return 1;
144 }
3b9077d4 145
bb849dbd
RC
146 /*
147 2) is there a version from one of the selected mirror sites available ?
6beebaa3 148 */
3f34f364
RC
149 for (packagesource::sitestype::const_iterator n = pkgsource.sites.begin();
150 n != pkgsource.sites.end(); ++n)
6beebaa3
MB
151 {
152 String fullname = prefix + rfc1738_escape_part (n->key) + "/" +
153 pkgsource.Canonical ();
154 if (io_stream::exists(fullname))
58ee6135 155 {
6beebaa3
MB
156 if (validateCachedPackage (fullname, pkgsource))
157 pkgsource.set_cached (fullname);
158 else
159 throw new Exception (TOSTRING(__LINE__) " " __FILE__,
160 String ("Package validation failure for ") + fullname,
161 APPERR_CORRUPT_PACKAGE);
162 return 1;
aa1e3b4d 163 }
6beebaa3 164 }
bb849dbd
RC
165 return 0;
166}
167
168/* download a file from a mirror site to the local cache. */
169static int
ab57ceaa 170download_one (packagesource & pkgsource, HWND owner)
bb849dbd 171{
58ee6135
RC
172 try
173 {
174 if (check_for_cached (pkgsource))
175 return 0;
176 }
177 catch (Exception * e)
178 {
179 // We know what to do with these..
180 if (e->errNo() == APPERR_CORRUPT_PACKAGE)
181 {
182 fatal (owner, IDS_CORRUPT_PACKAGE, pkgsource.Canonical());
183 return 1;
184 }
185 // Unexpected exception.
186 throw e;
187 }
bb849dbd
RC
188 /* try the download sites one after another */
189
190 int success = 0;
3f34f364
RC
191 for (packagesource::sitestype::const_iterator n = pkgsource.sites.begin();
192 n != pkgsource.sites.end() && !success; ++n)
d4a4527d 193 {
3c054baf 194 String const local = local_dir + "/" +
3f34f364 195 rfc1738_escape_part (n->key) + "/" +
3c054baf 196 pkgsource.Canonical ();
1ac649ed 197 io_stream::mkpath_p (PATH_TO_FILE, String ("file://") + local);
3c054baf 198
3f34f364 199 if (get_url_to_file(n->key + "/" + pkgsource.Canonical (),
1ac649ed 200 local + ".tmp", pkgsource.size, owner))
3b9077d4 201 {
bb849dbd
RC
202 /* FIXME: note new source ? */
203 continue;
3b9077d4
DD
204 }
205 else
206 {
e0a4db64 207 size_t size = get_file_size (String("file://") + local + ".tmp");
bb849dbd
RC
208 if (size == pkgsource.size)
209 {
aa1e3b4d 210 log (LOG_PLAIN) << "Downloaded " << local << endLog;
3c054baf
RC
211 if (_access (local.cstr_oneuse(), 0) == 0)
212 remove (local.cstr_oneuse());
213 rename ((local + ".tmp").cstr_oneuse(), local.cstr_oneuse());
bb849dbd 214 success = 1;
3c054baf
RC
215 pkgsource.set_cached (String ("file://") + local);
216 // FIXME: move the downloaded file to the
217 // original locations - without the mirror site dir in the way
bb849dbd
RC
218 continue;
219 }
220 else
221 {
aa1e3b4d
RC
222 log (LOG_PLAIN) << "Download " << local << " wrong size (" <<
223 size << " actual vs " << pkgsource.size << " expected)" <<
224 endLog;
3c054baf 225 remove ((local + ".tmp").cstr_oneuse());
bb849dbd
RC
226 continue;
227 }
3b9077d4
DD
228 }
229 }
bb849dbd
RC
230 if (success)
231 return 0;
232 /* FIXME: Do we want to note this? if so how? */
233 return 1;
3b9077d4
DD
234}
235
49560a44 236static int
ab57ceaa 237do_download_thread (HINSTANCE h, HWND owner)
23c9e63c 238{
2a1a01e0 239 int errors = 0;
2f9645a1
CV
240 total_download_bytes = 0;
241 total_download_bytes_sofar = 0;
242
bb849dbd
RC
243 packagedb db;
244 /* calculate the amount needed */
cfae3b8d
RC
245 for (vector <packagemeta *>::iterator i = db.packages.begin ();
246 i != db.packages.end (); ++i)
cbfc4215 247 {
cfae3b8d 248 packagemeta & pkg = **i;
3c196821 249 if (pkg.desired.changeRequested())
ab57ceaa 250 {
3c196821
RC
251 packageversion version = pkg.desired;
252 packageversion sourceversion = version.sourcePackage();
58ee6135
RC
253 try
254 {
ec13f13c
RC
255 if (version.picked())
256 {
257 for (vector<packagesource>::iterator i =
258 version.sources ()->begin();
259 i != version.sources ()->end(); ++i)
260 if (!check_for_cached (*i))
261 total_download_bytes += i->size;
262 }
263 if (sourceversion.picked ())
264 {
265 for (vector<packagesource>::iterator i =
266 sourceversion.sources ()->begin();
267 i != sourceversion.sources ()->end(); ++i)
268 if (!check_for_cached (*i))
269 total_download_bytes += i->size;
270 }
58ee6135
RC
271 }
272 catch (Exception * e)
273 {
274 // We know what to do with these..
275 if (e->errNo() == APPERR_CORRUPT_PACKAGE)
276 fatal (owner, IDS_CORRUPT_PACKAGE, pkg.name.cstr_oneuse());
277 // Unexpected exception.
278 throw e;
279 }
ab57ceaa 280 }
cbfc4215 281 }
23c9e63c 282
bb849dbd
RC
283 /* and do the download. FIXME: This here we assign a new name for the cached version
284 * and check that above.
285 */
cfae3b8d
RC
286 for (vector <packagemeta *>::iterator i = db.packages.begin ();
287 i != db.packages.end (); ++i)
cbfc4215 288 {
cfae3b8d 289 packagemeta & pkg = **i;
3c196821 290 if (pkg.desired.changeRequested())
ab57ceaa
RC
291 {
292 int e = 0;
3c196821
RC
293 packageversion version = pkg.desired;
294 packageversion sourceversion = version.sourcePackage();
295 if (version.picked())
ec13f13c
RC
296 {
297 for (vector<packagesource>::iterator i =
298 version.sources ()->begin();
299 i != version.sources ()->end(); ++i)
300 e += download_one (*i, owner);
301 }
3c196821 302 if (sourceversion && sourceversion.picked())
ec13f13c
RC
303 {
304 for (vector<packagesource>::iterator i =
305 sourceversion.sources ()->begin();
306 i != sourceversion.sources ()->end(); ++i)
307 e += download_one (*i, owner);
308 }
ab57ceaa 309 errors += e;
bb849dbd 310#if 0
ab57ceaa
RC
311 if (e)
312 pkg->action = ACTION_ERROR;
bb849dbd 313#endif
ab57ceaa 314 }
cbfc4215 315 }
23c9e63c 316
2a1a01e0
DD
317 if (errors)
318 {
ab57ceaa 319 if (yesno (owner, IDS_DOWNLOAD_INCOMPLETE) == IDYES)
2a1a01e0 320 {
49560a44 321 return IDD_SITE;
2a1a01e0
DD
322 }
323 }
324
bf1d5889
DD
325 if (source == IDC_SOURCE_DOWNLOAD)
326 {
2a1a01e0
DD
327 if (errors)
328 exit_msg = IDS_DOWNLOAD_INCOMPLETE;
f2ff9838 329 else if (!unattended_mode)
2a1a01e0 330 exit_msg = IDS_DOWNLOAD_COMPLETE;
49560a44 331 return 0;
bf1d5889
DD
332 }
333 else
49560a44 334 return IDD_S_INSTALL;
23c9e63c 335}
ab57ceaa 336
45e01f23 337static DWORD WINAPI
ab57ceaa
RC
338do_download_reflector (void *p)
339{
340 HANDLE *context;
341 context = (HANDLE *) p;
342
072fb49a
MB
343 try
344 {
49560a44
MB
345 int next_dialog =
346 do_download_thread ((HINSTANCE) context[0], (HWND) context[1]);
ab57ceaa 347
072fb49a
MB
348 // Tell the progress page that we're done downloading
349 Progress.PostMessage (WM_APP_DOWNLOAD_THREAD_COMPLETE, 0, next_dialog);
350 }
351 TOPLEVEL_CATCH("download");
ab57ceaa 352
45e01f23 353 ExitThread(0);
ab57ceaa
RC
354}
355
356static HANDLE context[2];
357
358void
359do_download (HINSTANCE h, HWND owner)
360{
361 context[0] = h;
362 context[1] = owner;
363
45e01f23
RC
364 DWORD threadID;
365 CreateThread (NULL, 0, do_download_reflector, context, 0, &threadID);
ab57ceaa 366}
This page took 0.085802 seconds and 5 git commands to generate.