summaryrefslogtreecommitdiff
path: root/src/driver/tpax_driver_ctx.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/driver/tpax_driver_ctx.c')
-rw-r--r--src/driver/tpax_driver_ctx.c380
1 files changed, 351 insertions, 29 deletions
diff --git a/src/driver/tpax_driver_ctx.c b/src/driver/tpax_driver_ctx.c
index d2fec77..b7b949e 100644
--- a/src/driver/tpax_driver_ctx.c
+++ b/src/driver/tpax_driver_ctx.c
@@ -6,6 +6,7 @@
#define _DEFAULT_SOURCE 1
+#include <regex.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
@@ -33,6 +34,9 @@
| TPAX_DRIVER_WRITE_FORMAT_USTAR \
| TPAX_DRIVER_WRITE_FORMAT_RUSTAR)
+#define TPAX_CACHE_MIN (1 << 12)
+#define TPAX_CACHE_MAX (1 << 24)
+
/* package info */
static const struct tpax_source_version tpax_src_version = {
TPAX_TAG_VER_MAJOR,
@@ -51,6 +55,9 @@ static const struct tpax_fd_ctx tpax_default_fdctx = {
.fdlog = (-1),
};
+/* fallback error description */
+static const char tpax_null_errdesc[] = "<no error description>";
+
struct tpax_driver_ctx_alloc {
struct argv_meta * meta;
struct tpax_driver_ctx_impl ctx;
@@ -74,6 +81,21 @@ static uint32_t tpax_argv_flags(uint32_t flags)
return ret;
}
+static const char * tpax_driver_errdesc(void)
+{
+ int lerrno;
+ const char * errstr;
+
+ lerrno = errno;
+ errno = 0;
+
+ errstr = strerror(lerrno);
+ errstr = errno ? tpax_null_errdesc : errstr;
+ errno = lerrno;
+
+ return errstr;
+}
+
static int tpax_driver_usage(
int fdout,
const char * program,
@@ -88,7 +110,7 @@ static int tpax_driver_usage(
"Synopsis:\n"
" %s [-d] [-f archive]\n"
" %s -r [-d] [-f archive]\n"
- " %s -w [−x format] [-b blocksize] [-dtv] [-H|-L] [-f archive]\n"
+ " %s -w [−x format] [-b blocksize] [-dtv] [-H|-L] [-f archive] [-s replstr]... \n"
" %s -r -w [-d]\n\n"
"Options:\n",
program,program,program,program,program);
@@ -169,8 +191,7 @@ static int tpax_driver_usage_copy_mode(
break;
default:
- if (!(errdesc = strerror(errno)))
- errdesc = "<no error description>";
+ errdesc = tpax_driver_errdesc();
tpax_dprintf(
fdout,
@@ -259,15 +280,7 @@ static int tpax_driver_error_archive_path(
struct argv_meta * meta,
bool fwrite)
{
- int lerrno;
- const char * errstr;
-
- lerrno = errno;
- errno = 0;
-
- errstr = strerror(lerrno);
- errstr = errno ? "" : errstr;
- errno = lerrno;
+ const char * errstr = tpax_driver_errdesc();
if (fwrite) {
tpax_dprintf(
@@ -322,17 +335,131 @@ static void tpax_set_archive_block_size(struct tpax_common_ctx * cctx)
cctx->blksize = TPAX_USTAR_BLOCK_SIZE;
}
+static int tpax_add_replstr(
+ struct argv_entry * entry,
+ struct tpax_replstr * replstr,
+ char ** mark)
+{
+ const char * src;
+ char * dst;
+ char sep;
+ int nsep;
+
+ /* non-null separator character */
+ if (!(sep = entry->arg[0]))
+ return -1;
+
+ /* exactly three separator characters */
+ for (nsep=1,src=&entry->arg[1]; *src; src++) {
+ if ((src[0] == '\\') && (src[1] == sep)) {
+ src++;
+
+ } else if (src[0] == sep) {
+ nsep++;
+ }
+ }
+
+ if (nsep != 3)
+ return -1;
+
+ /* regexp */
+ for (src=&entry->arg[1],dst=*mark; (*src != sep); src++) {
+ if ((src[0] == '\\') && (src[1] == sep))
+ src++;
+
+ *dst++ = *src;
+ }
+
+ replstr->replarg = entry->arg;
+ replstr->replstr = ++dst;
+ replstr->regexp = *mark;
+
+ /* replstr */
+ for (++src; (*src != sep); src++) {
+ if ((src[0] == '\\') && (src[1] == sep))
+ src++;
+
+ *dst++ = *src;
+ }
+
+ src++;
+ dst++;
+
+ *mark = dst;
+
+ /* flags */
+ if (src[0] && src[1] && src[2])
+ return -1;
+
+ if (src[0] && (src[0] == src[1]))
+ return -1;
+
+ if (src[0] && (src[0] != 'g') && (src[0] != 'p'))
+ return -1;
+
+ if (src[0] && src[1] && (src[1] != 'g') && (src[1] != 'p'))
+ return -1;
+
+ if (src[0] && ((src[0] == 'g') || (src[1] == 'g')))
+ replstr->flags |= TPAX_REPL_GLOBAL;
+
+ if (src[0] && ((src[0] == 'p') || (src[1] == 'p')))
+ replstr->flags |= TPAX_REPL_PRINT;
+
+ /* regex */
+ if (regcomp(&replstr->regex,replstr->regexp,0)) {
+ replstr->regexp = 0;
+ return -1;
+ }
+
+ return 0;
+}
+
+static int tpax_init_replstr_vector(
+ struct tpax_driver_ctx_impl * ctx,
+ struct argv_meta * meta)
+{
+ struct argv_entry * entry;
+ struct tpax_replstr * replstr;
+ char * mark;
+
+ if (!(replstr = ctx->replstrv))
+ return 0;
+
+ for (entry=meta->entries,mark=ctx->replstrs; entry->fopt || entry->arg; entry++) {
+ if (entry->tag == TAG_REPLSTR) {
+ if (tpax_add_replstr(entry,replstr,&mark) < 0)
+ return -1;
+
+ replstr++;
+ }
+ }
+
+ return 0;
+}
+
+static int tpax_driver_is_valid_keyval(struct argv_keyval * keyval)
+{
+ (void)keyval;
+ return 0;
+}
+
static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc(
struct argv_meta * meta,
const struct tpax_fd_ctx * fdctx,
const struct tpax_common_ctx * cctx,
- size_t nunits)
+ size_t nunits,
+ size_t nreplstr,
+ size_t sreplstr)
{
struct tpax_driver_ctx_alloc * ictx;
size_t size;
struct argv_entry * entry;
const char ** units;
int elements;
+ int nkeyval;
+ struct argv_keyval ** pkeyval;
+ struct argv_keyval * keyval;
size = sizeof(struct tpax_driver_ctx_alloc);
size += (nunits+1)*sizeof(const char *);
@@ -360,19 +487,49 @@ static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc(
if (!entry->fopt)
*units++ = entry->arg;
- if (cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE_COPY) {
- ictx->ctx.bufsize = TPAX_FILEIO_BUFLEN;
- ictx->ctx.bufaddr = mmap(
- 0,ictx->ctx.bufsize,
- PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS,
- -1,0);
+ for (entry=meta->entries,nkeyval=0; entry->fopt || entry->arg; entry++)
+ if (entry->keyv)
+ for (keyval=entry->keyv; keyval->keyword; keyval++)
+ nkeyval++;
- if (ictx->ctx.bufaddr == MAP_FAILED) {
- free(ictx);
- return 0;
- }
+ if (nkeyval && !(ictx->ctx.keyvalv = calloc(nkeyval+1,sizeof(*ictx->ctx.keyvalv)))) {
+ free(ictx);
+ return 0;
+ }
+
+ if (nreplstr && !(ictx->ctx.replstrv = calloc(++nreplstr,sizeof(*ictx->ctx.replstrv)))) {
+ free(ictx->ctx.keyvalv);
+ free(ictx);
+ return 0;
+ }
+
+ if (sreplstr && !(ictx->ctx.replstrs = calloc(sreplstr,1))) {
+ free(ictx->ctx.replstrv);
+ free(ictx->ctx.keyvalv);
+ free(ictx);
+ return 0;
+ }
+ if ((pkeyval = ictx->ctx.keyvalv))
+ for (entry=meta->entries; entry->fopt || entry->arg; entry++)
+ if (entry->keyv)
+ for (keyval=entry->keyv; keyval->keyword; keyval++)
+ *pkeyval++ = keyval;
+
+ ictx->ctx.bufsize = TPAX_FILEIO_BUFLEN;
+ ictx->ctx.bufaddr = mmap(
+ 0,ictx->ctx.bufsize,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS,
+ -1,0);
+
+ if (ictx->ctx.bufaddr == MAP_FAILED) {
+ free(ictx->ctx.keyvalv);
+ free(ictx);
+ return 0;
+ }
+
+ if (cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE_COPY) {
ictx->ctx.dirbuff = mmap(
0,TPAX_DIRENT_BUFLEN,
PROT_READ|PROT_WRITE,
@@ -381,6 +538,7 @@ static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc(
if (ictx->ctx.dirbuff == MAP_FAILED) {
munmap(ictx->ctx.bufaddr,ictx->ctx.bufsize);
+ free(ictx->ctx.keyvalv);
free(ictx);
return 0;
}
@@ -399,6 +557,77 @@ static int tpax_get_driver_ctx_fail(struct argv_meta * meta)
return -1;
}
+static int tpax_driver_keyval_error(
+ struct tpax_driver_ctx_impl * ctx,
+ struct argv_keyval * keyval,
+ const char * program)
+{
+ const char * equal;
+
+ switch (keyval->flags) {
+ case ARGV_KEYVAL_ASSIGN:
+ equal = "=";
+ break;
+
+ case ARGV_KEYVAL_OVERRIDE:
+ equal = ":=";
+ break;
+
+ default:
+ equal = "";
+ }
+
+ tpax_dprintf(
+ ctx->fdctx.fderr,
+ "%s: unsupported keyval argument (%s%s%s)\n",
+ program,keyval->keyword,equal,
+ keyval->value ? keyval->value : "");
+
+ tpax_lib_free_driver_ctx(&ctx->ctx);
+
+ return TPAX_ERROR;
+}
+
+static int tpax_driver_srcstat_error(
+ struct tpax_driver_ctx_impl * ctx,
+ const struct argv_entry * archive,
+ const char * program)
+{
+ const char * errstr = tpax_driver_errdesc();
+
+ if (archive) {
+ tpax_dprintf(
+ ctx->fdctx.fderr,
+ "%s: could not stat archive file '%s' (%s).\n",
+ program,archive->arg,errstr);
+ } else {
+ tpax_dprintf(
+ ctx->fdctx.fderr,
+ "%s: could not stat input source file <fd=%d> (%s).\n",
+ program,ctx->fdctx.fdin,errstr);
+ }
+
+ tpax_lib_free_driver_ctx(&ctx->ctx);
+
+ return TPAX_ERROR;
+}
+
+static int tpax_driver_cache_error(
+ struct tpax_driver_ctx_impl * ctx,
+ const char * program)
+{
+ const char * errstr = tpax_driver_errdesc();
+
+ tpax_dprintf(
+ ctx->fdctx.fderr,
+ "%s: failed to allocate source data cache (%s).\n",
+ program,errstr);
+
+ tpax_lib_free_driver_ctx(&ctx->ctx);
+
+ return TPAX_ERROR;
+}
+
int tpax_lib_get_driver_ctx(
char ** argv,
char ** envp,
@@ -413,8 +642,12 @@ int tpax_lib_get_driver_ctx(
struct argv_entry * entry;
struct argv_entry * archive;
struct argv_entry * operand;
+ struct argv_keyval ** pkeyval;
struct tpax_fd_ctx lfdctx;
size_t nunits;
+ size_t nreplstr;
+ size_t sreplstr;
+ size_t cachesize;
const char * program;
int fddst;
const char * ch;
@@ -438,6 +671,9 @@ int tpax_lib_get_driver_ctx(
program = argv_program_name(argv[0]);
memset(&cctx,0,sizeof(cctx));
+ nreplstr = 0;
+ sreplstr = 0;
+
cctx.drvflags = flags;
fddst = fdctx->fddst;
@@ -522,6 +758,12 @@ int tpax_lib_get_driver_ctx(
meta);
break;
+ case TAG_REPLSTR:
+ sreplstr += strlen(entry->arg);
+ sreplstr++;
+ nreplstr++;
+ break;
+
case TAG_RECURSE:
cctx.drvflags |= TPAX_DRIVER_DIR_MEMBER_RECURSE;
break;
@@ -544,6 +786,10 @@ int tpax_lib_get_driver_ctx(
cctx.drvflags |= TPAX_DRIVER_PAX_SYMLINK_ITEMS;
break;
+ case TAG_STRICT_DEVICE_ID:
+ cctx.drvflags |= TPAX_DRIVER_STRICT_DEVICE_ID;
+ break;
+
case TAG_STRICT_PATH:
cctx.drvflags |= TPAX_DRIVER_STRICT_PATH_INPUT;
break;
@@ -625,6 +871,8 @@ int tpax_lib_get_driver_ctx(
} else if (archive) {
memcpy(&lfdctx,fdctx,sizeof(*fdctx));
+ cctx.srcflags = TPAX_SOURCE_DATA_PENDING;
+
lfdctx.fdin = openat(
fdctx->fdcwd,
archive->arg,
@@ -636,7 +884,15 @@ int tpax_lib_get_driver_ctx(
program,archive->arg,
meta,false);
+ cctx.srcflags = TPAX_SOURCE_DATA_OPENED;
+
fdctx = &lfdctx;
+
+ } else if (cctx.drvflags & TPAX_DRIVER_EXEC_MODE_WRITE) {
+ cctx.srcflags = TPAX_SOURCE_DATA_NONE;
+
+ } else {
+ cctx.srcflags = TPAX_SOURCE_DATA_PENDING;
}
/* not implemented mode(s) */
@@ -679,22 +935,65 @@ int tpax_lib_get_driver_ctx(
return tpax_driver_error_not_implemented(
fdctx->fderr,program,"the pax format",meta);
- case TPAX_DRIVER_WRITE_FORMAT_CPIO:
- return tpax_driver_error_not_implemented(
- fdctx->fderr,program,"the cpio format",meta);
-
default:
break;
}
/* driver ctx */
- if (!(ctx = tpax_driver_ctx_alloc(meta,fdctx,&cctx,nunits))) {
+ if (!(ctx = tpax_driver_ctx_alloc(meta,fdctx,&cctx,nunits,nreplstr,sreplstr))) {
if (cctx.drvflags & TPAX_DRIVER_EXEC_MODE_COPY)
close(fddst);
return tpax_get_driver_ctx_fail(meta);
}
+ /* replstr validation and vector initialization */
+ if (tpax_init_replstr_vector(ctx,meta) < 0) {
+ tpax_lib_free_driver_ctx(&ctx->ctx);
+ return TPAX_ERROR;
+ }
+
+ /* keyval validation */
+ for (pkeyval=ctx->keyvalv; pkeyval && *pkeyval; pkeyval++)
+ if (!tpax_driver_is_valid_keyval(*pkeyval))
+ return tpax_driver_keyval_error(ctx,*pkeyval,program);
+
+ /* source data mapping (non-critical) */
+ if (cctx.srcflags) {
+ if (fstat(fdctx->fdin,&ctx->srcstat) < 0)
+ return tpax_driver_srcstat_error(ctx,archive,program);
+
+ ctx->mapsize = ctx->srcstat.st_size;
+ ctx->mapaddr = mmap(
+ 0,ctx->mapsize,
+ PROT_READ,MAP_PRIVATE,
+ fdctx->fdin,0);
+
+ if (ctx->mapaddr == MAP_FAILED) {
+ ctx->cctx.srcflags = TPAX_SOURCE_DATA_FILEIO;
+ ctx->mapaddr = 0;
+ ctx->mapsize = 0;
+ } else {
+ ctx->cctx.srcflags = TPAX_SOURCE_DATA_MAPPED;
+ }
+ }
+
+ /* allocate source data cache as needed */
+ if (ctx->cctx.srcflags == TPAX_SOURCE_DATA_FILEIO) {
+ cachesize = TPAX_CACHE_MAX;
+
+ for (; !ctx->cacheaddr && (cachesize >= TPAX_CACHE_MIN); )
+ if (!(ctx->cacheaddr = calloc(cachesize,1)))
+ cachesize >>= 1;
+
+ if (!ctx->cacheaddr)
+ return tpax_driver_cache_error(ctx,program);
+
+ ctx->cachemark = ctx->cacheaddr;
+ ctx->cachecap = &ctx->cacheaddr[cachesize];
+ }
+
+ /* all done */
if (archive) {
ctx->file = archive->arg;
ctx->ctx.file = &ctx->file;
@@ -713,6 +1012,8 @@ static void tpax_free_driver_ctx_impl(struct tpax_driver_ctx_alloc * ictx)
size_t size;
char ** ppref;
+ struct tpax_replstr * replstrv;
+
for (; ictx->ctx.dirents; ) {
next = ictx->ctx.dirents->next;
size = ictx->ctx.dirents->size;
@@ -721,6 +1022,24 @@ static void tpax_free_driver_ctx_impl(struct tpax_driver_ctx_alloc * ictx)
ictx->ctx.dirents = (struct tpax_dirent_buffer *)next;
}
+ for (replstrv=ictx->ctx.replstrv; replstrv && replstrv->regexp; replstrv++)
+ regfree(&replstrv->regex);
+
+ if (ictx->ctx.replstrv)
+ free(ictx->ctx.replstrv);
+
+ if (ictx->ctx.replstrs)
+ free(ictx->ctx.replstrs);
+
+ if (ictx->ctx.keyvalv)
+ free(ictx->ctx.keyvalv);
+
+ if (ictx->ctx.cacheaddr)
+ free(ictx->ctx.cacheaddr);
+
+ if (ictx->ctx.mapaddr)
+ munmap(ictx->ctx.mapaddr,ictx->ctx.mapsize);
+
if (ictx->ctx.bufaddr)
munmap(ictx->ctx.bufaddr,ictx->ctx.bufsize);
@@ -736,6 +1055,9 @@ static void tpax_free_driver_ctx_impl(struct tpax_driver_ctx_alloc * ictx)
if (ictx->ctx.direntv)
free(ictx->ctx.direntv);
+ if (ictx->ctx.cpiov)
+ free(ictx->ctx.cpiov);
+
argv_free(ictx->meta);
free(ictx);
}