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

[Minios-devel,v2,2/5] lib/cpio: Add CPIO extraction functionality



From: Robert Hrusecky <roberth@xxxxxxxxxxxxx>

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>
Signed-off-by: Gabriel Mocanu <gabi.mocanu98@xxxxxxxxx>
---
 lib/cpio/Makefile.uk         |   7 -
 lib/cpio/cpio.c              |   0
 lib/cpio/exportsyms.uk       |   1 -
 lib/cpio/include/uk/cpio.h   |   0
 lib/ukcpio/Config.uk         |   4 +
 lib/ukcpio/Makefile.uk       |   7 +
 lib/ukcpio/cpio.c            | 277 +++++++++++++++++++++++++++++++++++
 lib/ukcpio/exportsyms.uk     |   1 +
 lib/ukcpio/include/uk/cpio.h |  68 +++++++++
 9 files changed, 357 insertions(+), 8 deletions(-)
 delete mode 100644 lib/cpio/Makefile.uk
 delete mode 100644 lib/cpio/cpio.c
 delete mode 100644 lib/cpio/exportsyms.uk
 delete mode 100644 lib/cpio/include/uk/cpio.h
 create mode 100644 lib/ukcpio/Config.uk
 create mode 100644 lib/ukcpio/Makefile.uk
 create mode 100644 lib/ukcpio/cpio.c
 create mode 100644 lib/ukcpio/exportsyms.uk
 create mode 100644 lib/ukcpio/include/uk/cpio.h

