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:
parent
823b636cd1
commit
02365a6ef7
@ -34,12 +34,30 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
|
|||||||
|
|
||||||
if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) {
|
if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) {
|
||||||
/* Remove the entry if it exists */
|
/* Remove the entry if it exists */
|
||||||
if ((!S_ISDIR(file_header->mode))
|
if (!S_ISDIR(file_header->mode)) {
|
||||||
&& (unlink(file_header->name) == -1)
|
/* Is it hardlink?
|
||||||
&& (errno != ENOENT)
|
* We encode hard links as regular files of size 0 with a symlink */
|
||||||
) {
|
if (S_ISREG(file_header->mode)
|
||||||
bb_perror_msg_and_die("can't remove old file %s",
|
&& file_header->link_target
|
||||||
file_header->name);
|
&& 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) {
|
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
|
/* 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)
|
if (S_ISREG(file_header->mode)
|
||||||
&& file_header->link_target
|
&& file_header->link_target
|
||||||
&& file_header->size == 0
|
&& file_header->size == 0
|
||||||
|
@ -507,8 +507,9 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
|
|||||||
archive_handle->action_header(/*archive_handle->*/ file_header);
|
archive_handle->action_header(/*archive_handle->*/ file_header);
|
||||||
/* Note that we kill the '/' only after action_header() */
|
/* Note that we kill the '/' only after action_header() */
|
||||||
/* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
|
/* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */
|
||||||
if (cp) *cp = '\0';
|
if (cp)
|
||||||
archive_handle->ah_flags |= ARCHIVE_EXTRACT_QUIET;
|
*cp = '\0';
|
||||||
|
//archive_handle->ah_flags |= ARCHIVE_EXTRACT_QUIET; // why??
|
||||||
archive_handle->action_data(archive_handle);
|
archive_handle->action_data(archive_handle);
|
||||||
llist_add_to(&(archive_handle->passed), file_header->name);
|
llist_add_to(&(archive_handle->passed), file_header->name);
|
||||||
} else {
|
} else {
|
||||||
|
@ -4,20 +4,25 @@
|
|||||||
|
|
||||||
. ./testing.sh
|
. ./testing.sh
|
||||||
|
|
||||||
mkdir tempdir && cd tempdir || exit 1
|
rm -rf tar.tempdir 2>/dev/null
|
||||||
|
mkdir tar.tempdir && cd tar.tempdir || exit 1
|
||||||
|
|
||||||
# testing "test name" "script" "expected result" "file input" "stdin"
|
# testing "test name" "script" "expected result" "file input" "stdin"
|
||||||
|
|
||||||
testing "tar hardlinks and repeated files" "\
|
testing "tar hardlinks and repeated files" '\
|
||||||
rm -rf input_* test.tar 2>/dev/null
|
rm -rf input_* test.tar 2>/dev/null
|
||||||
>input_hard1
|
>input_hard1
|
||||||
ln input_hard1 input_hard2
|
ln input_hard1 input_hard2
|
||||||
mkdir input_dir
|
mkdir input_dir
|
||||||
>input_dir/file
|
>input_dir/file
|
||||||
|
chmod -R 644 *
|
||||||
|
chmod 755 input_dir
|
||||||
tar cf test.tar input input_dir/ input_hard1 input_hard2 input_hard1 input_dir/ input
|
tar cf test.tar input input_dir/ input_hard1 input_hard2 input_hard1 input_dir/ input
|
||||||
tar tvf test.tar | sed 's/.*[0-9] input/input/'
|
tar tvf test.tar | sed "s/.*[0-9] input/input/"
|
||||||
tar xf test.tar 2>&1 && echo Ok
|
tar xf test.tar 2>&1
|
||||||
" "\
|
echo Ok: $?
|
||||||
|
ls -l . input_dir/* | grep input_ | sed "s/\\(^[^ ]*\\) .* input/\\1 input/"
|
||||||
|
' "\
|
||||||
input
|
input
|
||||||
input_dir/
|
input_dir/
|
||||||
input_dir/file
|
input_dir/file
|
||||||
@ -27,7 +32,40 @@ input_hard1 -> input_hard1
|
|||||||
input_dir/
|
input_dir/
|
||||||
input_dir/file
|
input_dir/file
|
||||||
input
|
input
|
||||||
Ok
|
Ok: 0
|
||||||
|
-rw-r--r-- input_dir/file
|
||||||
|
drwxr-xr-x input_dir
|
||||||
|
-rw-r--r-- input_hard1
|
||||||
|
-rw-r--r-- input_hard2
|
||||||
|
" \
|
||||||
|
"" ""
|
||||||
|
|
||||||
|
testing "tar hardlinks mode" '\
|
||||||
|
rm -rf input_* test.tar 2>/dev/null
|
||||||
|
>input_hard1
|
||||||
|
chmod 741 input_hard1
|
||||||
|
ln input_hard1 input_hard2
|
||||||
|
mkdir input_dir
|
||||||
|
chmod 550 input_dir
|
||||||
|
ln input_hard1 input_dir
|
||||||
|
ln input_hard2 input_dir
|
||||||
|
tar cf test.tar input_*
|
||||||
|
tar tvf test.tar | sed "s/.*[0-9] input/input/"
|
||||||
|
tar xf test.tar 2>&1
|
||||||
|
echo Ok: $?
|
||||||
|
ls -l . input_dir/* | grep input_ | sed "s/\\(^[^ ]*\\) .* input/\\1 input/"
|
||||||
|
' "\
|
||||||
|
input_dir/
|
||||||
|
input_dir/input_hard1
|
||||||
|
input_dir/input_hard2 -> input_dir/input_hard1
|
||||||
|
input_hard1 -> input_dir/input_hard1
|
||||||
|
input_hard2 -> input_dir/input_hard1
|
||||||
|
Ok: 0
|
||||||
|
-rwxr----x input_dir/input_hard1
|
||||||
|
-rwxr----x input_dir/input_hard2
|
||||||
|
dr-xr-x--- input_dir
|
||||||
|
-rwxr----x input_hard1
|
||||||
|
-rwxr----x input_hard2
|
||||||
" \
|
" \
|
||||||
"" ""
|
"" ""
|
||||||
|
|
||||||
@ -46,6 +84,6 @@ Ok
|
|||||||
"Ok\n" ""
|
"Ok\n" ""
|
||||||
SKIP=
|
SKIP=
|
||||||
|
|
||||||
cd .. && rm -rf tempdir || exit 1
|
cd .. && rm -rf tar.tempdir || exit 1
|
||||||
|
|
||||||
exit $FAILCOUNT
|
exit $FAILCOUNT
|
||||||
|
Loading…
Reference in New Issue
Block a user