summaryrefslogtreecommitdiffstats
path: root/cpukit
diff options
context:
space:
mode:
authorSebastian Huber <sebastian.huber@embedded-brains.de>2019-11-21 08:06:28 +0100
committerSebastian Huber <sebastian.huber@embedded-brains.de>2019-11-25 11:32:19 +0100
commitb6f66d9345a6deea43310e31b519dd35bdbb5908 (patch)
tree344f0149e536d06b675a75c1195a70948194d229 /cpukit
parentlibtest: Output basename of source files (diff)
downloadrtems-b6f66d9345a6deea43310e31b519dd35bdbb5908.tar.bz2
untar: Unify untar support
Update #3823.
Diffstat (limited to 'cpukit')
-rw-r--r--cpukit/include/rtems/untar.h55
-rw-r--r--cpukit/libfs/src/imfs/imfs_load_tar.c197
-rw-r--r--cpukit/libmisc/untar/untar.c181
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
)