tar: shrink hardlink name handling code
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 22 Oct 2015 11:30:34 +0000 (13:30 +0200)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 22 Oct 2015 11:30:34 +0000 (13:30 +0200)
function                                             old     new   delta
data_extract_all                                    1069    1040     -29

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
archival/libarchive/data_extract_all.c

index bd51d2ad3dd93499794c31e8c74802734a907203..cf821c9de0deaa5f50b9eb9722dbdb6b89de7809 100644 (file)
@@ -12,12 +12,11 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
        file_header_t *file_header = archive_handle->file_header;
        int dst_fd;
        int res;
+       char *hard_link;
 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
        char *dst_name;
-       char *dst_link;
 #else
 # define dst_name (file_header->name)
-# define dst_link (file_header->link_target)
 #endif
 
 #if ENABLE_FEATURE_TAR_SELINUX
@@ -31,9 +30,14 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
        }
 #endif
 
+       /* Hard links are encoded as regular files of size 0
+        * with a nonempty link field */
+       hard_link = NULL;
+       if (S_ISREG(file_header->mode) && file_header->size == 0)
+               hard_link = file_header->link_target;
+
 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
        dst_name = file_header->name;
-       dst_link = file_header->link_target;
        if (archive_handle->tar__strip_components) {
                unsigned n = archive_handle->tar__strip_components;
                do {
@@ -47,21 +51,18 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
                         * Link target is shortened only for hardlinks:
                         * softlinks restored unchanged.
                         */
-                       if (S_ISREG(file_header->mode)
-                        && file_header->size == 0
-                        && dst_link
-                       ) {
+                       if (hard_link) {
 // GNU tar 1.26 does not check that we reached end of link name:
 // if "dir/hardlink" is hardlinked to "file",
 // tar xvf a.tar --strip-components=1 says:
 //  tar: hardlink: Cannot hard link to '': No such file or directory
 // and continues processing. We silently skip such entries.
-                               dst_link = strchr(dst_link, '/');
-                               if (!dst_link || dst_link[1] == '\0') {
+                               hard_link = strchr(hard_link, '/');
+                               if (!hard_link || hard_link[1] == '\0') {
                                        data_skip(archive_handle);
                                        return;
                                }
-                               dst_link++;
+                               hard_link++;
                        }
                } while (--n != 0);
        }
@@ -79,12 +80,7 @@ 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)) {
-                       /* Is it hardlink?
-                        * We encode hard links as regular files of size 0 with a symlink */
-                       if (S_ISREG(file_header->mode)
-                        && file_header->size == 0
-                        && dst_link
-                       ) {
+                       if (hard_link) {
                                /* Ugly special case:
                                 * tar cf t.tar hardlink1 hardlink2 hardlink1
                                 * results in this tarball structure:
@@ -92,7 +88,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
                                 * hardlink2 -> hardlink1
                                 * hardlink1 -> hardlink1 <== !!!
                                 */
-                               if (strcmp(dst_link, dst_name) == 0)
+                               if (strcmp(hard_link, dst_name) == 0)
                                        goto ret;
                        }
                        /* Proceed with deleting */
@@ -128,19 +124,14 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
                }
        }
 
-       /* Handle hard links separately
-        * We encode hard links as regular files of size 0 with a symlink */
-       if (S_ISREG(file_header->mode)
-        && file_header->size == 0
-        && dst_link
-       ) {
-               /* Hard link */
-               res = link(dst_link, dst_name);
+       /* Handle hard links separately */
+       if (hard_link) {
+               res = link(hard_link, dst_name);
                if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) {
                        bb_perror_msg("can't create %slink "
                                        "from %s to %s", "hard",
                                        dst_name,
-                                       dst_link);
+                                       hard_link);
                }
                /* Hardlinks have no separate mode/ownership, skip chown/chmod */
                goto ret;