summaryrefslogtreecommitdiffhomepage
path: root/src/logic/tpax_queue_vector.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/logic/tpax_queue_vector.c')
-rw-r--r--src/logic/tpax_queue_vector.c130
1 files changed, 126 insertions, 4 deletions
diff --git a/src/logic/tpax_queue_vector.c b/src/logic/tpax_queue_vector.c
index cae4da0..1b10feb 100644
--- a/src/logic/tpax_queue_vector.c
+++ b/src/logic/tpax_queue_vector.c
@@ -53,6 +53,118 @@ tpax_hidden const char * tpax_queue_item_full_path(
return pathbuf;
}
+static int tpax_cpio_dirent_compare(const void * a, const void * b)
+{
+ const struct tpax_dirent * direnta;
+ const struct tpax_dirent * direntb;
+
+ direnta = *(const struct tpax_dirent **)a;
+ direntb = *(const struct tpax_dirent **)b;
+
+ return (direnta->stdev == direntb->stdev)
+ ? direnta->stino - direntb->stino
+ : direnta->stdev - direntb->stdev;
+}
+
+static int tpax_update_cpio_queue_vector(const struct tpax_driver_ctx * dctx)
+{
+ struct tpax_driver_ctx_impl * ictx;
+ struct tpax_dirent ** cpiov;
+ struct tpax_dirent ** direntv;
+ struct tpax_dirent * cdent;
+ dev_t stdev;
+ ino_t stino;
+ int cpdev;
+ int cpino;
+ int nlink;
+ int idx;
+
+ /* driver */
+ ictx = tpax_get_driver_ictx(dctx);
+
+ /* not needed? */
+ if (ictx->nqueued == 0)
+ return 0;
+
+ /* vector copy */
+ direntv = ictx->direntv;
+ cpiov = ictx->cpiov;
+
+ for (; *direntv; )
+ *cpiov++ = *direntv++;
+
+ /* sort by real st_dev, st_ino */
+ qsort(ictx->cpiov,ictx->nqueued,sizeof(*cpiov),tpax_cpio_dirent_compare);
+
+ /* set the cpio internal c_dev, c_ino, and c_nlink fields (U+1F620) */
+ cpiov = ictx->cpiov;
+ cdent = cpiov[0];
+ cpiov++;
+
+ cpdev = 1;
+ cpino = 1;
+ nlink = 1;
+
+ stdev = cdent->stdev;
+ stino = cdent->stino;
+
+ cdent->cpdev = cpdev;
+ cdent->cpino = cpino;
+ cdent->nlink = nlink;
+
+ for (; *cpiov; ) {
+ cdent = *cpiov;
+
+ if (cdent->srdev > 0777777)
+ return TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR);
+
+ if ((cdent->stdev == stdev) && (cdent->stino == stino)) {
+ nlink++;
+
+ } else if (cdent->stdev > stdev) {
+ if (nlink > 1)
+ for (idx=2; idx<=nlink; idx++)
+ cpiov[-idx]->nlink = nlink;
+
+ cpdev++;
+ cpino = 1;
+ nlink = 1;
+
+ stdev = cdent->stdev;
+ stino = cdent->stino;
+
+ if (cpdev > 0777777)
+ return TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR);
+
+ } else if (cdent->stino > stino) {
+ if (nlink > 1)
+ for (idx=2; idx<=nlink; idx++)
+ cpiov[-idx]->nlink = nlink;
+
+ cpino++;
+ stino = cdent->stino;
+ nlink = 1;
+
+ if (cpino > 0777777)
+ return TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR);
+ }
+
+ cdent->cpdev = cpdev;
+ cdent->cpino = cpino;
+ cdent->nlink = nlink;
+
+ cpiov++;
+ }
+
+ return 0;
+}
+
tpax_hidden int tpax_update_queue_vector(const struct tpax_driver_ctx * dctx)
{
uintptr_t addr;
@@ -67,20 +179,26 @@ tpax_hidden int tpax_update_queue_vector(const struct tpax_driver_ctx * dctx)
ictx = tpax_get_driver_ictx(dctx);
/* vector alloc */
- if (ictx->direntv)
+ if (ictx->direntv) {
free(ictx->direntv);
+ free(ictx->cpiov);
+
+ ictx->direntv = 0;
+ ictx->cpiov = 0;
+ }
arrsize = ictx->nqueued + 1;
if (!(ictx->direntv = calloc(arrsize,sizeof(struct tpax_dirent *))))
return TPAX_SYSTEM_ERROR(dctx);
- if (ictx->nqueued == 0)
- return 0;
+ if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_CPIO)
+ if (!(ictx->cpiov = calloc(arrsize,sizeof(struct tpax_dirent *))))
+ return TPAX_SYSTEM_ERROR(dctx);
/* queue vector */
dentbuf = tpax_get_driver_dirents(dctx);
- cdent = dentbuf->dbuf;
+ cdent = ictx->nqueued ? dentbuf->dbuf : 0;
for (direntv=ictx->direntv; cdent; direntv++) {
*direntv = cdent;
@@ -97,5 +215,9 @@ tpax_hidden int tpax_update_queue_vector(const struct tpax_driver_ctx * dctx)
cdent = cnext;
}
+ if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_CPIO)
+ if (tpax_update_cpio_queue_vector(dctx) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
return 0;
}