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"
36 #include "filemanip.h"
38 #include "io_stream.h"
40 #include "package_db.h"
41 #include "package_meta.h"
42 #include "package_source.h"
46 #include "Exception.h"
48 extern ThreeBarProgressPage Progress
;
50 // Return true if selected checks pass, false if they don't and the
51 // user chooses to delete the file; otherwise throw an exception.
53 validateCachedPackage (const std::string
& fullname
, packagesource
& pkgsource
,
54 HWND owner
, bool check_hash
, bool check_size
)
59 pkgsource
.check_size_and_cache (fullname
);
61 pkgsource
.check_hash ();
66 pkgsource
.set_cached ("");
67 const char *filename
= fullname
.c_str ();
68 if (strncmp (filename
, "file://", 7) == 0)
70 if (e
->errNo() == APPERR_CORRUPT_PACKAGE
71 && yesno (owner
, IDS_QUERY_CORRUPT
, filename
) == IDYES
)
79 /* 0 if not cached; may throw exception if validation fails.
82 check_for_cached (packagesource
& pkgsource
, HWND owner
, bool mirror_mode
,
85 /* If the packagesource doesn't have a filename, it can't possibly be in the
87 if (!pkgsource
.Canonical())
92 /* Note that the cache dir is represented by a mirror site of file://local_dir */
93 std::string prefix
= "file://" + local_dir
+ "/";
94 std::string fullname
= prefix
+ pkgsource
.Canonical();
98 /* Just assume correctness of mirror. */
99 if (!pkgsource
.Cached())
100 pkgsource
.set_cached (fullname
);
104 // Already found one, which we can assume to have the right size.
105 if (pkgsource
.Cached())
107 if (validateCachedPackage (pkgsource
.Cached(), pkgsource
, owner
,
110 // If we get here, pkgsource.Cached() was corrupt and deleted.
111 pkgsource
.set_cached ("");
115 1) is there a legacy version in the cache dir available.
117 if (io_stream::exists (fullname
))
119 if (validateCachedPackage (fullname
, pkgsource
, owner
, check_hash
, true))
121 // If we get here, fullname was corrupt and deleted, but it
122 // might have been cached.
123 pkgsource
.set_cached ("");
127 2) is there a version from one of the selected mirror sites available ?
129 for (packagesource::sitestype::const_iterator n
= pkgsource
.sites
.begin();
130 n
!= pkgsource
.sites
.end(); ++n
)
132 std::string fullname
= prefix
+ rfc1738_escape_part (n
->key
) + "/" +
133 pkgsource
.Canonical ();
134 if (io_stream::exists(fullname
))
136 if (validateCachedPackage (fullname
, pkgsource
, owner
, check_hash
,
139 // If we get here, fullname was corrupt and deleted, but it
140 // might have been cached.
141 pkgsource
.set_cached ("");
147 /* download a file from a mirror site to the local cache. */
149 download_one (packagesource
& pkgsource
, HWND owner
)
153 if (check_for_cached (pkgsource
, owner
))
156 catch (Exception
* e
)
158 // We know what to do with these..
159 if (e
->errNo() == APPERR_CORRUPT_PACKAGE
)
161 fatal (owner
, IDS_CORRUPT_PACKAGE
, pkgsource
.Canonical());
164 // Unexpected exception.
167 /* try the download sites one after another */
170 for (packagesource::sitestype::const_iterator n
= pkgsource
.sites
.begin();
171 n
!= pkgsource
.sites
.end() && !success
; ++n
)
173 const std::string local
= local_dir
+ "/" +
174 rfc1738_escape_part (n
->key
) + "/" +
175 pkgsource
.Canonical ();
176 io_stream::mkpath_p (PATH_TO_FILE
, "file://" + local
, 0);
178 if (get_url_to_file(n
->key
+ pkgsource
.Canonical (),
179 local
+ ".tmp", pkgsource
.size
, owner
))
181 /* FIXME: note new source ? */
188 if (_access (local
.c_str(), 0) == 0)
189 remove (local
.c_str());
190 rename ((local
+ ".tmp").c_str(), local
.c_str());
191 pkgsource
.check_size_and_cache ("file://" + local
);
192 pkgsource
.check_hash ();
193 Log (LOG_PLAIN
) << "Downloaded " << local
<< endLog
;
195 // FIXME: move the downloaded file to the
196 // original locations - without the mirror site dir in the way
201 remove (local
.c_str());
202 pkgsource
.set_cached ("");
203 if (e
->errNo() == APPERR_CORRUPT_PACKAGE
)
205 Log (LOG_PLAIN
) << "Downloaded file " << local
206 << " is corrupt; deleting." << endLog
;
211 Log (LOG_PLAIN
) << "Unexpected exception while validating "
212 << "downloaded file " << local
213 << "; deleting." << endLog
;
224 static std::vector
<packageversion
> download_failures
;
225 static std::string download_warn_pkgs
;
227 static INT_PTR CALLBACK
228 download_error_proc (HWND h
, UINT message
, WPARAM wParam
, LPARAM lParam
)
233 eset (h
, IDC_DOWNLOAD_EDIT
, download_warn_pkgs
);
234 SetFocus (GetDlgItem(h
, IDRETRY
));
238 switch (LOWORD (wParam
))
244 EndDialog (h
, LOWORD (wParam
));
258 query_download_errors (HINSTANCE h
, HWND owner
)
260 download_warn_pkgs
= "";
261 Log (LOG_PLAIN
) << "The following package(s) had download errors:" << endLog
;
262 for (std::vector
<packageversion
>::const_iterator i
= download_failures
.begin (); i
!= download_failures
.end (); i
++)
264 packageversion pv
= *i
;
265 std::string pvs
= pv
.Name () + "-" + pv
.Canonical_version ();
266 Log (LOG_PLAIN
) << " " << pvs
<< endLog
;
267 download_warn_pkgs
+= pvs
+ "\r\n";
269 return DialogBox (h
, MAKEINTRESOURCE (IDD_DOWNLOAD_ERROR
), owner
,
270 download_error_proc
);
274 do_download_thread (HINSTANCE h
, HWND owner
)
277 total_download_bytes
= 0;
278 total_download_bytes_sofar
= 0;
279 download_failures
.clear ();
281 Progress
.SetText1 (IDS_PROGRESS_CHECKING
);
282 Progress
.SetText2 ("");
283 Progress
.SetText3 ("");
286 const SolverTransactionList
&t
= db
.solution
.transactions();
288 /* calculate the total size of the download */
289 for (SolverTransactionList::const_iterator i
= t
.begin (); i
!= t
.end (); ++i
)
291 if (i
->type
!= SolverTransaction::transInstall
)
293 packageversion version
= i
->version
;
297 if (!check_for_cached (*version
.source(), owner
))
298 total_download_bytes
+= version
.source()->size
;
300 catch (Exception
* e
)
302 // We know what to do with these..
303 if (e
->errNo() == APPERR_CORRUPT_PACKAGE
)
304 fatal (owner
, IDS_CORRUPT_PACKAGE
, version
.Name().c_str());
305 // Unexpected exception.
308 Progress
.SetBar2(std::distance(t
.begin(), i
) + 1, t
.size());
311 /* and do the download. FIXME: This here we assign a new name for the cached version
312 * and check that above.
314 for (SolverTransactionList::const_iterator i
= t
.begin (); i
!= t
.end (); ++i
)
316 if (i
->type
!= SolverTransaction::transInstall
)
318 packageversion version
= i
->version
;
322 e
+= download_one (*version
.source(), owner
);
325 download_failures
.push_back (version
);
328 pkg
->action
= ACTION_ERROR
;
335 // In unattended mode we retry the download, but not forever.
336 static int retries
= 5;
338 if (unattended_mode
&& --retries
<= 0)
340 Log (LOG_PLAIN
) << "download error in unattended_mode: out of retries" << endLog
;
343 else if (unattended_mode
)
345 Log (LOG_PLAIN
) << "download error in unattended_mode: " << retries
346 << (retries
> 1 ? " retries" : " retry") << " remaining." << endLog
;
350 rc
= query_download_errors (h
, owner
);
354 Progress
.SetActivateTask (WM_APP_START_DOWNLOAD
);
359 Logger ().setExitMsg (IDS_DOWNLOAD_INCOMPLETE_EXIT
);
368 if (source
== IDC_SOURCE_DOWNLOAD
)
371 Logger ().setExitMsg (IDS_DOWNLOAD_INCOMPLETE_EXIT
);
372 else if (!unattended_mode
)
373 Logger ().setExitMsg (IDS_DOWNLOAD_COMPLETE
);
377 return IDD_S_INSTALL
;
381 do_download_reflector (void *p
)
384 context
= (HANDLE
*) p
;
386 SetThreadUILanguage(langid
);
391 do_download_thread ((HINSTANCE
) context
[0], (HWND
) context
[1]);
393 // Tell the progress page that we're done downloading
394 Progress
.PostMessageNow (WM_APP_DOWNLOAD_THREAD_COMPLETE
, 0, next_dialog
);
396 TOPLEVEL_CATCH((HWND
) context
[1], "download");
401 static HANDLE context
[2];
404 do_download (HINSTANCE h
, HWND owner
)
410 CreateThread (NULL
, 0, do_download_reflector
, context
, 0, &threadID
);