From 2aec773688fd64857e9446838187170760acddd4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 20 Feb 2013 15:58:42 +0100 Subject: [PATCH] rpm: use "create+rename" method of replacing existing files Users were reporting getting errors like "ls: error while loading shared libraries: libc.so.6: ELF load command past end of file" while rpm was unpacking glibc tarball. Signed-off-by: Denys Vlasenko --- archival/libarchive/data_extract_all.c | 15 ++++++++++++++- archival/rpm.c | 4 ++-- include/bb_archive.h | 3 +++ 3 files changed, 19 insertions(+), 3 deletions(-) diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index 3f67b835f..45776dcbe 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c @@ -106,15 +106,28 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ + char *dst_name; int flags = O_WRONLY | O_CREAT | O_EXCL; if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) flags = O_WRONLY | O_CREAT | O_TRUNC; - dst_fd = xopen3(file_header->name, + dst_name = file_header->name; +#ifdef ARCHIVE_REPLACE_VIA_RENAME + if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) + /* rpm-style temp file name */ + dst_name = xasprintf("%s;%x", dst_name, (int)getpid()); +#endif + dst_fd = xopen3(dst_name, flags, file_header->mode ); bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); close(dst_fd); +#ifdef ARCHIVE_REPLACE_VIA_RENAME + if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { + xrename(dst_name, file_header->name); + free(dst_name); + } +#endif break; } case S_IFDIR: diff --git a/archival/rpm.c b/archival/rpm.c index 793701652..6b227d537 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -242,8 +242,8 @@ static void extract_cpio(int fd, const char *source_rpm) /* compat: overwrite existing files. * try "rpm -i foo.src.rpm" few times in a row - * standard rpm will not complain. - * (TODO? real rpm creates "file;1234" and then renames it) */ - | ARCHIVE_UNLINK_OLD; + */ + | ARCHIVE_REPLACE_VIA_RENAME; archive_handle->src_fd = fd; /*archive_handle->offset = 0; - init_handle() did it */ diff --git a/include/bb_archive.h b/include/bb_archive.h index a7a2a1135..b82cfd83c 100644 --- a/include/bb_archive.h +++ b/include/bb_archive.h @@ -122,6 +122,9 @@ typedef struct archive_handle_t { #define ARCHIVE_NUMERIC_OWNER (1 << 7) #define ARCHIVE_O_TRUNC (1 << 8) #define ARCHIVE_REMEMBER_NAMES (1 << 9) +#if ENABLE_RPM +#define ARCHIVE_REPLACE_VIA_RENAME (1 << 10) +#endif /* POSIX tar Header Block, from POSIX 1003.1-1990 */