|
|
5874a9 |
/**************************************************************/
|
|
|
5874a9 |
/* tpax: a topological pax implementation */
|
|
|
bef28d |
/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
|
|
|
5874a9 |
/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
|
|
|
5874a9 |
/**************************************************************/
|
|
|
3db888 |
|
|
|
3db888 |
#include <stdint.h>
|
|
|
3db888 |
#include <stdlib.h>
|
|
|
3db888 |
#include <string.h>
|
|
|
3db888 |
#include <unistd.h>
|
|
|
3db888 |
#include <fcntl.h>
|
|
|
3db888 |
#include <errno.h>
|
|
|
3db888 |
#include <grp.h>
|
|
|
3db888 |
#include <pwd.h>
|
|
|
022508 |
#include <sys/mman.h>
|
|
|
3db888 |
#include <sys/stat.h>
|
|
|
3db888 |
|
|
|
3db888 |
#include <tpax/tpax.h>
|
|
|
3db888 |
#include <tpax/tpax_specs.h>
|
|
|
3db888 |
#include "tpax_driver_impl.h"
|
|
|
022508 |
#include "tpax_getdents_impl.h"
|
|
|
e50240 |
#include "tpax_readlink_impl.h"
|
|
|
3db888 |
#include "tpax_tmpfile_impl.h"
|
|
|
3db888 |
#include "tpax_errinfo_impl.h"
|
|
|
3db888 |
|
|
|
43c39b |
static char * tpax_add_prefix_item(
|
|
|
9f55a1 |
const struct tpax_driver_ctx * dctx,
|
|
|
9f55a1 |
const char * prefix)
|
|
|
9f55a1 |
{
|
|
|
9f55a1 |
struct tpax_driver_ctx_impl * ictx;
|
|
|
9f55a1 |
char ** prefv;
|
|
|
9f55a1 |
char ** psrc;
|
|
|
9f55a1 |
char ** pdst;
|
|
|
9f55a1 |
off_t elements;
|
|
|
9f55a1 |
char * pitem;
|
|
|
9f55a1 |
|
|
|
9f55a1 |
ictx = tpax_get_driver_ictx(dctx);
|
|
|
9f55a1 |
|
|
|
9f55a1 |
for (psrc=ictx->prefixv; *psrc; psrc++)
|
|
|
9f55a1 |
if (!strcmp(*psrc,prefix))
|
|
|
9f55a1 |
return *psrc;
|
|
|
9f55a1 |
|
|
|
9f55a1 |
if (ictx->prefixp == ictx->prefcap) {
|
|
|
9f55a1 |
elements = ictx->prefcap - ictx->prefixv;
|
|
|
9f55a1 |
elements += 256;
|
|
|
9f55a1 |
|
|
|
9f55a1 |
if (!(prefv = calloc(elements,sizeof(char *))))
|
|
|
9f55a1 |
return 0;
|
|
|
9f55a1 |
|
|
|
9f55a1 |
for (psrc=ictx->prefixv,pdst=prefv; *psrc; psrc++,pdst++)
|
|
|
9f55a1 |
*pdst = *psrc;
|
|
|
9f55a1 |
|
|
|
9f55a1 |
if (ictx->prefixv != ictx->prefptr)
|
|
|
9f55a1 |
free(ictx->prefixv);
|
|
|
9f55a1 |
|
|
|
9f55a1 |
ictx->prefixv = prefv;
|
|
|
9f55a1 |
ictx->prefixp = pdst;
|
|
|
9f55a1 |
ictx->prefcap = &prefv[--elements];
|
|
|
9f55a1 |
}
|
|
|
9f55a1 |
|
|
|
9f55a1 |
if (!(pitem = strdup(prefix)))
|
|
|
9f55a1 |
return 0;
|
|
|
9f55a1 |
|
|
|
9f55a1 |
*ictx->prefixp++ = pitem;
|
|
|
9f55a1 |
|
|
|
9f55a1 |
return pitem;
|
|
|
9f55a1 |
}
|
|
|
9f55a1 |
|
|
|
43c39b |
static char * tpax_add_prefix_item_from_path(
|
|
|
76f93a |
const struct tpax_driver_ctx * dctx,
|
|
|
76f93a |
const char * path,
|
|
|
76f93a |
const char * mark)
|
|
|
76f93a |
{
|
|
|
76f93a |
off_t nbytes;
|
|
|
76f93a |
char pathbuf[PATH_MAX];
|
|
|
76f93a |
|
|
|
76f93a |
if ((nbytes = (mark - path)) >= (PATH_MAX - 1))
|
|
|
76f93a |
return 0;
|
|
|
76f93a |
|
|
|
76f93a |
memcpy(pathbuf,path,nbytes);
|
|
|
76f93a |
pathbuf[nbytes++] = '/';
|
|
|
76f93a |
pathbuf[nbytes] = '\0';
|
|
|
76f93a |
|
|
|
43c39b |
return tpax_add_prefix_item(dctx,pathbuf);
|
|
|
76f93a |
}
|
|
|
76f93a |
|
|
|
b56498 |
static int tpax_dirent_init_from_stat(
|
|
|
8034d0 |
const struct stat * st,
|
|
|
8034d0 |
const char * basename,
|
|
|
8034d0 |
struct dirent * dirent)
|
|
|
8034d0 |
{
|
|
|
8034d0 |
/* st_mode to d_type translation */
|
|
|
8034d0 |
if (S_ISREG(st->st_mode))
|
|
|
8034d0 |
dirent->d_type = DT_REG;
|
|
|
8034d0 |
else if (S_ISLNK(st->st_mode))
|
|
|
8034d0 |
dirent->d_type = DT_LNK;
|
|
|
8034d0 |
else if (S_ISDIR(st->st_mode))
|
|
|
8034d0 |
dirent->d_type = DT_DIR;
|
|
|
8034d0 |
else if (S_ISCHR(st->st_mode))
|
|
|
8034d0 |
dirent->d_type = DT_CHR;
|
|
|
8034d0 |
else if (S_ISBLK(st->st_mode))
|
|
|
8034d0 |
dirent->d_type = DT_CHR;
|
|
|
8034d0 |
else if (S_ISFIFO(st->st_mode))
|
|
|
8034d0 |
dirent->d_type = DT_CHR;
|
|
|
8034d0 |
else
|
|
|
8034d0 |
return -1;
|
|
|
8034d0 |
|
|
|
8034d0 |
/* d_off, d_ino */
|
|
|
8034d0 |
dirent->d_off = 0;
|
|
|
8034d0 |
dirent->d_ino = st->st_ino;
|
|
|
8034d0 |
|
|
|
8034d0 |
/* d_reclen */
|
|
|
8034d0 |
dirent->d_reclen = offsetof(struct dirent,d_name);
|
|
|
8034d0 |
dirent->d_reclen += strlen(basename) + 1;
|
|
|
8034d0 |
|
|
|
8034d0 |
dirent->d_reclen += 0x1;
|
|
|
8034d0 |
dirent->d_reclen |= 0x1;
|
|
|
8034d0 |
dirent->d_reclen ^= 0x1;
|
|
|
8034d0 |
|
|
|
8034d0 |
/* d_name */
|
|
|
8034d0 |
strcpy(dirent->d_name,basename);
|
|
|
8034d0 |
|
|
|
8034d0 |
return 0;
|
|
|
8034d0 |
}
|
|
|
8034d0 |
|
|
|
022508 |
static struct tpax_dirent_buffer * tpax_dirent_buf_first_alloc(
|
|
|
022508 |
const struct tpax_driver_ctx * dctx)
|
|
|
022508 |
{
|
|
|
022508 |
void * addr;
|
|
|
022508 |
struct tpax_driver_ctx_impl * ictx;
|
|
|
022508 |
|
|
|
022508 |
addr = (struct tpax_dirent_buffer *)mmap(
|
|
|
022508 |
0,TPAX_DIRENT_BUFLEN,
|
|
|
022508 |
PROT_READ|PROT_WRITE,
|
|
|
022508 |
MAP_PRIVATE|MAP_ANONYMOUS,
|
|
|
022508 |
-1,0);
|
|
|
022508 |
|
|
|
022508 |
if (addr == MAP_FAILED)
|
|
|
022508 |
return 0;
|
|
|
022508 |
|
|
|
022508 |
ictx = tpax_get_driver_ictx(dctx);
|
|
|
022508 |
ictx->dirents = (struct tpax_dirent_buffer *)addr;
|
|
|
022508 |
ictx->dirents->cdent = ictx->dirents->dbuf;
|
|
|
022508 |
|
|
|
022508 |
ictx->dirents->size = TPAX_DIRENT_BUFLEN;
|
|
|
022508 |
ictx->dirents->next = 0;
|
|
|
022508 |
|
|
|
022508 |
ictx->dirents->nfree = TPAX_DIRENT_BUFLEN;
|
|
|
022508 |
ictx->dirents->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
|
|
|
022508 |
|
|
|
022508 |
return ictx->dirents;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
static struct tpax_dirent_buffer * tpax_dirent_buf_next_alloc(
|
|
|
022508 |
struct tpax_dirent_buffer * current)
|
|
|
022508 |
{
|
|
|
022508 |
void * addr;
|
|
|
022508 |
|
|
|
022508 |
addr = (struct tpax_dirent_buffer *)mmap(
|
|
|
022508 |
0,TPAX_DIRENT_BUFLEN,
|
|
|
022508 |
PROT_READ|PROT_WRITE,
|
|
|
022508 |
MAP_PRIVATE|MAP_ANONYMOUS,
|
|
|
022508 |
-1,0);
|
|
|
022508 |
|
|
|
022508 |
if (addr == MAP_FAILED)
|
|
|
022508 |
return 0;
|
|
|
022508 |
|
|
|
022508 |
current->next = (struct tpax_dirent_buffer *)addr;
|
|
|
022508 |
current->next->cdent = current->next->dbuf;
|
|
|
022508 |
|
|
|
022508 |
current->next->size = TPAX_DIRENT_BUFLEN;
|
|
|
022508 |
current->next->next = 0;
|
|
|
022508 |
|
|
|
022508 |
current->next->nfree = TPAX_DIRENT_BUFLEN;
|
|
|
022508 |
current->next->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
|
|
|
022508 |
|
|
|
022508 |
return current->next;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
43c39b |
static int tpax_archive_enqueue_ret(
|
|
|
022508 |
int ret,
|
|
|
022508 |
struct tpax_unit_ctx * unit)
|
|
|
022508 |
{
|
|
|
022508 |
if (unit)
|
|
|
c9eeca |
tpax_lib_free_unit_ctx(unit);
|
|
|
022508 |
|
|
|
022508 |
return ret;
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
43c39b |
static int tpax_archive_add_queue_item(
|
|
|
3179bb |
const struct tpax_driver_ctx * dctx,
|
|
|
3179bb |
const struct dirent * dirent,
|
|
|
3179bb |
const struct tpax_dirent * parent,
|
|
|
9f55a1 |
const char * prefix,
|
|
|
f9e2cb |
dev_t stdev,
|
|
|
3179bb |
int depth,
|
|
|
9f55a1 |
int flags,
|
|
|
733811 |
int fdat,
|
|
|
3179bb |
bool * fkeep)
|
|
|
3179bb |
{
|
|
|
3179bb |
struct tpax_dirent_buffer * dentbuf;
|
|
|
3179bb |
struct tpax_dirent * cdent;
|
|
|
3179bb |
const char * src;
|
|
|
3179bb |
char * dst;
|
|
|
3179bb |
char * cap;
|
|
|
3179bb |
size_t needed;
|
|
|
3179bb |
|
|
|
3179bb |
if (!(dentbuf = tpax_get_driver_dirents(dctx)))
|
|
|
3179bb |
if (!(dentbuf = tpax_dirent_buf_first_alloc(dctx)))
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
3179bb |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
afec65 |
0);
|
|
|
3179bb |
|
|
|
3179bb |
needed = dirent->d_reclen;
|
|
|
3179bb |
needed += offsetof(struct tpax_dirent,dirent);
|
|
|
3179bb |
needed += 0x7;
|
|
|
3179bb |
needed |= 0x7;
|
|
|
3179bb |
needed ^= 0x7;
|
|
|
3179bb |
|
|
|
3179bb |
for (; dentbuf->next && (dentbuf->nfree < needed); )
|
|
|
3179bb |
dentbuf = dentbuf->next;
|
|
|
3179bb |
|
|
|
3179bb |
if (dentbuf->nfree < needed)
|
|
|
3179bb |
if (!(dentbuf = tpax_dirent_buf_next_alloc(dentbuf)))
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
3179bb |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
afec65 |
0);
|
|
|
3179bb |
|
|
|
3179bb |
*fkeep = true;
|
|
|
3179bb |
cdent = dentbuf->cdent;
|
|
|
3179bb |
|
|
|
733811 |
cdent->fdat = fdat;
|
|
|
3179bb |
cdent->depth = depth;
|
|
|
9f55a1 |
cdent->flags = flags;
|
|
|
f9e2cb |
cdent->stdev = stdev;
|
|
|
3179bb |
cdent->nsize = needed;
|
|
|
3179bb |
cdent->parent = parent;
|
|
|
9f55a1 |
cdent->prefix = prefix;
|
|
|
3179bb |
|
|
|
3179bb |
memset(&cdent->dirent,0,offsetof(struct dirent,d_name));
|
|
|
3179bb |
|
|
|
3179bb |
cdent->dirent.d_ino = dirent->d_ino;
|
|
|
3179bb |
cdent->dirent.d_type = dirent->d_type;
|
|
|
3179bb |
cdent->dirent.d_reclen = dirent->d_reclen;
|
|
|
3179bb |
|
|
|
3179bb |
src = dirent->d_name;
|
|
|
3179bb |
dst = cdent->dirent.d_name;
|
|
|
3179bb |
|
|
|
3179bb |
cap = dst - offsetof(struct dirent,d_name);
|
|
|
3179bb |
cap -= offsetof(struct tpax_dirent,dirent);
|
|
|
3179bb |
cap += needed;
|
|
|
3179bb |
|
|
|
3179bb |
for (; *src; )
|
|
|
3179bb |
*dst++ = *src++;
|
|
|
3179bb |
|
|
|
3179bb |
for (; dst
|
|
|
3179bb |
*dst++ = 0;
|
|
|
3179bb |
|
|
|
3179bb |
dentbuf->cdent = (struct tpax_dirent *)cap;
|
|
|
3179bb |
dentbuf->nfree -= needed;
|
|
|
3179bb |
|
|
|
a0e0a4 |
tpax_set_driver_dirmark(dctx,cdent);
|
|
|
a0e0a4 |
|
|
|
3179bb |
return 0;
|
|
|
3179bb |
}
|
|
|
3179bb |
|
|
|
43c39b |
static int tpax_archive_enqueue_dir_entries(
|
|
|
022508 |
const struct tpax_driver_ctx * dctx,
|
|
|
afec65 |
struct tpax_dirent * dent)
|
|
|
022508 |
{
|
|
|
022508 |
int fd;
|
|
|
afec65 |
int fdat;
|
|
|
e50240 |
int fdlnk;
|
|
|
afec65 |
int depth;
|
|
|
022508 |
bool fkeep;
|
|
|
e50240 |
bool flinks;
|
|
|
f9e2cb |
bool fstdev;
|
|
|
022508 |
long nbytes;
|
|
|
e50240 |
struct dirent * lnkent;
|
|
|
022508 |
struct dirent * dirent;
|
|
|
022508 |
struct dirent * dirents;
|
|
|
e50240 |
struct tpax_dirent * cdent;
|
|
|
afec65 |
struct tpax_unit_ctx * uctx;
|
|
|
022508 |
struct stat st;
|
|
|
e50240 |
struct stat lnkst;
|
|
|
022508 |
uintptr_t addr;
|
|
|
e50240 |
char lnktgt[PATH_MAX];
|
|
|
e50240 |
char lnkbuf[PATH_MAX + sizeof(struct dirent)];
|
|
|
022508 |
|
|
|
afec65 |
/* init */
|
|
|
afec65 |
fdat = dent->fdat;
|
|
|
afec65 |
depth = dent->depth;
|
|
|
022508 |
|
|
|
afec65 |
/* uctx on the fly */
|
|
|
c9eeca |
if (tpax_lib_get_unit_ctx(
|
|
|
afec65 |
dctx,fdat,
|
|
|
afec65 |
dent->dirent.d_name,
|
|
|
afec65 |
&uctx) < 0)
|
|
|
022508 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
022508 |
|
|
|
022508 |
/* verify that recursion item is still a directory */
|
|
|
afec65 |
if (!S_ISDIR(uctx->st->st_mode))
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
022508 |
TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
|
|
|
afec65 |
uctx);
|
|
|
022508 |
|
|
|
022508 |
/* obtain buffer for file-system directory entries */
|
|
|
022508 |
dirents = tpax_get_driver_getdents_buffer(dctx);
|
|
|
022508 |
dirent = dirents;
|
|
|
022508 |
fkeep = false;
|
|
|
022508 |
nbytes = 0;
|
|
|
022508 |
depth++;
|
|
|
022508 |
|
|
|
022508 |
/* open directory and obtain first directory entries */
|
|
|
afec65 |
if ((fd = openat(fdat,dent->dirent.d_name,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0)
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
afec65 |
uctx);
|
|
|
022508 |
|
|
|
e50240 |
lnkent = (struct dirent *)lnkbuf;
|
|
|
e50240 |
flinks = (dctx->cctx->drvflags & TPAX_DRIVER_PAX_SYMLINK_ITEMS);
|
|
|
f9e2cb |
fstdev = (dctx->cctx->drvflags & TPAX_DRIVER_STRICT_DEVICE_ID);
|
|
|
022508 |
nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
|
|
|
022508 |
|
|
|
f9e2cb |
/* debugging, struct stat initialization when fstdev is false */
|
|
|
f9e2cb |
memset(&st,0,sizeof(st));
|
|
|
f9e2cb |
|
|
|
022508 |
while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
|
|
|
022508 |
nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
|
|
|
022508 |
|
|
|
022508 |
if (nbytes < 0)
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
afec65 |
uctx);
|
|
|
022508 |
|
|
|
022508 |
/* iterate */
|
|
|
24b5f4 |
for (; nbytes; ) {
|
|
|
022508 |
if (!strcmp(dirent->d_name,".")) {
|
|
|
022508 |
(void)0;
|
|
|
022508 |
|
|
|
022508 |
} else if (!strcmp(dirent->d_name,"..")) {
|
|
|
022508 |
(void)0;
|
|
|
022508 |
|
|
|
022508 |
} else {
|
|
|
022508 |
if (dirent->d_type == DT_UNKNOWN) {
|
|
|
022508 |
if (fstatat(fd,dirent->d_name,&st,AT_SYMLINK_NOFOLLOW))
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
afec65 |
uctx);
|
|
|
022508 |
|
|
|
022508 |
if (S_ISDIR(st.st_mode)) {
|
|
|
022508 |
dirent->d_type = DT_DIR;
|
|
|
022508 |
}
|
|
|
f9e2cb |
} else if (fstdev) {
|
|
|
f9e2cb |
if (fstatat(fd,dirent->d_name,&st,AT_SYMLINK_NOFOLLOW))
|
|
|
f9e2cb |
return tpax_archive_enqueue_ret(
|
|
|
f9e2cb |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
f9e2cb |
uctx);
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
43c39b |
if (tpax_archive_add_queue_item(
|
|
|
f9e2cb |
dctx,dirent,dent,0,
|
|
|
f9e2cb |
st.st_dev,depth,
|
|
|
afec65 |
TPAX_ITEM_IMPLICIT,
|
|
|
afec65 |
fd,&fkeep) < 0)
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
afec65 |
TPAX_NESTED_ERROR(dctx),
|
|
|
afec65 |
uctx);
|
|
|
e50240 |
|
|
|
e50240 |
/* follow encountered symlink arguments as needed */
|
|
|
e50240 |
fdlnk = (flinks && (dirent->d_type == DT_LNK))
|
|
|
e50240 |
? openat(fd,dirent->d_name,O_RDONLY|O_CLOEXEC)
|
|
|
e50240 |
: (-1);
|
|
|
e50240 |
|
|
|
e50240 |
if (fdlnk >= 0) {
|
|
|
e50240 |
if (fstat(fdlnk,&lnkst) <0) {
|
|
|
e50240 |
close(fdlnk);
|
|
|
e50240 |
return tpax_archive_enqueue_ret(
|
|
|
e50240 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
e50240 |
uctx);
|
|
|
e50240 |
}
|
|
|
e50240 |
|
|
|
e50240 |
if (tpax_readlinkat(fd,dirent->d_name,lnktgt,PATH_MAX) < 0)
|
|
|
e50240 |
return tpax_archive_enqueue_ret(
|
|
|
e50240 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
e50240 |
uctx);
|
|
|
e50240 |
|
|
|
e50240 |
close(fdlnk);
|
|
|
e50240 |
|
|
|
b56498 |
if (tpax_dirent_init_from_stat(&lnkst,lnktgt,lnkent) < 0)
|
|
|
e50240 |
return tpax_archive_enqueue_ret(
|
|
|
e50240 |
TPAX_CUSTOM_ERROR(
|
|
|
e50240 |
dctx,
|
|
|
e50240 |
TPAX_ERR_FLOW_ERROR),
|
|
|
e50240 |
0);
|
|
|
e50240 |
|
|
|
e50240 |
cdent = tpax_get_driver_dirmark(dctx);
|
|
|
e50240 |
cdent->flags |= TPAX_ITEM_NAMEREF;
|
|
|
e50240 |
|
|
|
e50240 |
if (tpax_archive_add_queue_item(
|
|
|
f9e2cb |
dctx,lnkent,cdent,0,
|
|
|
f9e2cb |
lnkst.st_dev,depth+1,
|
|
|
e50240 |
TPAX_ITEM_IMPLICIT|TPAX_ITEM_SYMLINK,
|
|
|
e50240 |
fd,&fkeep) < 0)
|
|
|
e50240 |
return tpax_archive_enqueue_ret(
|
|
|
e50240 |
TPAX_NESTED_ERROR(dctx),
|
|
|
e50240 |
0);
|
|
|
e50240 |
}
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
022508 |
addr = (uintptr_t)dirent;
|
|
|
022508 |
addr += dirent->d_reclen;
|
|
|
022508 |
nbytes -= dirent->d_reclen;
|
|
|
022508 |
dirent = (struct dirent *)addr;
|
|
|
022508 |
|
|
|
022508 |
if (nbytes == 0) {
|
|
|
022508 |
nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
|
|
|
022508 |
|
|
|
022508 |
while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
|
|
|
022508 |
nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
|
|
|
022508 |
|
|
|
022508 |
if (nbytes < 0)
|
|
|
43c39b |
tpax_archive_enqueue_ret(
|
|
|
022508 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
afec65 |
uctx);
|
|
|
022508 |
|
|
|
022508 |
dirent = dirents;
|
|
|
022508 |
}
|
|
|
3db888 |
}
|
|
|
3db888 |
|
|
|
022508 |
/* all done */
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
022508 |
fkeep ? 0 : close(fd),
|
|
|
afec65 |
uctx);
|
|
|
022508 |
}
|
|
|
022508 |
|
|
|
76f93a |
static const char * tpax_path_prefix_mark(const char * path)
|
|
|
76f93a |
{
|
|
|
76f93a |
const char * src;
|
|
|
76f93a |
char * mark;
|
|
|
76f93a |
char pathbuf[PATH_MAX];
|
|
|
76f93a |
|
|
|
76f93a |
src = path;
|
|
|
76f93a |
mark = pathbuf;
|
|
|
76f93a |
|
|
|
76f93a |
for (; *src; )
|
|
|
76f93a |
*mark++ = *src++;
|
|
|
76f93a |
|
|
|
76f93a |
for (--mark; (*mark == '/'); mark--)
|
|
|
76f93a |
(void)0;
|
|
|
76f93a |
|
|
|
76f93a |
*++mark = '\0';
|
|
|
76f93a |
|
|
|
76f93a |
for (; (mark > pathbuf) && (mark[-1] != '/'); )
|
|
|
76f93a |
mark--;
|
|
|
76f93a |
|
|
|
76f93a |
return (mark <= pathbuf) ? 0 : &path[--mark-pathbuf];
|
|
|
76f93a |
}
|
|
|
76f93a |
|
|
|
43c39b |
int tpax_archive_enqueue(
|
|
|
022508 |
const struct tpax_driver_ctx * dctx,
|
|
|
f5ae32 |
const struct tpax_unit_ctx * uctx)
|
|
|
022508 |
{
|
|
|
76f93a |
int fdat;
|
|
|
37f513 |
int fdlnk;
|
|
|
1aa8ec |
uintptr_t addr;
|
|
|
76f93a |
const char * name;
|
|
|
76f93a |
const char * mark;
|
|
|
76f93a |
const char * prefix;
|
|
|
76f93a |
bool fkeep;
|
|
|
1aa8ec |
struct tpax_dirent_buffer * dentbuf;
|
|
|
1aa8ec |
struct tpax_dirent * cdent;
|
|
|
1aa8ec |
struct tpax_dirent * cnext;
|
|
|
76f93a |
struct dirent * dirent;
|
|
|
37f513 |
struct dirent * lnkent;
|
|
|
37f513 |
struct stat lnkst;
|
|
|
76f93a |
char entbuf[PATH_MAX + sizeof(struct dirent)];
|
|
|
37f513 |
char lnkbuf[PATH_MAX + sizeof(struct dirent)];
|
|
|
76f93a |
|
|
|
76f93a |
/* init */
|
|
|
76f93a |
fdat = tpax_driver_fdcwd(dctx);
|
|
|
76f93a |
dirent = (struct dirent *)entbuf;
|
|
|
37f513 |
lnkent = (struct dirent *)lnkbuf;
|
|
|
76f93a |
prefix = 0;
|
|
|
76f93a |
|
|
|
76f93a |
/* split path to prefix + basename */
|
|
|
76f93a |
if ((mark = tpax_path_prefix_mark(*uctx->path)))
|
|
|
43c39b |
if (!(prefix = tpax_add_prefix_item_from_path(
|
|
|
76f93a |
dctx,*uctx->path,mark)))
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
76f93a |
TPAX_BUFFER_ERROR(dctx),
|
|
|
76f93a |
0);
|
|
|
76f93a |
|
|
|
76f93a |
name = mark ? ++mark : *uctx->path;
|
|
|
76f93a |
|
|
|
76f93a |
if (prefix)
|
|
|
76f93a |
if ((fdat = openat(fdat,prefix,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0)
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
76f93a |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
76f93a |
0);
|
|
|
76f93a |
|
|
|
76f93a |
/* explicit item directory entry */
|
|
|
b56498 |
if (tpax_dirent_init_from_stat(uctx->st,name,dirent) < 0)
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
76f93a |
TPAX_CUSTOM_ERROR(
|
|
|
76f93a |
dctx,
|
|
|
76f93a |
TPAX_ERR_FLOW_ERROR),
|
|
|
76f93a |
0);
|
|
|
76f93a |
|
|
|
76f93a |
/* add to queue */
|
|
|
43c39b |
if (tpax_archive_add_queue_item(
|
|
|
f9e2cb |
dctx,dirent,0,prefix,
|
|
|
f9e2cb |
uctx->st->st_dev,0,
|
|
|
76f93a |
TPAX_ITEM_EXPLICIT,
|
|
|
76f93a |
fdat,&fkeep) < 0)
|
|
|
43c39b |
return tpax_archive_enqueue_ret(
|
|
|
76f93a |
TPAX_NESTED_ERROR(dctx),
|
|
|
76f93a |
0);
|
|
|
022508 |
|
|
|
37f513 |
/* follow command-line symlink arguments as needed */
|
|
|
37f513 |
fdlnk = (uctx->link[0] && (dctx->cctx->drvflags & TPAX_DRIVER_PAX_SYMLINK_ARGS))
|
|
|
37f513 |
? openat(fdat,uctx->link[0],O_RDONLY|O_CLOEXEC) : (-1);
|
|
|
37f513 |
|
|
|
37f513 |
if (fdlnk >= 0) {
|
|
|
37f513 |
if (fstat(fdlnk,&lnkst) <0) {
|
|
|
37f513 |
close(fdlnk);
|
|
|
37f513 |
return tpax_archive_enqueue_ret(
|
|
|
37f513 |
TPAX_SYSTEM_ERROR(dctx),
|
|
|
37f513 |
0);
|
|
|
37f513 |
}
|
|
|
37f513 |
|
|
|
37f513 |
close(fdlnk);
|
|
|
37f513 |
|
|
|
b56498 |
if (tpax_dirent_init_from_stat(&lnkst,uctx->link[0],lnkent) < 0)
|
|
|
37f513 |
return tpax_archive_enqueue_ret(
|
|
|
37f513 |
TPAX_CUSTOM_ERROR(
|
|
|
37f513 |
dctx,
|
|
|
37f513 |
TPAX_ERR_FLOW_ERROR),
|
|
|
37f513 |
0);
|
|
|
37f513 |
|
|
|
37f513 |
cdent = tpax_get_driver_dirmark(dctx);
|
|
|
37f513 |
cdent->flags |= TPAX_ITEM_NAMEREF;
|
|
|
37f513 |
|
|
|
37f513 |
if (tpax_archive_add_queue_item(
|
|
|
f9e2cb |
dctx,lnkent,cdent,0,
|
|
|
f9e2cb |
lnkst.st_dev,1,
|
|
|
37f513 |
TPAX_ITEM_EXPLICIT|TPAX_ITEM_SYMLINK,
|
|
|
37f513 |
fdat,&fkeep) < 0)
|
|
|
37f513 |
return tpax_archive_enqueue_ret(
|
|
|
37f513 |
TPAX_NESTED_ERROR(dctx),
|
|
|
37f513 |
0);
|
|
|
37f513 |
}
|
|
|
37f513 |
|
|
|
1aa8ec |
/* queue directory child items */
|
|
|
1aa8ec |
dentbuf = tpax_get_driver_dirents(dctx);
|
|
|
1aa8ec |
cdent = tpax_get_driver_dirmark(dctx);
|
|
|
1aa8ec |
|
|
|
1aa8ec |
for (; cdent; ) {
|
|
|
1aa8ec |
if (cdent->dirent.d_type == DT_DIR)
|
|
|
dac847 |
if (dctx->cctx->drvflags & TPAX_DRIVER_DIR_MEMBER_RECURSE)
|
|
|
43c39b |
if (tpax_archive_enqueue_dir_entries(dctx,cdent) < 0)
|
|
|
dac847 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
1aa8ec |
|
|
|
1aa8ec |
addr = (uintptr_t)cdent;
|
|
|
1aa8ec |
addr += cdent->nsize;
|
|
|
1aa8ec |
cnext = (struct tpax_dirent *)addr;
|
|
|
1aa8ec |
|
|
|
1aa8ec |
if (cnext == dentbuf->cdent) {
|
|
|
1aa8ec |
dentbuf = dentbuf->next;
|
|
|
1aa8ec |
cnext = dentbuf ? dentbuf->dbuf : 0;
|
|
|
1aa8ec |
}
|
|
|
1aa8ec |
|
|
|
1aa8ec |
cdent = cnext;
|
|
|
1aa8ec |
}
|
|
|
1aa8ec |
|
|
|
409008 |
return 0;
|
|
|
3db888 |
}
|