/**************************************************************/ /* tpax: a topological pax implementation */ /* Copyright (C) 2020--2024 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ /**************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #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; }