summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--include/tpax/tpax.h1
-rw-r--r--src/driver/tpax_driver_ctx.c109
-rw-r--r--src/internal/tpax_driver_impl.h2
-rw-r--r--src/skin/tpax_skin_default.c6
4 files changed, 109 insertions, 9 deletions
diff --git a/include/tpax/tpax.h b/include/tpax/tpax.h
index 8822ee1..172c7ae 100644
--- a/include/tpax/tpax.h
+++ b/include/tpax/tpax.h
@@ -117,6 +117,7 @@ struct tpax_driver_ctx {
const char ** units;
const char * program;
const char * module;
+ const char * const * file;
const struct tpax_common_ctx * cctx;
struct tpax_error_info ** errv;
const off_t * cpos;
diff --git a/src/driver/tpax_driver_ctx.c b/src/driver/tpax_driver_ctx.c
index 6497126..7cae777 100644
--- a/src/driver/tpax_driver_ctx.c
+++ b/src/driver/tpax_driver_ctx.c
@@ -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: the __copy__ mode does not permit specifying "
+ "an archive path.\n\n",program);
+ } else {
+ tpax_dprintf(
+ fdout,
+ "\n%s: the __copy__ mode requires a destination "
+ "directory argument.\n\n",program);
+ }
return TPAX_USAGE;
}
@@ -234,6 +242,42 @@ static int tpax_driver_usage_block_size_range(
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: archive file <%s> could not be created "
+ "or opened for writing (%s).\n",
+ program,arg,errstr);
+ } else {
+ tpax_dprintf(
+ fdout,
+ "%s: 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,
@@ -337,7 +381,9 @@ 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 tpax_fd_ctx lfdctx;
size_t nunits;
const char * program;
int fddst;
@@ -357,6 +403,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));
@@ -396,6 +443,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);
@@ -481,11 +532,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,
@@ -496,7 +547,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) */
@@ -555,6 +641,11 @@ int tpax_lib_get_driver_ctx(
return tpax_get_driver_ctx_fail(meta);
}
+ if (archive) {
+ ctx->file = archive->arg;
+ ctx->ctx.file = &ctx->file;
+ }
+
ctx->ctx.program = program;
ctx->ctx.cctx = &ctx->cctx;
diff --git a/src/internal/tpax_driver_impl.h b/src/internal/tpax_driver_impl.h
index cd734b0..1333f25 100644
--- a/src/internal/tpax_driver_impl.h
+++ b/src/internal/tpax_driver_impl.h
@@ -38,6 +38,7 @@ enum app_tags {
TAG_READ,
TAG_WRITE,
TAG_COPY,
+ TAG_FILE,
TAG_FORMAT,
TAG_BLKSIZE,
TAG_RECURSE,
@@ -65,6 +66,7 @@ struct tpax_dirent_buffer {
};
struct tpax_driver_ctx_impl {
+ const char * file;
struct tpax_common_ctx cctx;
struct tpax_driver_ctx ctx;
struct tpax_fd_ctx fdctx;
diff --git a/src/skin/tpax_skin_default.c b/src/skin/tpax_skin_default.c
index 1db63c8..a385aac 100644
--- a/src/skin/tpax_skin_default.c
+++ b/src/skin/tpax_skin_default.c
@@ -28,6 +28,12 @@ const tpax_hidden struct argv_option tpax_default_options[] = {
"copy mode (copy specified files "
"to a specified destination directory)"},
+ {"Wfile", 'f',TAG_FILE,ARGV_OPTARG_REQUIRED,
+ ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_EQUAL,
+ 0,"<ARCHIVE>",
+ "read from (in read or list modes), "
+ "or write to (in write mode) the specified %s "
+ "after (in write mode) creating it as necessary"},
{"Wformat", 'x',TAG_FORMAT,ARGV_OPTARG_REQUIRED,
ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_EQUAL,