[PATCH] Add Untar_FromChunk_Print() + Test

Gedare Bloom gedare at rtems.org
Wed Jul 13 14:17:34 UTC 2016


It may be worth using a constant expression for the 512byte header
parameter, since this 512 reappears in a couple of math expressions,
if one ever changed it that would be a problem. Unless it is not
changeable / part of the tar "specification"

On Wed, Jul 13, 2016 at 7:59 AM, Alexander Krutwig
<alexander.krutwig at embedded-brains.de> wrote:
> From: Sebastian Huber <sebastian.huber at embedded-brains.de>
>
> ---
>  cpukit/libmisc/untar/untar.c        | 135 ++++++++++++++++++++++++++++++++++++
>  cpukit/libmisc/untar/untar.h        |  30 ++++++++
>  testsuites/libtests/tar01/init.c    |  44 ++++++++++++
>  testsuites/libtests/tar01/tar01.doc |   1 +
>  testsuites/libtests/tar01/tar01.scn |  11 +++
>  5 files changed, 221 insertions(+)
>
> diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c
> index f6f4f0c..5287d5a 100644
> --- a/cpukit/libmisc/untar/untar.c
> +++ b/cpukit/libmisc/untar/untar.c
> @@ -542,6 +542,141 @@ Untar_FromFile_Print(
>  }
>
>  /*
> + * Function: Untar_ChunkContext_Init
> + *
> + * Description:
> + *
> + *    This is a simple subroutine that initializes the Untar_ChunkContext
> + *    files out of a part of a block of memory.
> + *
> + * Inputs:
> + *
> + *    Untar_ChunkContext *context    - Pointer to a context structure
> + *
> + * Output: None
> + */
> +void Untar_ChunkContext_Init(Untar_ChunkContext *context)
> +{
> +  context->state = UNTAR_CHUNK_HEADER;
> +  context->done_bytes = 0;
> +  context->out_fd = -1;
> +}
> +
> +/*
> + * Function: Untar_FromChunk_Print
> + *
> + * Description:
> + *
> + *    This is a simple subroutine used to rip links, directories, and
> + *    files out of a part of a block of memory.
> + *
> + * Inputs:
> + *
> + *    Untar_ChunkContext *context    - Pointer to a context structure
> + *    void *chunk                    - Pointer to a chunk of a TAR buffer
> + *    size_t chunk_size              - Length of the chunk of a TAR buffer
> + *
> + * Output:
> + *
> + *    int - UNTAR_SUCCESSFUL (0)    on successful completion.
> + *          UNTAR_FAIL              for a faulty step within the process
> + *          UNTAR_INVALID_CHECKSUM  for an invalid header checksum.
> + *          UNTAR_INVALID_HEADER    for an invalid header.
> + */
> +int Untar_FromChunk_Print(
> +  Untar_ChunkContext *context,
> +  void *chunk,
> +  size_t chunk_size,
> +  const rtems_printer* printer
> +)
> +{
> +  char *buf;
> +  size_t done;
> +  size_t todo;
> +  size_t remaining;
> +  size_t consume;
> +  int retval;
> +  unsigned char linkflag;
> +
> +  buf = chunk;
> +  done = 0;
> +  todo = chunk_size;
> +
> +  while (todo > 0) {
> +    switch (context->state) {
> +      case UNTAR_CHUNK_HEADER:
> +        remaining = 512 - context->done_bytes;
> +        consume = MIN(remaining, todo);
> +        memcpy(&context->header[context->done_bytes], &buf[done], consume);
> +        context->done_bytes += consume;
> +
> +        if (context->done_bytes == 512) {
> +          retval = Untar_ProcessHeader(
> +            &context->header[0],
> +            &context->fname[0],
> +            &context->todo_bytes,
> +            &context->todo_blocks,
> +            &linkflag,
> +            printer
> +          );
> +
> +          if (retval != UNTAR_SUCCESSFUL) {
> +            context->state = UNTAR_CHUNK_ERROR;
> +            return retval;
> +          }
> +
> +          if (linkflag == REGTYPE) {
> +            context->out_fd = creat(&context->fname[0], 0644);
> +
> +            if (context->out_fd >= 0) {
> +              context->state = UNTAR_CHUNK_WRITE;
> +            } else {
> +              context->state = UNTAR_CHUNK_SKIP;
> +              context->todo_bytes = 512 * context->todo_blocks;
> +            }
> +          } else {
> +              context->done_bytes = 0;
> +          }
> +        }
> +
> +        break;
> +      case UNTAR_CHUNK_SKIP:
> +        remaining = context->todo_bytes - context->done_bytes;
> +        consume = MIN(remaining, todo);
> +        context->done_bytes += consume;
> +
> +        if (context->done_bytes == context->todo_bytes) {
> +          context->state = UNTAR_CHUNK_HEADER;
> +          context->done_bytes = 0;
> +        }
> +
> +        break;
> +      case UNTAR_CHUNK_WRITE:
> +        remaining = context->todo_bytes - 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) {
> +          close(context->out_fd);
> +          context->out_fd = -1;
> +          context->state = UNTAR_CHUNK_SKIP;
> +          context->todo_bytes = 512 * context->todo_blocks - context->todo_bytes;
> +        }
> +
> +        break;
> +      default:
> +        return UNTAR_FAIL;
> +    }
> +
> +    done += consume;
> +    todo -= consume;
> +  }
> +
> +  return UNTAR_SUCCESSFUL;
> +}
> +
> +/*
>   * Function: Untar_FromFile
>   *
>   * Description:
> diff --git a/cpukit/libmisc/untar/untar.h b/cpukit/libmisc/untar/untar.h
> index d67c29e..5a74918 100644
> --- a/cpukit/libmisc/untar/untar.h
> +++ b/cpukit/libmisc/untar/untar.h
> @@ -44,6 +44,36 @@ int Untar_FromMemory_Print(void *tar_buf, size_t size, const rtems_printer* prin
>  int Untar_FromFile(const char *tar_name);
>  int Untar_FromFile_Print(const char *tar_name, const rtems_printer* printer);
>
> +typedef struct {
> +  enum {
> +    UNTAR_CHUNK_HEADER,
> +    UNTAR_CHUNK_SKIP,
> +    UNTAR_CHUNK_WRITE,
> +    UNTAR_CHUNK_ERROR
> +  } state;
> +
> +  char header[512];
> +
> +  char fname[100];
> +
> +  size_t done_bytes;
> +
> +  long unsigned todo_bytes;
> +
> +  unsigned long todo_blocks;
> +
> +  int out_fd;
> +} Untar_ChunkContext;
> +
> +void Untar_ChunkContext_Init(Untar_ChunkContext *context);
> +
> +int Untar_FromChunk_Print(
> +  Untar_ChunkContext *context,
> +  void *chunk,
> +  size_t chunk_size,
> +  const rtems_printer* printer
> +);
> +
>  /**************************************************************************
>   * This converts octal ASCII number representations into an
>   * unsigned long.  Only support 32-bit numbers for now.
> diff --git a/testsuites/libtests/tar01/init.c b/testsuites/libtests/tar01/init.c
> index 54760e9..3977447 100644
> --- a/testsuites/libtests/tar01/init.c
> +++ b/testsuites/libtests/tar01/init.c
> @@ -31,6 +31,7 @@ const char rtems_test_name[] = "TAR 1";
>  rtems_task Init(rtems_task_argument argument);
>  void test_untar_from_memory(void);
>  void test_untar_from_file(void);
> +void test_untar_chunks_from_memory(void);
>
>  #define TARFILE_START initial_filesystem_tar
>  #define TARFILE_SIZE  initial_filesystem_tar_size
> @@ -106,6 +107,47 @@ void test_untar_from_file(void)
>    test_cat( "/dest/symlink", 0, 0 );
>  }
>
> +void test_untar_chunks_from_memory(void)
> +{
> +  rtems_status_code sc;
> +  rtems_printer     printer;
> +  int rv;
> +  Untar_ChunkContext ctx;
> +  unsigned long counter = 0;
> +  char *buffer = (char *)TARFILE_START;
> +  size_t buflen = TARFILE_SIZE;
> +
> +  rtems_print_printer_printf(&printer);
> +
> +  /* make a directory to untar it into */
> +  rv = mkdir( "/dest2", 0777 );
> +  rtems_test_assert( rv == 0 );
> +
> +  rv = chdir( "/dest2" );
> +  rtems_test_assert( rv == 0 );
> +
> +  printf("Untaring chunks from memory - ");
> +  Untar_ChunkContext_Init(&ctx);
> +  do {
> +    sc = Untar_FromChunk_Print(&ctx, &buffer[counter], (size_t)1 , &printer);
> +    if (sc != RTEMS_SUCCESSFUL) {
> +      printf ("error: untar failed: %s\n", rtems_status_text (sc));
> +      exit(1);
> +    }
> +    counter ++;
> +  } while (counter < buflen);
> +  printf ("successful\n");
> +
> +  /******************/
> +  printf( "========= /home/test_file =========\n" );
> +  test_cat( "/home/test_file", 0, 0 );
> +
> +  /******************/
> +  printf( "========= /symlink =========\n" );
> +  test_cat( "/symlink", 0, 0 );
> +
> +}
> +
>  rtems_task Init(
>    rtems_task_argument ignored
>  )
> @@ -115,6 +157,8 @@ rtems_task Init(
>    test_untar_from_memory();
>    puts( "" );
>    test_untar_from_file();
> +  puts( "" );
> +  test_untar_chunks_from_memory();
>
>    TEST_END();
>    exit( 0 );
> diff --git a/testsuites/libtests/tar01/tar01.doc b/testsuites/libtests/tar01/tar01.doc
> index 463d6b3..1a8151c 100644
> --- a/testsuites/libtests/tar01/tar01.doc
> +++ b/testsuites/libtests/tar01/tar01.doc
> @@ -14,6 +14,7 @@ directives:
>
>    + Untar_FromMemory
>    + Untar_FromFile
> +  + Untar_ChunksFromMemory
>
>  concepts:
>
> diff --git a/testsuites/libtests/tar01/tar01.scn b/testsuites/libtests/tar01/tar01.scn
> index 2c4d6b0..ae20139 100644
> --- a/testsuites/libtests/tar01/tar01.scn
> +++ b/testsuites/libtests/tar01/tar01.scn
> @@ -19,4 +19,15 @@ initial tar image.
>  (0)This is a test of loading an RTEMS filesystem from an
>  initial tar image.
>
> +Untaring chunks from memory - untar: dir: home
> +untar: file: home/test_file (73)
> +successful
> +========= /home/test_file =========
> +(0)This is a test of loading an RTEMS filesystem from an
> +initial tar image.
> +
> +========= /symlink =========
> +(0)This is a test of loading an RTEMS filesystem from an
> +initial tar image.
> +
>  *** END OF TAR01 TEST ***
> --
> 1.8.4.5
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel



More information about the devel mailing list