From 1a8fe67acf5903caacc6da2854a074ed0c4b2743 Mon Sep 17 00:00:00 2001 From: Alexander Krutwig Date: Wed, 13 Jul 2016 09:22:35 +0200 Subject: Add Untar_FromChunk_Print() + Test --- cpukit/libmisc/untar/untar.c | 105 +++++++++++++++++++++++++++++++++++- cpukit/libmisc/untar/untar.h | 93 ++++++++++++++++++++++++++++++++ testsuites/libtests/tar01/init.c | 41 ++++++++++++++ testsuites/libtests/tar01/tar01.doc | 1 + testsuites/libtests/tar01/tar01.scn | 12 +++++ 5 files changed, 251 insertions(+), 1 deletion(-) diff --git a/cpukit/libmisc/untar/untar.c b/cpukit/libmisc/untar/untar.c index f6f4f0c837..9a14f67e4e 100644 --- a/cpukit/libmisc/untar/untar.c +++ b/cpukit/libmisc/untar/untar.c @@ -37,7 +37,6 @@ #include #include - /* * TAR file format: @@ -541,6 +540,110 @@ Untar_FromFile_Print( return retval; } + +void Untar_ChunkContext_Init(Untar_ChunkContext *context) +{ + context->state = UNTAR_CHUNK_HEADER; + context->done_bytes = 0; + context->out_fd = -1; +} + +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; + context->done_bytes = 0; + } else { + context->state = UNTAR_CHUNK_SKIP; + context->todo_bytes = 512 * context->todo_blocks; + context->done_bytes = 0; + } + } 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; + context->done_bytes = 0; + } + + break; + default: + return UNTAR_FAIL; + } + + done += consume; + todo -= consume; + } + + return UNTAR_SUCCESSFUL; +} + /* * Function: Untar_FromFile * diff --git a/cpukit/libmisc/untar/untar.h b/cpukit/libmisc/untar/untar.h index d67c29e7f4..006f06d065 100644 --- a/cpukit/libmisc/untar/untar.h +++ b/cpukit/libmisc/untar/untar.h @@ -44,6 +44,99 @@ 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 { + /** + * @brief Current context state. + */ + enum { + UNTAR_CHUNK_HEADER, + UNTAR_CHUNK_SKIP, + UNTAR_CHUNK_WRITE, + UNTAR_CHUNK_ERROR + } state; + + /** + * @brief Header buffer. + */ + char header[512]; + + /** + * @brief Name buffer. + */ + char fname[100]; + + /** + * @brief Number of bytes of overall length are already processed. + */ + size_t done_bytes; + + /** + * @brief Overall amount of bytes to be processed. + */ + long unsigned todo_bytes; + + /** + * @brief Overall amount of blocks to be processed. + */ + unsigned long todo_blocks; + + /** + * @brief File descriptor of output file. + */ + int out_fd; +} Untar_ChunkContext; + +typedef struct { + /** + * @brief Instance of Chunk Context needed for tar decompression. + */ + Untar_ChunkContext base; + + /** + * @brief Current zlib context. + */ + z_stream strm; + + /** + * @brief Buffer that contains the inflated data. + */ + void *inflateBuffer; + + /** + * @brief Size of buffer that contains the inflated data. + */ + size_t inflateBufferSize; + +} Untar_GzChunkContext; + +/** + * @brief Initializes the Untar_ChunkContext files out of a part of a block of + * memory. + * + * @param Untar_ChunkContext *context [in] Pointer to a context structure. + */ +void Untar_ChunkContext_Init(Untar_ChunkContext *context); + +/* + * @brief Rips links, directories and files out of a part of a block of memory. + * + * @param Untar_ChunkContext *context [in] Pointer to a context structure. + * @param void *chunk [in] Pointer to a chunk of a TAR buffer. + * @param size_t chunk_size [in] Length of the chunk of a TAR buffer. + * + * @retval UNTAR_SUCCESSFUL (0) on successful completion. + * @retval UNTAR_FAIL for a faulty step within the process. + * @retval UNTAR_INVALID_CHECKSUM for an invalid header checksum. + * @retval UNTAR_INVALID_HEADER for an invalid header. + */ + +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 54760e9e34..285c767280 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,44 @@ 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); + rtems_test_assert(sc == RTEMS_SUCCESSFUL); + counter ++; + } while (counter < buflen); + printf("successful\n"); + + /******************/ + printf( "========= /dest2/home/test_file =========\n" ); + test_cat( "/dest2/home/test_file", 0, 0 ); + + /******************/ + printf( "========= /dest2/symlink =========\n" ); + test_cat( "/dest2/symlink", 0, 0 ); + +} + rtems_task Init( rtems_task_argument ignored ) @@ -115,6 +154,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 463d6b3499..1a8151c5f2 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 2c4d6b0c08..078cedffca 100644 --- a/testsuites/libtests/tar01/tar01.scn +++ b/testsuites/libtests/tar01/tar01.scn @@ -19,4 +19,16 @@ 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 +========= /dest2/home/test_file ========= +(0)This is a test of loading an RTEMS filesystem from an +initial tar image. + +========= /dest2/symlink ========= +(0)This is a test of loading an RTEMS filesystem from an +initial tar image. + *** END OF TAR01 TEST *** -- cgit v1.2.3