From: Brian Dessent Date: Mon, 30 Jul 2007 22:55:50 +0000 (+0000) Subject: * CHANGES: Update. X-Git-Tag: setup_crypto_branch_branchpoint~16 X-Git-Url: https://cygwin.com/git/?a=commitdiff_plain;h=92ef6cf865bc258201941332368963ee2e3ed6e4;p=cygwin-apps%2Fsetup.git * CHANGES: Update. * configure.in (AM_INIT_AUTOMAKE): Enable more automake warnings. * Makefile.am (INCLUDES): Use AM_CPPFLAGS instead. (CLEANFILES): Add. Minor portability tweaks. * tests/Makefile.am (INCLUDES): Use AM_CPPFLAGS instead. * archive.cc (archive::extract): Try to be more compatible when opening tar files. * compress_bz.cc: Fix whitespace throughout. (compress_bz::~compress_bz): Ensure that underlying io_stream's dtor is also run. * install.cc (Installer::installOne): Refactor. * package_db.cc (ConnectedLoopFinder::doIt): Move some log spewage into setup.log.full from setup.log. (packagedb::connectedBegin): Ditto. Consolidate log output to one line. --- diff --git a/CHANGES b/CHANGES index 79c44b07..93efdcd2 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,10 @@ Note: For easier maintenance try to keep items in reverse chronological Version HEAD + - Alert user when encountering a .tar file of unsupported format rather than + silently failing to extract. Also be more accepting of non-GNU tar formats, + such as those created by libtar/cmake. + - If running on 9x/ME versions of Windows, look for setup_legacy.ini/.bz2 instead of setup.ini/.bz2, in support for future dropping of non-NT support and forking of the distro. diff --git a/ChangeLog b/ChangeLog index 7b012c7c..fc013e62 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2007-07-30 Brian Dessent + + * CHANGES: Update. + * configure.in (AM_INIT_AUTOMAKE): Enable more automake warnings. + * Makefile.am (INCLUDES): Use AM_CPPFLAGS instead. + (CLEANFILES): Add. Minor portability tweaks. + * tests/Makefile.am (INCLUDES): Use AM_CPPFLAGS instead. + * archive.cc (archive::extract): Try to be more compatible when + opening tar files. + * compress_bz.cc: Fix whitespace throughout. + (compress_bz::~compress_bz): Ensure that underlying io_stream's dtor is + also run. + * install.cc (Installer::installOne): Refactor. + * package_db.cc (ConnectedLoopFinder::doIt): Move some log spewage into + setup.log.full from setup.log. + (packagedb::connectedBegin): Ditto. Consolidate log output to one line. + 2007-07-02 Brian Dessent * CHANGES: Update. diff --git a/Makefile.am b/Makefile.am index 315912fb..f87718b0 100644 --- a/Makefile.am +++ b/Makefile.am @@ -34,8 +34,8 @@ AM_CFLAGS = $(AM_CXXFLAGS) -Wmissing-declarations -Winline \ -Wstrict-prototypes -Wmissing-prototypes AM_YFLAGS = -d AM_LFLAGS = -8 -WINDRES := @WINDRES@ -INCLUDES = -I$(srcdir)/libgetopt++/include +WINDRES = @WINDRES@ +AM_CPPFLAGS = -I$(srcdir)/libgetopt++/include noinst_PROGRAMS = setup @INILINT@ @@ -67,6 +67,8 @@ BUILT_SOURCES = \ setup_version.c \ iniparse.h +CLEANFILES = setup_version.c + if MINGWTARGET inilint_extras = \ autoload.c \ @@ -286,7 +288,7 @@ setup_version.c : $(srcdir)/ChangeLog Makefile echo 'const char *setup_version = version_store + sizeof (VERSION_PREFIX);') > version.tmp mv version.tmp setup_version.c -%.o: %.rc +.rc.o: $(WINDRES) --include-dir $(srcdir) -o $@ $< # this target creates: diff --git a/archive.cc b/archive.cc index fa70cbee..43d912ba 100644 --- a/archive.cc +++ b/archive.cc @@ -61,7 +61,8 @@ archive::extract (io_stream * original) char magic[longest_magic]; if (original->peek (magic, longest_magic) > 0) { - if (memcmp (&magic[257], "ustar\040\040\0", 8) == 0) + if (memcmp (&magic[257], "ustar\040\040\0", 8) == 0 + || memcmp (&magic[257], "ustar\0", 6) == 0) { /* tar */ archive_tar *rv = new archive_tar (original); diff --git a/compress_bz.cc b/compress_bz.cc index f2477041..3e239676 100644 --- a/compress_bz.cc +++ b/compress_bz.cc @@ -13,9 +13,8 @@ * */ -/* Archive IO operations for bz2 files. - derived from the fd convenience functions in the libbz2 package. - */ +/* Archive IO operations for bz2 files. Derived from the fd convenience + functions in the libbz2 package. */ #include "compress_bz.h" @@ -61,22 +60,21 @@ compress_bz::read (void *buffer, size_t len) return 0; if (peeklen) - { - ssize_t tmplen = std::min (peeklen, len); - peeklen -= tmplen; - memcpy (buffer, peekbuf, tmplen); - memmove (peekbuf, peekbuf + tmplen, tmplen); - ssize_t tmpread = read (&((char *) buffer)[tmplen], len - tmplen); - if (tmpread >= 0) + { + ssize_t tmplen = std::min (peeklen, len); + peeklen -= tmplen; + memcpy (buffer, peekbuf, tmplen); + memmove (peekbuf, peekbuf + tmplen, tmplen); + ssize_t tmpread = read (&((char *) buffer)[tmplen], len - tmplen); + if (tmpread >= 0) return tmpread + tmplen; - else + else return tmpread; } strm.avail_out = len; strm.next_out = (char *) buffer; - int - rlen = 1; + int rlen = 1; while (1) { if (original->error ()) @@ -89,8 +87,8 @@ compress_bz::read (void *buffer, size_t len) rlen = original->read (buf, 4096); if (rlen < 0) { - if (original->error()) - lasterr = original->error(); + if (original->error ()) + lasterr = original->error (); else lasterr = rlen; return -1; @@ -130,38 +128,40 @@ compress_bz::read (void *buffer, size_t len) ssize_t compress_bz::write (const void *buffer, size_t len) { - throw new logic_error("compress_bz::write is not implemented"); + throw new logic_error ("compress_bz::write is not implemented"); } ssize_t compress_bz::peek (void *buffer, size_t len) { if (writing) - { - lasterr = EBADF; + { + lasterr = EBADF; return -1; - } + } + /* can only peek 512 bytes */ if (len > 512) - return ENOMEM; + return ENOMEM; if (len > peeklen) - { - size_t want = len - peeklen; - ssize_t got = read (&peekbuf[peeklen], want); - if (got >= 0) - peeklen += got; - else - /* error */ - return got; - /* we may have read less than requested. */ - memcpy (buffer, peekbuf, peeklen); - return peeklen; - } + { + size_t want = len - peeklen; + ssize_t got = read (&peekbuf[peeklen], want); + if (got >= 0) + peeklen += got; + else + /* error */ + return got; + + /* we may have read less than requested. */ + memcpy (buffer, peekbuf, peeklen); + return peeklen; + } else - { - memcpy (buffer, peekbuf, len); - return len; - } + { + memcpy (buffer, peekbuf, len); + return len; + } return 0; } @@ -169,15 +169,15 @@ long compress_bz::tell () { if (writing) - throw new logic_error("compress_bz::tell is not implemented " - "in writing mode"); + throw new logic_error ("compress_bz::tell is not implemented " + "in writing mode"); return position; } int compress_bz::seek (long where, io_stream_seek_t whence) { - throw new logic_error("compress_bz::seek is not implemented"); + throw new logic_error ("compress_bz::seek is not implemented"); } int @@ -206,4 +206,6 @@ compress_bz::~compress_bz () { if (initialisedOk) BZ2_bzDecompressEnd (&strm); + if (original) + delete original; } diff --git a/configure.ac b/configure.ac index 78e38ad1..62735258 100644 --- a/configure.ac +++ b/configure.ac @@ -20,7 +20,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT([setup], [0], [cygwin-apps@cygwin.com]) AC_PREREQ(2.60) AC_CONFIG_AUX_DIR([cfgaux]) -AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects 1.9 foreign no-define]) +AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects 1.9 foreign no-define -Wall -Wno-portability]) dnl AM_CONFIG_HEADER(include/autoconf.h) AM_MAINTAINER_MODE AC_CONFIG_SRCDIR([Makefile.in]) diff --git a/configure.in b/configure.in index 78e38ad1..62735258 100644 --- a/configure.in +++ b/configure.in @@ -20,7 +20,7 @@ dnl Process this file with autoconf to produce a configure script. AC_INIT([setup], [0], [cygwin-apps@cygwin.com]) AC_PREREQ(2.60) AC_CONFIG_AUX_DIR([cfgaux]) -AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects 1.9 foreign no-define]) +AM_INIT_AUTOMAKE([dist-bzip2 subdir-objects 1.9 foreign no-define -Wall -Wno-portability]) dnl AM_CONFIG_HEADER(include/autoconf.h) AM_MAINTAINER_MODE AC_CONFIG_SRCDIR([Makefile.in]) diff --git a/install.cc b/install.cc index c9382e27..0e5b49d3 100644 --- a/install.cc +++ b/install.cc @@ -71,7 +71,7 @@ static int total_bytes = 0; static int total_bytes_sofar = 0; static int package_bytes = 0; -static BoolOption NoReplaceOnReboot (false, 'r', "no-replaceonreboot", +static BoolOption NoReplaceOnReboot (false, 'r', "no-replaceonreboot", "Disable replacing in-use files on next " "reboot."); @@ -223,188 +223,204 @@ Installer::installOne (packagemeta &pkgm, const packageversion &ver, const std::string& prefixURL, const std::string& prefixPath) { - Progress.SetText2 (source.Base ()); - if (!source.Cached() || !io_stream::exists (source.Cached ())) + Progress.SetText1 ("Installing"); + Progress.SetText2 (source.Base () ? source.Base () : "(unknown)"); + + io_stream *pkgfile = NULL; + + if (!source.Cached() || !io_stream::exists (source.Cached ()) + || !(pkgfile = io_stream::open (source.Cached (), "rb"))) { note (NULL, IDS_ERR_OPEN_READ, source.Cached (), "No such file"); ++errors; return; } - bool error_in_this_package = false; - io_stream *lst = 0; - package_bytes = source.size; - char msg[64]; - strcpy (msg, "Installing"); - Progress.SetText1 (msg); - log (LOG_PLAIN) << msg << " " << source.Cached () << endLog; - - io_stream *tmp = io_stream::open (source.Cached (), "rb"); - io_stream *tmp2 = 0; - archive *thefile = 0; - bool ignoreExtractErrors = unattended_mode; - if (tmp) + /* At this point pkgfile is an opened io_stream to either a .tar.bz2 file, + a .tar.gz file, or just a .tar file. Try it first as a compressed file + and if that fails try opening it as a tar directly. If both fail, abort. + + Note on io_stream pointer management: + + Both the archive and decompress classes take ownership of the io_stream + pointer they were opened with, meaning they delete it in their dtor. So + deleting tarstream should also result in deleting the underlying + try_decompress and pkgfile io_streams as well. */ + + archive *tarstream = NULL; + io_stream *try_decompress = NULL; + + if ((try_decompress = compress::decompress (pkgfile)) != NULL) { - tmp2 = compress::decompress (tmp); - if (tmp2) + if ((tarstream = archive::extract (try_decompress)) == NULL) { - thefile = archive::extract (tmp2); - // tmp2 now owned by archive instance - if (thefile) tmp2 = 0; + /* Decompression succeeded but we couldn't grok it as a valid tar + archive, so notify the user and abort processing this package. */ + delete try_decompress; + note (NULL, IDS_ERR_OPEN_READ, source.Cached (), + "Invalid or unsupported tar format"); + ++errors; + return; } + } + else if ((tarstream = archive::extract (pkgfile)) == NULL) + { + /* Not a compressed tarball, not a plain tarball, give up. */ + delete pkgfile; + note (NULL, IDS_ERR_OPEN_READ, source.Cached (), + "Unrecognisable file format"); + ++errors; + return; + } + + /* For binary packages, create a manifest in /etc/setup/ that lists the + filename of each file that was unpacked. */ + + io_stream *lst = NULL; + if (ver.Type () == package_binary) + { + std::string lstfn = "cygfile:///etc/setup/" + pkgm.name + ".lst.gz"; + + io_stream *tmp; + if ((tmp = io_stream::open (lstfn, "wb")) == NULL) + log (LOG_PLAIN) << "Warning: Unable to create lst file " + lstfn + + " - uninstall of this package will leave orphaned files." << endLog; else { - thefile = archive::extract (tmp); - // tmp now owned by archive instance - if (thefile) tmp = 0; + lst = new compress_gz (tmp, "w9"); + if (lst->error ()) + { + delete lst; + lst = NULL; + log (LOG_PLAIN) << "Warning: gzip unable to write to lst file " + + lstfn + " - uninstall of this package will leave orphaned files." + << endLog; + } } } - - /* FIXME: potential leak of either *tmp or *tmp2 */ - if (thefile) + + bool error_in_this_package = false; + bool ignoreExtractErrors = unattended_mode; + + package_bytes = source.size; + log (LOG_PLAIN) << "Extracting from " << source.Cached () << endLog; + + std::string fn; + while ((fn = tarstream->next_file_name ()).size ()) { - std::string fn; - if (ver.Type () == package_binary) - { - io_stream *tmp = io_stream::open(std::string("cygfile:///etc/setup/") - + std::string(pkgm.name) + - ".lst.gz", "wb"); - lst = new compress_gz (tmp, "w9"); - if (lst->error ()) - { - delete lst; - lst = NULL; - } - } - while ((fn = thefile->next_file_name ()).size()) - { - if (lst) - { - std::string tmp = fn + "\n"; - lst->write (tmp.c_str(), tmp.size()); - } - - std::string canonicalfn = prefixPath + fn; - if (Script::isAScript (fn)) - pkgm.desired.addScript (Script (canonicalfn)); - - Progress.SetText3 (canonicalfn.c_str()); - log (LOG_BABBLE) << "Installing file " << prefixURL << prefixPath - << fn << endLog; - bool firstIteration = true; - while (archive::extract_file (thefile, prefixURL, prefixPath) != 0) - { - if (!ignoreExtractErrors) - { - char msg[fn.size() + 300]; - sprintf (msg, - "%snable to extract /%s -- the file is in use.\r\n" - "Please stop %s Cygwin processes and select \"Retry\", or\r\n" - "select \"Continue\" to go on anyway (you will need to reboot).\r\n", - firstIteration?"U":"Still u", fn.c_str(), firstIteration?"all":"ALL"); - switch (MessageBox - (NULL, msg, "In-use files detected", - MB_RETRYCONTINUE | MB_ICONWARNING | MB_TASKMODAL)) - { - case IDRETRY: - // retry - firstIteration = false; - continue; - case IDCONTINUE: - ignoreExtractErrors = true; - break; - default: - break; - } - // fall through to previous functionality - } - if (NoReplaceOnReboot) - { - ++errors; - error_in_this_package = true; - log (LOG_PLAIN) << "Not replacing in-use file " - << prefixURL << prefixPath << fn << endLog; - } - else - //extract to temp location - if (archive::extract_file (thefile, prefixURL, prefixPath, ".new") != 0) - { - log (LOG_PLAIN) << "Unable to install file " - << prefixURL << prefixPath << fn << endLog; - ++errors; - error_in_this_package = true; - } - else - { - if (!IsWindowsNT()) - { - /* Get the short file names */ - char source[MAX_PATH]; - unsigned int len = - GetShortPathName(cygpath("/" + fn + ".new").c_str(), - source, MAX_PATH); - if (!len || len > MAX_PATH) - { - replaceOnRebootFailed(fn); - } - else - { - char dest[MAX_PATH]; - len = - GetShortPathName(cygpath("/" + fn).c_str(), - dest, MAX_PATH); - if (!len || len > MAX_PATH) - replaceOnRebootFailed (fn); - else - /* trigger a replacement on reboot */ - if (!WritePrivateProfileString - ("rename", dest, source, "WININIT.INI")) - replaceOnRebootFailed (fn); - else - replaceOnRebootSucceeded (fn, rebootneeded); - } - } - else - { - /* XXX FIXME: prefix may not be / for in use files - - * although it most likely is - * - we need a io method to get win32 paths - * or to wrap this system call - */ - if (!MoveFileEx(cygpath("/" + fn + ".new").c_str(), - cygpath("/" + fn).c_str(), - MOVEFILE_DELAY_UNTIL_REBOOT | - MOVEFILE_REPLACE_EXISTING)) - { - replaceOnRebootFailed (fn); - } - else - { - replaceOnRebootSucceeded (fn, rebootneeded); - } - } - } - // We're done with this file - break; - } - progress (tmp->tell ()); - num_installs++; - } - delete thefile; + std::string canonicalfn = prefixPath + fn; + Progress.SetText3 (canonicalfn.c_str ()); + log (LOG_BABBLE) << "Installing file " << prefixURL << prefixPath + << fn << endLog; + if (lst) + { + std::string tmp = fn + "\n"; + lst->write (tmp.c_str(), tmp.size()); + } + if (Script::isAScript (fn)) + pkgm.desired.addScript (Script (canonicalfn)); - total_bytes_sofar += package_bytes; + bool firstIteration = true; + while (archive::extract_file (tarstream, prefixURL, prefixPath) != 0) + { + if (!ignoreExtractErrors) + { + char msg[fn.size() + 300]; + sprintf (msg, + "%snable to extract /%s -- the file is in use.\r\n" + "Please stop %s Cygwin processes and select \"Retry\", or\r\n" + "select \"Continue\" to go on anyway (you will need to reboot).\r\n", + firstIteration?"U":"Still u", fn.c_str(), firstIteration?"all":"ALL"); + switch (MessageBox (NULL, msg, "In-use files detected", + MB_RETRYCONTINUE | MB_ICONWARNING | MB_TASKMODAL)) + { + case IDRETRY: + // retry + firstIteration = false; + continue; + case IDCONTINUE: + ignoreExtractErrors = true; + break; + default: + break; + } + // fall through to previous functionality + } + if (NoReplaceOnReboot) + { + ++errors; + error_in_this_package = true; + log (LOG_PLAIN) << "Not replacing in-use file " << prefixURL + << prefixPath << fn << endLog; + } + else + { + /* Extract a copy of the file with extension .new appended and + indicate it should be replaced on the next reboot. */ + if (archive::extract_file (tarstream, prefixURL, prefixPath, + ".new") != 0) + { + log (LOG_PLAIN) << "Unable to install file " << prefixURL + << prefixPath << fn << ".new" << endLog; + ++errors; + error_in_this_package = true; + } + else + { + std::string s = cygpath ("/" + fn + ".new"), + d = cygpath ("/" + fn); + + if (!IsWindowsNT()) + { + /* Get the short file names */ + char s2[MAX_PATH], d2[MAX_PATH]; + unsigned int slen = + GetShortPathName (s.c_str (), s2, MAX_PATH), + dlen = GetShortPathName (d.c_str (), d2, MAX_PATH); + + if (!slen || slen > MAX_PATH || !dlen || dlen > MAX_PATH) + replaceOnRebootFailed(fn); + else + if (!WritePrivateProfileString ("rename", d2, s2, + "WININIT.INI")) + replaceOnRebootFailed (fn); + else + replaceOnRebootSucceeded (fn, rebootneeded); + } + else + { + /* XXX FIXME: prefix may not be / for in use files - + * although it most likely is + * - we need a io method to get win32 paths + * or to wrap this system call + */ + if (!MoveFileEx (s.c_str (), d.c_str (), + MOVEFILE_DELAY_UNTIL_REBOOT | + MOVEFILE_REPLACE_EXISTING)) + replaceOnRebootFailed (fn); + else + replaceOnRebootSucceeded (fn, rebootneeded); + } + } + } + // We're done with this file + break; + } + progress (tarstream->tell ()); + num_installs++; } + if (lst) + delete lst; + delete tarstream; + + total_bytes_sofar += package_bytes; progress (0); - int df = diskfull (get_root_dir ().c_str()); + int df = diskfull (get_root_dir ().c_str ()); Progress.SetBar3 (df); - if (lst) delete lst; - if (tmp2) delete tmp2; - if (tmp) delete tmp; - if (ver.Type () == package_binary && !error_in_this_package) pkgm.installed = ver; } diff --git a/package_db.cc b/package_db.cc index 50899092..161f4fc5 100644 --- a/package_db.cc +++ b/package_db.cc @@ -243,7 +243,9 @@ ConnectedLoopFinder::doIt() if (pkg.installed && ! visitOrder[i]) visit (i); } - log (LOG_PLAIN) << "Visited: " << visited << " nodes out of " << db.packages.size() << "." << endLog; + log (LOG_BABBLE) << "Visited: " << visited << " nodes out of " + << db.packages.size() << " while creating dependency order." + << endLog; } static bool @@ -326,18 +328,17 @@ PackageDBConnectedIterator packagedb::connectedBegin() { if (!dependencyOrderedPackages.size()) - { - ConnectedLoopFinder doMe; - doMe.doIt(); - log(LOG_PLAIN) << "Dependency ordered install:" << endLog; - for (std::vector::iterator i = dependencyOrderedPackages.begin(); - i != dependencyOrderedPackages.end(); ++i) { - packagemeta &pkg (**i); - log(LOG_PLAIN) << pkg.name << endLog; + ConnectedLoopFinder doMe; + doMe.doIt(); + std::string s = "Dependency order of packages: "; + + for (std::vector::iterator i = + dependencyOrderedPackages.begin(); + i != dependencyOrderedPackages.end(); ++i) + s = s + (*i)->name + " "; + log (LOG_BABBLE) << s << endLog; } - } - return dependencyOrderedPackages.begin(); } diff --git a/tests/Makefile.am b/tests/Makefile.am index fdf42012..fad62459 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,7 +24,7 @@ AM_CXXFLAGS = -Werror -Wall -Wpointer-arith -Wcomments \ -Wcast-align -Wwrite-strings -Wstrict-prototypes -Wmissing-prototypes AM_CFLAGS = $(AM_CXXFLAGS) -Wmissing-declarations -Winline -INCLUDES= -I. -I$(srcdir) -I$(top_srcdir) +AM_CPPFLAGS = -I. -I$(srcdir) -I$(top_srcdir) check_PROGRAMS = \ UserSettingTest \