summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXavier Chantry <shiningxc@gmail.com>2009-01-18 14:01:24 +0100
committerXavier Chantry <shiningxc@gmail.com>2009-01-20 14:03:46 +0100
commiteab96848376db6f54f05773a7e924faf0355137f (patch)
tree1a0c3332b31b1f5871c9e9c057f5788d4619e001
parentc794661f1ea8c819d479948e92e5648de62787c5 (diff)
downloadpacman-eab96848376db6f54f05773a7e924faf0355137f.tar.gz
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.c32
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);
}