]> cygwin.com Git - cygwin-apps/setup.git/blame_incremental - download.cc
2002-07-08 Max Bowsher <maxb@ukf.net>
[cygwin-apps/setup.git] / download.cc
... / ...
CommitLineData
1/*
2 * Copyright (c) 2000, 2001, Red Hat, Inc.
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
19#if 0
20static const char *cvsid =
21 "\n%%% $Id$\n";
22#endif
23
24#include "download.h"
25
26#include "win32.h"
27
28#include <stdio.h>
29#include <unistd.h>
30#include <process.h>
31
32#include "resource.h"
33#include "msg.h"
34#include "dialog.h"
35#include "String++.h"
36#include "geturl.h"
37#include "state.h"
38#include "LogSingleton.h"
39#include "filemanip.h"
40
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
50#include "threebar.h"
51
52#include "md5.h"
53
54#include "Exception.h"
55
56extern ThreeBarProgressPage Progress;
57
58
59bool
60validateCachedPackage (String const &fullname, packagesource & pkgsource)
61{
62 if (pkgsource.md5.isSet())
63 {
64 // check the MD5 sum of the cached file here
65 io_stream *thefile = io_stream::open (fullname, "rb");
66 if (!thefile)
67 return 0;
68 md5_state_t pns;
69 md5_init (&pns);
70
71 log (LOG_BABBLE) << "Checking MD5 for " << fullname << endLog;
72
73 Progress.SetText1 ((String ("Checking MD5 for ") + pkgsource.Base()).cstr_oneuse());
74 Progress.SetText4 ("Progress:");
75 Progress.SetBar1 (0);
76
77 unsigned char buffer[16384];
78 ssize_t count;
79 while ((count = thefile->read (buffer, 16384)) > 0)
80 {
81 md5_append (&pns, buffer, count);
82 Progress.SetBar1 (thefile->tell(), thefile->get_size());
83 }
84 delete thefile;
85 if (count < 0)
86 throw new Exception ("__LINE__ __FILE__", (String ("IO Error reading ") + pkgsource.Cached()).cstr_oneuse(), APPERR_IO_ERROR);
87
88 md5_byte_t tempdigest[16];
89 md5_finish(&pns, tempdigest);
90 md5 tempMD5;
91 tempMD5.set (tempdigest);
92
93 log (LOG_BABBLE) << "For file '" << fullname <<
94 " ini digest is " << pkgsource.md5.print() <<
95 " file digest is " << tempMD5.print() << endLog;
96
97 if (pkgsource.md5 != tempMD5)
98 return false;
99 }
100 return true;
101}
102
103/* 0 on failure
104 */
105int
106check_for_cached (packagesource & pkgsource)
107{
108 /* search algo:
109 1) is there a legacy version in the cache dir available.
110 (Note that the cache dir is represented by a mirror site of
111 file://local_dir
112 */
113
114 // Already found one.
115 if (pkgsource.Cached())
116 return 1;
117
118 String prefix = String ("file://") + local_dir + "/";
119 DWORD size;
120 if ((size = get_file_size (prefix + pkgsource.Canonical ())) > 0)
121 if (size == pkgsource.size)
122 {
123 if (validateCachedPackage (prefix + pkgsource.Canonical (), pkgsource))
124 pkgsource.set_cached (prefix + pkgsource.Canonical ());
125 else
126 throw new Exception ("__LINE__ __FILE__", (String ("Package validation failure for ") + prefix + pkgsource.Canonical ()).cstr_oneuse(), APPERR_CORRUPT_PACKAGE);
127 return 1;
128 }
129
130 /*
131 2) is there a version from one of the selected mirror sites available ?
132 */
133 for (packagesource::sitestype::const_iterator n = pkgsource.sites.begin();
134 n != pkgsource.sites.end(); ++n)
135 {
136 String fullname = prefix + rfc1738_escape_part (n->key) + "/" +
137 pkgsource.Canonical ();
138 if ((size = get_file_size (fullname)) > 0)
139 if (size == pkgsource.size)
140 {
141 if (validateCachedPackage (fullname, pkgsource))
142 pkgsource.set_cached (fullname );
143 else
144 throw new Exception ("__LINE__ __FILE__", (String ("Package validation failure for ") + fullname).cstr_oneuse(), APPERR_CORRUPT_PACKAGE);
145 return 1;
146 }
147 }
148 return 0;
149}
150
151/* download a file from a mirror site to the local cache. */
152static int
153download_one (packagesource & pkgsource, HWND owner)
154{
155 try
156 {
157 if (check_for_cached (pkgsource))
158 return 0;
159 }
160 catch (Exception * e)
161 {
162 // We know what to do with these..
163 if (e->errNo() == APPERR_CORRUPT_PACKAGE)
164 {
165 fatal (owner, IDS_CORRUPT_PACKAGE, pkgsource.Canonical());
166 return 1;
167 }
168 // Unexpected exception.
169 throw e;
170 }
171 /* try the download sites one after another */
172
173 int success = 0;
174 for (packagesource::sitestype::const_iterator n = pkgsource.sites.begin();
175 n != pkgsource.sites.end() && !success; ++n)
176 {
177 String const local = local_dir + "/" +
178 rfc1738_escape_part (n->key) + "/" +
179 pkgsource.Canonical ();
180 io_stream::mkpath_p (PATH_TO_FILE, String ("file://") + local);
181
182 if (get_url_to_file(n->key + "/" + pkgsource.Canonical (),
183 local + ".tmp", pkgsource.size, owner))
184 {
185 /* FIXME: note new source ? */
186 continue;
187 }
188 else
189 {
190 size_t size = get_file_size (String("file://") + local + ".tmp");
191 if (size == pkgsource.size)
192 {
193 log (LOG_PLAIN) << "Downloaded " << local << endLog;
194 if (_access (local.cstr_oneuse(), 0) == 0)
195 remove (local.cstr_oneuse());
196 rename ((local + ".tmp").cstr_oneuse(), local.cstr_oneuse());
197 success = 1;
198 pkgsource.set_cached (String ("file://") + local);
199 // FIXME: move the downloaded file to the
200 // original locations - without the mirror site dir in the way
201 continue;
202 }
203 else
204 {
205 log (LOG_PLAIN) << "Download " << local << " wrong size (" <<
206 size << " actual vs " << pkgsource.size << " expected)" <<
207 endLog;
208 remove ((local + ".tmp").cstr_oneuse());
209 continue;
210 }
211 }
212 }
213 if (success)
214 return 0;
215 /* FIXME: Do we want to note this? if so how? */
216 return 1;
217}
218
219static void
220do_download_thread (HINSTANCE h, HWND owner)
221{
222 int errors = 0;
223 total_download_bytes = 0;
224 total_download_bytes_sofar = 0;
225
226 packagedb db;
227 /* calculate the amount needed */
228 for (size_t n = 1; n <= db.packages.number (); n++)
229 {
230 packagemeta & pkg = *db.packages[n];
231 if (pkg.desired.changeRequested())
232 {
233 packageversion version = pkg.desired;
234 packageversion sourceversion = version.sourcePackage();
235 try
236 {
237 if (version.picked() && !check_for_cached (*version.source()))
238 total_download_bytes += version.source()->size;
239 if (sourceversion.picked ()
240 && !check_for_cached (*sourceversion.source()))
241 total_download_bytes += sourceversion.source()->size;
242 }
243 catch (Exception * e)
244 {
245 // We know what to do with these..
246 if (e->errNo() == APPERR_CORRUPT_PACKAGE)
247 fatal (owner, IDS_CORRUPT_PACKAGE, pkg.name.cstr_oneuse());
248 // Unexpected exception.
249 throw e;
250 }
251 }
252 }
253
254 /* and do the download. FIXME: This here we assign a new name for the cached version
255 * and check that above.
256 */
257 for (size_t n = 1; n <= db.packages.number (); n++)
258 {
259 packagemeta & pkg = *db.packages[n];
260 if (pkg.desired.changeRequested())
261 {
262 int e = 0;
263 packageversion version = pkg.desired;
264 packageversion sourceversion = version.sourcePackage();
265 if (version.picked())
266 e += download_one (*version.source(), owner);
267 if (sourceversion && sourceversion.picked())
268 e += download_one (*version.source(), owner);
269 errors += e;
270#if 0
271 if (e)
272 pkg->action = ACTION_ERROR;
273#endif
274 }
275 }
276
277 if (errors)
278 {
279 if (yesno (owner, IDS_DOWNLOAD_INCOMPLETE) == IDYES)
280 {
281 next_dialog = IDD_SITE;
282 return;
283 }
284 }
285
286 if (source == IDC_SOURCE_DOWNLOAD)
287 {
288 if (errors)
289 exit_msg = IDS_DOWNLOAD_INCOMPLETE;
290 else
291 exit_msg = IDS_DOWNLOAD_COMPLETE;
292 next_dialog = 0;
293 }
294 else
295 next_dialog = IDD_S_INSTALL;
296}
297
298static DWORD WINAPI
299do_download_reflector (void *p)
300{
301 HANDLE *context;
302 context = (HANDLE *) p;
303
304 do_download_thread ((HINSTANCE) context[0], (HWND) context[1]);
305
306 // Tell the progress page that we're done downloading
307 Progress.PostMessage (WM_APP_DOWNLOAD_THREAD_COMPLETE, 0, next_dialog);
308
309 ExitThread(0);
310}
311
312static HANDLE context[2];
313
314void
315do_download (HINSTANCE h, HWND owner)
316{
317 context[0] = h;
318 context[1] = owner;
319
320 DWORD threadID;
321 CreateThread (NULL, 0, do_download_reflector, context, 0, &threadID);
322}
This page took 0.023519 seconds and 5 git commands to generate.