|
|
7a9a40 |
/******************************************************/
|
|
|
7a9a40 |
/* tpax: a topological pax implementation */
|
|
|
7a9a40 |
/* Copyright (C) 2020 Z. Gilboa */
|
|
|
7a9a40 |
/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
|
|
|
7a9a40 |
/******************************************************/
|
|
|
7a9a40 |
|
|
|
7a9a40 |
#include <stdint.h>
|
|
|
7a9a40 |
#include <stdlib.h>
|
|
|
7a9a40 |
#include <string.h>
|
|
|
7a9a40 |
#include <unistd.h>
|
|
|
7a9a40 |
#include <fcntl.h>
|
|
|
7a9a40 |
#include <errno.h>
|
|
|
7a9a40 |
#include <grp.h>
|
|
|
7a9a40 |
#include <pwd.h>
|
|
|
7a9a40 |
#include <sys/stat.h>
|
|
|
7a9a40 |
|
|
|
7a9a40 |
#include <tpax/tpax.h>
|
|
|
7a9a40 |
#include <tpax/tpax_specs.h>
|
|
|
7a9a40 |
#include "tpax_driver_impl.h"
|
|
|
7a9a40 |
|
|
|
7a9a40 |
#ifndef ssizeof
|
|
|
7a9a40 |
#define ssizeof(x) (ssize_t)(sizeof(x))
|
|
|
7a9a40 |
#endif
|
|
|
7a9a40 |
|
|
|
7a9a40 |
static void tpax_octal_write(char * ch, ssize_t len, uint64_t val)
|
|
|
7a9a40 |
{
|
|
|
7a9a40 |
for (--len,--len; len>=0 ; len--) {
|
|
|
7a9a40 |
ch[len] = val % 8 + '0';
|
|
|
7a9a40 |
val /= 8;
|
|
|
7a9a40 |
}
|
|
|
7a9a40 |
}
|
|
|
7a9a40 |
|
|
|
7a9a40 |
int tpax_init_ustar_header(
|
|
|
7a9a40 |
const struct tpax_driver_ctx * dctx,
|
|
|
7a9a40 |
const char * path,
|
|
|
7a9a40 |
const struct stat * st,
|
|
|
7a9a40 |
const char * linkname,
|
|
|
7a9a40 |
struct tpax_ustar_header * uhdr)
|
|
|
7a9a40 |
{
|
|
|
7a9a40 |
size_t len;
|
|
|
7a9a40 |
const char * cap;
|
|
|
7a9a40 |
const char * mark;
|
|
|
7a9a40 |
unsigned char * uch;
|
|
|
7a9a40 |
unsigned char * uchcap;
|
|
|
7a9a40 |
size_t lnklen;
|
|
|
7a9a40 |
size_t stsize;
|
|
|
7a9a40 |
int64_t stmtim;
|
|
|
7a9a40 |
uint32_t chksum;
|
|
|
7a9a40 |
char typeflag;
|
|
|
7a9a40 |
struct group grp;
|
|
|
7a9a40 |
struct group * grpres;
|
|
|
7a9a40 |
struct passwd pwd;
|
|
|
7a9a40 |
struct passwd * pwdres;
|
|
|
7a9a40 |
char pwdbuf[2048];
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* size & mtime validation */
|
|
|
7a9a40 |
stsize = S_ISREG(st->st_mode) ? st->st_size : 0;
|
|
|
7a9a40 |
stmtim = st->st_mtim.tv_sec;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
if (stsize > 077777777777)
|
|
|
7a9a40 |
return -1;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
if ((stmtim < 0) || (stmtim > 077777777777))
|
|
|
7a9a40 |
return -1;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* linkname validation */
|
|
|
7a9a40 |
if (S_ISLNK(st->st_mode) && !linkname)
|
|
|
7a9a40 |
return -1;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
lnklen = S_ISLNK(st->st_mode)
|
|
|
7a9a40 |
? strnlen(linkname,sizeof(uhdr->u_linkname) + 1)
|
|
|
7a9a40 |
: 0;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
if (lnklen > sizeof(uhdr->u_linkname))
|
|
|
7a9a40 |
return -1;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* typeflag validation */
|
|
|
7a9a40 |
if (S_ISREG(st->st_mode))
|
|
|
7a9a40 |
typeflag = TPAX_USTAR_TYPEFLAG_REGFILE;
|
|
|
7a9a40 |
else if (S_ISLNK(st->st_mode))
|
|
|
7a9a40 |
typeflag = TPAX_USTAR_TYPEFLAG_SYMLINK;
|
|
|
7a9a40 |
else if (S_ISCHR(st->st_mode))
|
|
|
7a9a40 |
typeflag = TPAX_USTAR_TYPEFLAG_CHARDEV;
|
|
|
7a9a40 |
else if (S_ISBLK(st->st_mode))
|
|
|
7a9a40 |
typeflag = TPAX_USTAR_TYPEFLAG_BLKDEV;
|
|
|
7a9a40 |
else if (S_ISFIFO(st->st_mode))
|
|
|
7a9a40 |
typeflag = TPAX_USTAR_TYPEFLAG_FIFODEV;
|
|
|
7a9a40 |
else
|
|
|
7a9a40 |
return -1;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* cap (without the trailing slash) */
|
|
|
7a9a40 |
mark = &path[strlen(path)];
|
|
|
7a9a40 |
cap = mark;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
for (--cap; (*cap == '/') && (cap > path); cap--)
|
|
|
7a9a40 |
(void)0;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
cap = ((cap == path) && (path[0] == '/'))
|
|
|
7a9a40 |
? mark : &cap[1];
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* path solely consists of slash symbols? */
|
|
|
7a9a40 |
if ((cap == mark) && (path[0] =='/')) {
|
|
|
7a9a40 |
if ((cap - path) > (ssizeof(uhdr->u_prefix) + 1 + ssizeof(uhdr->u_name)))
|
|
|
7a9a40 |
return -1;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
else if ((cap - path) <= ssizeof(uhdr->u_name))
|
|
|
7a9a40 |
mark = 0;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
else
|
|
|
7a9a40 |
mark -= sizeof(uhdr->u_name);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* path entirely fits in u_name? */
|
|
|
7a9a40 |
} else if ((cap - path) <= ssizeof(uhdr->u_name)) {
|
|
|
7a9a40 |
mark = 0;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* split between u_prefix and u_name as needed */
|
|
|
7a9a40 |
} else {
|
|
|
7a9a40 |
mark = cap;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
do {
|
|
|
7a9a40 |
for (--mark; (mark > path) && (*mark != '/'); mark--)
|
|
|
7a9a40 |
(void)0;
|
|
|
7a9a40 |
} while ((mark - path) > ssizeof(uhdr->u_prefix));
|
|
|
7a9a40 |
}
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* one shot */
|
|
|
7a9a40 |
memset(uhdr,0,sizeof(*uhdr));
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_name, u_prefix */
|
|
|
7a9a40 |
if (mark) {
|
|
|
7a9a40 |
memcpy(uhdr->u_prefix,path,mark-path);
|
|
|
7a9a40 |
memcpy(uhdr->u_name,&mark[1],cap - mark);
|
|
|
7a9a40 |
} else {
|
|
|
7a9a40 |
memcpy(uhdr->u_name,path,cap - path);
|
|
|
7a9a40 |
}
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_mode */
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_mode,ssizeof(uhdr->u_mode),st->st_mode & TPAX_USTAR_MODE_MASK);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_uid, u_gid, u_uname, u_gname */
|
|
|
7a9a40 |
if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_RUSTAR) {
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_uid,ssizeof(uhdr->u_uid),0);
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_gid,ssizeof(uhdr->u_gid),0);
|
|
|
7a9a40 |
} else {
|
|
|
7a9a40 |
if ((uint64_t)st->st_uid <= 07777777)
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_uid,ssizeof(uhdr->u_uid),st->st_uid);
|
|
|
7a9a40 |
else
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_uid,ssizeof(uhdr->u_uid),0);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
if ((uint64_t)st->st_gid <= 07777777)
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_gid,ssizeof(uhdr->u_gid),st->st_gid);
|
|
|
7a9a40 |
else
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_gid,ssizeof(uhdr->u_gid),0);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
pwdres = 0;
|
|
|
7a9a40 |
grpres = 0;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
getpwuid_r(
|
|
|
7a9a40 |
st->st_uid,&pwd,
|
|
|
7a9a40 |
pwdbuf,sizeof(pwdbuf),
|
|
|
7a9a40 |
&pwdres);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
if (pwdres && pwd.pw_name)
|
|
|
7a9a40 |
if ((len = strlen(pwd.pw_name)) < sizeof(uhdr->u_uname))
|
|
|
7a9a40 |
memcpy(uhdr->u_uname,pwd.pw_name,len);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
getgrgid_r(
|
|
|
7a9a40 |
st->st_gid,&grp,
|
|
|
7a9a40 |
pwdbuf,sizeof(pwdbuf),
|
|
|
7a9a40 |
&grpres);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
if (grpres && grp.gr_name)
|
|
|
7a9a40 |
if ((len = strlen(grp.gr_name)) < sizeof(uhdr->u_gname))
|
|
|
7a9a40 |
memcpy(uhdr->u_gname,grp.gr_name,len);
|
|
|
7a9a40 |
}
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_size, u_mtime */
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_size,ssizeof(uhdr->u_size),stsize);
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_mtime,ssizeof(uhdr->u_mtime),stmtim);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_typeflag */
|
|
|
7a9a40 |
uhdr->u_typeflag[0] = typeflag;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_linkname */
|
|
|
7a9a40 |
if (lnklen)
|
|
|
7a9a40 |
memcpy(uhdr->u_linkname,linkname,lnklen);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_magic */
|
|
|
7a9a40 |
uhdr->u_magic[0] = 'u';
|
|
|
7a9a40 |
uhdr->u_magic[1] = 's';
|
|
|
7a9a40 |
uhdr->u_magic[2] = 't';
|
|
|
7a9a40 |
uhdr->u_magic[3] = 'a';
|
|
|
7a9a40 |
uhdr->u_magic[4] = 'r';
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_version */
|
|
|
7a9a40 |
uhdr->u_version[0] = '0';
|
|
|
7a9a40 |
uhdr->u_version[1] = '0';
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_devmajor, u_devminor */
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_devmajor,ssizeof(uhdr->u_devmajor),0);
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_devminor,ssizeof(uhdr->u_devminor),0);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* u_chksum */
|
|
|
7a9a40 |
uch = (unsigned char *)uhdr->u_name;
|
|
|
7a9a40 |
uchcap = (unsigned char *)uhdr->u_pad;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
for (chksum=0; uch
|
|
|
7a9a40 |
chksum += *uch;
|
|
|
7a9a40 |
|
|
|
7a9a40 |
chksum += sizeof(uhdr->u_chksum) * ' ';
|
|
|
7a9a40 |
|
|
|
7a9a40 |
tpax_octal_write(uhdr->u_chksum,ssizeof(uhdr->u_chksum),chksum);
|
|
|
7a9a40 |
|
|
|
7a9a40 |
/* all done; caller may now change REGFILE to HARDLINK */
|
|
|
7a9a40 |
return 0;
|
|
|
7a9a40 |
}
|