]> cygwin.com Git - cygwin-apps/setup.git/blob - install.cc
Support xz and lzma decompression via liblzma
[cygwin-apps/setup.git] / install.cc
1 /*
2 * Copyright (c) 2000, Red Hat, Inc.
3 * Copyright (c) 2003, Robert Collins <rbtcollins@hotmail.com>
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 *
13 * Originally Written by DJ Delorie <dj@cygnus.com>
14 *
15 */
16
17 /* The purpose of this file is to install all the packages selected in
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
21 files in /etc/setup/\* and create the mount points. */
22
23 #if 0
24 static const char *cvsid = "\n%%% $Id$\n";
25 #endif
26
27 #include "getopt++/BoolOption.h"
28 #include "csu_util/MD5Sum.h"
29 #include "LogSingleton.h"
30
31 #include "win32.h"
32 #include "commctrl.h"
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <errno.h>
40 #include <process.h>
41
42 #include "ini.h"
43 #include "resource.h"
44 #include "dialog.h"
45 #include "geturl.h"
46 #include "state.h"
47 #include "diskfull.h"
48 #include "msg.h"
49 #include "mount.h"
50 #include "mount.h"
51 #include "filemanip.h"
52 #include "io_stream.h"
53 #include "compress.h"
54 #include "compress_gz.h"
55 #include "archive.h"
56 #include "archive_tar.h"
57 #include "script.h"
58
59 #include "package_db.h"
60 #include "package_meta.h"
61 #include "package_version.h"
62 #include "package_source.h"
63
64 #include "threebar.h"
65 #include "Exception.h"
66
67 using namespace std;
68
69 extern ThreeBarProgressPage Progress;
70
71 static int total_bytes = 0;
72 static int total_bytes_sofar = 0;
73 static int package_bytes = 0;
74
75 static BoolOption NoReplaceOnReboot (false, 'r', "no-replaceonreboot",
76 "Disable replacing in-use files on next "
77 "reboot.");
78
79 struct std_dirs_t {
80 const char *name;
81 mode_t mode;
82 };
83
84 class Installer
85 {
86 public:
87 static std_dirs_t StandardDirs[];
88 Installer();
89 void initDialog();
90 void progress (int bytes);
91 void preremoveOne (packagemeta &);
92 void uninstallOne (packagemeta &);
93 void replaceOnRebootFailed (const std::string& fn);
94 void replaceOnRebootSucceeded (const std::string& fn, bool &rebootneeded);
95 void installOne (packagemeta &pkg, const packageversion &ver,
96 packagesource &source,
97 const std::string& , const std::string&, HWND );
98 int errors;
99 };
100
101 Installer::Installer() : errors(0)
102 {
103 }
104
105 void
106 Installer::initDialog()
107 {
108 Progress.SetText2 ("");
109 Progress.SetText3 ("");
110 }
111
112 void
113 Installer::progress (int bytes)
114 {
115 if (package_bytes > 0)
116 Progress.SetBar1 (bytes, package_bytes);
117
118 if (total_bytes > 0)
119 Progress.SetBar2 (total_bytes_sofar + bytes, total_bytes);
120 }
121
122 std_dirs_t
123 Installer::StandardDirs[] = {
124 { "/bin", 0755 },
125 { "/home", 01777 },
126 { "/etc", 0755 },
127 { "/lib", 0755 },
128 { "/tmp", 01777 },
129 { "/usr", 0755 },
130 { "/usr/bin", 0755 },
131 { "/usr/lib", 0755 },
132 { "/usr/src", 0755 },
133 { "/usr/local", 0755 },
134 { "/usr/local/bin", 0755 },
135 { "/usr/local/etc", 0755 },
136 { "/usr/local/lib", 0755 },
137 { "/usr/tmp", 01777 },
138 { "/var/log", 01777 },
139 { "/var/run", 01777 },
140 { "/var/tmp", 01777 },
141 { NULL, 0 }
142 };
143
144 static int num_installs, num_uninstalls;
145 static void md5_one (const packagesource& source);
146
147 void
148 Installer::preremoveOne (packagemeta & pkg)
149 {
150 Progress.SetText1 ("Running preremove script...");
151 Progress.SetText2 (pkg.name.c_str());
152 log (LOG_PLAIN) << "Running preremove script for " << pkg.name << endLog;
153 try_run_script ("/etc/preremove/", pkg.name, ".sh");
154 try_run_script ("/etc/preremove/", pkg.name, ".bat");
155 }
156
157 void
158 Installer::uninstallOne (packagemeta & pkg)
159 {
160 Progress.SetText1 ("Uninstalling...");
161 Progress.SetText2 (pkg.name.c_str());
162 log (LOG_PLAIN) << "Uninstalling " << pkg.name << endLog;
163 pkg.uninstall ();
164 num_uninstalls++;
165 }
166
167 /* log failed scheduling of replace-on-reboot of a given file. */
168 /* also increment errors. */
169 void
170 Installer::replaceOnRebootFailed (const std::string& fn)
171 {
172 log (LOG_TIMESTAMP) << "Unable to schedule reboot replacement of file "
173 << cygpath("/" + fn) << " with " << cygpath("/" + fn + ".new")
174 << " (Win32 Error " << GetLastError() << ")" << endLog;
175 ++errors;
176 }
177
178 /* log successful scheduling of replace-on-reboot of a given file. */
179 /* also set rebootneeded. */
180 void
181 Installer::replaceOnRebootSucceeded (const std::string& fn, bool &rebootneeded)
182 {
183 log (LOG_TIMESTAMP) << "Scheduled reboot replacement of file "
184 << cygpath("/" + fn) << " with " << cygpath("/" + fn + ".new") << endLog;
185 rebootneeded = true;
186 }
187
188 #define MB_RETRYCONTINUE 7
189 #if !defined(IDCONTINUE)
190 #define IDCONTINUE IDCANCEL
191 #endif
192
193 static HHOOK hMsgBoxHook;
194 LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam) {
195 HWND hWnd;
196 switch (nCode) {
197 case HCBT_ACTIVATE:
198 hWnd = (HWND)wParam;
199 if (GetDlgItem(hWnd, IDCANCEL) != NULL)
200 SetDlgItemText(hWnd, IDCANCEL, "Continue");
201 UnhookWindowsHookEx(hMsgBoxHook);
202 }
203 return CallNextHookEx(hMsgBoxHook, nCode, wParam, lParam);
204 }
205
206 int _custom_MessageBox(HWND hWnd, LPCTSTR szText, LPCTSTR szCaption, UINT uType) {
207 int retval;
208 bool retry_continue = (uType & MB_TYPEMASK) == MB_RETRYCONTINUE;
209 if (retry_continue) {
210 uType &= ~MB_TYPEMASK; uType |= MB_RETRYCANCEL;
211 // Install a window hook, so we can intercept the message-box
212 // creation, and customize it
213 // Only install for THIS thread!!!
214 hMsgBoxHook = SetWindowsHookEx(WH_CBT, CBTProc, NULL, GetCurrentThreadId());
215 }
216 retval = MessageBox(hWnd, szText, szCaption, uType);
217 // Intercept the return value for less confusing results
218 if (retry_continue && retval == IDCANCEL)
219 return IDCONTINUE;
220 return retval;
221 }
222
223 #undef MessageBox
224 #define MessageBox _custom_MessageBox
225
226 static char all_null[512];
227
228 /* install one source at a given prefix. */
229 void
230 Installer::installOne (packagemeta &pkgm, const packageversion &ver,
231 packagesource &source,
232 const std::string& prefixURL,
233 const std::string& prefixPath,
234 HWND owner)
235 {
236 if (!source.Canonical())
237 return;
238 Progress.SetText1 ("Installing");
239 Progress.SetText2 (source.Base () ? source.Base () : "(unknown)");
240
241 io_stream *pkgfile = NULL;
242
243 if (!source.Cached() || !io_stream::exists (source.Cached ())
244 || !(pkgfile = io_stream::open (source.Cached (), "rb", 0)))
245 {
246 note (NULL, IDS_ERR_OPEN_READ, source.Cached (), "No such file");
247 ++errors;
248 return;
249 }
250
251
252 /* At this point pkgfile is an opened io_stream to either a .tar.bz2 file,
253 a .tar.gz file, a .tar.lzma file, or just a .tar file. Try it first as
254 a compressed file and if that fails try opening it as a tar directly.
255 If both fail, abort.
256
257 Note on io_stream pointer management:
258
259 Both the archive and decompress classes take ownership of the io_stream
260 pointer they were opened with, meaning they delete it in their dtor. So
261 deleting tarstream should also result in deleting the underlying
262 try_decompress and pkgfile io_streams as well. */
263
264 archive *tarstream = NULL;
265 io_stream *try_decompress = NULL;
266
267 if ((try_decompress = compress::decompress (pkgfile)) != NULL)
268 {
269 if ((tarstream = archive::extract (try_decompress)) == NULL)
270 {
271 /* Decompression succeeded but we couldn't grok it as a valid tar
272 archive. */
273 char c[512];
274 ssize_t len;
275 if ((len = try_decompress->peek (c, 512)) < 0
276 || !memcmp (c, all_null, len))
277 /* In some cases, maintainers have uploaded bzipped
278 0-byte files as dummy packages instead of empty tar files.
279 This is common enough that we should not treat this as an
280 error condition.
281 Same goes for tar archives consisting of a big block of
282 all zero bytes (the famous 46 bytes tar archives). */
283 ;
284 else
285 {
286 note (NULL, IDS_ERR_OPEN_READ, source.Cached (),
287 "Invalid or unsupported tar format");
288 ++errors;
289 }
290 delete try_decompress;
291 return;
292 }
293 }
294 else if ((tarstream = archive::extract (pkgfile)) == NULL)
295 {
296 /* Not a compressed tarball, not a plain tarball, give up. */
297 delete pkgfile;
298 note (NULL, IDS_ERR_OPEN_READ, source.Cached (),
299 "Unrecognisable file format");
300 ++errors;
301 return;
302 }
303
304 /* For binary packages, create a manifest in /etc/setup/ that lists the
305 filename of each file that was unpacked. */
306
307 io_stream *lst = NULL;
308 if (ver.Type () == package_binary)
309 {
310 std::string lstfn = "cygfile:///etc/setup/" + pkgm.name + ".lst.gz";
311
312 io_stream *tmp;
313 if ((tmp = io_stream::open (lstfn, "wb", 0644)) == NULL)
314 log (LOG_PLAIN) << "Warning: Unable to create lst file " + lstfn +
315 " - uninstall of this package will leave orphaned files." << endLog;
316 else
317 {
318 lst = new compress_gz (tmp, "w9");
319 if (lst->error ())
320 {
321 delete lst;
322 lst = NULL;
323 log (LOG_PLAIN) << "Warning: gzip unable to write to lst file " +
324 lstfn + " - uninstall of this package will leave orphaned files."
325 << endLog;
326 }
327 }
328 }
329
330 bool error_in_this_package = false;
331 bool ignoreExtractErrors = unattended_mode;
332
333 package_bytes = source.size;
334 log (LOG_PLAIN) << "Extracting from " << source.Cached () << endLog;
335
336 std::string fn;
337 while ((fn = tarstream->next_file_name ()).size ())
338 {
339 std::string canonicalfn = prefixPath + fn;
340 Progress.SetText3 (canonicalfn.c_str ());
341 log (LOG_BABBLE) << "Installing file " << prefixURL << prefixPath
342 << fn << endLog;
343 if (lst)
344 {
345 std::string tmp = fn + "\n";
346 lst->write (tmp.c_str(), tmp.size());
347 }
348 if (Script::isAScript (fn))
349 pkgm.desired.addScript (Script (canonicalfn));
350
351 bool firstIteration = true;
352 while (archive::extract_file (tarstream, prefixURL, prefixPath) != 0)
353 {
354 if (!ignoreExtractErrors)
355 {
356 char msg[fn.size() + 300];
357 sprintf (msg,
358 "%snable to extract /%s -- the file is in use.\r\n"
359 "Please stop %s Cygwin processes and select \"Retry\", or\r\n"
360 "select \"Continue\" to go on anyway (you will need to reboot).\r\n",
361 firstIteration?"U":"Still u", fn.c_str(), firstIteration?"all":"ALL");
362 switch (MessageBox (owner, msg, "In-use files detected",
363 MB_RETRYCONTINUE | MB_ICONWARNING | MB_TASKMODAL))
364 {
365 case IDRETRY:
366 // retry
367 firstIteration = false;
368 continue;
369 case IDCONTINUE:
370 ignoreExtractErrors = true;
371 break;
372 default:
373 break;
374 }
375 // fall through to previous functionality
376 }
377 if (NoReplaceOnReboot)
378 {
379 ++errors;
380 error_in_this_package = true;
381 log (LOG_PLAIN) << "Not replacing in-use file " << prefixURL
382 << prefixPath << fn << endLog;
383 }
384 else
385 {
386 /* Extract a copy of the file with extension .new appended and
387 indicate it should be replaced on the next reboot. */
388 if (archive::extract_file (tarstream, prefixURL, prefixPath,
389 ".new") != 0)
390 {
391 log (LOG_PLAIN) << "Unable to install file " << prefixURL
392 << prefixPath << fn << ".new" << endLog;
393 ++errors;
394 error_in_this_package = true;
395 }
396 else
397 {
398 std::string s = cygpath ("/" + fn + ".new"),
399 d = cygpath ("/" + fn);
400
401 if (!IsWindowsNT())
402 {
403 /* Get the short file names */
404 char s2[MAX_PATH], d2[MAX_PATH];
405 unsigned int slen =
406 GetShortPathName (s.c_str (), s2, MAX_PATH),
407 dlen = GetShortPathName (d.c_str (), d2, MAX_PATH);
408
409 if (!slen || slen > MAX_PATH || !dlen || dlen > MAX_PATH)
410 replaceOnRebootFailed(fn);
411 else
412 if (!WritePrivateProfileString ("rename", d2, s2,
413 "WININIT.INI"))
414 replaceOnRebootFailed (fn);
415 else
416 replaceOnRebootSucceeded (fn, rebootneeded);
417 }
418 else
419 {
420 /* XXX FIXME: prefix may not be / for in use files -
421 * although it most likely is
422 * - we need a io method to get win32 paths
423 * or to wrap this system call
424 */
425 WCHAR sname[s.size () + 7];
426 WCHAR dname[d.size () + 7];
427 /* Windows 2000 has a bug: Prepending \\?\ does not
428 * work in conjunction with MOVEFILE_DELAY_UNTIL_REBOOT.
429 * So in case of Windows 2000 we just convert the path
430 * to wide char and hope for the best. */
431 if (OSMajorVersion () == 5 && OSMinorVersion () == 0)
432 {
433 mbstowcs (sname, s.c_str (), s.size () + 7);
434 mbstowcs (dname, d.c_str (), d.size () + 7);
435 }
436 else
437 {
438 mklongpath (sname, s.c_str (), s.size () + 7);
439 mklongpath (dname, d.c_str (), d.size () + 7);
440 }
441 if (!MoveFileExW (sname, dname,
442 MOVEFILE_DELAY_UNTIL_REBOOT |
443 MOVEFILE_REPLACE_EXISTING))
444 replaceOnRebootFailed (fn);
445 else
446 replaceOnRebootSucceeded (fn, rebootneeded);
447 }
448 }
449 }
450 // We're done with this file
451 break;
452 }
453 progress (pkgfile->tell ());
454 num_installs++;
455 }
456
457 if (lst)
458 delete lst;
459 delete tarstream;
460
461 total_bytes_sofar += package_bytes;
462 progress (0);
463
464 int df = diskfull (get_root_dir ().c_str ());
465 Progress.SetBar3 (df);
466
467 if (ver.Type () == package_binary && !error_in_this_package)
468 pkgm.installed = ver;
469 }
470
471 static void
472 check_for_old_cygwin (HWND owner)
473 {
474 char buf[MAX_PATH + sizeof ("\\cygwin1.dll")];
475 if (!GetSystemDirectory (buf, sizeof (buf)))
476 return;
477 strcat (buf, "\\cygwin1.dll");
478 if (_access (buf, 0) != 0)
479 return;
480
481 char msg[sizeof (buf) + 132];
482 sprintf (msg,
483 "An old version of cygwin1.dll was found here:\r\n%s\r\nDelete?",
484 buf);
485 switch (MessageBox
486 (owner, msg, "What's that doing there?",
487 MB_YESNO | MB_ICONQUESTION | MB_TASKMODAL))
488 {
489 case IDYES:
490 if (!DeleteFile (buf))
491 {
492 sprintf (msg, "Couldn't delete file %s.\r\n"
493 "Is the DLL in use by another application?\r\n"
494 "You should delete the old version of cygwin1.dll\r\n"
495 "at your earliest convenience.", buf);
496 MessageBox (owner, buf, "Couldn't delete file",
497 MB_OK | MB_ICONEXCLAMATION | MB_TASKMODAL);
498 }
499 break;
500 default:
501 break;
502 }
503
504 return;
505 }
506
507 static void
508 do_install_thread (HINSTANCE h, HWND owner)
509 {
510 int i;
511
512 num_installs = 0, num_uninstalls = 0;
513 rebootneeded = false;
514
515 io_stream::mkpath_p (PATH_TO_DIR,
516 std::string("file://") + std::string(get_root_dir()),
517 0755);
518
519 for (i = 0; Installer::StandardDirs[i].name; i++)
520 {
521 std::string p = cygpath (Installer::StandardDirs[i].name);
522 if (p.size())
523 io_stream::mkpath_p (PATH_TO_DIR, "file://" + p,
524 Installer::StandardDirs[i].mode);
525 }
526
527 /* Create /var/run/utmp */
528 io_stream *utmp = io_stream::open ("cygfile:///var/run/utmp", "wb", 0666);
529 delete utmp;
530
531 Installer myInstaller;
532 myInstaller.initDialog();
533
534 total_bytes = 0;
535 total_bytes_sofar = 0;
536
537 int df = diskfull (get_root_dir ().c_str());
538 Progress.SetBar3 (df);
539
540 /* Writes Cygwin/setup/rootdir registry value */
541 if (!is_legacy)
542 create_install_root ();
543 else
544 {
545 int istext = (root_text == IDC_ROOT_TEXT) ? 1 : 0;
546 int issystem = (root_scope == IDC_ROOT_SYSTEM) ? 1 : 0;
547
548 create_mount ("/", get_root_dir (), istext, issystem);
549 create_mount ("/usr/bin", cygpath ("/bin"), istext, issystem);
550 create_mount ("/usr/lib", cygpath ("/lib"), istext, issystem);
551 set_cygdrive_flags (istext, issystem);
552 }
553
554 /* Let's hope people won't uninstall packages before installing [b]ash */
555 init_run_script ();
556
557 vector <packagemeta *> install_q, uninstall_q, sourceinstall_q;
558
559 packagedb db;
560 for (vector <packagemeta *>::iterator i = db.packages.begin ();
561 i != db.packages.end (); ++i)
562 {
563 packagemeta & pkg = **i;
564
565 if (pkg.desired.picked())
566 {
567 try
568 {
569 md5_one (*pkg.desired.source ());
570 }
571 catch (Exception *e)
572 {
573 if (yesno (owner, IDS_SKIP_PACKAGE, e->what()) == IDYES)
574 pkg.desired.pick (false, &pkg);
575 }
576 if (pkg.desired.picked())
577 {
578 total_bytes += pkg.desired.source()->size;
579 install_q.push_back (&pkg);
580 }
581 }
582
583 if (pkg.desired.sourcePackage ().picked())
584 {
585 try
586 {
587 md5_one (*pkg.desired.sourcePackage ().source ());
588 }
589 catch (Exception *e)
590 {
591 if (yesno (owner, IDS_SKIP_PACKAGE, e->what()) == IDYES)
592 pkg.desired.sourcePackage ().pick (false, &pkg);
593 }
594 if (pkg.desired.sourcePackage().picked())
595 {
596 total_bytes += pkg.desired.sourcePackage ().source()->size;
597 sourceinstall_q.push_back (&pkg);
598 }
599 }
600
601 if ((pkg.installed && pkg.desired != pkg.installed)
602 || pkg.installed.picked ())
603 {
604 uninstall_q.push_back (&pkg);
605 }
606 }
607
608 /* start with uninstalls - remove files that new packages may replace */
609 for (vector <packagemeta *>::iterator i = uninstall_q.begin ();
610 i != uninstall_q.end (); ++i)
611 {
612 myInstaller.preremoveOne (**i);
613 }
614 for (vector <packagemeta *>::iterator i = uninstall_q.begin ();
615 i != uninstall_q.end (); ++i)
616 {
617 myInstaller.uninstallOne (**i);
618 }
619
620 for (vector <packagemeta *>::iterator i = install_q.begin ();
621 i != install_q.end (); ++i)
622 {
623 packagemeta & pkg = **i;
624 try {
625 myInstaller.installOne (pkg, pkg.desired, *pkg.desired.source(),
626 "cygfile://", "/", owner);
627 }
628 catch (exception *e)
629 {
630 if (yesno (owner, IDS_INSTALL_ERROR, e->what()) != IDYES)
631 {
632 log (LOG_TIMESTAMP)
633 << "User cancelled setup after install error" << endLog;
634 LogSingleton::GetInstance().exit (1);
635 return;
636 }
637 }
638 }
639
640 for (vector <packagemeta *>::iterator i = sourceinstall_q.begin ();
641 i != sourceinstall_q.end (); ++i)
642 {
643 packagemeta & pkg = **i;
644 myInstaller.installOne (pkg, pkg.desired.sourcePackage(),
645 *pkg.desired.sourcePackage().source(),
646 "cygfile://", "/usr/src/", owner);
647 }
648
649 if (rebootneeded)
650 note (owner, IDS_REBOOT_REQUIRED);
651
652 int temperr;
653 if ((temperr = db.flush ()))
654 {
655 const char *err = strerror (temperr);
656 if (!err)
657 err = "(unknown error)";
658 fatal (owner, IDS_ERR_OPEN_WRITE, "Package Database",
659 err);
660 }
661
662 if (!myInstaller.errors)
663 check_for_old_cygwin (owner);
664 if (num_installs == 0 && num_uninstalls == 0)
665 {
666 if (!unattended_mode) exit_msg = IDS_NOTHING_INSTALLED;
667 return;
668 }
669 if (num_installs == 0)
670 {
671 if (!unattended_mode) exit_msg = IDS_UNINSTALL_COMPLETE;
672 return;
673 }
674
675 if (myInstaller.errors)
676 exit_msg = IDS_INSTALL_INCOMPLETE;
677 else if (!unattended_mode)
678 exit_msg = IDS_INSTALL_COMPLETE;
679
680 if (rebootneeded)
681 exit_msg = IDS_REBOOT_REQUIRED;
682 }
683
684 static DWORD WINAPI
685 do_install_reflector (void *p)
686 {
687 HANDLE *context;
688 context = (HANDLE *) p;
689
690 try
691 {
692 do_install_thread ((HINSTANCE) context[0], (HWND) context[1]);
693
694 // Tell the progress page that we're done downloading
695 Progress.PostMessage (WM_APP_INSTALL_THREAD_COMPLETE);
696 }
697 TOPLEVEL_CATCH("install");
698
699 ExitThread (0);
700 }
701
702 static HANDLE context[2];
703
704 void
705 do_install (HINSTANCE h, HWND owner)
706 {
707 context[0] = h;
708 context[1] = owner;
709
710 DWORD threadID;
711 CreateThread (NULL, 0, do_install_reflector, context, 0, &threadID);
712 }
713
714 void md5_one (const packagesource& pkgsource)
715 {
716 if (pkgsource.md5.isSet() && pkgsource.Cached ())
717 {
718 std::string fullname (pkgsource.Cached ());
719
720 io_stream *thefile = io_stream::open (fullname, "rb", 0);
721 if (!thefile)
722 throw new Exception (TOSTRING (__LINE__) " " __FILE__,
723 std::string ("IO Error opening ") + fullname,
724 APPERR_IO_ERROR);
725 MD5Sum tempMD5;
726 tempMD5.begin ();
727
728 log (LOG_BABBLE) << "Checking MD5 for " << fullname << endLog;
729
730 Progress.SetText1 ((std::string ("Checking MD5 for ")
731 + pkgsource.Base ()).c_str ());
732 Progress.SetText4 ("Progress:");
733 Progress.SetBar1 (0);
734
735 unsigned char buffer[16384];
736 ssize_t count;
737 while ((count = thefile->read (buffer, sizeof (buffer))) > 0)
738 {
739 tempMD5.append (buffer, count);
740 Progress.SetBar1 (thefile->tell (), thefile->get_size ());
741 }
742 delete thefile;
743 if (count < 0)
744 throw new Exception (TOSTRING(__LINE__) " " __FILE__,
745 "IO Error reading " + fullname,
746 APPERR_IO_ERROR);
747
748 tempMD5.finish ();
749
750 if (pkgsource.md5 != tempMD5)
751 {
752 log (LOG_BABBLE) << "INVALID PACKAGE: " << fullname
753 << " - MD5 mismatch: Ini-file: " << pkgsource.md5.str()
754 << " != On-disk: " << tempMD5.str() << endLog;
755 throw new Exception (TOSTRING(__LINE__) " " __FILE__,
756 "MD5 failure for " + fullname,
757 APPERR_CORRUPT_PACKAGE);
758 }
759
760 log (LOG_BABBLE) << "MD5 verified OK: " << fullname << " "
761 << pkgsource.md5.str() << endLog;
762 }
763 }
This page took 0.102368 seconds and 5 git commands to generate.