summaryrefslogtreecommitdiffstats
path: root/cpukit/libfs/src/imfs/imfs_load_tar.c
diff options
context:
space:
mode:
Diffstat (limited to 'cpukit/libfs/src/imfs/imfs_load_tar.c')
-rw-r--r--cpukit/libfs/src/imfs/imfs_load_tar.c186
1 files changed, 186 insertions, 0 deletions
diff --git a/cpukit/libfs/src/imfs/imfs_load_tar.c b/cpukit/libfs/src/imfs/imfs_load_tar.c
new file mode 100644
index 0000000000..3cb3c4e195
--- /dev/null
+++ b/cpukit/libfs/src/imfs/imfs_load_tar.c
@@ -0,0 +1,186 @@
+/*
+ * COPYRIGHT (c) 1989-2010.
+ * On-Line Applications Research Corporation (OAR).
+ *
+ * The license and distribution terms for this file may be
+ * found in the file LICENSE in this distribution or at
+ * http://www.rtems.com/license/LICENSE.
+ *
+ * $Id$
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+/*
+ * This file implements the "mount" procedure for tar-based IMFS
+ * extensions. The TAR is not actually mounted under the IMFS.
+ * Directories from the TAR file are created as usual in the IMFS.
+ * File entries are created as IMFS_LINEAR_FILE nodes with their nods
+ * pointing to addresses in the TAR image.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <tar.h>
+
+#include <string.h>
+
+#include <rtems.h>
+#include <rtems/libio_.h>
+#include <rtems/imfs.h>
+#include <rtems/untar.h>
+
+/*
+ * TAR file format:
+ *
+ * Offset Length Contents
+ * 0 100 bytes File name ('\0' terminated, 99 maxmum length)
+ * 100 8 bytes File mode (in octal ascii)
+ * 108 8 bytes User ID (in octal ascii)
+ * 116 8 bytes Group ID (in octal ascii)
+ * 124 12 bytes File size (s) (in octal ascii)
+ * 136 12 bytes Modify time (in octal ascii)
+ * 148 8 bytes Header checksum (in octal ascii)
+ * 156 1 bytes Link flag
+ * 157 100 bytes Linkname ('\0' terminated, 99 maxmum length)
+ * 257 8 bytes Magic PAX ("ustar\0" + 2 bytes padding)
+ * 257 8 bytes Magic GNU tar ("ustar \0")
+ * 265 32 bytes User name ('\0' terminated, 31 maxmum length)
+ * 297 32 bytes Group name ('\0' terminated, 31 maxmum length)
+ * 329 8 bytes Major device ID (in octal ascii)
+ * 337 8 bytes Minor device ID (in octal ascii)
+ * 345 167 bytes Padding
+ * 512 (s+p)bytes File contents (s+p) := (((s) + 511) & ~511),
+ * round up to 512 bytes
+ *
+ * Checksum:
+ * int i, sum;
+ * char* header = tar_header_pointer;
+ * sum = 0;
+ * for(i = 0; i < 512; i++)
+ * sum += 0xFF & header[i];
+ */
+
+#define MAX_NAME_FIELD_SIZE 99
+
+#define MIN(a,b) ((a)>(b)?(b):(a))
+
+/*
+ * rtems_tarfs_load
+ *
+ * Here we create the mountpoint directory and load the tarfs at
+ * that node. Once the IMFS has been mounted, we work through the
+ * tar image and perform as follows:
+ * - For directories, simply call mkdir(). The IMFS creates nodes as
+ * needed.
+ * - For files, we make our own calls to IMFS eval_for_make and
+ * create_node.
+ */
+int rtems_tarfs_load(
+ char *mountpoint,
+ uint8_t *tar_image,
+ size_t tar_size
+)
+{
+ rtems_filesystem_location_info_t root_loc;
+ rtems_filesystem_location_info_t loc;
+ 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;
+ IMFS_jnode_t *node;
+ int status;
+
+ status = rtems_filesystem_evaluate_path(
+ mountpoint,
+ strlen(mountpoint),
+ 0,
+ &root_loc,
+ 0
+ );
+ if (status != 0)
+ return -1;
+
+ if (root_loc.ops != &IMFS_ops && root_loc.ops != &fifoIMFS_ops)
+ return -1;
+
+ /*
+ * Create an IMFS node structure pointing to tar image memory.
+ */
+ offset = 0;
+ while (1) {
+ 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 files, create a file node with special tarfs properties.
+ */
+ if (linkflag == DIRTYPE) {
+ strcpy(full_filename, mountpoint);
+ if (full_filename[strlen(full_filename)-1] != '/')
+ strcat(full_filename, "/");
+ strcat(full_filename, filename);
+ mkdir(full_filename, S_IRWXU | S_IRWXG | S_IRWXO);
+ }
+ /*
+ * Create a LINEAR_FILE node
+ *
+ * NOTE: Coverity Id 20 reports this as a leak.
+ * While technically not a leak, it indicated that
+ * IMFS_create_node was ONLY passed a NULL when we created the
+ * root node. We added a new IMFS_create_root_node() so this
+ * path no longer existed. The result was simpler code which
+ * should not have this path.
+ */
+ else if (linkflag == REGTYPE) {
+ const char *name;
+
+ loc = root_loc;
+ if (IMFS_evaluate_for_make(filename, &loc, &name) == 0) {
+ node = IMFS_create_node(
+ &loc,
+ IMFS_LINEAR_FILE, (char *)name,
+ (file_mode & (S_IRWXU | S_IRWXG | S_IRWXO)) | S_IFREG,
+ NULL
+ );
+ node->info.linearfile.size = file_size;
+ node->info.linearfile.direct = &tar_image[offset];
+ }
+
+ nblocks = (((file_size) + 511) & ~511) / 512;
+ offset += 512 * nblocks;
+ }
+ }
+ return status;
+}
+