diff options
Diffstat (limited to 'src/driver')
-rw-r--r-- | src/driver/tpax_amain.c | 31 | ||||
-rw-r--r-- | src/driver/tpax_driver_ctx.c | 260 | ||||
-rw-r--r-- | src/driver/tpax_unit_ctx.c | 8 |
3 files changed, 238 insertions, 61 deletions
diff --git a/src/driver/tpax_amain.c b/src/driver/tpax_amain.c index b11dd68..429633e 100644 --- a/src/driver/tpax_amain.c +++ b/src/driver/tpax_amain.c @@ -1,6 +1,6 @@ /**************************************************************/ /* tpax: a topological pax implementation */ -/* Copyright (C) 2020--2021 SysDeer Technologies, LLC */ +/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ /**************************************************************/ @@ -38,7 +38,7 @@ static ssize_t tpax_version(struct tpax_driver_ctx * dctx, int fdout) const struct tpax_source_version * verinfo; const char * const * verclr; - verinfo = tpax_source_version(); + verinfo = tpax_api_source_version(); verclr = isatty(fdout) ? tpax_ver_color : tpax_ver_plain; return tpax_dprintf( @@ -54,13 +54,27 @@ static void tpax_perform_unit_actions( struct tpax_unit_ctx * uctx) { if (dctx->cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE) - tpax_archive_append(dctx,uctx,0); + tpax_archive_enqueue(dctx,uctx); +} + +static void tpax_archive_write_and_seal( + const struct tpax_driver_ctx * dctx) +{ + if (tpax_archive_write(dctx) == TPAX_OK) + tpax_archive_seal(dctx); +} + +static void tpax_perform_archive_actions( + const struct tpax_driver_ctx * dctx) +{ + if (dctx->cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE) + tpax_archive_write_and_seal(dctx); } static int tpax_exit(struct tpax_driver_ctx * dctx, int ret) { tpax_output_error_vector(dctx); - tpax_free_driver_ctx(dctx); + tpax_lib_free_driver_ctx(dctx); return ret; } @@ -78,7 +92,7 @@ int tpax_main(char ** argv, char ** envp, const struct tpax_fd_ctx * fdctx) fdout = fdctx ? fdctx->fdout : STDOUT_FILENO; fdcwd = fdctx ? fdctx->fdcwd : AT_FDCWD; - if ((ret = tpax_get_driver_ctx(argv,envp,flags,fdctx,&dctx))) + if ((ret = tpax_lib_get_driver_ctx(argv,envp,flags,fdctx,&dctx))) return (ret == TPAX_USAGE) ? !argv || !argv[0] || !argv[1] : TPAX_ERROR; @@ -88,14 +102,13 @@ int tpax_main(char ** argv, char ** envp, const struct tpax_fd_ctx * fdctx) return tpax_exit(dctx,TPAX_ERROR); for (unit=dctx->units; *unit; unit++) { - if (!(tpax_get_unit_ctx(dctx,fdcwd,*unit,&uctx))) { + if (!(tpax_lib_get_unit_ctx(dctx,fdcwd,*unit,&uctx))) { tpax_perform_unit_actions(dctx,uctx); - tpax_free_unit_ctx(uctx); + tpax_lib_free_unit_ctx(uctx); } } - if ((dctx->cctx->drvflags & TPAX_DRIVER_EXEC_MODE_WRITE) && dctx->units[0]) - tpax_archive_seal(dctx); + tpax_perform_archive_actions(dctx); return tpax_exit(dctx,dctx->errv[0] ? TPAX_ERROR : TPAX_OK); } diff --git a/src/driver/tpax_driver_ctx.c b/src/driver/tpax_driver_ctx.c index 0a92537..79518f0 100644 --- a/src/driver/tpax_driver_ctx.c +++ b/src/driver/tpax_driver_ctx.c @@ -1,6 +1,6 @@ /**************************************************************/ /* tpax: a topological pax implementation */ -/* Copyright (C) 2020--2021 SysDeer Technologies, LLC */ +/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ /**************************************************************/ @@ -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,24 @@ 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 struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc( struct argv_meta * meta, const struct tpax_fd_ctx * fdctx, @@ -276,6 +348,12 @@ static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc( ictx->ctx.errinfp = &ictx->ctx.erriptr[0]; ictx->ctx.erricap = &ictx->ctx.erriptr[--elements]; + elements = sizeof(ictx->ctx.prefptr) / sizeof(*ictx->ctx.prefptr); + + ictx->ctx.prefixv = &ictx->ctx.prefptr[0]; + ictx->ctx.prefixp = &ictx->ctx.prefptr[0]; + ictx->ctx.prefcap = &ictx->ctx.prefptr[--elements]; + ictx->meta = meta; for (entry=meta->entries,units=ictx->units; entry->fopt || entry->arg; entry++) @@ -295,12 +373,11 @@ static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc( 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); @@ -309,6 +386,8 @@ static struct tpax_driver_ctx_impl * tpax_driver_ctx_alloc( } } + tpax_set_archive_block_size(&ictx->ctx.cctx); + ictx->ctx.ctx.units = ictx->units; ictx->ctx.ctx.errv = ictx->ctx.errinfp; return &ictx->ctx; @@ -320,7 +399,7 @@ static int tpax_get_driver_ctx_fail(struct argv_meta * meta) return -1; } -int tpax_get_driver_ctx( +int tpax_lib_get_driver_ctx( char ** argv, char ** envp, uint32_t flags, @@ -332,7 +411,9 @@ int tpax_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; @@ -352,6 +433,7 @@ int tpax_get_driver_ctx( return -1; nunits = 0; + archive = 0; operand = 0; program = argv_program_name(argv[0]); memset(&cctx,0,sizeof(cctx)); @@ -375,6 +457,10 @@ int tpax_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; @@ -391,6 +477,10 @@ int tpax_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); @@ -413,17 +503,23 @@ int tpax_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: @@ -434,6 +530,24 @@ int tpax_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; @@ -476,11 +590,11 @@ int tpax_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, @@ -491,7 +605,42 @@ int tpax_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) */ @@ -550,6 +699,11 @@ int tpax_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; @@ -561,6 +715,7 @@ static void tpax_free_driver_ctx_impl(struct tpax_driver_ctx_alloc * ictx) { void * next; size_t size; + char ** ppref; for (; ictx->ctx.dirents; ) { next = ictx->ctx.dirents->next; @@ -576,11 +731,20 @@ static void tpax_free_driver_ctx_impl(struct tpax_driver_ctx_alloc * ictx) if (ictx->ctx.dirbuff) munmap(ictx->ctx.dirbuff,TPAX_DIRENT_BUFLEN); + for (ppref=ictx->ctx.prefixv; *ppref; ppref++) + free(*ppref); + + if (ictx->ctx.prefixv != ictx->ctx.prefptr) + free(ictx->ctx.prefixv); + + if (ictx->ctx.direntv) + free(ictx->ctx.direntv); + argv_free(ictx->meta); free(ictx); } -void tpax_free_driver_ctx(struct tpax_driver_ctx * ctx) +void tpax_lib_free_driver_ctx(struct tpax_driver_ctx * ctx) { struct tpax_driver_ctx_alloc * ictx; uintptr_t addr; @@ -593,12 +757,12 @@ void tpax_free_driver_ctx(struct tpax_driver_ctx * ctx) } } -const struct tpax_source_version * tpax_source_version(void) +const struct tpax_source_version * tpax_api_source_version(void) { return &tpax_src_version; } -int tpax_get_driver_fdctx( +int tpax_lib_get_driver_fdctx( const struct tpax_driver_ctx * dctx, struct tpax_fd_ctx * fdctx) { @@ -616,7 +780,7 @@ int tpax_get_driver_fdctx( return 0; } -int tpax_set_driver_fdctx( +int tpax_lib_set_driver_fdctx( struct tpax_driver_ctx * dctx, const struct tpax_fd_ctx * fdctx) { diff --git a/src/driver/tpax_unit_ctx.c b/src/driver/tpax_unit_ctx.c index b272257..5c4cf80 100644 --- a/src/driver/tpax_unit_ctx.c +++ b/src/driver/tpax_unit_ctx.c @@ -1,6 +1,6 @@ /**************************************************************/ /* tpax: a topological pax implementation */ -/* Copyright (C) 2020--2021 SysDeer Technologies, LLC */ +/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */ /* Released under GPLv2 and GPLv3; see COPYING.TPAX. */ /**************************************************************/ @@ -25,7 +25,7 @@ static int tpax_free_unit_ctx_impl(struct tpax_unit_ctx_impl * ctx, int ret) return ret; } -int tpax_get_unit_ctx( +int tpax_lib_get_unit_ctx( const struct tpax_driver_ctx * dctx, int fdat, const char * path, @@ -65,7 +65,7 @@ int tpax_get_unit_ctx( } ctx->path = path; - ctx->link = ctx->linkbuf; + ctx->link = ctx->linkbuf[0] ? ctx->linkbuf : 0; ctx->uctx.path = &ctx->path; ctx->uctx.link = &ctx->link; @@ -76,7 +76,7 @@ int tpax_get_unit_ctx( return 0; } -void tpax_free_unit_ctx(struct tpax_unit_ctx * ctx) +void tpax_lib_free_unit_ctx(struct tpax_unit_ctx * ctx) { struct tpax_unit_ctx_impl * ictx; uintptr_t addr; |