diff options
author | Xavier Chantry <shiningxc@gmail.com> | 2009-01-18 14:01:24 +0100 |
---|---|---|
committer | Xavier Chantry <shiningxc@gmail.com> | 2009-01-20 14:03:46 +0100 |
commit | eab96848376db6f54f05773a7e924faf0355137f (patch) | |
tree | 1a0c3332b31b1f5871c9e9c057f5788d4619e001 | |
parent | c794661f1ea8c819d479948e92e5648de62787c5 (diff) | |
download | pacman-eab96848376db6f54f05773a7e924faf0355137f.tar.xz |
alpm_unpack : change prefix handling to workaround FS#12148.
Instead of appending the prefix to each entry name, we can chdir to the
prefix before extracting, and restoring when it is done.
This seems to work better with the strange and special case of FS#12148
where an archive contained the "./" entry.
Signed-off-by: Xavier Chantry <shiningxc@gmail.com>
-rw-r--r-- | lib/libalpm/util.c | 32 |
1 files changed, 24 insertions, 8 deletions
diff --git a/lib/libalpm/util.c b/lib/libalpm/util.c index 1bec6344..75f6042d 100644 --- a/lib/libalpm/util.c +++ b/lib/libalpm/util.c @@ -288,19 +288,21 @@ int _alpm_lckrm() * @param archive the archive to unpack * @param prefix where to extract the files * @param fn a file within the archive to unpack or NULL for all + * @return 0 on success, 1 on failure */ int _alpm_unpack(const char *archive, const char *prefix, const char *fn) { - int ret = 1; + int ret = 0; mode_t oldmask; struct archive *_archive; struct archive_entry *entry; - char expath[PATH_MAX]; + char cwd[PATH_MAX]; + int restore_cwd = 0; ALPM_LOG_FUNC; if((_archive = archive_read_new()) == NULL) - RET_ERR(PM_ERR_LIBARCHIVE, -1); + RET_ERR(PM_ERR_LIBARCHIVE, 1); archive_read_support_compression_all(_archive); archive_read_support_format_all(_archive); @@ -309,10 +311,25 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn) ARCHIVE_DEFAULT_BYTES_PER_BLOCK) != ARCHIVE_OK) { _alpm_log(PM_LOG_ERROR, _("could not open %s: %s\n"), archive, archive_error_string(_archive)); - RET_ERR(PM_ERR_PKG_OPEN, -1); + RET_ERR(PM_ERR_PKG_OPEN, 1); } oldmask = umask(0022); + + /* save the cwd so we can restore it later */ + if(getcwd(cwd, PATH_MAX) == NULL) { + _alpm_log(PM_LOG_ERROR, _("could not get current working directory\n")); + } else { + restore_cwd = 1; + } + + /* just in case our cwd was removed in the upgrade operation */ + if(chdir(prefix) != 0) { + _alpm_log(PM_LOG_ERROR, _("could not change directory to %s (%s)\n"), prefix, strerror(errno)); + ret = 1; + goto cleanup; + } + while(archive_read_next_header(_archive, &entry) == ARCHIVE_OK) { const struct stat *st; const char *entryname; /* the name of the file in the archive */ @@ -337,10 +354,6 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn) } /* Extract the archive entry. */ - ret = 0; - snprintf(expath, PATH_MAX, "%s/%s", prefix, entryname); - archive_entry_set_pathname(entry, expath); - int readret = archive_read_extract(_archive, entry, 0); if(readret == ARCHIVE_WARN) { /* operation succeeded but a non-critical error was encountered */ @@ -361,6 +374,9 @@ int _alpm_unpack(const char *archive, const char *prefix, const char *fn) cleanup: umask(oldmask); archive_read_finish(_archive); + if(restore_cwd) { + chdir(cwd); + } return(ret); } |