/**************************************************************/ /* tpax: a topological pax implementation */ /* Copyright (C) 2020--2024 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ /**************************************************************/ #include #include #include #include "tpax_driver_impl.h" #include "tpax_errinfo_impl.h" #include "tpax_visibility_impl.h" #define TPAX_MAX_DEPTH 512 tpax_hidden const char * tpax_queue_item_full_path( const struct tpax_driver_ctx * dctx, const struct tpax_dirent * cdent) { char * ch; char * pathbuf; const struct tpax_dirent * pparent; const struct tpax_dirent ** pdirent; const struct tpax_dirent * dirstck[TPAX_MAX_DEPTH]; if (cdent->depth >= TPAX_MAX_DEPTH) return 0; ch = pathbuf = (tpax_get_driver_ictx(dctx))->dirbuff; for (pparent=cdent,pdirent=dirstck; pparent; pparent=pparent->parent) *pdirent++ = pparent; *pdirent-- = 0; if (pdirent[0]->prefix) ch += sprintf(ch,"%s",pdirent[0]->prefix); for (; pdirent > dirstck; ) { if (!(pdirent[0]->flags & TPAX_ITEM_SYMLINK)) ch += sprintf(ch,"%s/",pdirent[0]->dirent.d_name); pdirent--; } if (pdirent[0]->flags & TPAX_ITEM_SYMLINK) { *--ch = '\0'; } else { sprintf(ch,"%s",pdirent[0]->dirent.d_name); } 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++; } if (nlink > 1) for (idx=2; idx<=nlink; idx++) cpiov[-idx]->nlink = nlink; return 0; } tpax_hidden int tpax_update_queue_vector(const struct tpax_driver_ctx * dctx) { uintptr_t addr; struct tpax_driver_ctx_impl * ictx; struct tpax_dirent_buffer * dentbuf; struct tpax_dirent ** direntv; struct tpax_dirent * cdent; struct tpax_dirent * cnext; size_t arrsize; /* driver */ ictx = tpax_get_driver_ictx(dctx); /* vector alloc */ 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 (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 = ictx->nqueued ? dentbuf->dbuf : 0; for (direntv=ictx->direntv; cdent; direntv++) { *direntv = cdent; addr = (uintptr_t)cdent; addr += cdent->nsize; cnext = (struct tpax_dirent *)addr; if (cnext == dentbuf->cdent) { dentbuf = dentbuf->next; cnext = dentbuf ? dentbuf->dbuf : 0; } 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; }