]>
Commit | Line | Data |
---|---|---|
23c9e63c DD |
1 | /* |
2 | * Copyright (c) 2000, Red Hat, Inc. | |
ad646f43 | 3 | * Copyright (c) 2003, Robert Collins <rbtcollins@hotmail.com> |
23c9e63c DD |
4 | * |
5 | * This program is free software; you can redistribute it and/or modify | |
6 | * it under the terms of the GNU General Public License as published by | |
7 | * the Free Software Foundation; either version 2 of the License, or | |
8 | * (at your option) any later version. | |
9 | * | |
10 | * A copy of the GNU General Public License can be found at | |
11 | * http://www.gnu.org/ | |
12 | * | |
ad646f43 | 13 | * Originally Written by DJ Delorie <dj@cygnus.com> |
23c9e63c DD |
14 | * |
15 | */ | |
16 | ||
8e9aa511 | 17 | /* The purpose of this file is to install all the packages selected in |
23c9e63c DD |
18 | the install list (in ini.h). Note that we use a separate thread to |
19 | maintain the progress dialog, so we avoid the complexity of | |
20 | handling two tasks in one thread. We also create or update all the | |
b24c88b3 | 21 | files in /etc/setup/\* and create the mount points. */ |
23c9e63c | 22 | |
b24c88b3 | 23 | #if 0 |
ad3c7385 | 24 | static const char *cvsid = "\n%%% $Id$\n"; |
b24c88b3 | 25 | #endif |
8507f105 | 26 | |
23c9e63c DD |
27 | #include "win32.h" |
28 | #include "commctrl.h" | |
29 | ||
30 | #include <stdio.h> | |
904d24fe | 31 | #include <stdlib.h> |
4a83b7b0 | 32 | #include <unistd.h> |
23c9e63c DD |
33 | #include <sys/types.h> |
34 | #include <sys/stat.h> | |
35 | #include <errno.h> | |
ab57ceaa RC |
36 | #include <process.h> |
37 | ||
87c42361 | 38 | #include "zlib/zlib.h" |
23c9e63c DD |
39 | |
40 | #include "resource.h" | |
23c9e63c | 41 | #include "dialog.h" |
23c9e63c | 42 | #include "geturl.h" |
23c9e63c | 43 | #include "state.h" |
23c9e63c DD |
44 | #include "diskfull.h" |
45 | #include "msg.h" | |
46 | #include "mount.h" | |
89b1a15b | 47 | #include "log.h" |
a351e48c | 48 | #include "mount.h" |
c46a33a9 | 49 | #include "filemanip.h" |
b24c88b3 RC |
50 | #include "io_stream.h" |
51 | #include "compress.h" | |
52 | #include "compress_gz.h" | |
53 | #include "archive.h" | |
54 | #include "archive_tar.h" | |
8e9aa511 | 55 | #include "script.h" |
4a83b7b0 | 56 | |
fa0c0d10 RC |
57 | #include "package_db.h" |
58 | #include "package_meta.h" | |
bb849dbd RC |
59 | #include "package_version.h" |
60 | #include "package_source.h" | |
fa0c0d10 | 61 | |
4a83b7b0 | 62 | #include "port.h" |
23c9e63c | 63 | |
ab57ceaa | 64 | #include "threebar.h" |
58ee6135 RC |
65 | |
66 | #include "md5.h" | |
67 | ||
68 | #include "Exception.h" | |
a75ed5ce | 69 | #include "getopt++/BoolOption.h" |
58ee6135 | 70 | |
6625e635 RC |
71 | using namespace std; |
72 | ||
ab57ceaa | 73 | extern ThreeBarProgressPage Progress; |
23c9e63c DD |
74 | |
75 | static int total_bytes = 0; | |
76 | static int total_bytes_sofar = 0; | |
77 | static int package_bytes = 0; | |
78 | ||
a75ed5ce RC |
79 | static BoolOption NoReplaceOnReboot (false, 'r', "no-replaceonreboot", |
80 | "Disable replacing in-use files on next " | |
81 | "reboot."); | |
82 | ||
ad646f43 RC |
83 | class Installer |
84 | { | |
85 | public: | |
86 | static const char *StandardDirs[]; | |
87 | Installer(); | |
88 | void initDialog(); | |
89 | void progress (int bytes); | |
90 | void uninstallOne (packagemeta &); | |
91 | int replaceOne (packagemeta &); | |
92 | void replaceOnRebootFailed (String const &fn); | |
93 | void replaceOnRebootSucceeded (String const &fn, bool &rebootneeded); | |
94 | int installOneSource (packagemeta &, packagesource &, String const &, String const &, package_type_t); | |
95 | int errors; | |
96 | }; | |
97 | ||
98 | Installer::Installer() : errors(0) | |
99 | { | |
100 | } | |
101 | ||
102 | void | |
103 | Installer::initDialog() | |
23c9e63c | 104 | { |
ab57ceaa RC |
105 | Progress.SetText2 (""); |
106 | Progress.SetText3 (""); | |
23c9e63c DD |
107 | } |
108 | ||
ad646f43 RC |
109 | void |
110 | Installer::progress (int bytes) | |
23c9e63c | 111 | { |
ab57ceaa | 112 | if (package_bytes > 0) |
ab57ceaa | 113 | Progress.SetBar1 (bytes, package_bytes); |
23c9e63c | 114 | |
ab57ceaa | 115 | if (total_bytes > 0) |
ab57ceaa | 116 | Progress.SetBar2 (total_bytes_sofar + bytes, total_bytes); |
23c9e63c DD |
117 | } |
118 | ||
ad646f43 RC |
119 | const char * |
120 | Installer::StandardDirs[] = { | |
1a18aed7 | 121 | "/bin", |
904d24fe | 122 | "/etc", |
1a18aed7 | 123 | "/lib", |
904d24fe | 124 | "/tmp", |
4a83b7b0 | 125 | "/usr", |
1a18aed7 DD |
126 | "/usr/bin", |
127 | "/usr/lib", | |
ef45c299 | 128 | "/usr/src", |
4a83b7b0 | 129 | "/usr/local", |
1a18aed7 DD |
130 | "/usr/local/bin", |
131 | "/usr/local/etc", | |
132 | "/usr/local/lib", | |
904d24fe | 133 | "/usr/tmp", |
1a18aed7 | 134 | "/var/run", |
904d24fe DD |
135 | "/var/tmp", |
136 | 0 | |
137 | }; | |
138 | ||
ad3c7385 | 139 | static int num_installs, num_replacements, num_uninstalls; |
970149e8 | 140 | static void md5_one (const packagesource& source); |
ad3c7385 | 141 | static bool rebootneeded; |
3b9077d4 | 142 | |
ad646f43 RC |
143 | void |
144 | Installer::uninstallOne (packagemeta & pkgm) | |
3b9077d4 | 145 | { |
ab57ceaa | 146 | Progress.SetText1 ("Uninstalling..."); |
3c054baf | 147 | Progress.SetText2 (pkgm.name.cstr_oneuse()); |
1ac649ed | 148 | log (LOG_PLAIN, String("Uninstalling ") + pkgm.name); |
ab57ceaa RC |
149 | pkgm.uninstall (); |
150 | num_uninstalls++; | |
3b9077d4 DD |
151 | } |
152 | ||
ad3c7385 RC |
153 | /* uninstall and install a package, preserving configuration |
154 | * files and the like. | |
155 | * This method should also know about replacing in-use file. | |
156 | * ASSUMPTIONS: pkgm is installed. | |
157 | * pkgm has a desired package. | |
158 | */ | |
ad646f43 RC |
159 | int |
160 | Installer::replaceOne (packagemeta &pkg) | |
ad3c7385 RC |
161 | { |
162 | int errors = 0; | |
163 | Progress.SetText1 ("Replacing..."); | |
3c054baf | 164 | Progress.SetText2 (pkg.name.cstr_oneuse()); |
b6001c0d | 165 | Progress.SetText3 (""); |
1ac649ed | 166 | log (LOG_PLAIN, String( "Replacing ") + pkg.name); |
ad3c7385 RC |
167 | pkg.uninstall (); |
168 | ||
169 | errors += | |
ad646f43 | 170 | installOneSource (pkg, *pkg.desired.source(), "cygfile://","/", package_binary); |
ad3c7385 RC |
171 | if (!errors) |
172 | pkg.installed = pkg.desired; | |
173 | num_replacements++; | |
174 | return errors; | |
175 | } | |
42bf5b92 | 176 | |
46ccc05f MB |
177 | /* log failed scheduling of replace-on-reboot of a given file. */ |
178 | /* also increment errors. */ | |
ad646f43 RC |
179 | void |
180 | Installer::replaceOnRebootFailed (String const &fn) | |
46ccc05f MB |
181 | { |
182 | log (LOG_TIMESTAMP, | |
183 | "Unable to schedule reboot replacement of file %s with %s (Win32 Error %ld)", | |
184 | cygpath (String ("/") + fn).cstr_oneuse(), | |
185 | cygpath (String ("/") + fn + ".new").cstr_oneuse(), | |
186 | GetLastError ()); | |
187 | ++errors; | |
188 | } | |
189 | ||
190 | /* log successful scheduling of replace-on-reboot of a given file. */ | |
191 | /* also set rebootneeded. */ | |
ad646f43 RC |
192 | void |
193 | Installer::replaceOnRebootSucceeded (String const &fn, bool &rebootneeded) | |
46ccc05f MB |
194 | { |
195 | log (LOG_TIMESTAMP, | |
196 | "Scheduled reboot replacement of file %s with %s", | |
197 | cygpath (String ("/") + fn).cstr_oneuse(), | |
198 | cygpath (String ("/") + fn + ".new").cstr_oneuse()); | |
199 | rebootneeded = true; | |
200 | } | |
bb849dbd RC |
201 | |
202 | /* install one source at a given prefix. */ | |
ad646f43 RC |
203 | int |
204 | Installer::installOneSource (packagemeta & pkgm, packagesource & source, | |
3c054baf | 205 | String const &prefixURL, String const &prefixPath, package_type_t type) |
3b9077d4 | 206 | { |
ab57ceaa | 207 | Progress.SetText2 (source.Base ()); |
7c6ef2c3 | 208 | if (!source.Cached () || !io_stream::exists (source.Cached ())) |
c46a33a9 | 209 | { |
ab57ceaa | 210 | note (NULL, IDS_ERR_OPEN_READ, source.Cached (), "No such file"); |
bb849dbd | 211 | return 1; |
c46a33a9 | 212 | } |
bb849dbd | 213 | io_stream *lst = 0; |
b24c88b3 | 214 | |
bb849dbd | 215 | package_bytes = source.size; |
3b9077d4 | 216 | |
bb849dbd RC |
217 | char msg[64]; |
218 | strcpy (msg, "Installing"); | |
ab57ceaa | 219 | Progress.SetText1 (msg); |
1ac649ed | 220 | log (LOG_PLAIN, String (msg) + " " + source.Cached ()); |
58ee6135 | 221 | |
bb849dbd RC |
222 | io_stream *tmp = io_stream::open (source.Cached (), "rb"); |
223 | archive *thefile = 0; | |
224 | if (tmp) | |
d4a4527d | 225 | { |
bb849dbd RC |
226 | io_stream *tmp2 = compress::decompress (tmp); |
227 | if (tmp2) | |
228 | thefile = archive::extract (tmp2); | |
229 | else | |
230 | thefile = archive::extract (tmp); | |
3b9077d4 | 231 | } |
970149e8 | 232 | |
bb849dbd RC |
233 | /* FIXME: potential leak of either *tmp or *tmp2 */ |
234 | if (thefile) | |
d4a4527d | 235 | { |
3c054baf | 236 | String fn; |
970149e8 RC |
237 | if (type == package_binary) |
238 | { | |
239 | io_stream *tmp = io_stream::open (String ("cygfile:///etc/setup/") + | |
240 | pkgm.name + ".lst.gz", "wb"); | |
241 | lst = new compress_gz (tmp, "w9"); | |
242 | if (lst->error ()) | |
243 | { | |
244 | delete lst; | |
245 | lst = NULL; | |
246 | } | |
247 | } | |
3c054baf | 248 | while ((fn = thefile->next_file_name ()).size()) |
bb849dbd RC |
249 | { |
250 | if (lst) | |
3c054baf RC |
251 | { |
252 | String tmp=fn + "\n"; | |
2fa7c5a4 | 253 | lst->write (tmp.cstr_oneuse(), tmp.size()); |
3c054baf RC |
254 | } |
255 | ||
256 | String canonicalfn = prefixPath + fn; | |
ad646f43 RC |
257 | if (Script::isAScript (fn)) |
258 | pkgm.desired.addScript (Script (canonicalfn)); | |
bb849dbd | 259 | |
3c054baf RC |
260 | Progress.SetText3 (canonicalfn.cstr_oneuse()); |
261 | log (LOG_BABBLE, String("Installing file ") + prefixURL + prefixPath + fn); | |
6dc75764 | 262 | if (archive::extract_file (thefile, prefixURL, prefixPath) != 0) |
bb849dbd | 263 | { |
a75ed5ce RC |
264 | if (NoReplaceOnReboot) |
265 | { | |
266 | ++errors; | |
267 | log (LOG_PLAIN, String("Not replacing in-use file ") + | |
268 | prefixURL + prefixPath + fn); | |
269 | } | |
270 | else | |
ad3c7385 | 271 | //extract to temp location |
6dc75764 | 272 | if (archive::extract_file (thefile, prefixURL, prefixPath, ".new") != 0) |
ad3c7385 | 273 | { |
1ac649ed RC |
274 | log (LOG_PLAIN, |
275 | String("Unable to install file ") + | |
276 | prefixURL + prefixPath + fn); | |
ad646f43 | 277 | ++errors; |
ad3c7385 RC |
278 | } |
279 | else | |
280 | //switch Win32::OS | |
281 | { | |
282 | switch (Win32::OS ()) | |
283 | { | |
284 | case Win32::Win9x:{ | |
285 | /* Get the short file names */ | |
286 | char source[MAX_PATH]; | |
287 | unsigned int len = | |
1ac649ed RC |
288 | GetShortPathName (cygpath (String ("/") + fn + |
289 | ".new").cstr_oneuse(), | |
ad3c7385 RC |
290 | source, MAX_PATH); |
291 | if (!len || len > MAX_PATH) | |
292 | { | |
ad646f43 | 293 | replaceOnRebootFailed(fn); |
ad3c7385 RC |
294 | } |
295 | else | |
296 | { | |
297 | char dest[MAX_PATH]; | |
298 | len = | |
1ac649ed RC |
299 | GetShortPathName (cygpath (String ("/") + |
300 | fn).cstr_oneuse(), | |
301 | dest, MAX_PATH); | |
ad3c7385 | 302 | if (!len || len > MAX_PATH) |
ad646f43 | 303 | replaceOnRebootFailed (fn); |
ad3c7385 RC |
304 | else |
305 | /* trigger a replacement on reboot */ | |
306 | if (!WritePrivateProfileString | |
307 | ("rename", dest, source, "WININIT.INI")) | |
ad646f43 | 308 | replaceOnRebootFailed (fn); |
46ccc05f | 309 | else |
ad646f43 | 310 | replaceOnRebootSucceeded (fn, rebootneeded); |
ad3c7385 RC |
311 | } |
312 | } | |
313 | break; | |
314 | case Win32::WinNT: | |
315 | /* XXX FIXME: prefix may not be / for in use files - | |
316 | * although it most likely is | |
317 | * - we need a io method to get win32 paths | |
318 | * or to wrap this system call | |
319 | */ | |
1ac649ed RC |
320 | if (!MoveFileEx (cygpath (String ("/") + fn + |
321 | ".new").cstr_oneuse(), | |
322 | cygpath (String ("/") + fn).cstr_oneuse(), | |
ad3c7385 RC |
323 | MOVEFILE_DELAY_UNTIL_REBOOT | |
324 | MOVEFILE_REPLACE_EXISTING)) | |
325 | { | |
ad646f43 | 326 | replaceOnRebootFailed (fn); |
ad3c7385 RC |
327 | } |
328 | else | |
46ccc05f | 329 | { |
ad646f43 | 330 | replaceOnRebootSucceeded (fn, rebootneeded); |
46ccc05f | 331 | } |
ad3c7385 RC |
332 | break; |
333 | } | |
334 | } | |
bb849dbd | 335 | } |
bb849dbd RC |
336 | progress (tmp->tell ()); |
337 | num_installs++; | |
338 | } | |
339 | delete thefile; | |
340 | ||
341 | total_bytes_sofar += package_bytes; | |
d4a4527d | 342 | } |
3b9077d4 | 343 | |
bb849dbd RC |
344 | progress (0); |
345 | ||
3c054baf | 346 | int df = diskfull (get_root_dir ().cstr_oneuse()); |
ab57ceaa | 347 | Progress.SetBar3 (df); |
bb849dbd RC |
348 | |
349 | if (lst) | |
350 | delete lst; | |
351 | ||
352 | return errors; | |
353 | } | |
354 | ||
355 | /* install a package, install both the binary and source aspects if needed */ | |
356 | static int | |
357 | install_one (packagemeta & pkg) | |
358 | { | |
359 | int errors = 0; | |
360 | ||
ad646f43 | 361 | Installer myInstaller; |
3c196821 | 362 | if (pkg.installed != pkg.desired && pkg.desired.picked()) |
ab57ceaa | 363 | { |
bb849dbd | 364 | errors += |
ad646f43 | 365 | myInstaller.installOneSource (pkg, *pkg.desired.source(), "cygfile://","/", |
ab57ceaa RC |
366 | package_binary); |
367 | if (!errors) | |
368 | pkg.installed = pkg.desired; | |
369 | } | |
3c196821 | 370 | if (pkg.desired.sourcePackage().picked()) |
ab57ceaa | 371 | errors += |
ad646f43 | 372 | myInstaller.installOneSource (pkg, *pkg.desired.sourcePackage().source(), "cygfile://","/usr/src/", |
ab57ceaa | 373 | package_source); |
bb849dbd RC |
374 | |
375 | /* FIXME: make a upgrade method and reinstate this */ | |
376 | #if 0 | |
1ac649ed | 377 | String msg; |
c46a33a9 | 378 | if (!pkg->installed) |
1ac649ed | 379 | msg = "Installing"; |
c46a33a9 CF |
380 | else |
381 | { | |
382 | int n = strcmp (pi->version, pkg->installed->version); | |
383 | if (n < 0) | |
1ac649ed | 384 | msg = "Reverting"; |
c46a33a9 | 385 | else if (n == 0) |
1ac649ed | 386 | msg = "Reinstalling"; |
c46a33a9 | 387 | else |
1ac649ed | 388 | msg = "Upgrading"; |
c46a33a9 CF |
389 | } |
390 | ||
391 | switch (pkg->action) | |
3b9077d4 | 392 | { |
c46a33a9 | 393 | case ACTION_PREV: |
1ac649ed | 394 | msg += " previous version..."; |
3b9077d4 | 395 | break; |
c46a33a9 | 396 | case ACTION_CURR: |
1ac649ed | 397 | msg += "..."; |
3b9077d4 | 398 | break; |
c46a33a9 | 399 | case ACTION_TEST: |
1ac649ed | 400 | msg += " test version..."; |
42bf5b92 | 401 | break; |
b24c88b3 RC |
402 | default: |
403 | /* FIXME: log this somehow */ | |
404 | break; | |
3b9077d4 | 405 | } |
1ac649ed RC |
406 | SetWindowText (ins_action, msg.cstr_oneuse()); |
407 | log (LOG_PLAIN, msg + " " + file); | |
bb849dbd | 408 | #endif |
c46a33a9 | 409 | |
3b9077d4 DD |
410 | return errors; |
411 | } | |
412 | ||
72fd1d1e CF |
413 | static void |
414 | check_for_old_cygwin () | |
415 | { | |
416 | char buf[_MAX_PATH + sizeof ("\\cygwin1.dll")]; | |
417 | if (!GetSystemDirectory (buf, sizeof (buf))) | |
418 | return; | |
419 | strcat (buf, "\\cygwin1.dll"); | |
420 | if (_access (buf, 0) != 0) | |
421 | return; | |
422 | ||
423 | char msg[sizeof (buf) + 132]; | |
b24c88b3 RC |
424 | sprintf (msg, |
425 | "An old version of cygwin1.dll was found here:\r\n%s\r\nDelete?", | |
426 | buf); | |
427 | switch (MessageBox | |
428 | (NULL, msg, "What's that doing there?", | |
429 | MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL)) | |
72fd1d1e CF |
430 | { |
431 | case IDYES: | |
432 | if (!DeleteFile (buf)) | |
433 | { | |
434 | sprintf (msg, "Couldn't delete file %s.\r\n" | |
b24c88b3 | 435 | "Is the DLL in use by another application?\r\n" |
7c7034e8 RC |
436 | "You should delete the old version of cygwin1.dll\r\n" |
437 | "at your earliest convenience.", buf); | |
b24c88b3 RC |
438 | MessageBox (NULL, buf, "Couldn't delete file", |
439 | MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL); | |
72fd1d1e CF |
440 | } |
441 | break; | |
442 | default: | |
b24c88b3 | 443 | break; |
72fd1d1e CF |
444 | } |
445 | ||
446 | return; | |
447 | } | |
448 | ||
ab57ceaa RC |
449 | static void |
450 | do_install_thread (HINSTANCE h, HWND owner) | |
23c9e63c | 451 | { |
3b9077d4 | 452 | int i; |
2a1a01e0 DD |
453 | int errors = 0; |
454 | ||
ad3c7385 RC |
455 | num_installs = 0, num_uninstalls = 0, num_replacements = 0; |
456 | rebootneeded = false; | |
3b9077d4 | 457 | |
50225eae | 458 | next_dialog = IDD_DESKTOP; |
23c9e63c | 459 | |
490717ef | 460 | io_stream::mkpath_p (PATH_TO_DIR, String ("file://") + get_root_dir ()); |
904d24fe | 461 | |
ad646f43 | 462 | for (i = 0; Installer::StandardDirs[i]; i++) |
904d24fe | 463 | { |
ad646f43 | 464 | String p = cygpath (Installer::StandardDirs[i]); |
3c054baf | 465 | if (p.size()) |
490717ef | 466 | io_stream::mkpath_p (PATH_TO_DIR, String ("file://") + p); |
904d24fe DD |
467 | } |
468 | ||
1a18aed7 | 469 | /* Create /var/run/utmp */ |
b24c88b3 RC |
470 | io_stream *utmp = io_stream::open ("cygfile:///var/run/utmp", "wb"); |
471 | delete utmp; | |
1a18aed7 | 472 | |
ad646f43 RC |
473 | Installer myInstaller; |
474 | myInstaller.initDialog(); | |
23c9e63c DD |
475 | |
476 | total_bytes = 0; | |
477 | total_bytes_sofar = 0; | |
478 | ||
3c054baf | 479 | int df = diskfull (get_root_dir ().cstr_oneuse()); |
ab57ceaa | 480 | Progress.SetBar3 (df); |
d07591a3 | 481 | |
0af2d779 CF |
482 | int istext = (root_text == IDC_ROOT_TEXT) ? 1 : 0; |
483 | int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0; | |
484 | ||
1ac649ed RC |
485 | create_mount ("/", get_root_dir (), istext, issystem); |
486 | create_mount ("/usr/bin", cygpath ("/bin"), istext, issystem); | |
487 | create_mount ("/usr/lib", cygpath ("/lib"), istext, issystem); | |
0af2d779 CF |
488 | set_cygdrive_flags (istext, issystem); |
489 | ||
8e9aa511 RC |
490 | /* Let's hope people won't uninstall packages before installing [b]ash */ |
491 | init_run_script (); | |
492 | ||
bb849dbd | 493 | packagedb db; |
cfae3b8d RC |
494 | for (vector <packagemeta *>::iterator i = db.packages.begin (); |
495 | i != db.packages.end (); ++i) | |
cbfc4215 | 496 | { |
cfae3b8d | 497 | packagemeta & pkg = **i; |
ab57ceaa | 498 | |
3c196821 | 499 | if (pkg.desired.changeRequested()) |
ab57ceaa | 500 | { |
3c196821 | 501 | if (pkg.desired.picked()) |
970149e8 | 502 | { |
970149e8 RC |
503 | try |
504 | { | |
505 | md5_one (*pkg.desired.source ()); | |
506 | } | |
507 | catch (Exception *e) | |
508 | { | |
509 | if (yesno (owner, IDS_SKIP_PACKAGE, e->what()) == IDYES) | |
970149e8 | 510 | pkg.desired.pick (false); |
970149e8 | 511 | } |
f430003c | 512 | if (pkg.desired.picked()) |
970149e8 RC |
513 | total_bytes += pkg.desired.source()->size; |
514 | } | |
3c196821 | 515 | if (pkg.desired.sourcePackage ().picked()) |
970149e8 | 516 | { |
970149e8 RC |
517 | try |
518 | { | |
519 | md5_one (*pkg.desired.sourcePackage ().source ()); | |
520 | } | |
521 | catch (Exception *e) | |
522 | { | |
f430003c | 523 | if (yesno (owner, IDS_SKIP_PACKAGE, e->what()) == IDYES) |
970149e8 | 524 | pkg.desired.sourcePackage ().pick (false); |
970149e8 | 525 | } |
f430003c | 526 | if (pkg.desired.sourcePackage().picked()) |
970149e8 RC |
527 | total_bytes += pkg.desired.sourcePackage ().source()->size; |
528 | } | |
ab57ceaa | 529 | } |
cbfc4215 | 530 | } |
bb849dbd | 531 | |
ad3c7385 | 532 | /* start with uninstalls - remove files that new packages may replace */ |
cfae3b8d RC |
533 | for (vector <packagemeta *>::iterator i = db.packages.begin (); |
534 | i != db.packages.end (); ++i) | |
23c9e63c | 535 | { |
cfae3b8d | 536 | packagemeta & pkg = **i; |
970149e8 RC |
537 | if (pkg.installed && (!pkg.desired || (pkg.desired != pkg.installed && |
538 | pkg.desired.picked ()))) | |
ad646f43 | 539 | myInstaller.uninstallOne (pkg); |
ad3c7385 RC |
540 | } |
541 | ||
542 | /* now in-place binary upgrades/reinstalls, as these may remove fils | |
543 | * that have been moved into new packages | |
544 | */ | |
545 | ||
cfae3b8d RC |
546 | for (vector <packagemeta *>::iterator i = db.packages.begin (); |
547 | i != db.packages.end (); ++i) | |
ad3c7385 | 548 | { |
cfae3b8d | 549 | packagemeta & pkg = **i; |
3c196821 | 550 | if (pkg.installed && pkg.desired.picked()) |
4a83b7b0 | 551 | { |
58ee6135 RC |
552 | try { |
553 | int e = 0; | |
ad646f43 | 554 | e += myInstaller.replaceOne (pkg); |
58ee6135 RC |
555 | if (e) |
556 | errors++; | |
557 | } | |
558 | catch (exception *e) | |
559 | { | |
560 | if (yesno (owner, IDS_INSTALL_ERROR, e->what()) != IDYES) | |
561 | { | |
562 | log (LOG_TIMESTAMP, String ("User cancelled setup after install error")); | |
9f4a0c62 | 563 | LogSingleton::GetInstance().exit (1); |
58ee6135 RC |
564 | return; |
565 | } | |
566 | } | |
4a83b7b0 | 567 | } |
ad3c7385 RC |
568 | } |
569 | ||
cfae3b8d RC |
570 | for (vector <packagemeta *>::iterator i = db.packages.begin (); |
571 | i != db.packages.end (); ++i) | |
ad3c7385 | 572 | { |
cfae3b8d | 573 | packagemeta & pkg = **i; |
23c9e63c | 574 | |
3c196821 | 575 | if (pkg.desired && pkg.desired.changeRequested()) |
23c9e63c | 576 | { |
58ee6135 | 577 | try |
40aef45e | 578 | { |
58ee6135 RC |
579 | int e = 0; |
580 | e += install_one (pkg); | |
581 | if (e) | |
582 | errors++; | |
583 | } | |
584 | catch (exception *e) | |
585 | { | |
586 | if (yesno (owner, IDS_INSTALL_ERROR, e->what()) != IDYES) | |
587 | { | |
588 | log (LOG_TIMESTAMP, String ("User cancelled setup after install error")); | |
9f4a0c62 | 589 | LogSingleton::GetInstance().exit (1); |
58ee6135 RC |
590 | return; |
591 | } | |
40aef45e | 592 | } |
4a83b7b0 | 593 | } |
b24c88b3 | 594 | } // end of big package loop |
4a83b7b0 | 595 | |
ad3c7385 RC |
596 | if (rebootneeded) |
597 | note (owner, IDS_REBOOT_REQUIRED); | |
598 | ||
7c7034e8 RC |
599 | int temperr; |
600 | if ((temperr = db.flush ())) | |
23c9e63c | 601 | { |
7c7034e8 | 602 | const char *err = strerror (temperr); |
23c9e63c DD |
603 | if (!err) |
604 | err = "(unknown error)"; | |
3c054baf RC |
605 | fatal (owner, IDS_ERR_OPEN_WRITE, "Package Database", |
606 | err); | |
23c9e63c DD |
607 | } |
608 | ||
72fd1d1e CF |
609 | if (!errors) |
610 | check_for_old_cygwin (); | |
4a83b7b0 DD |
611 | if (num_installs == 0 && num_uninstalls == 0) |
612 | { | |
f2ff9838 | 613 | if (!unattended_mode) exit_msg = IDS_NOTHING_INSTALLED; |
4a83b7b0 DD |
614 | return; |
615 | } | |
616 | if (num_installs == 0) | |
617 | { | |
f2ff9838 | 618 | if (!unattended_mode) exit_msg = IDS_UNINSTALL_COMPLETE; |
4a83b7b0 DD |
619 | return; |
620 | } | |
621 | ||
2a1a01e0 DD |
622 | if (errors) |
623 | exit_msg = IDS_INSTALL_INCOMPLETE; | |
f2ff9838 | 624 | else if (!unattended_mode) |
2a1a01e0 | 625 | exit_msg = IDS_INSTALL_COMPLETE; |
23c9e63c | 626 | } |
ab57ceaa | 627 | |
45e01f23 | 628 | static DWORD WINAPI |
ab57ceaa RC |
629 | do_install_reflector (void *p) |
630 | { | |
631 | HANDLE *context; | |
632 | context = (HANDLE *) p; | |
633 | ||
634 | do_install_thread ((HINSTANCE) context[0], (HWND) context[1]); | |
635 | ||
636 | // Tell the progress page that we're done downloading | |
637 | Progress.PostMessage (WM_APP_INSTALL_THREAD_COMPLETE); | |
638 | ||
45e01f23 | 639 | ExitThread (0); |
ab57ceaa RC |
640 | } |
641 | ||
642 | static HANDLE context[2]; | |
643 | ||
644 | void | |
645 | do_install (HINSTANCE h, HWND owner) | |
646 | { | |
647 | context[0] = h; | |
648 | context[1] = owner; | |
649 | ||
45e01f23 RC |
650 | DWORD threadID; |
651 | CreateThread (NULL, 0, do_install_reflector, context, 0, &threadID); | |
ab57ceaa | 652 | } |
970149e8 RC |
653 | |
654 | void md5_one (const packagesource& source) | |
655 | { | |
656 | if (source.md5.isSet()) | |
657 | { | |
658 | // check the MD5 sum of the cached file here | |
659 | io_stream *thefile = io_stream::open (source.Cached (), "rb"); | |
660 | if (!thefile) | |
661 | throw new Exception ("__LINE__ __FILE__", String ("IO Error opening ") + source.Cached(), APPERR_IO_ERROR); | |
662 | md5_state_t pns; | |
663 | md5_init (&pns); | |
664 | ||
665 | unsigned char buffer[16384]; | |
666 | ssize_t count; | |
667 | while ((count = thefile->read (buffer, 16384)) > 0) | |
668 | md5_append (&pns, buffer, count); | |
669 | delete thefile; | |
670 | if (count < 0) | |
671 | throw new Exception ("__LINE__ __FILE__", String ("IO Error reading ") + source.Cached(), APPERR_IO_ERROR); | |
672 | ||
673 | md5_byte_t tempdigest[16]; | |
674 | md5_finish(&pns, tempdigest); | |
675 | md5 tempMD5; | |
676 | tempMD5.set (tempdigest); | |
677 | ||
678 | log (LOG_BABBLE, String ("For file ") + source.Cached() + " ini digest is " + source.md5.print() + " file digest is " + tempMD5.print()); | |
679 | ||
680 | if (source.md5 != tempMD5) | |
681 | throw new Exception ("__LINE__ __FILE__", String ("Checksum failure for ") + source.Cached(), APPERR_CORRUPT_PACKAGE); | |
682 | } | |
683 | } |