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>
This commit is contained in:
Denys Vlasenko
2010-04-09 10:52:52 +02:00
parent 823b636cd1
commit 02365a6ef7
3 changed files with 73 additions and 16 deletions

View File

@@ -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

View File

@@ -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 {