diff options
Diffstat (limited to 'src/driver/tpax_driver_ctx.c')
-rw-r--r-- | src/driver/tpax_driver_ctx.c | 299 |
1 files changed, 257 insertions, 42 deletions
diff --git a/src/driver/tpax_driver_ctx.c b/src/driver/tpax_driver_ctx.c index 8ab684d..dff6ef6 100644 --- a/src/driver/tpax_driver_ctx.c +++ b/src/driver/tpax_driver_ctx.c @@ -86,9 +86,9 @@ static int tpax_driver_usage( snprintf(header,sizeof(header), "%s — topological pax implementation\n\n" "Synopsis:\n" - " %s [-d]\n" - " %s -r [-d]\n" - " %s -w [−x format] [-b blocksize] [-d]\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 -r -w [-d]\n\n" "Options:\n", program,program,program,program,program); @@ -112,9 +112,9 @@ static int tpax_driver_usage_exec_mode( tpax_dprintf( fdout, - "\nWhen using explicit (long) mode options, " + "\n%s: usage error: When using explicit (long) mode options, " "only one of --list, --read, --write, --copy " - "may be used.\n"); + "may be used.\n",program); return TPAX_USAGE; } @@ -125,19 +125,27 @@ static int tpax_driver_usage_copy_mode( const char * arg, const struct argv_option ** optv, struct argv_meta * meta, - struct argv_entry * operand) + struct argv_entry * operand, + struct argv_entry * archive) { const char * errdesc; - if (!operand) { + if (archive || !operand) { tpax_driver_usage( fdout,program, arg,optv,meta); - tpax_dprintf( - fdout, - "\nThe copy mode requires a destination " - "directory argument.\n\n"); + if (archive) { + tpax_dprintf( + fdout, + "\n%s: usage error: the __copy__ mode does not permit specifying " + "an archive path.\n\n",program); + } else { + tpax_dprintf( + fdout, + "\n%s: usage error: the __copy__ mode requires a destination " + "directory argument.\n\n",program); + } return TPAX_USAGE; } @@ -146,7 +154,7 @@ static int tpax_driver_usage_copy_mode( case ENOENT: tpax_dprintf( fdout, - "%s: error: " + "%s: file-system error: " "the destination directory '%s' " "does not exist.\n\n", program,operand->arg); @@ -155,7 +163,7 @@ static int tpax_driver_usage_copy_mode( case ENOTDIR: tpax_dprintf( fdout, - "%s: error: " + "%s: file-system error: " "'%s' is not a directory.\n\n", program,operand->arg); break; @@ -166,7 +174,7 @@ static int tpax_driver_usage_copy_mode( tpax_dprintf( fdout, - "%s: error: while opening the " + "%s: general error: while opening the " "destination directory '%s': %s.\n\n", program,operand->arg,errdesc); break; @@ -190,8 +198,8 @@ static int tpax_driver_usage_write_format( tpax_dprintf( fdout, - "\nArchive format may only be specified " - "in write mode.\n"); + "\n%s: usage error: Archive format may only be specified " + "in write mode.\n",program); return TPAX_USAGE; } @@ -200,17 +208,14 @@ static int tpax_driver_usage_block_size( int fdout, const char * program, const char * arg, - const struct argv_option ** optv, struct argv_meta * meta) { - tpax_driver_usage( - fdout,program, - arg,optv,meta); - tpax_dprintf( fdout, - "`%s' is not a valid positive decimal integer.\n", - arg); + "%s: usage error: the requested block size `%s' is not a positive decimal integer.\n", + program,arg); + + argv_free(meta); return TPAX_USAGE; } @@ -219,21 +224,70 @@ static int tpax_driver_usage_block_size_range( int fdout, const char * program, const char * arg, - const struct argv_option ** optv, struct argv_meta * meta) { - tpax_driver_usage( - fdout,program, - arg,optv,meta); + tpax_dprintf( + fdout, + "%s: usage error: `%s' is outside the specified range of 512 to 32256.\n", + program,arg); + + argv_free(meta); + return TPAX_USAGE; +} + +static int tpax_driver_usage_block_constraints( + int fdout, + const char * program, + const char * arg, + struct argv_meta * meta) +{ tpax_dprintf( fdout, - "`%s' is outside the specified range of 512 to 32256.\n", - arg); + "%s: usage error: the specified block size `%s' is not a multiple of 512 bytes.\n", + program,arg); + + argv_free(meta); return TPAX_USAGE; } +static int tpax_driver_error_archive_path( + int fdout, + const char * program, + const char * arg, + struct argv_meta * meta, + bool fwrite) +{ + int lerrno; + const char * errstr; + + lerrno = errno; + errno = 0; + + errstr = strerror(lerrno); + errstr = errno ? "" : errstr; + errno = lerrno; + + if (fwrite) { + tpax_dprintf( + fdout, + "%s: file-system error: archive file <%s> could not be created " + "or opened for writing (%s).\n", + program,arg,errstr); + } else { + tpax_dprintf( + fdout, + "%s: file-system error: archive file <%s> could not be opened " + "for reading (%s).\n", + program,arg,errstr); + } + + argv_free(meta); + + return TPAX_FATAL; +} + static int tpax_driver_error_not_implemented( int fdout, const char * program, @@ -250,6 +304,30 @@ static int tpax_driver_error_not_implemented( return TPAX_FATAL; } +static void tpax_set_archive_block_size(struct tpax_common_ctx * cctx) +{ + if (cctx->blksize) + (void)0; + + else if (cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_PAX) + cctx->blksize = TPAX_PAX_BLOCK_SIZE; + + else if (cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_CPIO) + cctx->blksize = TPAX_CPIO_BLOCK_SIZE; + + else if (cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_USTAR) + cctx->blksize = TPAX_USTAR_BLOCK_SIZE; + + else if (cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_RUSTAR) + cctx->blksize = TPAX_USTAR_BLOCK_SIZE; +} + +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, @@ -261,6 +339,9 @@ static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc( 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 *); @@ -288,6 +369,22 @@ static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc( if (!entry->fopt) *units++ = entry->arg; + for (entry=meta->entries,nkeyval=0; entry->fopt || entry->arg; entry++) + if (entry->keyv) + for (keyval=entry->keyv; keyval->keyword; keyval++) + nkeyval++; + + if (nkeyval && !(ictx->ctx.keyvalv = calloc(nkeyval+1,sizeof(*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; + if (cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE_COPY) { ictx->ctx.bufsize = TPAX_FILEIO_BUFLEN; ictx->ctx.bufaddr = mmap( @@ -297,24 +394,27 @@ static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc( -1,0); if (ictx->ctx.bufaddr == MAP_FAILED) { + free(ictx->ctx.keyvalv); free(ictx); return 0; } - if (cctx->drvflags & TPAX_DRIVER_DIR_MEMBER_RECURSE) - ictx->ctx.dirbuff = mmap( - 0,TPAX_DIRENT_BUFLEN, - PROT_READ|PROT_WRITE, - MAP_PRIVATE|MAP_ANONYMOUS, - -1,0); + ictx->ctx.dirbuff = mmap( + 0,TPAX_DIRENT_BUFLEN, + PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, + -1,0); if (ictx->ctx.dirbuff == MAP_FAILED) { munmap(ictx->ctx.bufaddr,ictx->ctx.bufsize); + free(ictx->ctx.keyvalv); free(ictx); return 0; } } + tpax_set_archive_block_size(&ictx->ctx.cctx); + ictx->ctx.ctx.units = ictx->units; ictx->ctx.ctx.errv = ictx->ctx.errinfp; return &ictx->ctx; @@ -326,6 +426,37 @@ 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; +} + int tpax_lib_get_driver_ctx( char ** argv, char ** envp, @@ -338,7 +469,10 @@ int tpax_lib_get_driver_ctx( const struct argv_option * optv[TPAX_OPTV_ELEMENTS]; struct argv_meta * meta; struct argv_entry * entry; + struct argv_entry * archive; struct argv_entry * operand; + struct argv_keyval ** pkeyval; + struct tpax_fd_ctx lfdctx; size_t nunits; const char * program; int fddst; @@ -358,6 +492,7 @@ int tpax_lib_get_driver_ctx( return -1; nunits = 0; + archive = 0; operand = 0; program = argv_program_name(argv[0]); memset(&cctx,0,sizeof(cctx)); @@ -381,6 +516,10 @@ int tpax_lib_get_driver_ctx( cctx.drvflags |= TPAX_DRIVER_VERSION; break; + case TAG_VERBOSE: + cctx.drvflags |= TPAX_DRIVER_VERBOSE; + break; + case TAG_LIST: cctx.drvflags |= TPAX_DRIVER_EXEC_MODE_LIST; break; @@ -397,6 +536,10 @@ int tpax_lib_get_driver_ctx( cctx.drvflags |= TPAX_DRIVER_EXEC_MODE_COPY; break; + case TAG_FILE: + archive = entry; + break; + case TAG_FORMAT: cctx.drvflags &= ~(uint64_t)(TPAX_DRIVER_WRITE_FORMAT_MASK); @@ -419,17 +562,23 @@ int tpax_lib_get_driver_ctx( for (; *ch; ch++) if ((*ch < '0') || (*ch > '9')) return tpax_driver_usage_block_size( - fdctx->fdout, + fdctx->fderr, program,entry->arg, - optv,meta); + meta); cctx.blksize = atoi(entry->arg); if ((cctx.blksize < 512) || (cctx.blksize > 32256)) return tpax_driver_usage_block_size_range( - fdctx->fdout, + fdctx->fderr, program,entry->arg, - optv,meta); + meta); + + if (cctx.blksize % 512) + return tpax_driver_usage_block_constraints( + fdctx->fderr, + program,entry->arg, + meta); break; case TAG_RECURSE: @@ -440,6 +589,24 @@ int tpax_lib_get_driver_ctx( cctx.drvflags &= ~(uintptr_t)TPAX_DRIVER_DIR_MEMBER_RECURSE; break; + case TAG_PRESERVE_ATIME: + cctx.drvflags |= TPAX_DRIVER_PRESERVE_ATIME; + break; + + case TAG_PAX_SYMLINK_ARGS: + cctx.drvflags |= TPAX_DRIVER_PAX_SYMLINK_ARGS; + cctx.drvflags &= ~(uint64_t)TPAX_DRIVER_PAX_SYMLINK_ITEMS; + break; + + case TAG_PAX_SYMLINK_ITEMS: + cctx.drvflags |= TPAX_DRIVER_PAX_SYMLINK_ARGS; + 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; @@ -482,11 +649,11 @@ int tpax_lib_get_driver_ctx( /* copy mode: destination directory */ if (cctx.drvflags & TPAX_DRIVER_EXEC_MODE_COPY) { - if (!operand) + if (archive || !operand) return tpax_driver_usage_copy_mode( fdctx->fderr, program,entry->arg, - optv,meta,operand); + optv,meta,operand,archive); fddst = openat( fdctx->fdcwd, @@ -497,7 +664,42 @@ int tpax_lib_get_driver_ctx( return tpax_driver_usage_copy_mode( fdctx->fderr, program,entry->arg, - optv,meta,operand); + optv,meta,operand,archive); + } + + /* archive path */ + if (archive && (cctx.drvflags & TPAX_DRIVER_EXEC_MODE_WRITE)) { + memcpy(&lfdctx,fdctx,sizeof(*fdctx)); + + lfdctx.fdout = openat( + fdctx->fdcwd, + archive->arg, + O_WRONLY|O_CREAT|O_TRUNC, + 0644); + + if (lfdctx.fdout < 0) + return tpax_driver_error_archive_path( + fdctx->fderr, + program,archive->arg, + meta,true); + + fdctx = &lfdctx; + + } else if (archive) { + memcpy(&lfdctx,fdctx,sizeof(*fdctx)); + + lfdctx.fdin = openat( + fdctx->fdcwd, + archive->arg, + O_RDONLY,0); + + if (lfdctx.fdin < 0) + return tpax_driver_error_archive_path( + fdctx->fderr, + program,archive->arg, + meta,false); + + fdctx = &lfdctx; } /* not implemented mode(s) */ @@ -556,6 +758,16 @@ int tpax_lib_get_driver_ctx( return tpax_get_driver_ctx_fail(meta); } + /* keyval validation */ + for (pkeyval=ctx->keyvalv; pkeyval && *pkeyval; pkeyval++) + if (!tpax_driver_is_valid_keyval(*pkeyval)) + return tpax_driver_keyval_error(ctx,*pkeyval,program); + + if (archive) { + ctx->file = archive->arg; + ctx->ctx.file = &ctx->file; + } + ctx->ctx.program = program; ctx->ctx.cctx = &ctx->cctx; @@ -577,6 +789,9 @@ static void tpax_free_driver_ctx_impl(struct tpax_driver_ctx_alloc * ictx) ictx->ctx.dirents = (struct tpax_dirent_buffer *)next; } + if (ictx->ctx.keyvalv) + free(ictx->ctx.keyvalv); + if (ictx->ctx.bufaddr) munmap(ictx->ctx.bufaddr,ictx->ctx.bufsize); |