[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