diff options
Diffstat (limited to 'src/meta/tpax_init_cpio_header.c')
-rw-r--r-- | src/meta/tpax_init_cpio_header.c | 145 |
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; +} |