diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2015-10-22 13:30:34 +0200 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2015-10-22 13:30:34 +0200 |
commit | f167e4503d08561054e75deb2ff123be2b30afa5 (patch) | |
tree | 9b5d8c110cdf4438d59df874f70204da8c55003b | |
parent | 62ae323df0856546754ecfe226fc9bf0dc16bcb8 (diff) | |
download | busybox-w32-f167e4503d08561054e75deb2ff123be2b30afa5.tar.gz busybox-w32-f167e4503d08561054e75deb2ff123be2b30afa5.tar.bz2 busybox-w32-f167e4503d08561054e75deb2ff123be2b30afa5.zip |
tar: shrink hardlink name handling code
function old new delta
data_extract_all 1069 1040 -29
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
-rw-r--r-- | archival/libarchive/data_extract_all.c | 43 |
1 files changed, 17 insertions, 26 deletions
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index bd51d2ad3..cf821c9de 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c | |||
@@ -12,12 +12,11 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
12 | file_header_t *file_header = archive_handle->file_header; | 12 | file_header_t *file_header = archive_handle->file_header; |
13 | int dst_fd; | 13 | int dst_fd; |
14 | int res; | 14 | int res; |
15 | char *hard_link; | ||
15 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS | 16 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS |
16 | char *dst_name; | 17 | char *dst_name; |
17 | char *dst_link; | ||
18 | #else | 18 | #else |
19 | # define dst_name (file_header->name) | 19 | # define dst_name (file_header->name) |
20 | # define dst_link (file_header->link_target) | ||
21 | #endif | 20 | #endif |
22 | 21 | ||
23 | #if ENABLE_FEATURE_TAR_SELINUX | 22 | #if ENABLE_FEATURE_TAR_SELINUX |
@@ -31,9 +30,14 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
31 | } | 30 | } |
32 | #endif | 31 | #endif |
33 | 32 | ||
33 | /* Hard links are encoded as regular files of size 0 | ||
34 | * with a nonempty link field */ | ||
35 | hard_link = NULL; | ||
36 | if (S_ISREG(file_header->mode) && file_header->size == 0) | ||
37 | hard_link = file_header->link_target; | ||
38 | |||
34 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS | 39 | #if ENABLE_FEATURE_TAR_LONG_OPTIONS |
35 | dst_name = file_header->name; | 40 | dst_name = file_header->name; |
36 | dst_link = file_header->link_target; | ||
37 | if (archive_handle->tar__strip_components) { | 41 | if (archive_handle->tar__strip_components) { |
38 | unsigned n = archive_handle->tar__strip_components; | 42 | unsigned n = archive_handle->tar__strip_components; |
39 | do { | 43 | do { |
@@ -47,21 +51,18 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
47 | * Link target is shortened only for hardlinks: | 51 | * Link target is shortened only for hardlinks: |
48 | * softlinks restored unchanged. | 52 | * softlinks restored unchanged. |
49 | */ | 53 | */ |
50 | if (S_ISREG(file_header->mode) | 54 | if (hard_link) { |
51 | && file_header->size == 0 | ||
52 | && dst_link | ||
53 | ) { | ||
54 | // GNU tar 1.26 does not check that we reached end of link name: | 55 | // GNU tar 1.26 does not check that we reached end of link name: |
55 | // if "dir/hardlink" is hardlinked to "file", | 56 | // if "dir/hardlink" is hardlinked to "file", |
56 | // tar xvf a.tar --strip-components=1 says: | 57 | // tar xvf a.tar --strip-components=1 says: |
57 | // tar: hardlink: Cannot hard link to '': No such file or directory | 58 | // tar: hardlink: Cannot hard link to '': No such file or directory |
58 | // and continues processing. We silently skip such entries. | 59 | // and continues processing. We silently skip such entries. |
59 | dst_link = strchr(dst_link, '/'); | 60 | hard_link = strchr(hard_link, '/'); |
60 | if (!dst_link || dst_link[1] == '\0') { | 61 | if (!hard_link || hard_link[1] == '\0') { |
61 | data_skip(archive_handle); | 62 | data_skip(archive_handle); |
62 | return; | 63 | return; |
63 | } | 64 | } |
64 | dst_link++; | 65 | hard_link++; |
65 | } | 66 | } |
66 | } while (--n != 0); | 67 | } while (--n != 0); |
67 | } | 68 | } |
@@ -79,12 +80,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
79 | if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { | 80 | if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { |
80 | /* Remove the entry if it exists */ | 81 | /* Remove the entry if it exists */ |
81 | if (!S_ISDIR(file_header->mode)) { | 82 | if (!S_ISDIR(file_header->mode)) { |
82 | /* Is it hardlink? | 83 | if (hard_link) { |
83 | * We encode hard links as regular files of size 0 with a symlink */ | ||
84 | if (S_ISREG(file_header->mode) | ||
85 | && file_header->size == 0 | ||
86 | && dst_link | ||
87 | ) { | ||
88 | /* Ugly special case: | 84 | /* Ugly special case: |
89 | * tar cf t.tar hardlink1 hardlink2 hardlink1 | 85 | * tar cf t.tar hardlink1 hardlink2 hardlink1 |
90 | * results in this tarball structure: | 86 | * results in this tarball structure: |
@@ -92,7 +88,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
92 | * hardlink2 -> hardlink1 | 88 | * hardlink2 -> hardlink1 |
93 | * hardlink1 -> hardlink1 <== !!! | 89 | * hardlink1 -> hardlink1 <== !!! |
94 | */ | 90 | */ |
95 | if (strcmp(dst_link, dst_name) == 0) | 91 | if (strcmp(hard_link, dst_name) == 0) |
96 | goto ret; | 92 | goto ret; |
97 | } | 93 | } |
98 | /* Proceed with deleting */ | 94 | /* Proceed with deleting */ |
@@ -128,19 +124,14 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
128 | } | 124 | } |
129 | } | 125 | } |
130 | 126 | ||
131 | /* Handle hard links separately | 127 | /* Handle hard links separately */ |
132 | * We encode hard links as regular files of size 0 with a symlink */ | 128 | if (hard_link) { |
133 | if (S_ISREG(file_header->mode) | 129 | res = link(hard_link, dst_name); |
134 | && file_header->size == 0 | ||
135 | && dst_link | ||
136 | ) { | ||
137 | /* Hard link */ | ||
138 | res = link(dst_link, dst_name); | ||
139 | if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { | 130 | if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { |
140 | bb_perror_msg("can't create %slink " | 131 | bb_perror_msg("can't create %slink " |
141 | "from %s to %s", "hard", | 132 | "from %s to %s", "hard", |
142 | dst_name, | 133 | dst_name, |
143 | dst_link); | 134 | hard_link); |
144 | } | 135 | } |
145 | /* Hardlinks have no separate mode/ownership, skip chown/chmod */ | 136 | /* Hardlinks have no separate mode/ownership, skip chown/chmod */ |
146 | goto ret; | 137 | goto ret; |