diff options
author | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2019-11-21 08:06:28 +0100 |
---|---|---|
committer | Sebastian Huber <sebastian.huber@embedded-brains.de> | 2019-11-25 11:32:19 +0100 |
commit | b6f66d9345a6deea43310e31b519dd35bdbb5908 (patch) | |
tree | 344f0149e536d06b675a75c1195a70948194d229 /cpukit | |
parent | libtest: Output basename of source files (diff) | |
download | rtems-b6f66d9345a6deea43310e31b519dd35bdbb5908.tar.bz2 |
untar: Unify untar support
Update #3823.
Diffstat (limited to '')
-rw-r--r-- | cpukit/include/rtems/untar.h | 55 | ||||
-rw-r--r-- | cpukit/libfs/src/imfs/imfs_load_tar.c | 197 | ||||
-rw-r--r-- | cpukit/libmisc/untar/untar.c | 181 |
3 files changed, 163 insertions, 270 deletions
diff --git a/cpukit/include/rtems/untar.h b/cpukit/include/rtems/untar.h index ba99eb04b9..5c30e750d3 100644 --- a/cpukit/include/rtems/untar.h +++ b/cpukit/include/rtems/untar.h @@ -48,7 +48,27 @@ 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); +#define UNTAR_FILE_NAME_SIZE 100 + +typedef struct { + char *file_path; + char *file_name; + char link_name[UNTAR_FILE_NAME_SIZE]; + 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 File path buffer. + */ + char buf[UNTAR_FILE_NAME_SIZE]; + /** * @brief Current context state. */ @@ -65,31 +85,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. */ int out_fd; @@ -238,20 +238,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..ed2d2a0f97 100644 --- a/cpukit/libfs/src/imfs/imfs_load_tar.c +++ b/cpukit/libfs/src/imfs/imfs_load_tar.c @@ -19,161 +19,74 @@ #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 +#include <string.h> 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'; - - 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); - - if (_rtems_tar_header_checksum(hdr_ptr) != hdr_chksum) - break; - - /* - * 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; - } + rtems_filesystem_eval_path_context_t eval_ctx; + int eval_flags; + rtems_filesystem_location_info_t *loc; + bool is_imfs; + char buf[ 156 + UNTAR_FILE_NAME_SIZE ]; + size_t len; + Untar_HeaderContext ctx; + unsigned long ptr; + + len = strlen( mountpoint ); + if ( len >= sizeof( buf ) - UNTAR_FILE_NAME_SIZE - 2 ) { + return -1; + } + + eval_flags = RTEMS_FS_FOLLOW_LINK; + loc = rtems_filesystem_eval_path_start( &eval_ctx, mountpoint, eval_flags ); + is_imfs = IMFS_is_imfs_instance( loc ); + rtems_filesystem_eval_path_cleanup( &eval_ctx ); + if ( !is_imfs ) { + return -1; + } + + ctx.printer = NULL; + ctx.file_path = memcpy( buf, mountpoint, len ); + + if ( len > 0 && ctx.file_path[ len - 1 ] != '/') { + ctx.file_path[ len ] = '/'; + ctx.file_name = ctx.file_path + len + 1; + } else { + ctx.file_name = ctx.file_path + len; + } + + ptr = 0; + + while ( ptr + 512 <= tar_size ) { + int retval; + + 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 ) + ptr += 512; + + if ( ctx.linkflag == REGTYPE ) { + retval = IMFS_make_linearfile( + ctx.file_path, + ctx.mode, + &tar_image[ ptr ], + ctx.file_size ); - rtems_filesystem_eval_path_continue( &ctx ); - - 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 - ); + if ( retval != 0 ) { + return -1; } - 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); + 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..c6f75e3f93 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->file_name[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->file_name, bufr, UNTAR_FILE_NAME_SIZE); - *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->link_name, &bufr[157], sizeof(ctx->link_name)); + rtems_printf(ctx->printer, "untar: symlink: %s -> %s\n", + ctx->link_name, ctx->file_path); + symlink(ctx->link_name, ctx->file_path); + } else if (ctx->linkflag == REGTYPE) { + rtems_printf(ctx->printer, "untar: file: %s (s:%lu,m:%04lo)\n", + ctx->file_path, ctx->file_size, ctx->mode); + ctx->nblocks = (((ctx->file_size) + 511) & ~511) / 512; + if (Make_Path(ctx->printer, ctx->file_path, 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->file_path); + if (Make_Path(ctx->printer, ctx->file_path, true) < 0) { retval = UNTAR_FAIL; } - r = mkdir(fname, S_IRWXU | S_IRWXG | S_IRWXO); + r = mkdir(ctx->file_path, 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->file_path, &stat_buf) == 0) { if (S_ISDIR(stat_buf.st_mode)) { r = 0; } else { - r = unlink(fname); + r = unlink(ctx->file_path); if (r == 0) { - r = mkdir(fname, *mode); + r = mkdir(ctx->file_path, ctx->mode); } } } } if (r < 0) { - Print_Error(printer, "mkdir", fname); + Print_Error(ctx->printer, "mkdir", ctx->file_path); retval = UNTAR_FAIL; } } @@ -368,17 +361,17 @@ Untar_FromMemory_Print( const rtems_printer *printer ) { - int fd; - const char *tar_ptr = (const char *)tar_buf; - const char *bufr; - char fname[100]; - int retval = UNTAR_SUCCESSFUL; - unsigned long ptr; - unsigned long nblocks = 0; - unsigned long file_size = 0; - unsigned long mode = 0; - unsigned char linkflag = 0; - + int fd; + const char *tar_ptr = (const char *)tar_buf; + const char *bufr; + char buf[UNTAR_FILE_NAME_SIZE]; + Untar_HeaderContext ctx; + int retval = UNTAR_SUCCESSFUL; + unsigned long ptr; + + ctx.file_path = buf; + ctx.file_name = buf; + ctx.printer = printer; rtems_printf(printer, "untar: memory at %p (%zu)\n", tar_buf, size); ptr = 0; @@ -392,18 +385,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.file_path, + O_TRUNC | O_CREAT | O_WRONLY, ctx.mode)) == -1) { + Print_Error(printer, "open", ctx.file_path); + 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 +405,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.file_path); retval = UNTAR_FAIL; break; } @@ -487,16 +480,13 @@ Untar_FromFile_Print( const rtems_printer *printer ) { - 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; + int fd; + char *bufr; + ssize_t n; + int retval; + unsigned long i; + char buf[UNTAR_FILE_NAME_SIZE]; + Untar_HeaderContext ctx; retval = UNTAR_SUCCESSFUL; @@ -510,6 +500,10 @@ Untar_FromFile_Print( return(UNTAR_FAIL); } + ctx.file_path = buf; + ctx.file_name = buf; + ctx.printer = printer; + while (1) { /* Read the header */ /* If the header read fails, we just consider it the end of the tarfile. */ @@ -517,13 +511,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 +524,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.file_path, 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); @@ -553,6 +546,8 @@ Untar_FromFile_Print( void Untar_ChunkContext_Init(Untar_ChunkContext *context) { + context->base.file_path = context->buf; + context->base.file_name = context->buf; context->state = UNTAR_CHUNK_HEADER; context->done_bytes = 0; context->out_fd = -1; @@ -571,12 +566,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 +583,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 +592,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.file_path, + 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 +611,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 +679,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 ) |