diff --git a/lib/cpio/Makefile.uk b/lib/cpio/Makefile.uk
deleted file mode 100644
index c3411bf..0000000
--- a/lib/cpio/Makefile.uk
+++ /dev/null
@@ -1,7 +0,0 @@
-$(eval $(call addlib_s,libcpio,$(CONFIG_LIBCPIO)))
-
-# LIBCPIO_CFLAGS-$(call gcc_version_ge,8,0) += -Wno-cast-function-type
-
-CINCLUDES-$(CONFIG_LIBCPIO) += -I$(LIBCPIO_BASE)/include
-CXXINCLUDES-$(CONFIG_LIBCPIO) += -I$(LIBCPIO_BASE)/include
-LIBCPIO_SRCS-y += $(LIBCPIO_BASE)/cpio.c
diff --git a/lib/cpio/cpio.c b/lib/cpio/cpio.c
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/cpio/exportsyms.uk b/lib/cpio/exportsyms.uk
deleted file mode 100644
index b0047fa..0000000
--- a/lib/cpio/exportsyms.uk
+++ /dev/null
@@ -1 +0,0 @@
-None
diff --git a/lib/cpio/include/uk/cpio.h b/lib/cpio/include/uk/cpio.h
deleted file mode 100644
index e69de29..0000000
diff --git a/lib/ukcpio/Config.uk b/lib/ukcpio/Config.uk
new file mode 100644
index 0000000..5c412db
--- /dev/null
+++ b/lib/ukcpio/Config.uk
@@ -0,0 +1,4 @@
+config LIBUKCPIO
+  bool "ukcpio: CPIO archive extraction"
+  depends on LIBVFSCORE
+  default n
diff --git a/lib/ukcpio/Makefile.uk b/lib/ukcpio/Makefile.uk
new file mode 100644
index 0000000..b601e96
--- /dev/null
+++ b/lib/ukcpio/Makefile.uk
@@ -0,0 +1,7 @@
+$(eval $(call addlib_s,libukcpio,$(CONFIG_LIBUKCPIO)))
+
+# LIBUKCPIO_CFLAGS-$(call gcc_version_ge,8,0) += -Wno-cast-function-type
+
+CINCLUDES-$(CONFIG_LIBUKCPIO) += -I$(LIBUKCPIO_BASE)/include
+CXXINCLUDES-$(CONFIG_LIBUKCPIO) += -I$(LIBUKCPIO_BASE)/include
+LIBUKCPIO_SRCS-y += $(LIBUKCPIO_BASE)/cpio.c
diff --git a/lib/ukcpio/cpio.c b/lib/ukcpio/cpio.c
new file mode 100644
index 0000000..1b7386e
--- /dev/null
+++ b/lib/ukcpio/cpio.c
@@ -0,0 +1,277 @@
+/* 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.
+ *
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <uk/assert.h>
+#include <uk/print.h>
+#include <uk/cpio.h>
+#include <uk/essentials.h>
+#include <sys/mount.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#define UKCPIO_MAGIC_NEWC "070701"
+#define UKCPIO_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 s8hex_to_u32(buf) ((uint32_t) snhex_to_int((buf), 8))
+#define GET_MODE(hdr) ((mode_t)s8hex_to_u32((hdr)->mode))
+
+#define filename(header) ((const char *)header + sizeof(struct cpio_header))
+
+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 int valid_magic(struct cpio_header *header)
+{
+       return memcmp(header->magic, UKCPIO_MAGIC_NEWC, 6) == 0
+              || memcmp(header->magic, UKCPIO_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(const char *buf, size_t count)
+{
+       unsigned int val = 0;
+       size_t i;
+
+  UK_ASSERT(buf);
+
+       for (i = 0; i < count; i++) {
+               val *= 16;
+               if (buf[i] >= '0' && buf[i] <= '9')
+                       val += (buf[i] - '0');
+               else if (buf[i] >= 'A' && buf[i] <= 'F')
+                       val += (buf[i] - 'A') + 10;
+               else if (buf[i] >= 'a' && buf[i] <= 'f')
+                       val += (buf[i] - 'a') + 10;
+               else
+                       return 0;
+       }
+       return val;
+}
+
+static char *absolute_path(const char *prefix,const char *path)
+{
+  int add_slash;
+  size_t prefix_len;
+  size_t path_len;
+  size_t abs_path_len;
+  char *abs_path;
+
+  UK_ASSERT(prefix);
+  UK_ASSERT(path);
+
+  prefix_len = strlen(prefix);
+  path_len = strlen(path);
+
+  add_slash = prefix[prefix_len - 1] == '/' ? 0 : 1;
+  abs_path_len = prefix_len + add_slash + path_len + 1;
+
+  abs_path = malloc(abs_path_len);
+
+       if (abs_path == NULL)
+               return NULL;
+
+       memcpy(abs_path, prefix, prefix_len);
+       if (add_slash)
+               abs_path[prefix_len] = '/';
+  memcpy(&abs_path[prefix_len + add_slash], path, path_len);
+
+  abs_path[abs_path_len - 1] = '\0';
+       return abs_path;
+}
+
+static enum ukcpio_error read_section(struct cpio_header **header_ptr,
+                                   const char *dest, uintptr_t last)
+{
+
+  enum ukcpio_error error = UKCPIO_SUCCESS;
+  int fd;
+  struct cpio_header *header;
+  char *path_from_root;
+  mode_t header_mode;
+  uint32_t header_filesize;
+  uint32_t header_namesize;
+  char *data_location;
+  uint32_t bytes_to_write;
+  int bytes_written;
+  struct cpio_header *next_header;
+
+  if (strcmp(filename(*header_ptr), "TRAILER!!!") == 0) {
+               *header_ptr = NULL;
+               return UKCPIO_SUCCESS;
+       }
+
+       if (!valid_magic(*header_ptr)) {
+               *header_ptr = NULL;
+               return -UKCPIO_INVALID_HEADER;
+       }
+
+  UK_ASSERT(dest);
+
+       header = *header_ptr;
+       path_from_root = absolute_path(dest, filename(header));
+
+       if (path_from_root == NULL) {
+               *header_ptr = NULL;
+               error = -UKCPIO_NOMEM;
+    goto out;
+       }
+
+       header_mode = GET_MODE(header);
+       header_filesize = s8hex_to_u32(header->filesize);
+       header_namesize = s8hex_to_u32(header->namesize);
+
+       if ((uintptr_t)header + sizeof(struct cpio_header) > last) {
+               *header_ptr = NULL;
+    error = -UKCPIO_MALFORMED_FILE;
+    goto out;
+       }
+
+       if (IS_FILE(header_mode) && header_filesize != 0) {
+               uk_pr_info("Extracting %s...\n", path_from_root);
+               fd = open(path_from_root, O_CREAT | O_RDWR);
+
+               if (fd < 0) {
+                       *header_ptr = NULL;
+                       error = -UKCPIO_FILE_CREATE_FAILED;
+      goto out;
+               }
+
+               data_location = (char *)ALIGN_4(
+                   (char *)(header) + sizeof(struct cpio_header)
+                   + header_namesize);
+
+               if ((uintptr_t)data_location + header_filesize > last) {
+                       *header_ptr = NULL;
+                       error = -UKCPIO_MALFORMED_FILE;
+      goto out;
+               }
+
+               bytes_to_write = header_filesize;
+               bytes_written = 0;
+
+               while (bytes_to_write > 0) {
+                       if ((bytes_written =
+                                write(fd, data_location + bytes_written,
+                                      bytes_to_write))
+                           < 0) {
+                               *header_ptr = NULL;
+                               error = -UKCPIO_FILE_WRITE_FAILED;
+        goto out;
+                       }
+                       bytes_to_write -= bytes_written;
+               }
+
+               if (chmod(path_from_root, header_mode & 0777) < 0)
+                       uk_pr_err("Failed to chmod %s\n", path_from_root);
+
+               if (close(fd) < 0) {
+                       *header_ptr = NULL;
+                       error = -UKCPIO_FILE_CLOSE_FAILED;
+      goto out;
+               }
+       } else if (IS_DIR(header_mode)) {
+               uk_pr_info("Extracting %s...\n", path_from_root);
+               if (strcmp(".", filename(header)) != 0
+                   && mkdir(path_from_root, header_mode & 0777) < 0) {
+                       *header_ptr = NULL;
+                       error = -UKCPIO_MKDIR_FAILED;
+      goto out;
+               }
+       }
+
+  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;
+       
+  out:
+    free(path_from_root);
+    return error;
+}
+
+enum ukcpio_error ukcpio_extract(const char *dest, void *buf, size_t buflen)
+{
+       enum ukcpio_error error = UKCPIO_SUCCESS;
+       struct cpio_header *header = (struct cpio_header *)(buf);
+       struct cpio_header **header_ptr = &header;
+       uintptr_t end = (uintptr_t)header;
+
+       if (dest == NULL)
+               return -UKCPIO_NODEST;
+
+       while (!error && header) {
+               error = read_section(header_ptr, dest, end + buflen);
+               header = *header_ptr;
+       }
+
+       return error;
+}
diff --git a/lib/ukcpio/exportsyms.uk b/lib/ukcpio/exportsyms.uk
new file mode 100644
index 0000000..c25c393
--- /dev/null
+++ b/lib/ukcpio/exportsyms.uk
@@ -0,0 +1 @@
+ukcpio_extract
diff --git a/lib/ukcpio/include/uk/cpio.h b/lib/ukcpio/include/uk/cpio.h
new file mode 100644
index 0000000..41ac05e
--- /dev/null
+++ b/lib/ukcpio/include/uk/cpio.h
@@ -0,0 +1,68 @@
+/* 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.
+ *
+ */
+
+#ifndef __UK_CPIO_H__
+#define __UK_CPIO_H__
+
+#ifdef __cplusplus
+extern C {
+#endif /* __cplusplus */
+
+
+/**
+ * Include also the case of unsupported headers
+ */
+
+enum ukcpio_error {
+       UKCPIO_SUCCESS = 0,
+       UKCPIO_INVALID_HEADER,
+       UKCPIO_FILE_CREATE_FAILED,
+       UKCPIO_FILE_WRITE_FAILED,
+       UKCPIO_FILE_CHMOD_FAILED,
+       UKCPIO_FILE_CLOSE_FAILED,
+       UKCPIO_MKDIR_FAILED,
+       UKCPIO_MALFORMED_FILE,
+       UKCPIO_NOMEM,
+       UKCPIO_NODEST,
+  UKCPIO_MOUNT_FAILED
+};
+
+enum ukcpio_error ukcpio_extract(const char *dest, void *buf, size_t buflen);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /*__CPIO_H__*/
-- 
2.17.1




 


Rackspace

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