|
|
acc91b |
/**************************************************************/
|
|
|
acc91b |
/* tpax: a topological pax implementation */
|
|
|
acc91b |
/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
|
|
|
acc91b |
/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
|
|
|
acc91b |
/**************************************************************/
|
|
|
acc91b |
|
|
|
acc91b |
#include <stdint.h>
|
|
|
acc91b |
#include <stdlib.h>
|
|
|
acc91b |
|
|
|
acc91b |
#include <tpax/tpax.h>
|
|
|
acc91b |
#include "tpax_driver_impl.h"
|
|
|
acc91b |
#include "tpax_errinfo_impl.h"
|
|
|
acc91b |
#include "tpax_visibility_impl.h"
|
|
|
acc91b |
|
|
|
de63a0 |
#define TPAX_MAX_DEPTH 512
|
|
|
de63a0 |
|
|
|
de63a0 |
tpax_hidden const char * tpax_queue_item_full_path(
|
|
|
de63a0 |
const struct tpax_driver_ctx * dctx,
|
|
|
de63a0 |
const struct tpax_dirent * cdent)
|
|
|
de63a0 |
{
|
|
|
de63a0 |
char * ch;
|
|
|
de63a0 |
char * pathbuf;
|
|
|
de63a0 |
const struct tpax_dirent * pparent;
|
|
|
de63a0 |
const struct tpax_dirent ** pdirent;
|
|
|
de63a0 |
const struct tpax_dirent * dirstck[TPAX_MAX_DEPTH];
|
|
|
de63a0 |
|
|
|
de63a0 |
if (cdent->depth >= TPAX_MAX_DEPTH)
|
|
|
de63a0 |
return 0;
|
|
|
de63a0 |
|
|
|
de63a0 |
ch = pathbuf = (tpax_get_driver_ictx(dctx))->dirbuff;
|
|
|
de63a0 |
|
|
|
de63a0 |
for (pparent=cdent,pdirent=dirstck; pparent; pparent=pparent->parent)
|
|
|
de63a0 |
*pdirent++ = pparent;
|
|
|
de63a0 |
|
|
|
de63a0 |
*pdirent-- = 0;
|
|
|
de63a0 |
|
|
|
de63a0 |
if (pdirent[0]->prefix)
|
|
|
de63a0 |
ch += sprintf(ch,"%s",pdirent[0]->prefix);
|
|
|
de63a0 |
|
|
|
de63a0 |
for (; pdirent > dirstck; ) {
|
|
|
37f513 |
if (!(pdirent[0]->flags & TPAX_ITEM_SYMLINK))
|
|
|
37f513 |
ch += sprintf(ch,"%s/",pdirent[0]->dirent.d_name);
|
|
|
37f513 |
|
|
|
de63a0 |
pdirent--;
|
|
|
de63a0 |
}
|
|
|
de63a0 |
|
|
|
37f513 |
if (pdirent[0]->flags & TPAX_ITEM_SYMLINK) {
|
|
|
37f513 |
*--ch = '\0';
|
|
|
37f513 |
} else {
|
|
|
37f513 |
sprintf(ch,"%s",pdirent[0]->dirent.d_name);
|
|
|
37f513 |
}
|
|
|
de63a0 |
|
|
|
de63a0 |
return pathbuf;
|
|
|
de63a0 |
}
|
|
|
de63a0 |
|
|
|
f66f53 |
static int tpax_cpio_dirent_compare(const void * a, const void * b)
|
|
|
f66f53 |
{
|
|
|
f66f53 |
const struct tpax_dirent * direnta;
|
|
|
f66f53 |
const struct tpax_dirent * direntb;
|
|
|
f66f53 |
|
|
|
f66f53 |
direnta = *(const struct tpax_dirent **)a;
|
|
|
f66f53 |
direntb = *(const struct tpax_dirent **)b;
|
|
|
f66f53 |
|
|
|
f66f53 |
return (direnta->stdev == direntb->stdev)
|
|
|
f66f53 |
? direnta->stino - direntb->stino
|
|
|
f66f53 |
: direnta->stdev - direntb->stdev;
|
|
|
f66f53 |
}
|
|
|
f66f53 |
|
|
|
f66f53 |
static int tpax_update_cpio_queue_vector(const struct tpax_driver_ctx * dctx)
|
|
|
f66f53 |
{
|
|
|
f66f53 |
struct tpax_driver_ctx_impl * ictx;
|
|
|
f66f53 |
struct tpax_dirent ** cpiov;
|
|
|
f66f53 |
struct tpax_dirent ** direntv;
|
|
|
f66f53 |
struct tpax_dirent * cdent;
|
|
|
f66f53 |
dev_t stdev;
|
|
|
f66f53 |
ino_t stino;
|
|
|
f66f53 |
int cpdev;
|
|
|
f66f53 |
int cpino;
|
|
|
f66f53 |
int nlink;
|
|
|
f66f53 |
int idx;
|
|
|
f66f53 |
|
|
|
f66f53 |
/* driver */
|
|
|
f66f53 |
ictx = tpax_get_driver_ictx(dctx);
|
|
|
f66f53 |
|
|
|
f66f53 |
/* not needed? */
|
|
|
f66f53 |
if (ictx->nqueued == 0)
|
|
|
f66f53 |
return 0;
|
|
|
f66f53 |
|
|
|
f66f53 |
/* vector copy */
|
|
|
f66f53 |
direntv = ictx->direntv;
|
|
|
f66f53 |
cpiov = ictx->cpiov;
|
|
|
f66f53 |
|
|
|
f66f53 |
for (; *direntv; )
|
|
|
f66f53 |
*cpiov++ = *direntv++;
|
|
|
f66f53 |
|
|
|
f66f53 |
/* sort by real st_dev, st_ino */
|
|
|
f66f53 |
qsort(ictx->cpiov,ictx->nqueued,sizeof(*cpiov),tpax_cpio_dirent_compare);
|
|
|
f66f53 |
|
|
|
f66f53 |
/* set the cpio internal c_dev, c_ino, and c_nlink fields (U+1F620) */
|
|
|
f66f53 |
cpiov = ictx->cpiov;
|
|
|
f66f53 |
cdent = cpiov[0];
|
|
|
f66f53 |
cpiov++;
|
|
|
f66f53 |
|
|
|
f66f53 |
cpdev = 1;
|
|
|
f66f53 |
cpino = 1;
|
|
|
f66f53 |
nlink = 1;
|
|
|
f66f53 |
|
|
|
f66f53 |
stdev = cdent->stdev;
|
|
|
f66f53 |
stino = cdent->stino;
|
|
|
f66f53 |
|
|
|
f66f53 |
cdent->cpdev = cpdev;
|
|
|
f66f53 |
cdent->cpino = cpino;
|
|
|
f66f53 |
cdent->nlink = nlink;
|
|
|
f66f53 |
|
|
|
f66f53 |
for (; *cpiov; ) {
|
|
|
f66f53 |
cdent = *cpiov;
|
|
|
f66f53 |
|
|
|
f66f53 |
if (cdent->srdev > 0777777)
|
|
|
f66f53 |
return TPAX_CUSTOM_ERROR(
|
|
|
f66f53 |
dctx,
|
|
|
f66f53 |
TPAX_ERR_FLOW_ERROR);
|
|
|
f66f53 |
|
|
|
f66f53 |
if ((cdent->stdev == stdev) && (cdent->stino == stino)) {
|
|
|
f66f53 |
nlink++;
|
|
|
f66f53 |
|
|
|
f66f53 |
} else if (cdent->stdev > stdev) {
|
|
|
f66f53 |
if (nlink > 1)
|
|
|
f66f53 |
for (idx=2; idx<=nlink; idx++)
|
|
|
f66f53 |
cpiov[-idx]->nlink = nlink;
|
|
|
f66f53 |
|
|
|
f66f53 |
cpdev++;
|
|
|
f66f53 |
cpino = 1;
|
|
|
f66f53 |
nlink = 1;
|
|
|
f66f53 |
|
|
|
f66f53 |
stdev = cdent->stdev;
|
|
|
f66f53 |
stino = cdent->stino;
|
|
|
f66f53 |
|
|
|
f66f53 |
if (cpdev > 0777777)
|
|
|
f66f53 |
return TPAX_CUSTOM_ERROR(
|
|
|
f66f53 |
dctx,
|
|
|
f66f53 |
TPAX_ERR_FLOW_ERROR);
|
|
|
f66f53 |
|
|
|
f66f53 |
} else if (cdent->stino > stino) {
|
|
|
f66f53 |
if (nlink > 1)
|
|
|
f66f53 |
for (idx=2; idx<=nlink; idx++)
|
|
|
f66f53 |
cpiov[-idx]->nlink = nlink;
|
|
|
f66f53 |
|
|
|
f66f53 |
cpino++;
|
|
|
f66f53 |
stino = cdent->stino;
|
|
|
f66f53 |
nlink = 1;
|
|
|
f66f53 |
|
|
|
f66f53 |
if (cpino > 0777777)
|
|
|
f66f53 |
return TPAX_CUSTOM_ERROR(
|
|
|
f66f53 |
dctx,
|
|
|
f66f53 |
TPAX_ERR_FLOW_ERROR);
|
|
|
f66f53 |
}
|
|
|
f66f53 |
|
|
|
f66f53 |
cdent->cpdev = cpdev;
|
|
|
f66f53 |
cdent->cpino = cpino;
|
|
|
f66f53 |
cdent->nlink = nlink;
|
|
|
f66f53 |
|
|
|
f66f53 |
cpiov++;
|
|
|
f66f53 |
}
|
|
|
f66f53 |
|
|
|
f66f53 |
return 0;
|
|
|
f66f53 |
}
|
|
|
f66f53 |
|
|
|
acc91b |
tpax_hidden int tpax_update_queue_vector(const struct tpax_driver_ctx * dctx)
|
|
|
acc91b |
{
|
|
|
acc91b |
uintptr_t addr;
|
|
|
acc91b |
struct tpax_driver_ctx_impl * ictx;
|
|
|
acc91b |
struct tpax_dirent_buffer * dentbuf;
|
|
|
acc91b |
struct tpax_dirent ** direntv;
|
|
|
acc91b |
struct tpax_dirent * cdent;
|
|
|
acc91b |
struct tpax_dirent * cnext;
|
|
|
acc91b |
size_t arrsize;
|
|
|
acc91b |
|
|
|
acc91b |
/* driver */
|
|
|
acc91b |
ictx = tpax_get_driver_ictx(dctx);
|
|
|
acc91b |
|
|
|
acc91b |
/* vector alloc */
|
|
|
f66f53 |
if (ictx->direntv) {
|
|
|
acc91b |
free(ictx->direntv);
|
|
|
f66f53 |
free(ictx->cpiov);
|
|
|
f66f53 |
|
|
|
f66f53 |
ictx->direntv = 0;
|
|
|
f66f53 |
ictx->cpiov = 0;
|
|
|
f66f53 |
}
|
|
|
acc91b |
|
|
|
acc91b |
arrsize = ictx->nqueued + 1;
|
|
|
acc91b |
|
|
|
acc91b |
if (!(ictx->direntv = calloc(arrsize,sizeof(struct tpax_dirent *))))
|
|
|
acc91b |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
acc91b |
|
|
|
f66f53 |
if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_CPIO)
|
|
|
f66f53 |
if (!(ictx->cpiov = calloc(arrsize,sizeof(struct tpax_dirent *))))
|
|
|
f66f53 |
return TPAX_SYSTEM_ERROR(dctx);
|
|
|
acc91b |
|
|
|
acc91b |
/* queue vector */
|
|
|
acc91b |
dentbuf = tpax_get_driver_dirents(dctx);
|
|
|
f66f53 |
cdent = ictx->nqueued ? dentbuf->dbuf : 0;
|
|
|
acc91b |
|
|
|
acc91b |
for (direntv=ictx->direntv; cdent; direntv++) {
|
|
|
acc91b |
*direntv = cdent;
|
|
|
acc91b |
|
|
|
acc91b |
addr = (uintptr_t)cdent;
|
|
|
acc91b |
addr += cdent->nsize;
|
|
|
acc91b |
cnext = (struct tpax_dirent *)addr;
|
|
|
acc91b |
|
|
|
acc91b |
if (cnext == dentbuf->cdent) {
|
|
|
acc91b |
dentbuf = dentbuf->next;
|
|
|
acc91b |
cnext = dentbuf ? dentbuf->dbuf : 0;
|
|
|
acc91b |
}
|
|
|
acc91b |
|
|
|
acc91b |
cdent = cnext;
|
|
|
acc91b |
}
|
|
|
acc91b |
|
|
|
f66f53 |
if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_CPIO)
|
|
|
f66f53 |
if (tpax_update_cpio_queue_vector(dctx) < 0)
|
|
|
f66f53 |
return TPAX_NESTED_ERROR(dctx);
|
|
|
f66f53 |
|
|
|
acc91b |
return 0;
|
|
|
acc91b |
}
|