diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2010-04-09 10:52:52 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2010-04-09 10:52:52 +0200 |
commit | 02365a6ef73defb8689d3ed5228125d72993dec9 (patch) | |
tree | 26358e718c5232ee44ad750f1b386f0f4138512a /archival | |
parent | 823b636cd14d337ebb8766c5c181737fb3860b42 (diff) |
tar: fix mishandling of repeated hardlink in tarball; expand tests
function old new delta
data_extract_all 727 767 +40
get_header_tar 1576 1572 -4
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
Diffstat (limited to 'archival')
-rw-r--r-- | archival/libunarchive/data_extract_all.c | 32 | ||||
-rw-r--r-- | archival/libunarchive/get_header_tar.c | 5 |
2 files changed, 28 insertions, 9 deletions
diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c index cc4894229..de2367ac2 100644 --- a/archival/libunarchive/data_extract_all.c +++ b/archival/libunarchive/data_extract_all.c @@ -34,12 +34,30 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { /* Remove the entry if it exists */ - if ((!S_ISDIR(file_header->mode)) - && (unlink(file_header->name) == -1) - && (errno != ENOENT) - ) { - bb_perror_msg_and_die("can't remove old file %s", - file_header->name); + if (!S_ISDIR(file_header->mode)) { + /* Is it hardlink? + * We encode hard links as regular files of size 0 with a symlink */ + if (S_ISREG(file_header->mode) + && file_header->link_target + && file_header->size == 0 + ) { + /* Ugly special case: + * tar cf t.tar hardlink1 hardlink2 hardlink1 + * results in this tarball structure: + * hardlink1 + * hardlink2 -> hardlink1 + * hardlink1 -> hardlink1 <== !!! + */ + if (strcmp(file_header->link_target, file_header->name) == 0) + goto ret; + } + /* Proceed with deleting */ + if (unlink(file_header->name) == -1 + && errno != ENOENT + ) { + bb_perror_msg_and_die("can't remove old file %s", + file_header->name); + } } } else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { @@ -65,7 +83,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) } /* Handle hard links separately - * We identified hard links as regular files of size 0 with a symlink */ + * We encode hard links as regular files of size 0 with a symlink */ if (S_ISREG(file_header->mode) && file_header->link_target && file_header->size == 0 diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c index cf0b9ab02..adb4c157b 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libunarchive/get_header_tar.c @@ -507,8 +507,9 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) archive_handle->action_header(/*archive_handle->*/ file_header); /* Note that we kill the '/' only after action_header() */ /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */ - if (cp) *cp = '\0'; - archive_handle->ah_flags |= ARCHIVE_EXTRACT_QUIET; + if (cp) + *cp = '\0'; + //archive_handle->ah_flags |= ARCHIVE_EXTRACT_QUIET; // why?? archive_handle->action_data(archive_handle); llist_add_to(&(archive_handle->passed), file_header->name); } else { |