summaryrefslogtreecommitdiffhomepage
path: root/src/meta/tpax_init_cpio_header.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/meta/tpax_init_cpio_header.c')
-rw-r--r--src/meta/tpax_init_cpio_header.c145
1 files changed, 145 insertions, 0 deletions
diff --git a/src/meta/tpax_init_cpio_header.c b/src/meta/tpax_init_cpio_header.c
new file mode 100644
index 0000000..3de22f6
--- /dev/null
+++ b/src/meta/tpax_init_cpio_header.c
@@ -0,0 +1,145 @@
+/**************************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/**************************************************************/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/stat.h>
+
+#include <tpax/tpax.h>
+#include <tpax/tpax_specs.h>
+#include "tpax_driver_impl.h"
+
+#ifndef ssizeof
+#define ssizeof(x) (ssize_t)(sizeof(x))
+#endif
+
+#define TPAX_CPIO_PERM_MASK \
+ ( S_ISUID | S_ISGID \
+ | S_IRUSR | S_IWUSR | S_IXUSR \
+ | S_IRGRP | S_IWGRP | S_IXGRP \
+ | S_IROTH | S_IWOTH | S_IXOTH )
+
+static void tpax_octal_write(char * ch, ssize_t len, uint64_t val)
+{
+ for (; len; ) {
+ ch[--len] = val % 8 + '0';
+ val /= 8;
+ }
+}
+
+int tpax_meta_init_cpio_header(
+ const char * path,
+ const struct stat * st,
+ const char * linkname,
+ int cdev,
+ int cino,
+ int cnlink,
+ struct tpax_cpio_header * chdr)
+{
+ size_t fnsize;
+ size_t lnklen;
+ size_t stsize;
+ int64_t stmtim;
+ uint32_t typeflag;
+ uint32_t permbits;
+ uint32_t modebits;
+
+ /* filename size */
+ fnsize = strlen(path) + 1;
+
+ /* size & mtime validation */
+ stsize = S_ISREG(st->st_mode) ? st->st_size : 0;
+ stmtim = st->st_mtim.tv_sec;
+
+ if (stsize > 077777777777)
+ return -1;
+
+ if ((stmtim < 0) || (stmtim > 077777777777))
+ return -1;
+
+ /* linkname validation */
+ if (S_ISLNK(st->st_mode) && !linkname)
+ return -1;
+
+ lnklen = S_ISLNK(st->st_mode)
+ ? strlen(linkname)
+ : 0;
+
+ /* typeflag validation */
+ if (S_ISREG(st->st_mode))
+ typeflag = TPAX_CPIO_FILEMODE_ISREG;
+ else if (S_ISLNK(st->st_mode))
+ typeflag = TPAX_CPIO_FILEMODE_ISLNK;
+ else if (S_ISDIR(st->st_mode))
+ typeflag = TPAX_CPIO_FILEMODE_ISDIR;
+ else if (S_ISCHR(st->st_mode))
+ typeflag = TPAX_CPIO_FILEMODE_ISCHR;
+ else if (S_ISBLK(st->st_mode))
+ typeflag = TPAX_CPIO_FILEMODE_ISBLK;
+ else if (S_ISFIFO(st->st_mode))
+ typeflag = TPAX_CPIO_FILEMODE_ISFIFO;
+ else if (S_ISSOCK(st->st_mode))
+ typeflag = TPAX_CPIO_FILEMODE_ISSOCK;
+ else
+ return -1;
+
+ /* permbits, modeflag */
+ permbits = st->st_mode & TPAX_CPIO_PERM_MASK;
+ modebits = permbits | typeflag;
+
+ /* one shot */
+ memset(chdr,0,sizeof(*chdr));
+
+ /* c_magic */
+ chdr->c_magic[0] = '0';
+ chdr->c_magic[1] = '7';
+ chdr->c_magic[2] = '0';
+ chdr->c_magic[3] = '7';
+ chdr->c_magic[4] = '0';
+ chdr->c_magic[5] = '7';
+
+ /* c_dev, c_ino */
+ tpax_octal_write(chdr->c_dev,ssizeof(chdr->c_dev),cdev);
+ tpax_octal_write(chdr->c_ino,ssizeof(chdr->c_ino),cino);
+
+ /* c_mode */
+ tpax_octal_write(chdr->c_mode,ssizeof(chdr->c_mode),modebits);
+
+ /* c_uid, c_gid */
+ if ((uint64_t)st->st_uid <= 0777777)
+ tpax_octal_write(chdr->c_uid,ssizeof(chdr->c_uid),st->st_uid);
+ else
+ tpax_octal_write(chdr->c_uid,ssizeof(chdr->c_uid),0);
+
+ if ((uint64_t)st->st_gid <= 0777777)
+ tpax_octal_write(chdr->c_gid,ssizeof(chdr->c_gid),st->st_gid);
+ else
+ tpax_octal_write(chdr->c_gid,ssizeof(chdr->c_gid),0);
+
+ /* c_nlink */
+ tpax_octal_write(chdr->c_nlink,ssizeof(chdr->c_nlink),cnlink);
+
+ /* c_rdev */
+ tpax_octal_write(chdr->c_rdev,ssizeof(chdr->c_rdev),st->st_rdev);
+
+ /* c_mtime */
+ tpax_octal_write(chdr->c_mtime,ssizeof(chdr->c_mtime),stmtim);
+
+ /* c_namesize */
+ tpax_octal_write(chdr->c_namesize,ssizeof(chdr->c_namesize),fnsize);
+
+ /* c_filesize */
+ tpax_octal_write(chdr->c_filesize,ssizeof(chdr->c_filesize),lnklen ? lnklen : stsize);
+
+ /* all done; c_name to be written along with c_filedata */
+ return 0;
+}