2 * Copyright (c) 2000, 2001, Red Hat, Inc.
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.
9 * A copy of the GNU General Public License can be found at
12 * Written by DJ Delorie <dj@cygnus.com>
16 /* The purpose of this file is to download all the files we need to
17 do the installation. */
19 #include "csu_util/rfc1738.h"
35 #include "filemanip.h"
37 #include "io_stream.h"
39 #include "package_db.h"
40 #include "package_meta.h"
41 #include "package_version.h"
42 #include "package_source.h"
46 #include "Exception.h"
48 #include "getopt++/BoolOption.h"
52 extern ThreeBarProgressPage Progress
;
54 BoolOption
IncludeSource (false, 'I', "include-source", "Automatically include source download");
57 validateCachedPackage (const std::string
& fullname
, packagesource
& pkgsource
)
59 DWORD size
= get_file_size(fullname
);
60 if (size
!= pkgsource
.size
)
62 Log (LOG_BABBLE
) << "INVALID PACKAGE: " << fullname
63 << " - Size mismatch: Ini-file: " << pkgsource
.size
64 << " != On-disk: " << size
<< endLog
;
73 check_for_cached (packagesource
& pkgsource
, bool mirror_mode
)
76 if (pkgsource
.Cached())
79 /* Note that the cache dir is represented by a mirror site of file://local_dir */
80 std::string prefix
= "file://" + local_dir
+ "/";
81 std::string fullname
= prefix
+ pkgsource
.Canonical();
85 /* Just assume correctness of mirror. */
86 pkgsource
.set_cached (fullname
);
91 1) is there a legacy version in the cache dir available.
93 if (io_stream::exists (fullname
))
95 if (validateCachedPackage (fullname
, pkgsource
))
96 pkgsource
.set_cached (fullname
);
98 throw new Exception (TOSTRING(__LINE__
) " " __FILE__
,
99 "Package validation failure for " + fullname
,
100 APPERR_CORRUPT_PACKAGE
);
105 2) is there a version from one of the selected mirror sites available ?
107 for (packagesource::sitestype::const_iterator n
= pkgsource
.sites
.begin();
108 n
!= pkgsource
.sites
.end(); ++n
)
110 std::string fullname
= prefix
+ rfc1738_escape_part (n
->key
) + "/" +
111 pkgsource
.Canonical ();
112 if (io_stream::exists(fullname
))
114 if (validateCachedPackage (fullname
, pkgsource
))
115 pkgsource
.set_cached (fullname
);
117 throw new Exception (TOSTRING(__LINE__
) " " __FILE__
,
118 "Package validation failure for " + fullname
,
119 APPERR_CORRUPT_PACKAGE
);
126 /* download a file from a mirror site to the local cache. */
128 download_one (packagesource
& pkgsource
, HWND owner
)
132 if (check_for_cached (pkgsource
))
135 catch (Exception
* e
)
137 // We know what to do with these..
138 if (e
->errNo() == APPERR_CORRUPT_PACKAGE
)
140 fatal (owner
, IDS_CORRUPT_PACKAGE
, pkgsource
.Canonical());
143 // Unexpected exception.
146 /* try the download sites one after another */
149 for (packagesource::sitestype::const_iterator n
= pkgsource
.sites
.begin();
150 n
!= pkgsource
.sites
.end() && !success
; ++n
)
152 const std::string local
= local_dir
+ "/" +
153 rfc1738_escape_part (n
->key
) + "/" +
154 pkgsource
.Canonical ();
155 io_stream::mkpath_p (PATH_TO_FILE
, "file://" + local
, 0);
157 if (get_url_to_file(n
->key
+ pkgsource
.Canonical (),
158 local
+ ".tmp", pkgsource
.size
, owner
))
160 /* FIXME: note new source ? */
165 size_t size
= get_file_size ("file://" + local
+ ".tmp");
166 if (size
== pkgsource
.size
)
168 Log (LOG_PLAIN
) << "Downloaded " << local
<< endLog
;
169 if (_access (local
.c_str(), 0) == 0)
170 remove (local
.c_str());
171 rename ((local
+ ".tmp").c_str(), local
.c_str());
173 pkgsource
.set_cached ("file://" + local
);
174 // FIXME: move the downloaded file to the
175 // original locations - without the mirror site dir in the way
180 Log (LOG_PLAIN
) << "Download " << local
<< " wrong size (" <<
181 size
<< " actual vs " << pkgsource
.size
<< " expected)" <<
183 remove ((local
+ ".tmp").c_str());
190 /* FIXME: Do we want to note this? if so how? */
195 do_download_thread (HINSTANCE h
, HWND owner
)
198 total_download_bytes
= 0;
199 total_download_bytes_sofar
= 0;
201 Progress
.SetText1 ("Checking for packages to download...");
202 Progress
.SetText2 ("");
203 Progress
.SetText3 ("");
206 /* calculate the amount needed */
207 for (packagedb::packagecollection::iterator i
= db
.packages
.begin ();
208 i
!= db
.packages
.end (); ++i
)
210 packagemeta
& pkg
= *(i
->second
);
211 if (pkg
.desired
.picked () || pkg
.desired
.sourcePackage ().picked ())
213 packageversion version
= pkg
.desired
;
214 packageversion sourceversion
= version
.sourcePackage();
217 if (version
.picked())
219 if (!check_for_cached (*version
.source()))
220 total_download_bytes
+= version
.source()->size
;
222 if (sourceversion
.picked () || IncludeSource
)
224 if (!check_for_cached (*sourceversion
.source()))
225 total_download_bytes
+= sourceversion
.source()->size
;
228 catch (Exception
* e
)
230 // We know what to do with these..
231 if (e
->errNo() == APPERR_CORRUPT_PACKAGE
)
232 fatal (owner
, IDS_CORRUPT_PACKAGE
, pkg
.name
.c_str());
233 // Unexpected exception.
239 /* and do the download. FIXME: This here we assign a new name for the cached version
240 * and check that above.
242 for (packagedb::packagecollection::iterator i
= db
.packages
.begin ();
243 i
!= db
.packages
.end (); ++i
)
245 packagemeta
& pkg
= *(i
->second
);
246 if (pkg
.desired
.picked () || pkg
.desired
.sourcePackage ().picked ())
249 packageversion version
= pkg
.desired
;
250 packageversion sourceversion
= version
.sourcePackage();
251 if (version
.picked())
253 e
+= download_one (*version
.source(), owner
);
255 if (sourceversion
&& (sourceversion
.picked() || IncludeSource
))
257 e
+= download_one (*sourceversion
.source (), owner
);
262 pkg
->action
= ACTION_ERROR
;
269 /* In unattended mode, all dialog boxes automatically get
270 answered with a Yes/OK/other positive response. This
271 means that if there's a download problem, setup will
272 potentially retry forever if we don't take care to give
273 up at some finite point. */
274 static int retries
= 4;
275 if (unattended_mode
&& retries
-- <= 0)
277 Log (LOG_PLAIN
) << "download error in unattended_mode: out of retries" << endLog
;
278 Logger ().setExitMsg (IDS_INSTALL_INCOMPLETE
);
281 else if (unattended_mode
)
283 Log (LOG_PLAIN
) << "download error in unattended_mode: " << retries
284 << (retries
> 1 ? " retries" : " retry") << " remaining." << endLog
;
287 else if (yesno (owner
, IDS_DOWNLOAD_INCOMPLETE
) == IDYES
)
291 if (source
== IDC_SOURCE_DOWNLOAD
)
294 Logger ().setExitMsg (IDS_DOWNLOAD_INCOMPLETE
);
295 else if (!unattended_mode
)
296 Logger ().setExitMsg (IDS_DOWNLOAD_COMPLETE
);
300 return IDD_S_INSTALL
;
304 do_download_reflector (void *p
)
307 context
= (HANDLE
*) p
;
312 do_download_thread ((HINSTANCE
) context
[0], (HWND
) context
[1]);
314 // Tell the progress page that we're done downloading
315 Progress
.PostMessageNow (WM_APP_DOWNLOAD_THREAD_COMPLETE
, 0, next_dialog
);
317 TOPLEVEL_CATCH("download");
322 static HANDLE context
[2];
325 do_download (HINSTANCE h
, HWND owner
)
331 CreateThread (NULL
, 0, do_download_reflector
, context
, 0, &threadID
);