[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Minios-devel] [UNIKRAFT PATCH 4/5] lib/cpio: Add CPIO extraction functionality



Modeled after the FreeBSD libarchive:
https://github.com/freebsd/freebsd/blob/master/contrib/libarchive/libarchive/archive_read_support_format_cpio.c

The implementation is mostly complete except that it does not yet
support symlinks

Signed-off-by: Robert Hrusecky <roberth@xxxxxxxxxxxxx>
Signed-off-by: Omar Jamil <omarj2898@xxxxxxxxx>
Signed-off-by: Sachin Beldona <sachinbeldona@xxxxxxxxxx>
---
 lib/cpio/cpio.c            | 239 +++++++++++++++++++++++++++++++++++++
 lib/cpio/exportsyms.uk     |   2 +-
 lib/cpio/include/uk/cpio.h |  57 +++++++++
 3 files changed, 297 insertions(+), 1 deletion(-)

diff --git a/lib/cpio/cpio.c b/lib/cpio/cpio.c
index e69de29..e27e99b 100644
--- a/lib/cpio/cpio.c
+++ b/lib/cpio/cpio.c
@@ -0,0 +1,239 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Robert Hrusecky <roberth@xxxxxxxxxxxxx>
+ *          Omar Jamil <omarj2898@xxxxxxxxx>
+ *          Sachin Beldona <sachinbeldona@xxxxxxxxxx>
+ *
+ * Copyright (c) 2017, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <uk/cpio.h>
+#include <uk/essentials.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define CPIO_MAGIC_NEWC "070701"
+#define CPIO_MAGIC_CRC "070702"
+#define FILE_TYPE_MASK 0170000
+#define DIRECTORY_BITS 040000
+#define FILE_BITS 0100000
+
+#define ALIGN_4(ptr) ((void *)ALIGN_UP((uintptr_t)(ptr), 4))
+
+#define IS_FILE_OF_TYPE(mode, bits) (((mode) & (FILE_TYPE_MASK)) == (bits))
+#define IS_FILE(mode) IS_FILE_OF_TYPE((mode), (FILE_BITS))
+#define IS_DIR(mode) IS_FILE_OF_TYPE((mode), (DIRECTORY_BITS))
+
+#define GET_MODE(hdr) ((mode_t)strhex8_to_u32((hdr)->mode))
+
+struct cpio_header {
+       char magic[6];
+       char inode_num[8];
+       char mode[8];
+       char uid[8];
+       char gid[8];
+       char nlink[8];
+       char mtime[8];
+       char filesize[8];
+       char major[8];
+       char minor[8];
+       char ref_major[8];
+       char ref_minor[8];
+       char namesize[8];
+       char chksum[8];
+};
+
+static bool valid_magic(struct cpio_header *header)
+{
+       return memcmp(header->magic, CPIO_MAGIC_NEWC, 6) == 0
+              || memcmp(header->magic, CPIO_MAGIC_CRC, 6) == 0;
+}
+
+/* Function to convert len digits of hexadecimal string loc
+ * to an integer.
+ * Returns the converted unsigned integer value on success.
+ * Returns 0 on error.
+ */
+static unsigned int snhex_to_int(size_t len, char *loc)
+{
+       int val = 0;
+       size_t i;
+
+       for (i = 0; i < len; i++) {
+               val *= 16;
+               if (*(loc + i) >= '0' && *(loc + i) <= '9')
+                       val += (*(loc + i) - '0');
+               else if (*(loc + i) >= 'A' && *(loc + i) <= 'F')
+                       val += (*(loc + i) - 'A') + 10;
+               else if (*(loc + i) >= 'a' && *(loc + i) <= 'f')
+                       val += (*(loc + i) - 'a') + 10;
+               else
+                       return 0;
+       }
+       return val;
+}
+
+static uint32_t strhex8_to_u32(char *loc)
+{
+       return snhex_to_int(8, loc);
+}
+
+static inline char *filename(struct cpio_header *header)
+{
+       return (char *)header + sizeof(struct cpio_header);
+}
+
+static char *absolute_path(char *path_to_prepend, char *path)
+{
+       int dir_slash_included =
+           *(path_to_prepend + strlen(path_to_prepend) - 1) == '/' ? 1 : 2;
+       char *abs_path = (char *)malloc(strlen(path) + strlen(path_to_prepend)
+                                       + dir_slash_included);
+       if (abs_path == NULL)
+               return NULL;
+       memcpy(abs_path, path_to_prepend, strlen(path_to_prepend));
+       if (dir_slash_included == 2)
+               *(abs_path + strlen(path_to_prepend)) = '/';
+       memcpy(abs_path + strlen(path_to_prepend) + dir_slash_included - 1,
+              path, strlen(path));
+       *(abs_path + strlen(path) + strlen(path_to_prepend) + dir_slash_included
+         - 1) = '\0';
+       return abs_path;
+}
+
+static enum cpio_error read_section(struct cpio_header **header_ptr,
+                                   char *mount_loc, uintptr_t last)
+{
+       if (strcmp(filename(*header_ptr), "TRAILER!!!") == 0) {
+               *header_ptr = NULL;
+               return CPIO_SUCCESS;
+       }
+
+       if (!valid_magic(*header_ptr)) {
+               *header_ptr = NULL;
+               return -CPIO_INVALID_HEADER;
+       }
+
+       if (mount_loc == NULL) {
+               *header_ptr = NULL;
+               return -CPIO_NO_MOUNT_LOCATION;
+       }
+
+       struct cpio_header *header = *header_ptr;
+       char *path_from_root = absolute_path(mount_loc, filename(header));
+
+       if (path_from_root == NULL) {
+               *header_ptr = NULL;
+               return -CPIO_NOMEM;
+       }
+       mode_t header_mode = GET_MODE(header);
+       uint32_t header_filesize = strhex8_to_u32(header->filesize);
+       uint32_t header_namesize = strhex8_to_u32(header->namesize);
+
+       if ((uintptr_t)header + sizeof(struct cpio_header) > last) {
+               *header_ptr = NULL;
+               return -CPIO_MALFORMED_FILE;
+       }
+       if (IS_FILE(header_mode) && header_filesize != 0) {
+               uk_pr_debug("Creating file %s...\n", path_from_root);
+               int fd = open(path_from_root, O_CREAT | O_RDWR);
+
+               if (fd < 0) {
+                       *header_ptr = NULL;
+                       return -CPIO_FILE_CREATE_FAILED;
+               }
+               uk_pr_debug("File %s created\n", path_from_root);
+               char *data_location = (char *)ALIGN_4(
+                   (char *)(header) + sizeof(struct cpio_header)
+                   + header_namesize);
+
+               if ((uintptr_t)data_location + header_filesize > last) {
+                       *header_ptr = NULL;
+                       return -CPIO_MALFORMED_FILE;
+               }
+               uint32_t bytes_to_write = header_filesize;
+               int bytes_written = 0;
+
+               while (bytes_to_write > 0) {
+                       if ((bytes_written =
+                                write(fd, data_location + bytes_written,
+                                      bytes_to_write))
+                           < 0) {
+                               *header_ptr = NULL;
+                               return -CPIO_FILE_WRITE_FAILED;
+                       }
+                       bytes_to_write -= bytes_written;
+               }
+               if (chmod(path_from_root, header_mode & 0777) < 0)
+                       uk_pr_info("chmod on file %s failed\n", path_from_root);
+               if (close(fd) < 0) {
+                       *header_ptr = NULL;
+                       return -CPIO_FILE_CLOSE_FAILED;
+               }
+       } else if (IS_DIR(header_mode)) {
+               if (strcmp(".", filename(header)) != 0
+                   && mkdir(path_from_root, header_mode & 0777) < 0) {
+                       *header_ptr = NULL;
+                       return -CPIO_MKDIR_FAILED;
+               }
+       }
+       free(path_from_root);
+       struct cpio_header *next_header = (struct cpio_header *)ALIGN_4(
+           (char *)header + sizeof(struct cpio_header) + header_namesize);
+
+       next_header = (struct cpio_header *)ALIGN_4((char *)next_header
+                                                   + header_filesize);
+       *header_ptr = next_header;
+       return CPIO_SUCCESS;
+}
+
+enum cpio_error cpio_extract(char *mount_loc, void *memory_region, size_t len)
+{
+       enum cpio_error error = CPIO_SUCCESS;
+       struct cpio_header *header = (struct cpio_header *)(memory_region);
+       struct cpio_header **header_ptr = &header;
+       uintptr_t end = (uintptr_t)header;
+
+       if (mount_loc == NULL)
+               return -CPIO_NO_MOUNT_LOCATION;
+
+       while (error == CPIO_SUCCESS && header != NULL) {
+               error = read_section(header_ptr, mount_loc, end + len);
+               header = *header_ptr;
+       }
+       return error;
+}
diff --git a/lib/cpio/exportsyms.uk b/lib/cpio/exportsyms.uk
index b0047fa..090dd8d 100644
--- a/lib/cpio/exportsyms.uk
+++ b/lib/cpio/exportsyms.uk
@@ -1 +1 @@
-None
+cpio_extract
diff --git a/lib/cpio/include/uk/cpio.h b/lib/cpio/include/uk/cpio.h
index e69de29..86bc002 100644
--- a/lib/cpio/include/uk/cpio.h
+++ b/lib/cpio/include/uk/cpio.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: BSD-3-Clause */
+/*
+ * Authors: Robert Hrusecky <roberth@xxxxxxxxxxxxx>
+ *          Omar Jamil <omarj2898@xxxxxxxxx>
+ *          Sachin Beldona <sachinbeldona@xxxxxxxxxx>
+ *
+ * Copyright (c) 2017, NEC Europe Ltd., NEC Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the copyright holder nor the names of its
+ *    contributors may be used to endorse or promote products derived from
+ *    this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ *
+ * THIS HEADER MAY NOT BE EXTRACTED OR MODIFIED IN ANY WAY.
+ */
+
+#ifndef __CPIO_H__
+#define __CPIO_H__
+#include <uk/plat/memory.h>
+
+enum cpio_error {
+       CPIO_SUCCESS = 0,
+       CPIO_INVALID_HEADER,
+       CPIO_FILE_CREATE_FAILED,
+       CPIO_FILE_WRITE_FAILED,
+       CPIO_FILE_CHMOD_FAILED,
+       CPIO_FILE_CLOSE_FAILED,
+       CPIO_MKDIR_FAILED,
+       CPIO_MOUNT_FAILED,
+       CPIO_NO_MEMREGION,
+       CPIO_MALFORMED_FILE,
+       CPIO_NOMEM,
+       CPIO_NO_MOUNT_LOCATION
+};
+
+enum cpio_error cpio_extract(char *loc, void *mem, size_t len);
+#endif /*__CPIO_H__*/
-- 
2.24.0


_______________________________________________
Minios-devel mailing list
Minios-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/minios-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.