tar: add support for PAX-encoded path=LONGFILENAME
authorDenys Vlasenko <vda.linux@googlemail.com>
Thu, 23 Feb 2012 12:45:18 +0000 (13:45 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Thu, 23 Feb 2012 12:45:18 +0000 (13:45 +0100)
function                                             old     new   delta
get_header_tar                                      1478    1759    +281

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

index f565e54..3f67b83 100644 (file)
@@ -13,13 +13,13 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle)
        int res;
 
 #if ENABLE_FEATURE_TAR_SELINUX
-       char *sctx = archive_handle->tar__next_file_sctx;
+       char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
        if (!sctx)
-               sctx = archive_handle->tar__global_sctx;
+               sctx = archive_handle->tar__sctx[PAX_GLOBAL];
        if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
                setfscreatecon(sctx);
-               free(archive_handle->tar__next_file_sctx);
-               archive_handle->tar__next_file_sctx = NULL;
+               free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
+               archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
        }
 #endif
 
index cc2ff77..a2ce33b 100644 (file)
@@ -64,13 +64,13 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle)
        file_header_t *file_header = archive_handle->file_header;
 
 #if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */
-       char *sctx = archive_handle->tar__next_file_sctx;
+       char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE];
        if (!sctx)
-               sctx = archive_handle->tar__global_sctx;
+               sctx = archive_handle->tar__sctx[PAX_GLOBAL];
        if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */
                setfscreatecon(sctx);
-               free(archive_handle->tar__next_file_sctx);
-               archive_handle->tar__next_file_sctx = NULL;
+               free(archive_handle->tar__sctx[PAX_NEXT_FILE]);
+               archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL;
        }
 #endif
 
index a63c0fb..8c69975 100644 (file)
@@ -90,23 +90,20 @@ static unsigned long long getOctal(char *str, int len)
 }
 #define GET_OCTAL(a) getOctal((a), sizeof(a))
 
-#if ENABLE_FEATURE_TAR_SELINUX
-/* Scan a PAX header for SELinux contexts, via "RHT.security.selinux" keyword.
- * This is what Red Hat's patched version of tar uses.
- */
-# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
-static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz)
+/* "global" is 0 or 1 */
+static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global)
 {
        char *buf, *p;
-       char *result;
+       unsigned blk_sz;
+
+       blk_sz = (sz + 511) & (~511);
+       p = buf = xmalloc(blk_sz + 1);
+       xread(archive_handle->src_fd, buf, blk_sz);
+       archive_handle->offset += blk_sz;
 
-       p = buf = xmalloc(sz + 1);
        /* prevent bb_strtou from running off the buffer */
        buf[sz] = '\0';
-       xread(archive_handle->src_fd, buf, sz);
-       archive_handle->offset += sz;
 
-       result = NULL;
        while (sz != 0) {
                char *end, *value;
                unsigned len;
@@ -133,19 +130,33 @@ static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, uns
                 * (we do not bother to check that it *was* a newline)
                 */
                p[-1] = '\0';
-               /* Is it selinux security context? */
                value = end + 1;
+
+#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
+               if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) {
+                       value += sizeof("path=") - 1;
+                       free(archive_handle->tar__longname);
+                       archive_handle->tar__longname = xstrdup(value);
+                       continue;
+               }
+#endif
+
+#if ENABLE_FEATURE_TAR_SELINUX
+               /* Scan for SELinux contexts, via "RHT.security.selinux" keyword.
+                * This is what Red Hat's patched version of tar uses.
+                */
+# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
                if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) {
                        value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
-                       result = xstrdup(value);
-                       break;
+                       free(archive_handle->tar__sctx[global]);
+                       archive_handle->tar__sctx[global] = xstrdup(value);
+                       continue;
                }
+#endif
        }
 
        free(buf);
-       return result;
 }
-#endif
 
 char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
 {
@@ -418,12 +429,14 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
        case 'S':       /* Sparse file */
        case 'V':       /* Volume header */
 #endif
-#if !ENABLE_FEATURE_TAR_SELINUX
        case 'g':       /* pax global header */
-       case 'x':       /* pax extended header */
-#else
+       case 'x': {     /* pax extended header */
+               if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
+                       goto skip_ext_hdr;
+               process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g'));
+               goto again_after_align;
+       }
  skip_ext_hdr:
-#endif
        {
                off_t sz;
                bb_error_msg("warning: skipping header '%c'", tar.typeflag);
@@ -435,18 +448,6 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
                /* return get_header_tar(archive_handle); */
                goto again_after_align;
        }
-#if ENABLE_FEATURE_TAR_SELINUX
-       case 'g':       /* pax global header */
-       case 'x': {     /* pax extended header */
-               char **pp;
-               if ((uoff_t)file_header->size > 0xfffff) /* paranoia */
-                       goto skip_ext_hdr;
-               pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx;
-               free(*pp);
-               *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size);
-               goto again;
-       }
-#endif
        default:
                bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag);
        }
index d1a9a34..4987de6 100644 (file)
@@ -77,19 +77,20 @@ typedef struct archive_handle_t {
        off_t offset;
 
        /* Archiver specific. Can make it a union if it ever gets big */
+#define PAX_NEXT_FILE 0
+#define PAX_GLOBAL    1
 #if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB
        smallint tar__end;
 # if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
        char* tar__longname;
        char* tar__linkname;
 # endif
-#if ENABLE_FEATURE_TAR_TO_COMMAND
+# if ENABLE_FEATURE_TAR_TO_COMMAND
        char* tar__to_command;
        const char* tar__to_command_shell;
-#endif
+# endif
 # if ENABLE_FEATURE_TAR_SELINUX
-       char* tar__global_sctx;
-       char* tar__next_file_sctx;
+       char* tar__sctx[2];
 # endif
 #endif
 #if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM