Blame src/logic/tpax_queue_vector.c

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
}