diff options
Diffstat (limited to 'src/driver')
-rw-r--r-- | src/driver/tpax_driver_ctx.c | 376 |
1 files changed, 347 insertions, 29 deletions
diff --git a/src/driver/tpax_driver_ctx.c b/src/driver/tpax_driver_ctx.c index 79518f0..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; @@ -629,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, @@ -640,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) */ @@ -683,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; @@ -717,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; @@ -725,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); @@ -740,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); } |