[PATCH 1/3] untar: Unify untar support

Sebastian Huber sebastian.huber at embedded-brains.de
Thu Nov 21 09:36:43 UTC 2019


Update #3823.
---
 cpukit/include/rtems/untar.h          |  47 +++-------
 cpukit/libfs/src/imfs/imfs_load_tar.c | 158 ++++------------------------------
 cpukit/libmisc/untar/untar.c          | 151 +++++++++++++++-----------------
 3 files changed, 97 insertions(+), 259 deletions(-)

diff --git a/cpukit/include/rtems/untar.h b/cpukit/include/rtems/untar.h
index ba99eb04b9..814edd2689 100644
--- a/cpukit/include/rtems/untar.h
+++ b/cpukit/include/rtems/untar.h
@@ -49,6 +49,18 @@ int Untar_FromFile(const char *tar_name);
 int Untar_FromFile_Print(const char *tar_name, const rtems_printer* printer);
 
 typedef struct {
+  char fname[100];
+  char linkname[100];
+  unsigned long mode;
+  unsigned long file_size;
+  unsigned long nblocks;
+  unsigned char linkflag;
+  const rtems_printer *printer;
+} Untar_HeaderContext;
+
+typedef struct {
+  Untar_HeaderContext base;
+
   /**
    * @brief Current context state.
    */
@@ -64,31 +76,11 @@ typedef struct {
    */
   char header[512];
 
-  /**
-   * @brief Name buffer.
-   */
-  char fname[100];
-
   /**
    * @brief Number of bytes of overall length are already processed.
    */
   size_t done_bytes;
 
-  /**
-   * @brief Mode of the file.
-   */
-  unsigned long mode;
-
-  /**
-   * @brief Overall amount of bytes to be processed.
-   */
-  unsigned long todo_bytes;
-
-  /**
-   * @brief Overall amount of blocks to be processed.
-   */
-  unsigned long todo_blocks;
-
   /**
    * @brief File descriptor of output file.
    */
@@ -238,20 +230,7 @@ int Untar_FromXzChunk_Print(
   const rtems_printer* printer
 );
 
-/**************************************************************************
- * This converts octal ASCII number representations into an
- * unsigned long.  Only support 32-bit numbers for now.
- *************************************************************************/
-extern unsigned long
-_rtems_octal2ulong(const char *octascii, size_t len);
-
-/************************************************************************
- * Compute the TAR checksum and check with the value in
- * the archive.  The checksum is computed over the entire
- * header, but the checksum field is substituted with blanks.
- ************************************************************************/
-extern int
-_rtems_tar_header_checksum(const char *bufr);
+int Untar_ProcessHeader(Untar_HeaderContext *ctx, const char *bufr);
 
 #ifdef __cplusplus
 }
diff --git a/cpukit/libfs/src/imfs/imfs_load_tar.c b/cpukit/libfs/src/imfs/imfs_load_tar.c
index 6298a3f32d..f2a2d4afc9 100644
--- a/cpukit/libfs/src/imfs/imfs_load_tar.c
+++ b/cpukit/libfs/src/imfs/imfs_load_tar.c
@@ -19,161 +19,35 @@
 #endif
 
 #include <rtems/imfs.h>
-
-#include <sys/param.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <tar.h>
-#include <unistd.h>
-
 #include <rtems/untar.h>
 
-#define MAX_NAME_FIELD_SIZE      99
-
 int rtems_tarfs_load(
   const char *mountpoint,
-  uint8_t *tar_image,
-  size_t tar_size
+  uint8_t    *tar_image,
+  size_t      tar_size
 )
 {
-   const char                       *hdr_ptr;
-   char                             filename[100];
-   char                             full_filename[256];
-   int                              hdr_chksum;
-   unsigned char                    linkflag;
-   unsigned long                    file_size;
-   unsigned long                    file_mode;
-   int                              offset;
-   unsigned long                    nblocks;
-   int rv = 0;
-   int eval_flags = RTEMS_FS_FOLLOW_LINK;
-   rtems_filesystem_eval_path_context_t ctx;
-   rtems_filesystem_location_info_t rootloc;
-   rtems_filesystem_location_info_t *currentloc =
-     rtems_filesystem_eval_path_start( &ctx, mountpoint, eval_flags );
-
-   rtems_filesystem_eval_path_extract_currentloc( &ctx, &rootloc );
-   rtems_filesystem_eval_path_set_flags(
-     &ctx,
-     RTEMS_FS_MAKE | RTEMS_FS_EXCLUSIVE
-   );
-
-   if ( !IMFS_is_imfs_instance( &rootloc ) ) {
-     rv = -1;
-   }
-
-   /*
-    * Create an IMFS node structure pointing to tar image memory.
-    */
-   offset = 0;
-   while ( rv == 0 ) {
-    if (offset + 512 > tar_size)
-      break;
-
-    /*
-     * Read a header.
-     */
-    hdr_ptr = (char *) &tar_image[offset];
-    offset += 512;
-    if (strncmp(&hdr_ptr[257], "ustar", 5))
-      break;
-
-    strncpy(filename, hdr_ptr, MAX_NAME_FIELD_SIZE);
-    filename[MAX_NAME_FIELD_SIZE] = '\0';
+  Untar_HeaderContext ctx;
+  unsigned long       ptr;
 
-    linkflag   = hdr_ptr[156];
-    file_mode  = _rtems_octal2ulong(&hdr_ptr[100], 8);
-    file_size  = _rtems_octal2ulong(&hdr_ptr[124], 12);
-    hdr_chksum = _rtems_octal2ulong(&hdr_ptr[148], 8);
+  ctx.printer = NULL;
+  ptr = 0;
 
-    if (_rtems_tar_header_checksum(hdr_ptr) != hdr_chksum)
-      break;
+  while (ptr + 512 <= tar_size) {
+    int retval;
 
-    /*
-     * Generate an IMFS node depending on the file type.
-     * - For directories, just create directories as usual.  IMFS
-     *   will take care of the rest.
-     * - For symbolic links, create as usual
-     * - For files, create a file node with special tarfs properties.
-     */
-    if (linkflag == DIRTYPE) {
-      int len;
-      strncpy(full_filename, mountpoint, 255);
-      if (full_filename[(len=strlen(full_filename))-1] != '/')
-        strcat(full_filename, "/");
-      ++len;
-      strncat(full_filename, filename, 256-len-1);
-      if ( mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO) != 0 ) {
-        if (errno == EEXIST) {
-          struct stat stat_buf;
-          if ( stat(full_filename, &stat_buf) == 0 ) {
-            if (  S_ISDIR(stat_buf.st_mode) ) {
-              continue;
-            } else {
-              if ( unlink(full_filename) != -1 ) {
-                if ( mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO) == 0 )
-                  continue;
-              }
-            }
-          }
-        }
-        rv = -1;
-      }
+    retval = Untar_ProcessHeader(&ctx, (const char *) &tar_image[ptr]);
+    if (retval != UNTAR_SUCCESSFUL) {
+      return -1;
     }
 
-    /*
-     * Create a LINEAR_FILE node
-     */
-    else if (linkflag == REGTYPE) {
-      rtems_filesystem_location_free( currentloc );
-      rtems_filesystem_location_clone( currentloc, &rootloc );
-      rtems_filesystem_eval_path_set_path(
-        &ctx,
-        filename,
-        strlen( filename )
-      );
-      rtems_filesystem_eval_path_continue( &ctx );
+    ptr += 512;
 
-      if ( !rtems_filesystem_location_is_null( currentloc ) ) {
-        IMFS_linearfile_context linctx = {
-          .data = &tar_image[offset],
-          .size = file_size
-        };
-
-        IMFS_create_node(
-          currentloc,
-          &IMFS_node_control_linfile,
-          sizeof( IMFS_file_t ),
-          rtems_filesystem_eval_path_get_token( &ctx ),
-          rtems_filesystem_eval_path_get_tokenlen( &ctx ),
-          (file_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG,
-          &linctx
-        );
-      }
-
-      nblocks = (((file_size) + 511) & ~511) / 512;
-      offset += 512 * nblocks;
-    }
-    /*
-     * Create a symbolic link
-     */
-    else if (linkflag == SYMTYPE) {
-      const char *linkto = hdr_ptr + 157;
-      int len;
-
-      strncpy(full_filename, mountpoint, 255);
-      if (full_filename[(len=strlen(full_filename))-1] != '/')
-        strcat(full_filename, "/");
-      ++len;
-      strncat(full_filename, filename, 256-len-1);
-
-      rv = symlink(linkto, full_filename);
+    if (ctx.linkflag == REGTYPE) {
+      IMFS_make_linearfile(ctx.fname, ctx.mode, &tar_image[ptr], ctx.file_size);
+      ptr += 512 * ctx.nblocks;
     }
   }
 
-  rtems_filesystem_location_free( &rootloc );
-  rtems_filesystem_eval_path_cleanup( &ctx );
-
-  return rv;
+  return 0;
 }
-
diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c
index 13d8c36185..2bd1ab243c 100644
--- a/cpukit/libmisc/untar/untar.c
+++ b/cpukit/libmisc/untar/untar.c
@@ -70,13 +70,13 @@
 
 #define MAX_NAME_FIELD_SIZE      99
 
+static int _rtems_tar_header_checksum(const char *bufr);
+
 /*
  * This converts octal ASCII number representations into an
  * unsigned long.  Only support 32-bit numbers for now.
- *
- * warning: this code is referenced in the IMFS.
  */
-unsigned long
+static unsigned long
 _rtems_octal2ulong(
   const char *octascii,
   size_t len
@@ -246,26 +246,20 @@ Make_Path(const rtems_printer *printer, const char* filename, bool end_is_dir)
   return 0;
 }
 
-static int
+int
 Untar_ProcessHeader(
-  const char          *bufr,
-  char                *fname,
-  unsigned long       *mode,
-  unsigned long       *file_size,
-  unsigned long       *nblocks,
-  unsigned char       *linkflag,
-  const rtems_printer *printer
+  Untar_HeaderContext *ctx,
+  const char          *bufr
 )
 {
-  char           linkname[100];
   int            sum;
   int            hdr_chksum;
   int            retval = UNTAR_SUCCESSFUL;
 
-  fname[0] = '\0';
-  *file_size = 0;
-  *nblocks = 0;
-  *linkflag = -1;
+  ctx->fname[0] = '\0';
+  ctx->file_size = 0;
+  ctx->nblocks = 0;
+  ctx->linkflag = -1;
 
   if (strncmp(&bufr[257], "ustar", 5)) {
     return UNTAR_SUCCESSFUL;
@@ -280,57 +274,56 @@ Untar_ProcessHeader(
   sum        = _rtems_tar_header_checksum(bufr);
 
   if (sum != hdr_chksum) {
-    rtems_printf(printer, "untar: file header checksum error\n");
+    rtems_printf(ctx->printer, "untar: file header checksum error\n");
     return UNTAR_INVALID_CHECKSUM;
   }
 
-  strncpy(fname, bufr, MAX_NAME_FIELD_SIZE);
-  fname[MAX_NAME_FIELD_SIZE] = '\0';
+  strlcpy(ctx->fname, bufr, sizeof(ctx->fname));
 
-  *mode = strtoul(&bufr[100], NULL, 8);
+  ctx->mode = strtoul(&bufr[100], NULL, 8);
 
-  *linkflag   = bufr[156];
-  *file_size = _rtems_octal2ulong(&bufr[124], 12);
+  ctx->linkflag   = bufr[156];
+  ctx->file_size = _rtems_octal2ulong(&bufr[124], 12);
 
   /*
    * We've decoded the header, now figure out what it contains and do something
    * with it.
    */
-  if (*linkflag == SYMTYPE) {
-    strncpy(linkname, &bufr[157], MAX_NAME_FIELD_SIZE);
-    linkname[MAX_NAME_FIELD_SIZE] = '\0';
-    rtems_printf(printer, "untar: symlink: %s -> %s\n", linkname, fname);
-    symlink(linkname, fname);
-  } else if (*linkflag == REGTYPE) {
-    rtems_printf(printer, "untar: file: %s (s:%i,m:%04o)\n",
-                 fname, (int) *file_size, (int) *mode);
-    *nblocks = (((*file_size) + 511) & ~511) / 512;
-    if (Make_Path(printer, fname, false) < 0) {
+  if (ctx->linkflag == SYMTYPE) {
+    strlcpy(ctx->linkname, &bufr[157], sizeof(ctx->linkname));
+    rtems_printf(ctx->printer, "untar: symlink: %s -> %s\n",
+                 ctx->linkname, ctx->fname);
+    symlink(ctx->linkname, ctx->fname);
+  } else if (ctx->linkflag == REGTYPE) {
+    rtems_printf(ctx->printer, "untar: file: %s (s:%lu,m:%04lo)\n",
+                 ctx->fname, ctx->file_size, ctx->mode);
+    ctx->nblocks = (((ctx->file_size) + 511) & ~511) / 512;
+    if (Make_Path(ctx->printer, ctx->fname, false) < 0) {
       retval  = UNTAR_FAIL;
     }
-  } else if (*linkflag == DIRTYPE) {
+  } else if (ctx->linkflag == DIRTYPE) {
     int r;
-    rtems_printf(printer, "untar:  dir: %s\n", fname);
-    if (Make_Path(printer, fname, true) < 0) {
+    rtems_printf(ctx->printer, "untar:  dir: %s\n", ctx->fname);
+    if (Make_Path(ctx->printer, ctx->fname, true) < 0) {
       retval  = UNTAR_FAIL;
     }
-    r = mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO);
+    r = mkdir(ctx->fname, S_IRWXU | S_IRWXG | S_IRWXO);
     if (r < 0) {
       if (errno == EEXIST) {
         struct stat stat_buf;
-        if (stat(fname, &stat_buf) == 0) {
+        if (stat(ctx->fname, &stat_buf) == 0) {
           if (S_ISDIR(stat_buf.st_mode)) {
             r = 0;
           } else {
-            r = unlink(fname);
+            r = unlink(ctx->fname);
             if (r == 0) {
-              r = mkdir(fname, *mode);
+              r = mkdir(ctx->fname, ctx->mode);
             }
           }
         }
       }
       if (r < 0) {
-        Print_Error(printer, "mkdir", fname);
+        Print_Error(ctx->printer, "mkdir", ctx->fname);
         retval = UNTAR_FAIL;
       }
     }
@@ -371,14 +364,11 @@ Untar_FromMemory_Print(
   int            fd;
   const char     *tar_ptr = (const char *)tar_buf;
   const char     *bufr;
-  char           fname[100];
+  Untar_HeaderContext ctx;
   int            retval = UNTAR_SUCCESSFUL;
   unsigned long  ptr;
-  unsigned long  nblocks = 0;
-  unsigned long  file_size = 0;
-  unsigned long  mode = 0;
-  unsigned char  linkflag = 0;
 
+  ctx.printer = printer;
   rtems_printf(printer, "untar: memory at %p (%zu)\n", tar_buf, size);
 
   ptr = 0;
@@ -392,18 +382,18 @@ Untar_FromMemory_Print(
     bufr = &tar_ptr[ptr];
     ptr += 512;
 
-    retval = Untar_ProcessHeader(bufr, fname, &mode, &file_size,
-                                 &nblocks, &linkflag, printer);
+    retval = Untar_ProcessHeader(&ctx, bufr);
 
     if (retval != UNTAR_SUCCESSFUL)
       break;
 
-    if (linkflag == REGTYPE) {
-      if ((fd = open(fname, O_TRUNC | O_CREAT | O_WRONLY, mode)) == -1) {
-        Print_Error(printer, "open", fname);
-        ptr += 512 * nblocks;
+    if (ctx.linkflag == REGTYPE) {
+      if ((fd = open(ctx.fname,
+                     O_TRUNC | O_CREAT | O_WRONLY, ctx.mode)) == -1) {
+        Print_Error(printer, "open", ctx.fname);
+        ptr += 512 * ctx.nblocks;
       } else {
-        unsigned long sizeToGo = file_size;
+        unsigned long sizeToGo = ctx.file_size;
         ssize_t       len;
         ssize_t       i;
         ssize_t       n;
@@ -412,11 +402,11 @@ Untar_FromMemory_Print(
          * Read out the data.  There are nblocks of data where nblocks is the
          * file_size rounded to the nearest 512-byte boundary.
          */
-        for (i = 0; i < nblocks; i++) {
+        for (i = 0; i < ctx.nblocks; i++) {
           len = ((sizeToGo < 512L) ? (sizeToGo) : (512L));
           n = write(fd, &tar_ptr[ptr], len);
           if (n != len) {
-            Print_Error(printer, "write", fname);
+            Print_Error(printer, "write", ctx.fname);
             retval  = UNTAR_FAIL;
             break;
           }
@@ -490,13 +480,9 @@ Untar_FromFile_Print(
   int            fd;
   char           *bufr;
   ssize_t        n;
-  char           fname[100];
   int            retval;
   unsigned long  i;
-  unsigned long  nblocks = 0;
-  unsigned long  file_size = 0;
-  unsigned long  mode = 0;
-  unsigned char  linkflag = 0;
+  Untar_HeaderContext ctx;
 
   retval = UNTAR_SUCCESSFUL;
 
@@ -510,6 +496,8 @@ Untar_FromFile_Print(
     return(UNTAR_FAIL);
   }
 
+  ctx.printer = printer;
+
   while (1) {
     /* Read the header */
     /* If the header read fails, we just consider it the end of the tarfile. */
@@ -517,13 +505,12 @@ Untar_FromFile_Print(
       break;
     }
 
-    retval = Untar_ProcessHeader(bufr, fname, &mode, &file_size,
-                                 &nblocks, &linkflag, printer);
+    retval = Untar_ProcessHeader(&ctx, bufr);
 
     if (retval != UNTAR_SUCCESSFUL)
       break;
 
-    if (linkflag == REGTYPE) {
+    if (ctx.linkflag == REGTYPE) {
       int out_fd;
 
       /*
@@ -531,12 +518,12 @@ Untar_FromFile_Print(
        * is the size rounded to the nearest 512-byte boundary.
        */
 
-      if ((out_fd = creat(fname, mode)) == -1) {
-        (void) lseek(fd, SEEK_CUR, 512UL * nblocks);
+      if ((out_fd = creat(ctx.fname, ctx.mode)) == -1) {
+        (void) lseek(fd, SEEK_CUR, 512UL * ctx.nblocks);
       } else {
-        for (i = 0; i < nblocks; i++) {
+        for (i = 0; i < ctx.nblocks; i++) {
           n = read(fd, bufr, 512);
-          n = MIN(n, file_size - (i * 512UL));
+          n = MIN(n, ctx.file_size - (i * 512UL));
           (void) write(out_fd, bufr, n);
         }
         close(out_fd);
@@ -571,12 +558,13 @@ int Untar_FromChunk_Print(
   size_t remaining;
   size_t consume;
   int retval;
-  unsigned char linkflag;
 
   buf = chunk;
   done = 0;
   todo = chunk_size;
 
+  context->base.printer = printer;
+
   while (todo > 0) {
     switch (context->state) {
       case UNTAR_CHUNK_HEADER:
@@ -587,13 +575,8 @@ int Untar_FromChunk_Print(
 
         if (context->done_bytes == 512) {
           retval = Untar_ProcessHeader(
-            &context->header[0],
-            &context->fname[0],
-            &context->mode,
-            &context->todo_bytes,
-            &context->todo_blocks,
-            &linkflag,
-            printer
+            &context->base,
+            &context->header[0]
           );
 
           if (retval != UNTAR_SUCCESSFUL) {
@@ -601,15 +584,16 @@ int Untar_FromChunk_Print(
             return retval;
           }
 
-          if (linkflag == REGTYPE) {
-            context->out_fd = creat(&context->fname[0], context->mode);
+          if (context->base.linkflag == REGTYPE) {
+            context->out_fd = creat(&context->base.fname[0],
+                                    context->base.mode);
 
             if (context->out_fd >= 0) {
               context->state = UNTAR_CHUNK_WRITE;
               context->done_bytes = 0;
             } else {
               context->state = UNTAR_CHUNK_SKIP;
-              context->todo_bytes = 512 * context->todo_blocks;
+              context->base.file_size = 512 * context->base.nblocks;
               context->done_bytes = 0;
             }
           } else {
@@ -619,27 +603,28 @@ int Untar_FromChunk_Print(
 
         break;
       case UNTAR_CHUNK_SKIP:
-        remaining = context->todo_bytes - context->done_bytes;
+        remaining = context->base.file_size - context->done_bytes;
         consume = MIN(remaining, todo);
         context->done_bytes += consume;
 
-        if (context->done_bytes == context->todo_bytes) {
+        if (context->done_bytes == context->base.file_size) {
           context->state = UNTAR_CHUNK_HEADER;
           context->done_bytes = 0;
         }
 
         break;
       case UNTAR_CHUNK_WRITE:
-        remaining = context->todo_bytes - context->done_bytes;
+        remaining = context->base.file_size - context->done_bytes;
         consume = MIN(remaining, todo);
         write(context->out_fd, &buf[done], consume);
         context->done_bytes += consume;
 
-        if (context->done_bytes == context->todo_bytes) {
+        if (context->done_bytes == context->base.file_size) {
           close(context->out_fd);
           context->out_fd = -1;
           context->state = UNTAR_CHUNK_SKIP;
-          context->todo_bytes = 512 * context->todo_blocks - context->todo_bytes;
+          context->base.file_size = 512 * context->base.nblocks
+            - context->base.file_size;
           context->done_bytes = 0;
         }
 
@@ -686,7 +671,7 @@ Untar_FromFile(
  * the archive.  The checksum is computed over the entire
  * header, but the checksum field is substituted with blanks.
  */
-int
+static int
 _rtems_tar_header_checksum(
   const char *bufr
 )
-- 
2.16.4



More information about the devel mailing list