summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/driver/tpax_amain.c31
-rw-r--r--src/driver/tpax_driver_ctx.c242
-rw-r--r--src/driver/tpax_unit_ctx.c8
-rw-r--r--src/internal/argv/argv.h16
-rw-r--r--src/internal/tpax_dprintf_impl.c6
-rw-r--r--src/internal/tpax_driver_impl.h64
-rw-r--r--src/internal/tpax_errinfo_impl.c5
-rw-r--r--src/internal/tpax_errinfo_impl.h2
-rw-r--r--src/internal/tpax_ftime_impl.c48
-rw-r--r--src/internal/tpax_ftime_impl.h24
-rw-r--r--src/internal/tpax_getdents_impl.h2
-rw-r--r--src/internal/tpax_readlink_impl.h2
-rw-r--r--src/internal/tpax_tmpfile_impl.c28
-rw-r--r--src/internal/tpax_visibility_impl.h26
-rw-r--r--src/io/tpax_create_memory_snapshot.c (renamed from src/logic/tpax_file_create_memory_snapshot.c)16
-rw-r--r--src/io/tpax_create_tmpfs_snapshot.c (renamed from src/logic/tpax_file_create_tmpfs_snapshot.c)18
-rw-r--r--src/logic/tpax_archive_append.c709
-rw-r--r--src/logic/tpax_archive_enqueue.c475
-rw-r--r--src/logic/tpax_archive_reset.c59
-rw-r--r--src/logic/tpax_archive_write.c306
-rw-r--r--src/logic/tpax_queue_vector.c95
-rw-r--r--src/meta/tpax_init_ustar_header.c (renamed from src/logic/tpax_init_ustar_header.c)4
-rw-r--r--src/output/tpax_output_error.c2
-rw-r--r--src/skin/tpax_skin_default.c59
-rw-r--r--src/tpax.c2
-rw-r--r--src/util/tpax_path_copy.c (renamed from src/helper/tpax_path_copy.c)4
-rw-r--r--src/util/tpax_stat_compare.c (renamed from src/helper/tpax_stat_compare.c)4
27 files changed, 1410 insertions, 847 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..e8ecb9e 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] [-d] [-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));
@@ -391,6 +473,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 +499,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 +526,10 @@ 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_STRICT_PATH:
cctx.drvflags |= TPAX_DRIVER_STRICT_PATH_INPUT;
break;
@@ -476,11 +572,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 +587,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 +681,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 +697,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 +713,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 +739,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 +762,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;
diff --git a/src/internal/argv/argv.h b/src/internal/argv/argv.h
index d66440c..e6051cf 100644
--- a/src/internal/argv/argv.h
+++ b/src/internal/argv/argv.h
@@ -833,6 +833,7 @@ static void argv_usage_impl(
{
const struct argv_option ** optv;
const struct argv_option * option;
+ int nlong;
bool fshort,flong,fboth;
size_t len,optlen,desclen;
char cache;
@@ -865,7 +866,7 @@ static void argv_usage_impl(
if (header)
argv_dprintf(fd,"%s",header);
- for (optlen=0,optv=options; *optv; optv++) {
+ for (optlen=0,nlong=0,optv=options; *optv; optv++) {
option = *optv;
/* indent + comma */
@@ -884,6 +885,11 @@ static void argv_usage_impl(
/* optlen */
if (len > optlen)
optlen = len;
+
+ /* long (vs. hybrid-only) option? */
+ if (option->long_name)
+ if (!(option->flags & ARGV_OPTION_HYBRID_ONLY))
+ nlong++;
}
if (optlen >= optcap) {
@@ -904,7 +910,7 @@ static void argv_usage_impl(
/* color */
if (fcolor) {
color = (color == ccyan) ? cblue : ccyan;
- argv_dprintf(fd,color);
+ argv_dprintf(fd,color,0);
}
/* description, using either paradigm or argname if applicable */
@@ -916,7 +922,11 @@ static void argv_usage_impl(
/* long/hybrid option prefix (-/--) */
prefix = option->flags & ARGV_OPTION_HYBRID_ONLY
- ? " -" : "--";
+ ? " -" : " --";
+
+ /* avoid extra <stace> when all long opts are hybrid-only */
+ if (nlong == 0)
+ prefix++;
/* option string */
if (fboth && option->short_name && option->long_name)
diff --git a/src/internal/tpax_dprintf_impl.c b/src/internal/tpax_dprintf_impl.c
index b8d2b0b..2bc83a8 100644
--- a/src/internal/tpax_dprintf_impl.c
+++ b/src/internal/tpax_dprintf_impl.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. */
/**************************************************************/
@@ -10,7 +10,9 @@
#include <unistd.h>
#include <errno.h>
-int tpax_dprintf(int fd, const char * fmt, ...)
+#include "tpax_visibility_impl.h"
+
+tpax_hidden int tpax_dprintf(int fd, const char * fmt, ...)
{
int ret;
int cnt;
diff --git a/src/internal/tpax_driver_impl.h b/src/internal/tpax_driver_impl.h
index 5fabb0a..1e898e9 100644
--- a/src/internal/tpax_driver_impl.h
+++ b/src/internal/tpax_driver_impl.h
@@ -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. */
/**************************************************************/
@@ -26,6 +26,9 @@
(TPAX_DRIVER_EXEC_MODE_WRITE | \
TPAX_DRIVER_EXEC_MODE_COPY)
+#define TPAX_ITEM_EXPLICIT 0X1
+#define TPAX_ITEM_IMPLICIT 0X2
+
extern const struct argv_option tpax_default_options[];
enum app_tags {
@@ -35,18 +38,22 @@ enum app_tags {
TAG_READ,
TAG_WRITE,
TAG_COPY,
+ TAG_FILE,
TAG_FORMAT,
TAG_BLKSIZE,
TAG_RECURSE,
TAG_NORECURSE,
TAG_STRICT_PATH,
TAG_PURE_PATH,
+ TAG_PRESERVE_ATIME,
};
struct tpax_dirent {
int fdat;
int depth;
+ int flags;
size_t nsize;
+ const char * prefix;
const struct tpax_dirent * parent;
struct dirent dirent;
};
@@ -60,6 +67,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;
@@ -69,10 +77,17 @@ struct tpax_driver_ctx_impl {
struct tpax_error_info ** erricap;
struct tpax_error_info * erriptr[64];
struct tpax_error_info erribuf[64];
+ char ** prefixv;
+ char ** prefixp;
+ char ** prefcap;
+ char * prefptr[64];
+ struct tpax_dirent ** direntv;
struct tpax_dirent_buffer * dirents;
+ struct tpax_dirent * dirmark;
void * dirbuff;
void * bufaddr;
size_t bufsize;
+ size_t nqueued;
off_t cpos;
};
@@ -143,42 +158,42 @@ static inline void tpax_driver_set_ectx(
static inline int tpax_driver_fdin(const struct tpax_driver_ctx * dctx)
{
struct tpax_fd_ctx fdctx;
- tpax_get_driver_fdctx(dctx,&fdctx);
+ tpax_lib_get_driver_fdctx(dctx,&fdctx);
return fdctx.fdin;
}
static inline int tpax_driver_fdout(const struct tpax_driver_ctx * dctx)
{
struct tpax_fd_ctx fdctx;
- tpax_get_driver_fdctx(dctx,&fdctx);
+ tpax_lib_get_driver_fdctx(dctx,&fdctx);
return fdctx.fdout;
}
static inline int tpax_driver_fderr(const struct tpax_driver_ctx * dctx)
{
struct tpax_fd_ctx fdctx;
- tpax_get_driver_fdctx(dctx,&fdctx);
+ tpax_lib_get_driver_fdctx(dctx,&fdctx);
return fdctx.fderr;
}
static inline int tpax_driver_fdlog(const struct tpax_driver_ctx * dctx)
{
struct tpax_fd_ctx fdctx;
- tpax_get_driver_fdctx(dctx,&fdctx);
+ tpax_lib_get_driver_fdctx(dctx,&fdctx);
return fdctx.fdlog;
}
static inline int tpax_driver_fdcwd(const struct tpax_driver_ctx * dctx)
{
struct tpax_fd_ctx fdctx;
- tpax_get_driver_fdctx(dctx,&fdctx);
+ tpax_lib_get_driver_fdctx(dctx,&fdctx);
return fdctx.fdcwd;
}
static inline int tpax_driver_fddst(const struct tpax_driver_ctx * dctx)
{
struct tpax_fd_ctx fdctx;
- tpax_get_driver_fdctx(dctx,&fdctx);
+ tpax_lib_get_driver_fdctx(dctx,&fdctx);
return fdctx.fddst;
}
@@ -203,6 +218,21 @@ static inline struct tpax_dirent_buffer * tpax_get_driver_dirents(const struct t
return ictx->dirents;
}
+static inline struct tpax_dirent * tpax_get_driver_dirmark(const struct tpax_driver_ctx * dctx)
+{
+ struct tpax_driver_ctx_impl * ictx;
+ ictx = tpax_get_driver_ictx(dctx);
+ return ictx->dirmark;
+}
+
+static inline void tpax_set_driver_dirmark(const struct tpax_driver_ctx * dctx, struct tpax_dirent * dirent)
+{
+ struct tpax_driver_ctx_impl * ictx;
+ ictx = tpax_get_driver_ictx(dctx);
+ ictx->dirmark = dirent;
+ ictx->nqueued++;
+}
+
static inline off_t tpax_get_unit_hpos(const struct tpax_unit_ctx * uctx)
{
struct tpax_unit_ctx_impl * ictx;
@@ -231,22 +261,10 @@ static inline void tpax_set_unit_dpos(const struct tpax_unit_ctx * uctx, off_t d
ictx->dpos = dpos;
}
-static inline ssize_t tpax_get_archive_block_size(const struct tpax_driver_ctx * dctx)
-{
- if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_PAX)
- return TPAX_PAX_BLOCK_SIZE;
-
- else if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_CPIO)
- return TPAX_CPIO_BLOCK_SIZE;
-
- else if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_USTAR)
- return TPAX_USTAR_BLOCK_SIZE;
+int tpax_update_queue_vector(const struct tpax_driver_ctx * dctx);
- else if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_RUSTAR)
- return TPAX_USTAR_BLOCK_SIZE;
-
- else
- return 0;
-}
+const char * tpax_queue_item_full_path(
+ const struct tpax_driver_ctx *,
+ const struct tpax_dirent *);
#endif
diff --git a/src/internal/tpax_errinfo_impl.c b/src/internal/tpax_errinfo_impl.c
index 5fd2247..50a99a5 100644
--- a/src/internal/tpax_errinfo_impl.c
+++ b/src/internal/tpax_errinfo_impl.c
@@ -1,14 +1,15 @@
/**************************************************************/
/* 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. */
/**************************************************************/
#include <tpax/tpax.h>
#include "tpax_driver_impl.h"
#include "tpax_errinfo_impl.h"
+#include "tpax_visibility_impl.h"
-int tpax_record_error(
+tpax_hidden int tpax_record_error(
const struct tpax_driver_ctx * dctx,
int esyscode,
int elibcode,
diff --git a/src/internal/tpax_errinfo_impl.h b/src/internal/tpax_errinfo_impl.h
index 99b416b..e8151c5 100644
--- a/src/internal/tpax_errinfo_impl.h
+++ b/src/internal/tpax_errinfo_impl.h
@@ -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. */
/**************************************************************/
diff --git a/src/internal/tpax_ftime_impl.c b/src/internal/tpax_ftime_impl.c
new file mode 100644
index 0000000..19c6d7b
--- /dev/null
+++ b/src/internal/tpax_ftime_impl.c
@@ -0,0 +1,48 @@
+/**************************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/**************************************************************/
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include "tpax_ftime_impl.h"
+#include "tpax_driver_impl.h"
+#include "tpax_visibility_impl.h"
+
+tpax_hidden void tpax_ftime_restore(
+ const struct tpax_driver_ctx * dctx,
+ int fd,
+ const struct stat * refst)
+{
+ struct timespec ts[2];
+
+ if (dctx->cctx->drvflags & TPAX_DRIVER_PRESERVE_ATIME) {
+ ts[0].tv_sec = refst->st_atim.tv_sec;
+ ts[0].tv_nsec = refst->st_atim.tv_nsec;
+ } else {
+ ts[0].tv_nsec = UTIME_OMIT;
+ }
+
+ if (dctx->cctx->drvflags & TPAX_DRIVER_PRESERVE_MTIME) {
+ ts[1].tv_sec = refst->st_mtim.tv_sec;
+ ts[1].tv_nsec = refst->st_mtim.tv_nsec;
+ } else {
+ ts[1].tv_nsec = UTIME_OMIT;
+ }
+
+ if ((ts[0].tv_nsec != UTIME_OMIT) || (ts[1].tv_nsec != UTIME_OMIT)) {
+ futimens(fd,ts);
+ }
+}
+
+tpax_hidden void tpax_ftime_restore_and_close(
+ const struct tpax_driver_ctx * dctx,
+ int fd,
+ const struct stat * refst)
+{
+ tpax_ftime_restore(dctx,fd,refst);
+ close(fd);
+}
diff --git a/src/internal/tpax_ftime_impl.h b/src/internal/tpax_ftime_impl.h
new file mode 100644
index 0000000..2d0e981
--- /dev/null
+++ b/src/internal/tpax_ftime_impl.h
@@ -0,0 +1,24 @@
+/**************************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/**************************************************************/
+
+#ifndef TPAX_FTIME_IMPL_H
+#define TPAX_FTIME_IMPL_H
+
+#include <time.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#include "tpax_driver_impl.h"
+
+void tpax_ftime_restore(
+ const struct tpax_driver_ctx *,
+ int fd, const struct stat *);
+
+void tpax_ftime_restore_and_close(
+ const struct tpax_driver_ctx *,
+ int fd, const struct stat *);
+
+#endif
diff --git a/src/internal/tpax_getdents_impl.h b/src/internal/tpax_getdents_impl.h
index 42b9da0..2f46d63 100644
--- a/src/internal/tpax_getdents_impl.h
+++ b/src/internal/tpax_getdents_impl.h
@@ -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. */
/**************************************************************/
diff --git a/src/internal/tpax_readlink_impl.h b/src/internal/tpax_readlink_impl.h
index d6c5580..e2febe1 100644
--- a/src/internal/tpax_readlink_impl.h
+++ b/src/internal/tpax_readlink_impl.h
@@ -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. */
/**************************************************************/
diff --git a/src/internal/tpax_tmpfile_impl.c b/src/internal/tpax_tmpfile_impl.c
index 56d5c92..aa78e40 100644
--- a/src/internal/tpax_tmpfile_impl.c
+++ b/src/internal/tpax_tmpfile_impl.c
@@ -1,16 +1,22 @@
/**************************************************************/
/* 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. */
/**************************************************************/
#define _GNU_SOURCE
+#include <time.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
+#include <inttypes.h>
+
+#include "tpax_visibility_impl.h"
+
+#define PPRIX64 "%"PRIx64
/* mkostemp might be guarded by non-standard macros */
/* unless HAVE_NO_MKOSTEMP, assume it is available */
@@ -51,11 +57,11 @@ static int tpax_mkostemp(char * tmplate)
return fd;
}
-int tpax_tmpfile(void)
+tpax_hidden int tpax_tmpfile(void)
{
int fd;
- unsigned seed;
- char tmplate[64];
+ void * addr;
+ char tmplate[128];
/* try with __fs_tmpfile() */
if ((fd = tpax_tmpfile_by_framework()) >= 0)
@@ -66,10 +72,18 @@ int tpax_tmpfile(void)
return fd;
/* fallback to mk{o}stemp */
- seed = getpid();
+ addr = tmplate;
memset(tmplate,0,sizeof(tmplate));
- snprintf(tmplate,sizeof(tmplate),"/tmp/tpax_%d_%d_%d_XXXXXXXXXXXX",
- getppid(),getpid(),rand_r(&seed));
+ snprintf(tmplate,sizeof(tmplate),
+ "/tmp/"
+ ".tpax.tmpfile"
+ ".time."PPRIX64
+ ".salt.%p"
+ ".pid.%d"
+ ".XXXXXXXXXXXX",
+ time(0),
+ addr,
+ getpid());
return tpax_mkostemp(tmplate);
}
diff --git a/src/internal/tpax_visibility_impl.h b/src/internal/tpax_visibility_impl.h
new file mode 100644
index 0000000..6812494
--- /dev/null
+++ b/src/internal/tpax_visibility_impl.h
@@ -0,0 +1,26 @@
+#ifndef TPAX_VISIBILITY_IMPL_H
+#define TPAX_VISIBILITY_IMPL_H
+
+/**********************************************************************/
+/* PE targets: __dllexport suffices for the purpose of exporting only */
+/* the desired subset of global symbols; this makes the visibility */
+/* attribute not only redundant, but also tricky if not properly */
+/* supported by the toolchain. */
+/* */
+/* When targeting Midipix, __PE__, __dllexport and __dllimport are */
+/* always defined by the toolchain. Otherwise, the absnece of these */
+/* macros has been detected by sofort's ccenv.sh during ./configure, */
+/* and they have accordingly been added to CFLAGS_OS. */
+/**********************************************************************/
+
+#ifdef __PE__
+#define tpax_hidden
+#else
+#ifdef _ATTR_VISIBILITY_HIDDEN
+#define tpax_hidden _ATTR_VISIBILITY_HIDDEN
+#else
+#define tpax_hidden
+#endif
+#endif
+
+#endif
diff --git a/src/logic/tpax_file_create_memory_snapshot.c b/src/io/tpax_create_memory_snapshot.c
index 7c1f90e..6be087f 100644
--- a/src/logic/tpax_file_create_memory_snapshot.c
+++ b/src/io/tpax_create_memory_snapshot.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. */
/**************************************************************/
@@ -18,12 +18,13 @@
#include <tpax/tpax_specs.h>
#include "tpax_driver_impl.h"
#include "tpax_errinfo_impl.h"
+#include "tpax_ftime_impl.h"
#ifndef ssizeof
#define ssizeof(x) (ssize_t)(sizeof(x))
#endif
-int tpax_file_create_memory_snapshot(
+int tpax_io_create_memory_snapshot(
const struct tpax_driver_ctx * dctx,
int fdat,
const char * path,
@@ -53,7 +54,7 @@ int tpax_file_create_memory_snapshot(
close(fd);
return TPAX_SYSTEM_ERROR(dctx);
- } else if (tpax_stat_compare(srcst,&dstst)) {
+ } else if (tpax_util_stat_compare(srcst,&dstst)) {
close(fd);
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FILE_CHANGED);
}
@@ -69,11 +70,11 @@ int tpax_file_create_memory_snapshot(
nread = read(fd,ch,cap-ch);
if (nread < 0) {
- close(fd);
+ tpax_ftime_restore_and_close(dctx,fd,&dstst);
return TPAX_SYSTEM_ERROR(dctx);
} else if (nread == 0) {
- close(fd);
+ tpax_ftime_restore_and_close(dctx,fd,&dstst);
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
} else {
@@ -81,12 +82,15 @@ int tpax_file_create_memory_snapshot(
}
}
+ /* preserve last data access time as needed */
+ tpax_ftime_restore(dctx,fd,&dstst);
+
/* stat compare */
if ((fstat(fd,&dstst)) < 0) {
close(fd);
return TPAX_SYSTEM_ERROR(dctx);
- } else if (tpax_stat_compare(srcst,&dstst)) {
+ } else if (tpax_util_stat_compare(srcst,&dstst)) {
close(fd);
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FILE_CHANGED);
}
diff --git a/src/logic/tpax_file_create_tmpfs_snapshot.c b/src/io/tpax_create_tmpfs_snapshot.c
index 5620238..99a1665 100644
--- a/src/logic/tpax_file_create_tmpfs_snapshot.c
+++ b/src/io/tpax_create_tmpfs_snapshot.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. */
/**************************************************************/
@@ -19,12 +19,13 @@
#include "tpax_driver_impl.h"
#include "tpax_tmpfile_impl.h"
#include "tpax_errinfo_impl.h"
+#include "tpax_ftime_impl.h"
#ifndef ssizeof
#define ssizeof(x) (ssize_t)(sizeof(x))
#endif
-int tpax_file_create_tmpfs_snapshot(
+int tpax_io_create_tmpfs_snapshot(
const struct tpax_driver_ctx * dctx,
int fdat,
const char * path,
@@ -64,7 +65,7 @@ int tpax_file_create_tmpfs_snapshot(
close(fdtmp);
return TPAX_SYSTEM_ERROR(dctx);
- } else if (tpax_stat_compare(srcst,&dstst)) {
+ } else if (tpax_util_stat_compare(srcst,&dstst)) {
close(fdsrc);
close(fdtmp);
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FILE_CHANGED);
@@ -78,12 +79,12 @@ int tpax_file_create_tmpfs_snapshot(
nbytes = read(fdsrc,buf,buflen);
if (nbytes < 0) {
- close(fdsrc);
+ tpax_ftime_restore_and_close(dctx,fdsrc,&dstst);
close(fdtmp);
return TPAX_SYSTEM_ERROR(dctx);
} else if (nbytes == 0) {
- close(fdsrc);
+ tpax_ftime_restore_and_close(dctx,fdsrc,&dstst);
close(fdtmp);
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
@@ -98,7 +99,7 @@ int tpax_file_create_tmpfs_snapshot(
ret = write(fdtmp,ch,nbytes);
if (ret < 0) {
- close(fdsrc);
+ tpax_ftime_restore_and_close(dctx,fdsrc,&dstst);
close(fdtmp);
return TPAX_SYSTEM_ERROR(dctx);
@@ -108,13 +109,16 @@ int tpax_file_create_tmpfs_snapshot(
}
}
+ /* preserve last data access time as needed */
+ tpax_ftime_restore(dctx,fdsrc,&dstst);
+
/* stat compare */
if ((fstat(fdsrc,&dstst)) < 0) {
close(fdsrc);
close(fdtmp);
return TPAX_SYSTEM_ERROR(dctx);
- } else if (tpax_stat_compare(srcst,&dstst)) {
+ } else if (tpax_util_stat_compare(srcst,&dstst)) {
close(fdsrc);
close(fdtmp);
return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FILE_CHANGED);
diff --git a/src/logic/tpax_archive_append.c b/src/logic/tpax_archive_append.c
deleted file mode 100644
index 76ac436..0000000
--- a/src/logic/tpax_archive_append.c
+++ /dev/null
@@ -1,709 +0,0 @@
-/**************************************************************/
-/* tpax: a topological pax implementation */
-/* Copyright (C) 2020--2021 SysDeer Technologies, LLC */
-/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
-/**************************************************************/
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <grp.h>
-#include <pwd.h>
-#include <sys/mman.h>
-#include <sys/stat.h>
-
-#include <tpax/tpax.h>
-#include <tpax/tpax_specs.h>
-#include "tpax_driver_impl.h"
-#include "tpax_getdents_impl.h"
-#include "tpax_tmpfile_impl.h"
-#include "tpax_errinfo_impl.h"
-
-#ifndef ssizeof
-#define ssizeof(x) (ssize_t)(sizeof(x))
-#endif
-
-static int tpax_archive_append_memory_data(
- int fdout,
- void * buf,
- ssize_t nbytes)
-{
- ssize_t ret;
- char * ch;
-
- for (ch=buf; nbytes; ch+=ret) {
- ret = write(fdout,ch,nbytes);
-
- while ((ret < 0) && (errno == EINTR))
- ret = write(fdout,ch,nbytes);
-
- if (ret < 0)
- return ret;
-
- nbytes -= ret;
- }
-
- return 0;
-}
-
-static int tpax_archive_append_pad(
- const struct tpax_driver_ctx * dctx,
- int fdout,
- const struct stat * st)
-{
- int ret;
- off_t cpos;
- ssize_t nbytes;
- char buf[512];
-
- nbytes = st->st_size;
- nbytes += 0x1ff;
- nbytes |= 0x1ff;
- nbytes ^= 0x1ff;
- nbytes -= st->st_size;
-
- memset(buf,0,nbytes);
-
- cpos = tpax_get_driver_cpos(dctx);
- cpos += st->st_size + nbytes;
-
- if (!(ret = tpax_archive_append_memory_data(fdout,buf,nbytes)))
- tpax_set_driver_cpos(dctx,cpos);
-
- return ret;
-}
-
-static struct tpax_dirent_buffer * tpax_dirent_buf_first_alloc(
- const struct tpax_driver_ctx * dctx)
-{
- void * addr;
- struct tpax_driver_ctx_impl * ictx;
-
- addr = (struct tpax_dirent_buffer *)mmap(
- 0,TPAX_DIRENT_BUFLEN,
- PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS,
- -1,0);
-
- if (addr == MAP_FAILED)
- return 0;
-
- ictx = tpax_get_driver_ictx(dctx);
- ictx->dirents = (struct tpax_dirent_buffer *)addr;
- ictx->dirents->cdent = ictx->dirents->dbuf;
-
- ictx->dirents->size = TPAX_DIRENT_BUFLEN;
- ictx->dirents->next = 0;
-
- ictx->dirents->nfree = TPAX_DIRENT_BUFLEN;
- ictx->dirents->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
-
- return ictx->dirents;
-}
-
-static struct tpax_dirent_buffer * tpax_dirent_buf_next_alloc(
- struct tpax_dirent_buffer * current)
-{
- void * addr;
-
- addr = (struct tpax_dirent_buffer *)mmap(
- 0,TPAX_DIRENT_BUFLEN,
- PROT_READ|PROT_WRITE,
- MAP_PRIVATE|MAP_ANONYMOUS,
- -1,0);
-
- if (addr == MAP_FAILED)
- return 0;
-
- current->next = (struct tpax_dirent_buffer *)addr;
- current->next->cdent = current->next->dbuf;
-
- current->next->size = TPAX_DIRENT_BUFLEN;
- current->next->next = 0;
-
- current->next->nfree = TPAX_DIRENT_BUFLEN;
- current->next->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
-
- return current->next;
-}
-
-static int tpax_archive_append_ret(
- int ret,
- struct tpax_unit_ctx * unit)
-{
- if (unit)
- tpax_free_unit_ctx(unit);
-
- return ret;
-}
-
-static int tpax_archive_append_one(
- const struct tpax_driver_ctx * dctx,
- const struct tpax_unit_ctx * uctx,
- const struct dirent * dent,
- int fdat,
- const char * prefix,
- const struct tpax_dirent * parent,
- const char * pdir)
-{
- struct tpax_unit_ctx * unit;
- struct tpax_ustar_header uhdr;
- off_t hpos;
- off_t dpos;
- int fdout;
- int fdtmp;
- ssize_t nread;
- ssize_t nbytes;
- void * buf;
- size_t buflen;
- size_t cmplen;
- void * membuf;
- size_t nlen;
- const char * path;
- const char * src;
- char * dst;
- char pbuf[1024];
-
- /* fake uctx for recursion items */
- unit = 0;
-
- if (dent && tpax_get_unit_ctx(
- dctx,fdat,dent->d_name,
- &unit) < 0)
- return TPAX_NESTED_ERROR(dctx);
-
- uctx = dent ? unit : uctx;
-
- /* prefixed path */
- if (!prefix && !parent && !pdir) {
- path = *uctx->path;
-
- } else {
- nlen = strlen(*uctx->path);
- nlen += prefix ? strlen(prefix) + 1 : 0;
- nlen += parent ? strlen(parent->dirent.d_name) + 1 : 0;
-
- if (nlen >= sizeof(pbuf))
- return TPAX_BUFFER_ERROR(dctx);
-
- dst = pbuf;
-
- if (prefix) {
- src = prefix;
-
- for (; *src; )
- *dst++ = *src++;
-
- if (dst[-1] != '/')
- *dst++ = '/';
- }
-
- if (parent) {
- src = parent->dirent.d_name;
-
- for (; *src; )
- *dst++ = *src++;
-
- *dst++ = '/';
- }
-
- if (pdir) {
- src = pdir;
-
- for (; *src; )
- *dst++ = *src++;
-
- *dst++ = '/';
- }
-
- src = *uctx->path;
-
- for (; *src; )
- *dst++ = *src++;
-
- *dst = 0;
- path = pbuf;
- }
-
- /* record errors */
- tpax_driver_set_ectx(
- dctx,0,path);
-
- /* driver */
- fdout = tpax_driver_fdout(dctx);
-
- /* header and data offsets: todo pax and cpio */
- hpos = tpax_get_driver_cpos(dctx);
- dpos = hpos + sizeof(uhdr);
-
- /* header */
- if (tpax_init_ustar_header(
- dctx,path,uctx->st,
- *uctx->link,&uhdr) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
-
- /* buffer */
- membuf = 0;
- fdtmp = -1;
-
- /* associated data? */
- if S_ISREG(uctx->st->st_mode) {
- buf = tpax_get_driver_anon_map_addr(
- dctx,&buflen);
-
- if (buflen >= (cmplen = uctx->st->st_size))
- membuf = buf;
-
- /* snapshot */
- if (membuf) {
- if (tpax_file_create_memory_snapshot(
- dctx,fdat,*uctx->path,
- uctx->st,membuf) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
- } else {
- if ((fdtmp = tpax_file_create_tmpfs_snapshot(
- dctx,fdat,*uctx->path,
- uctx->st)) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
-
- if (lseek(fdtmp,0,SEEK_SET) < 0)
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
- }
- }
-
- /* append header */
- if (tpax_archive_append_memory_data(fdout,&uhdr,ssizeof(uhdr)) < 0) {
- if (fdtmp >= 0)
- close(fdtmp);
-
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
- }
-
- tpax_set_driver_cpos(dctx,dpos);
-
- /* all done? */
- if (!(S_ISREG(uctx->st->st_mode))) {
- tpax_archive_append_ret(0,unit);
- return 0;
- }
-
- /* append data from snapshot */
- if (fdtmp >= 0) {
- buf = tpax_get_driver_anon_map_addr(
- dctx,&buflen);
-
- for (nread=0; nread<uctx->st->st_size; ) {
- nbytes = read(fdtmp,buf,buflen);
-
- while ((nbytes < 0) && (errno == EINTR))
- nbytes = read(fdtmp,buf,buflen);
-
- if (nbytes < 0) {
- close(fdtmp);
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- } else if (nbytes == 0) {
- close(fdtmp);
- return tpax_archive_append_ret(
- TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
- unit);
-
- } else {
- nread += nbytes;
- }
-
- if (tpax_archive_append_memory_data(fdout,buf,nbytes) < 0) {
- close(fdtmp);
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
- }
- }
-
- close(fdtmp);
- } else {
- if (tpax_archive_append_memory_data(
- fdout,membuf,
- uctx->st->st_size) < 0)
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
- }
-
- return tpax_archive_append_ret(
- tpax_archive_append_pad(dctx,fdout,uctx->st),
- unit);
-}
-
-static int tpax_archive_append_dir(
- const struct tpax_driver_ctx * dctx,
- const struct tpax_unit_ctx * uctx,
- struct tpax_dirent * dent,
- int fdat,
- int depth,
- const char * prefix,
- const struct tpax_dirent * parent)
-{
- int fd;
- bool fkeep;
- long nbytes;
- size_t needed;
- struct dirent * dirent;
- struct dirent * dirents;
- struct tpax_dirent_buffer * dentbuf;
- struct tpax_dirent * cdent;
- struct tpax_unit_ctx * unit;
- struct stat st;
- uintptr_t addr;
- char * src;
- char * dst;
- char * cap;
-
- /* fake uctx for recursion items */
- unit = 0;
-
- if (dent && tpax_get_unit_ctx(
- dctx,dent->fdat,dent->dirent.d_name,
- &unit) < 0)
- return TPAX_NESTED_ERROR(dctx);
-
- uctx = dent ? unit : uctx;
-
- /* verify that recursion item is still a directory */
- if (unit && !S_ISDIR(unit->st->st_mode))
- return tpax_archive_append_ret(
- TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
- unit);
-
- /* append directory entry to archive */
- if (tpax_archive_append_one(
- dctx,uctx,0,
- tpax_driver_fdcwd(dctx),
- prefix,0,0) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
-
- /* obtain buffer for file-system directory entries */
- dirents = tpax_get_driver_getdents_buffer(dctx);
- dirent = dirents;
- fkeep = false;
- nbytes = 0;
- depth++;
-
- /* open directory and obtain first directory entries */
- if ((fd = openat(fdat,*uctx->path,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0)
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
-
- while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
- nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
-
- if (nbytes < 0)
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- /* iterate */
- for (; nbytes>0; ) {
- if (!strcmp(dirent->d_name,".")) {
- (void)0;
-
- } else if (!strcmp(dirent->d_name,"..")) {
- (void)0;
-
- } else {
- if (dirent->d_type == DT_UNKNOWN) {
- if (fstatat(fd,dirent->d_name,&st,AT_SYMLINK_NOFOLLOW))
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- if (S_ISDIR(st.st_mode)) {
- dirent->d_type = DT_DIR;
- }
- }
-
- if (dirent->d_type == DT_DIR) {
- if (!(dentbuf = tpax_get_driver_dirents(dctx)))
- if (!(dentbuf = tpax_dirent_buf_first_alloc(dctx)))
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- needed = dirent->d_reclen;
- needed += offsetof(struct tpax_dirent,dirent);
- needed += 0x7;
- needed |= 0x7;
- needed ^= 0x7;
-
- for (; dentbuf->next && (dentbuf->nfree < needed); )
- dentbuf = dentbuf->next;
-
- if (dentbuf->nfree < needed)
- if (!(dentbuf = tpax_dirent_buf_next_alloc(dentbuf)))
- return tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- fkeep = true;
- cdent = dentbuf->cdent;
-
- cdent->fdat = fd;
- cdent->depth = depth;
- cdent->nsize = needed;
- cdent->parent = parent;
-
- memset(&cdent->dirent,0,offsetof(struct dirent,d_name));
-
- cdent->dirent.d_type = dirent->d_type;
- cdent->dirent.d_reclen = dirent->d_reclen;
-
- src = dirent->d_name;
- dst = cdent->dirent.d_name;
-
- cap = dst - offsetof(struct dirent,d_name);
- cap -= offsetof(struct tpax_dirent,dirent);
- cap += needed;
-
- for (; *src; )
- *dst++ = *src++;
-
- for (; dst<cap; )
- *dst++ = 0;
-
- dentbuf->cdent = (struct tpax_dirent *)cap;
- dentbuf->nfree -= needed;
- } else {
- if (tpax_archive_append_one(
- dctx,0,dirent,fd,prefix,
- 0,*uctx->path) < 0)
- return tpax_archive_append_ret(
- TPAX_NESTED_ERROR(dctx),
- unit);
- }
- }
-
- addr = (uintptr_t)dirent;
- addr += dirent->d_reclen;
- nbytes -= dirent->d_reclen;
- dirent = (struct dirent *)addr;
-
- if (nbytes == 0) {
- nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
-
- while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
- nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
-
- if (nbytes < 0)
- tpax_archive_append_ret(
- TPAX_SYSTEM_ERROR(dctx),
- unit);
-
- dirent = dirents;
- }
- }
-
- /* all done */
- return tpax_archive_append_ret(
- fkeep ? 0 : close(fd),
- unit);
-}
-
-static int tpax_archive_append_impl(
- const struct tpax_driver_ctx * dctx,
- const struct tpax_unit_ctx * uctx,
- int depth,
- const char * prefix,
- struct tpax_dirent * parent)
-{
- if (S_ISDIR(uctx->st->st_mode))
- if (dctx->cctx->drvflags & TPAX_DRIVER_DIR_MEMBER_RECURSE)
- return tpax_archive_append_dir(
- dctx,uctx,0,
- tpax_driver_fdcwd(dctx),
- depth,prefix,parent);
-
- return tpax_archive_append_one(
- dctx,uctx,0,
- tpax_driver_fdcwd(dctx),
- prefix,0,0);
-}
-
-int tpax_archive_append(
- const struct tpax_driver_ctx * dctx,
- const struct tpax_unit_ctx * uctx,
- const char * prefix)
-{
- struct tpax_dirent_buffer * dentbuf;
- struct tpax_dirent * cdent;
- struct tpax_dirent * cnext;
- const struct tpax_dirent * parent;
- uintptr_t addr;
- const char * rdir;
- const char * src;
- char * dst;
- char * cap;
- char * mark;
- int idx;
- const char * dirv[256];
- char pbuf[2048];
-
- /* normalized prefix */
- if (prefix && (prefix[0] == '.') && (!prefix[1]))
- prefix = 0;
-
- if (prefix && (prefix[0] == '.') && (prefix[1] == '/'))
- for (++prefix; *prefix=='/'; prefix++)
- (void)0;
-
- /* append explicit item */
- tpax_archive_append_impl(dctx,uctx,0,prefix,0);
-
- /* iterate through queued items */
- dentbuf = tpax_get_driver_dirents(dctx);
- cdent = dentbuf ? dentbuf->dbuf : 0;
-
- if (cdent) {
- dst = pbuf;
- cap = &pbuf[sizeof(pbuf)];
-
- if (prefix && prefix[0]) {
- for (; *src && dst<cap; )
- *dst++ = *src++;
-
- if (dst == cap)
- return TPAX_BUFFER_ERROR(dctx);
-
- if (dst[-1] != '/')
- *dst++ = '/';
- }
-
- src = *uctx->path;
-
- for (; *src && dst<cap; )
- *dst++ = *src++;
-
- if (dst == cap)
- return TPAX_BUFFER_ERROR(dctx);
-
- if (dst[-1] != '/')
- *dst++ = '/';
-
- *dst = 0;
- mark = dst;
- rdir = pbuf;
-
- (void)mark;
- }
-
- for (; cdent; ) {
- switch (cdent->dirent.d_type) {
- case DT_DIR:
- if (tpax_archive_append_dir(
- dctx,0,cdent,cdent->fdat,
- cdent->depth,rdir,cdent) < 0)
- return TPAX_NESTED_ERROR(dctx);
-
- break;
-
- default:
- if (tpax_archive_append_one(
- dctx,0,&cdent->dirent,
- cdent->fdat,rdir,cdent,0) < 0)
- return TPAX_NESTED_ERROR(dctx);
- }
-
- addr = (uintptr_t)cdent;
- addr += cdent->nsize;
- cnext = (struct tpax_dirent *)addr;
-
- if (cnext == dentbuf->cdent) {
- dentbuf = dentbuf->next;
- cnext = dentbuf ? dentbuf->dbuf : 0;
- }
-
- if (cnext && (cnext->parent != cdent->parent)) {
- if (cnext->depth > 256)
- return TPAX_BUFFER_ERROR(dctx);
-
- for (parent=cnext->parent; parent; parent=parent->parent)
- dirv[parent->depth - 1] = parent->dirent.d_name;
-
- for (idx=0,dst=mark; idx<cnext->parent->depth; idx++) {
- src = dirv[idx];
-
- for (; *src; )
- *dst++ = *src++;
-
- *dst++ = '/';
- }
-
- *--dst = 0;
- }
-
- cdent = cnext;
- }
-
- return 0;
-}
-
-int tpax_archive_seal(const struct tpax_driver_ctx * dctx)
-{
- int fdout;
- off_t cpos;
- ssize_t nbytes;
- ssize_t nwritten;
- ssize_t blksize;
- char buf[512];
-
- blksize = tpax_get_archive_block_size(dctx);
- cpos = tpax_get_driver_cpos(dctx);
-
- if (cpos % 512)
- return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
-
- fdout = tpax_driver_fdout(dctx);
- memset(buf,0,sizeof(buf));
-
- switch (cpos % blksize) {
- case 0:
- nbytes = cpos + blksize;
- break;
-
- default:
- nbytes = cpos / blksize;
- nbytes *= blksize;
- nbytes += blksize;
-
- if (nbytes-cpos == 512)
- nbytes += blksize;
- }
-
- for (nwritten=cpos; nwritten<nbytes; nwritten+=512) {
- if (tpax_archive_append_memory_data(fdout,buf,512) < 0)
- return TPAX_SYSTEM_ERROR(dctx);
-
- tpax_set_driver_cpos(dctx,nwritten);
- }
-
- return 0;
-}
diff --git a/src/logic/tpax_archive_enqueue.c b/src/logic/tpax_archive_enqueue.c
new file mode 100644
index 0000000..222b0ad
--- /dev/null
+++ b/src/logic/tpax_archive_enqueue.c
@@ -0,0 +1,475 @@
+/**************************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/**************************************************************/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+
+#include <tpax/tpax.h>
+#include <tpax/tpax_specs.h>
+#include "tpax_driver_impl.h"
+#include "tpax_getdents_impl.h"
+#include "tpax_tmpfile_impl.h"
+#include "tpax_errinfo_impl.h"
+
+static char * tpax_add_prefix_item(
+ const struct tpax_driver_ctx * dctx,
+ const char * prefix)
+{
+ struct tpax_driver_ctx_impl * ictx;
+ char ** prefv;
+ char ** psrc;
+ char ** pdst;
+ off_t elements;
+ char * pitem;
+
+ ictx = tpax_get_driver_ictx(dctx);
+
+ for (psrc=ictx->prefixv; *psrc; psrc++)
+ if (!strcmp(*psrc,prefix))
+ return *psrc;
+
+ if (ictx->prefixp == ictx->prefcap) {
+ elements = ictx->prefcap - ictx->prefixv;
+ elements += 256;
+
+ if (!(prefv = calloc(elements,sizeof(char *))))
+ return 0;
+
+ for (psrc=ictx->prefixv,pdst=prefv; *psrc; psrc++,pdst++)
+ *pdst = *psrc;
+
+ if (ictx->prefixv != ictx->prefptr)
+ free(ictx->prefixv);
+
+ ictx->prefixv = prefv;
+ ictx->prefixp = pdst;
+ ictx->prefcap = &prefv[--elements];
+ }
+
+ if (!(pitem = strdup(prefix)))
+ return 0;
+
+ *ictx->prefixp++ = pitem;
+
+ return pitem;
+}
+
+static char * tpax_add_prefix_item_from_path(
+ const struct tpax_driver_ctx * dctx,
+ const char * path,
+ const char * mark)
+{
+ off_t nbytes;
+ char pathbuf[PATH_MAX];
+
+ if ((nbytes = (mark - path)) >= (PATH_MAX - 1))
+ return 0;
+
+ memcpy(pathbuf,path,nbytes);
+ pathbuf[nbytes++] = '/';
+ pathbuf[nbytes] = '\0';
+
+ return tpax_add_prefix_item(dctx,pathbuf);
+}
+
+static struct tpax_dirent_buffer * tpax_dirent_buf_first_alloc(
+ const struct tpax_driver_ctx * dctx)
+{
+ void * addr;
+ struct tpax_driver_ctx_impl * ictx;
+
+ addr = (struct tpax_dirent_buffer *)mmap(
+ 0,TPAX_DIRENT_BUFLEN,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS,
+ -1,0);
+
+ if (addr == MAP_FAILED)
+ return 0;
+
+ ictx = tpax_get_driver_ictx(dctx);
+ ictx->dirents = (struct tpax_dirent_buffer *)addr;
+ ictx->dirents->cdent = ictx->dirents->dbuf;
+
+ ictx->dirents->size = TPAX_DIRENT_BUFLEN;
+ ictx->dirents->next = 0;
+
+ ictx->dirents->nfree = TPAX_DIRENT_BUFLEN;
+ ictx->dirents->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
+
+ return ictx->dirents;
+}
+
+static struct tpax_dirent_buffer * tpax_dirent_buf_next_alloc(
+ struct tpax_dirent_buffer * current)
+{
+ void * addr;
+
+ addr = (struct tpax_dirent_buffer *)mmap(
+ 0,TPAX_DIRENT_BUFLEN,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS,
+ -1,0);
+
+ if (addr == MAP_FAILED)
+ return 0;
+
+ current->next = (struct tpax_dirent_buffer *)addr;
+ current->next->cdent = current->next->dbuf;
+
+ current->next->size = TPAX_DIRENT_BUFLEN;
+ current->next->next = 0;
+
+ current->next->nfree = TPAX_DIRENT_BUFLEN;
+ current->next->nfree -= offsetof(struct tpax_dirent_buffer,dbuf);
+
+ return current->next;
+}
+
+static int tpax_archive_enqueue_ret(
+ int ret,
+ struct tpax_unit_ctx * unit)
+{
+ if (unit)
+ tpax_lib_free_unit_ctx(unit);
+
+ return ret;
+}
+
+static int tpax_archive_add_queue_item(
+ const struct tpax_driver_ctx * dctx,
+ const struct dirent * dirent,
+ const struct tpax_dirent * parent,
+ const char * prefix,
+ int depth,
+ int flags,
+ int fdat,
+ bool * fkeep)
+{
+ struct tpax_dirent_buffer * dentbuf;
+ struct tpax_dirent * cdent;
+ const char * src;
+ char * dst;
+ char * cap;
+ size_t needed;
+
+ if (!(dentbuf = tpax_get_driver_dirents(dctx)))
+ if (!(dentbuf = tpax_dirent_buf_first_alloc(dctx)))
+ return tpax_archive_enqueue_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ 0);
+
+ needed = dirent->d_reclen;
+ needed += offsetof(struct tpax_dirent,dirent);
+ needed += 0x7;
+ needed |= 0x7;
+ needed ^= 0x7;
+
+ for (; dentbuf->next && (dentbuf->nfree < needed); )
+ dentbuf = dentbuf->next;
+
+ if (dentbuf->nfree < needed)
+ if (!(dentbuf = tpax_dirent_buf_next_alloc(dentbuf)))
+ return tpax_archive_enqueue_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ 0);
+
+ *fkeep = true;
+ cdent = dentbuf->cdent;
+
+ cdent->fdat = fdat;
+ cdent->depth = depth;
+ cdent->flags = flags;
+ cdent->nsize = needed;
+ cdent->parent = parent;
+ cdent->prefix = prefix;
+
+ memset(&cdent->dirent,0,offsetof(struct dirent,d_name));
+
+ cdent->dirent.d_ino = dirent->d_ino;
+ cdent->dirent.d_type = dirent->d_type;
+ cdent->dirent.d_reclen = dirent->d_reclen;
+
+ src = dirent->d_name;
+ dst = cdent->dirent.d_name;
+
+ cap = dst - offsetof(struct dirent,d_name);
+ cap -= offsetof(struct tpax_dirent,dirent);
+ cap += needed;
+
+ for (; *src; )
+ *dst++ = *src++;
+
+ for (; dst<cap; )
+ *dst++ = 0;
+
+ dentbuf->cdent = (struct tpax_dirent *)cap;
+ dentbuf->nfree -= needed;
+
+ tpax_set_driver_dirmark(dctx,cdent);
+
+ return 0;
+}
+
+static int tpax_archive_enqueue_dir_entries(
+ const struct tpax_driver_ctx * dctx,
+ struct tpax_dirent * dent)
+{
+ int fd;
+ int fdat;
+ int depth;
+ bool fkeep;
+ long nbytes;
+ struct dirent * dirent;
+ struct dirent * dirents;
+ struct tpax_unit_ctx * uctx;
+ struct stat st;
+ uintptr_t addr;
+
+ /* init */
+ fdat = dent->fdat;
+ depth = dent->depth;
+
+ /* uctx on the fly */
+ if (tpax_lib_get_unit_ctx(
+ dctx,fdat,
+ dent->dirent.d_name,
+ &uctx) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ /* verify that recursion item is still a directory */
+ if (!S_ISDIR(uctx->st->st_mode))
+ return tpax_archive_enqueue_ret(
+ TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
+ uctx);
+
+ /* obtain buffer for file-system directory entries */
+ dirents = tpax_get_driver_getdents_buffer(dctx);
+ dirent = dirents;
+ fkeep = false;
+ nbytes = 0;
+ depth++;
+
+ /* open directory and obtain first directory entries */
+ if ((fd = openat(fdat,dent->dirent.d_name,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0)
+ return tpax_archive_enqueue_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+
+ nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
+
+ while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
+ nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
+
+ if (nbytes < 0)
+ return tpax_archive_enqueue_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+
+ /* iterate */
+ for (; nbytes>0; ) {
+ if (!strcmp(dirent->d_name,".")) {
+ (void)0;
+
+ } else if (!strcmp(dirent->d_name,"..")) {
+ (void)0;
+
+ } else {
+ if (dirent->d_type == DT_UNKNOWN) {
+ if (fstatat(fd,dirent->d_name,&st,AT_SYMLINK_NOFOLLOW))
+ return tpax_archive_enqueue_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+
+ if (S_ISDIR(st.st_mode)) {
+ dirent->d_type = DT_DIR;
+ }
+ }
+
+ if (tpax_archive_add_queue_item(
+ dctx,dirent,
+ dent,0,depth,
+ TPAX_ITEM_IMPLICIT,
+ fd,&fkeep) < 0)
+ return tpax_archive_enqueue_ret(
+ TPAX_NESTED_ERROR(dctx),
+ uctx);
+ }
+
+ addr = (uintptr_t)dirent;
+ addr += dirent->d_reclen;
+ nbytes -= dirent->d_reclen;
+ dirent = (struct dirent *)addr;
+
+ if (nbytes == 0) {
+ nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
+
+ while ((nbytes == -EINTR) || ((nbytes < 0) && (errno == EINTR)))
+ nbytes = tpax_getdents(fd,dirents,TPAX_DIRENT_BUFLEN);
+
+ if (nbytes < 0)
+ tpax_archive_enqueue_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+
+ dirent = dirents;
+ }
+ }
+
+ /* all done */
+ return tpax_archive_enqueue_ret(
+ fkeep ? 0 : close(fd),
+ uctx);
+}
+
+static const char * tpax_path_prefix_mark(const char * path)
+{
+ const char * src;
+ char * mark;
+ char pathbuf[PATH_MAX];
+
+ src = path;
+ mark = pathbuf;
+
+ for (; *src; )
+ *mark++ = *src++;
+
+ for (--mark; (*mark == '/'); mark--)
+ (void)0;
+
+ *++mark = '\0';
+
+ for (; (mark > pathbuf) && (mark[-1] != '/'); )
+ mark--;
+
+ return (mark <= pathbuf) ? 0 : &path[--mark-pathbuf];
+}
+
+static int tpax_dirent_init_from_uctx(
+ const struct stat * st,
+ const char * basename,
+ struct dirent * dirent)
+{
+ /* st_mode to d_type translation */
+ if (S_ISREG(st->st_mode))
+ dirent->d_type = DT_REG;
+ else if (S_ISLNK(st->st_mode))
+ dirent->d_type = DT_LNK;
+ else if (S_ISDIR(st->st_mode))
+ dirent->d_type = DT_DIR;
+ else if (S_ISCHR(st->st_mode))
+ dirent->d_type = DT_CHR;
+ else if (S_ISBLK(st->st_mode))
+ dirent->d_type = DT_CHR;
+ else if (S_ISFIFO(st->st_mode))
+ dirent->d_type = DT_CHR;
+ else
+ return -1;
+
+ /* d_off, d_ino */
+ dirent->d_off = 0;
+ dirent->d_ino = st->st_ino;
+
+ /* d_reclen */
+ dirent->d_reclen = offsetof(struct dirent,d_name);
+ dirent->d_reclen += strlen(basename) + 1;
+
+ dirent->d_reclen += 0x1;
+ dirent->d_reclen |= 0x1;
+ dirent->d_reclen ^= 0x1;
+
+ /* d_name */
+ strcpy(dirent->d_name,basename);
+
+ return 0;
+}
+
+int tpax_archive_enqueue(
+ const struct tpax_driver_ctx * dctx,
+ const struct tpax_unit_ctx * uctx)
+{
+ int fdat;
+ uintptr_t addr;
+ const char * name;
+ const char * mark;
+ const char * prefix;
+ bool fkeep;
+ struct tpax_dirent_buffer * dentbuf;
+ struct tpax_dirent * cdent;
+ struct tpax_dirent * cnext;
+ struct dirent * dirent;
+ char entbuf[PATH_MAX + sizeof(struct dirent)];
+
+ /* init */
+ fdat = tpax_driver_fdcwd(dctx);
+ dirent = (struct dirent *)entbuf;
+ prefix = 0;
+
+ /* split path to prefix + basename */
+ if ((mark = tpax_path_prefix_mark(*uctx->path)))
+ if (!(prefix = tpax_add_prefix_item_from_path(
+ dctx,*uctx->path,mark)))
+ return tpax_archive_enqueue_ret(
+ TPAX_BUFFER_ERROR(dctx),
+ 0);
+
+ name = mark ? ++mark : *uctx->path;
+
+ if (prefix)
+ if ((fdat = openat(fdat,prefix,O_RDONLY|O_DIRECTORY|O_CLOEXEC,0)) < 0)
+ return tpax_archive_enqueue_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ 0);
+
+ /* explicit item directory entry */
+ if (tpax_dirent_init_from_uctx(uctx->st,name,dirent) < 0)
+ return tpax_archive_enqueue_ret(
+ TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR),
+ 0);
+
+ /* add to queue */
+ if (tpax_archive_add_queue_item(
+ dctx,dirent,0,prefix,0,
+ TPAX_ITEM_EXPLICIT,
+ fdat,&fkeep) < 0)
+ return tpax_archive_enqueue_ret(
+ TPAX_NESTED_ERROR(dctx),
+ 0);
+
+ /* queue directory child items */
+ dentbuf = tpax_get_driver_dirents(dctx);
+ cdent = tpax_get_driver_dirmark(dctx);
+
+ for (; cdent; ) {
+ if (cdent->dirent.d_type == DT_DIR)
+ if (dctx->cctx->drvflags & TPAX_DRIVER_DIR_MEMBER_RECURSE)
+ if (tpax_archive_enqueue_dir_entries(dctx,cdent) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ addr = (uintptr_t)cdent;
+ addr += cdent->nsize;
+ cnext = (struct tpax_dirent *)addr;
+
+ if (cnext == dentbuf->cdent) {
+ dentbuf = dentbuf->next;
+ cnext = dentbuf ? dentbuf->dbuf : 0;
+ }
+
+ cdent = cnext;
+ }
+
+ return 0;
+}
diff --git a/src/logic/tpax_archive_reset.c b/src/logic/tpax_archive_reset.c
new file mode 100644
index 0000000..52a9008
--- /dev/null
+++ b/src/logic/tpax_archive_reset.c
@@ -0,0 +1,59 @@
+/**************************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/**************************************************************/
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/mman.h>
+
+#include <tpax/tpax.h>
+#include "tpax_driver_impl.h"
+
+/**********************************************/
+/* release and reset the following objects: */
+/* */
+/* - item queue */
+/* - queue vector */
+/* - cached prefixes */
+/* - prefix vector */
+/* */
+/**********************************************/
+
+int tpax_archive_reset(const struct tpax_driver_ctx * dctx)
+{
+ struct tpax_driver_ctx_impl * ictx;
+ void * next;
+ size_t size;
+ char ** ppref;
+
+ ictx = tpax_get_driver_ictx(dctx);
+
+ for (; ictx->dirents; ) {
+ next = ictx->dirents->next;
+ size = ictx->dirents->size;
+
+ munmap(ictx->dirents,size);
+ ictx->dirents = (struct tpax_dirent_buffer *)next;
+ }
+
+ for (ppref=ictx->prefixv; *ppref; ppref++)
+ free(*ppref);
+
+ for (ppref=ictx->prefptr; ppref<ictx->prefcap; ppref++)
+ *ppref = 0;
+
+ if (ictx->prefixv != ictx->prefptr)
+ free(ictx->prefixv);
+
+ if (ictx->direntv)
+ free(ictx->direntv);
+
+ ictx->nqueued = 0;
+ ictx->dirents = 0;
+ ictx->direntv = 0;
+ ictx->prefixv = ictx->prefptr;
+
+ return 0;
+}
diff --git a/src/logic/tpax_archive_write.c b/src/logic/tpax_archive_write.c
new file mode 100644
index 0000000..2555d26
--- /dev/null
+++ b/src/logic/tpax_archive_write.c
@@ -0,0 +1,306 @@
+/**************************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/**************************************************************/
+
+#include <tpax/tpax.h>
+#include "tpax_driver_impl.h"
+#include "tpax_errinfo_impl.h"
+#include "tpax_visibility_impl.h"
+
+#ifndef ssizeof
+#define ssizeof(x) (ssize_t)(sizeof(x))
+#endif
+
+static int tpax_archive_append_memory_data(
+ int fdout,
+ void * buf,
+ ssize_t nbytes)
+{
+ ssize_t ret;
+ char * ch;
+
+ for (ch=buf; nbytes; ch+=ret) {
+ ret = write(fdout,ch,nbytes);
+
+ while ((ret < 0) && (errno == EINTR))
+ ret = write(fdout,ch,nbytes);
+
+ if (ret < 0)
+ return ret;
+
+ nbytes -= ret;
+ }
+
+ return 0;
+}
+
+static int tpax_archive_append_pad(
+ const struct tpax_driver_ctx * dctx,
+ int fdout,
+ const struct stat * st)
+{
+ int ret;
+ off_t cpos;
+ ssize_t nbytes;
+ char buf[512];
+
+ nbytes = st->st_size;
+ nbytes += 0x1ff;
+ nbytes |= 0x1ff;
+ nbytes ^= 0x1ff;
+ nbytes -= st->st_size;
+
+ memset(buf,0,nbytes);
+
+ cpos = tpax_get_driver_cpos(dctx);
+ cpos += st->st_size + nbytes;
+
+ if (!(ret = tpax_archive_append_memory_data(fdout,buf,nbytes)))
+ tpax_set_driver_cpos(dctx,cpos);
+
+ return ret;
+}
+
+static int tpax_archive_write_ret(
+ int ret,
+ struct tpax_unit_ctx * uctx)
+{
+ tpax_lib_free_unit_ctx(uctx);
+ return ret;
+}
+
+static int tpax_archive_write_impl(
+ const struct tpax_driver_ctx * dctx,
+ const struct tpax_dirent * cdent,
+ int fdcwd,
+ int fdout)
+{
+ struct tpax_unit_ctx * uctx;
+ struct tpax_ustar_header uhdr;
+ const char * path;
+ off_t hpos;
+ off_t dpos;
+ int fdtmp;
+ ssize_t nread;
+ ssize_t nbytes;
+ void * buf;
+ size_t buflen;
+ size_t cmplen;
+ void * membuf;
+
+ /* full path */
+ if (!(path = tpax_queue_item_full_path(dctx,cdent)))
+ return TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR);
+
+ /* uctx */
+ if (tpax_lib_get_unit_ctx(dctx,fdcwd,path,&uctx) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ /* record errors */
+ tpax_driver_set_ectx(
+ dctx,0,path);
+
+ /* header and data offsets: todo pax and cpio */
+ hpos = tpax_get_driver_cpos(dctx);
+ dpos = hpos + sizeof(uhdr);
+
+ /* header */
+ if (tpax_meta_init_ustar_header(
+ dctx,path,uctx->st,
+ *uctx->link,&uhdr) < 0)
+ return tpax_archive_write_ret(
+ TPAX_NESTED_ERROR(dctx),
+ uctx);
+
+ /* buffer */
+ membuf = 0;
+ fdtmp = -1;
+
+ /* associated data? */
+ if S_ISREG(uctx->st->st_mode) {
+ buf = tpax_get_driver_anon_map_addr(
+ dctx,&buflen);
+
+ if (buflen >= (cmplen = uctx->st->st_size))
+ membuf = buf;
+
+ /* snapshot */
+ if (membuf) {
+ if (tpax_io_create_memory_snapshot(
+ dctx,fdcwd,path,
+ uctx->st,membuf) < 0)
+ return tpax_archive_write_ret(
+ TPAX_NESTED_ERROR(dctx),
+ uctx);
+ } else {
+ if ((fdtmp = tpax_io_create_tmpfs_snapshot(
+ dctx,fdcwd,path,
+ uctx->st)) < 0)
+ return tpax_archive_write_ret(
+ TPAX_NESTED_ERROR(dctx),
+ uctx);
+
+ if (lseek(fdtmp,0,SEEK_SET) < 0)
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
+ }
+
+ /* append header */
+ if (tpax_archive_append_memory_data(fdout,&uhdr,ssizeof(uhdr)) < 0) {
+ if (fdtmp >= 0)
+ close(fdtmp);
+
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
+
+ tpax_set_driver_cpos(dctx,dpos);
+
+ /* all done? */
+ if (!(S_ISREG(uctx->st->st_mode))) {
+ tpax_lib_free_unit_ctx(uctx);
+ return 0;
+ }
+
+ /* append data from snapshot */
+ if (fdtmp >= 0) {
+ buf = tpax_get_driver_anon_map_addr(
+ dctx,&buflen);
+
+ for (nread=0; nread<uctx->st->st_size; ) {
+ nbytes = read(fdtmp,buf,buflen);
+
+ while ((nbytes < 0) && (errno == EINTR))
+ nbytes = read(fdtmp,buf,buflen);
+
+ if (nbytes < 0) {
+ close(fdtmp);
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+
+ } else if (nbytes == 0) {
+ close(fdtmp);
+ return tpax_archive_write_ret(
+ TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR),
+ uctx);
+
+ } else {
+ nread += nbytes;
+ }
+
+ if (tpax_archive_append_memory_data(fdout,buf,nbytes) < 0) {
+ close(fdtmp);
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
+ }
+
+ close(fdtmp);
+ } else {
+ if (tpax_archive_append_memory_data(
+ fdout,membuf,
+ uctx->st->st_size) < 0)
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
+
+ return tpax_archive_write_ret(
+ tpax_archive_append_pad(dctx,fdout,uctx->st),
+ uctx);
+}
+
+int tpax_archive_write(const struct tpax_driver_ctx * dctx)
+{
+ struct tpax_driver_ctx_impl * ictx;
+ struct tpax_dirent ** direntv;
+ int fdcwd;
+ int fdout;
+
+ /* driver */
+ ictx = tpax_get_driver_ictx(dctx);
+ fdcwd = tpax_driver_fdcwd(dctx);
+ fdout = tpax_driver_fdout(dctx);
+
+ /* quote to archive */
+ if (tpax_update_queue_vector(dctx) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ for (direntv=ictx->direntv; *direntv; direntv++)
+ if (tpax_archive_write_impl(dctx,*direntv,fdcwd,fdout) < 0)
+ return TPAX_NESTED_ERROR(dctx);
+
+ return 0;
+}
+
+static int tpax_archive_seal_cpio(const struct tpax_driver_ctx * dctx)
+{
+ (void)dctx;
+ return -1;
+}
+
+int tpax_archive_seal(const struct tpax_driver_ctx * dctx)
+{
+ int fdout;
+ off_t cpos;
+ ssize_t nbytes;
+ ssize_t nwritten;
+ ssize_t blksize;
+ char buf[1024];
+
+ /* archive block size, current position */
+ blksize = dctx->cctx->blksize;
+ cpos = tpax_get_driver_cpos(dctx);
+
+ /* internal error? */
+ if (cpos % 512)
+ return TPAX_CUSTOM_ERROR(dctx,TPAX_ERR_FLOW_ERROR);
+
+ /* cpio trailer? */
+ if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_CPIO)
+ return tpax_archive_seal_cpio(dctx);
+
+ /* ustar, pax */
+ fdout = tpax_driver_fdout(dctx);
+ memset(buf,0,sizeof(buf));
+
+ if (tpax_archive_append_memory_data(fdout,buf,2*512) < 0)
+ return TPAX_SYSTEM_ERROR(dctx);
+
+ cpos += 2*512;
+
+ /* pax? */
+ if (dctx->cctx->drvflags & TPAX_DRIVER_WRITE_FORMAT_PAX) {
+ tpax_set_driver_cpos(dctx,cpos);
+ return 0;
+ }
+
+ /* already at block boundary? */
+ if ((cpos % blksize) == 0) {
+ tpax_set_driver_cpos(dctx,cpos);
+ return 0;
+ }
+
+ /* zero-fill the remainder of the block */
+ nbytes = cpos / blksize;
+ nbytes *= blksize;
+ nbytes += blksize;
+
+ for (nwritten=cpos; nwritten<nbytes; nwritten+=512)
+ if (tpax_archive_append_memory_data(fdout,buf,512) < 0)
+ return TPAX_SYSTEM_ERROR(dctx);
+
+ /* all done */
+ tpax_set_driver_cpos(dctx,nwritten);
+
+ return 0;
+}
diff --git a/src/logic/tpax_queue_vector.c b/src/logic/tpax_queue_vector.c
new file mode 100644
index 0000000..82930b1
--- /dev/null
+++ b/src/logic/tpax_queue_vector.c
@@ -0,0 +1,95 @@
+/**************************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/**************************************************************/
+
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <tpax/tpax.h>
+#include "tpax_driver_impl.h"
+#include "tpax_errinfo_impl.h"
+#include "tpax_visibility_impl.h"
+
+#define TPAX_MAX_DEPTH 512
+
+tpax_hidden const char * tpax_queue_item_full_path(
+ const struct tpax_driver_ctx * dctx,
+ const struct tpax_dirent * cdent)
+{
+ char * ch;
+ char * pathbuf;
+ const struct tpax_dirent * pparent;
+ const struct tpax_dirent ** pdirent;
+ const struct tpax_dirent * dirstck[TPAX_MAX_DEPTH];
+
+ if (cdent->depth >= TPAX_MAX_DEPTH)
+ return 0;
+
+ ch = pathbuf = (tpax_get_driver_ictx(dctx))->dirbuff;
+
+ for (pparent=cdent,pdirent=dirstck; pparent; pparent=pparent->parent)
+ *pdirent++ = pparent;
+
+ *pdirent-- = 0;
+
+ if (pdirent[0]->prefix)
+ ch += sprintf(ch,"%s",pdirent[0]->prefix);
+
+ for (; pdirent > dirstck; ) {
+ ch += sprintf(ch,"%s/",pdirent[0]->dirent.d_name);
+ pdirent--;
+ }
+
+ sprintf(ch,"%s",pdirent[0]->dirent.d_name);
+
+ return pathbuf;
+}
+
+tpax_hidden int tpax_update_queue_vector(const struct tpax_driver_ctx * dctx)
+{
+ uintptr_t addr;
+ struct tpax_driver_ctx_impl * ictx;
+ struct tpax_dirent_buffer * dentbuf;
+ struct tpax_dirent ** direntv;
+ struct tpax_dirent * cdent;
+ struct tpax_dirent * cnext;
+ size_t arrsize;
+
+ /* driver */
+ ictx = tpax_get_driver_ictx(dctx);
+
+ /* vector alloc */
+ if (ictx->direntv)
+ free(ictx->direntv);
+
+ arrsize = ictx->nqueued + 1;
+
+ if (!(ictx->direntv = calloc(arrsize,sizeof(struct tpax_dirent *))))
+ return TPAX_SYSTEM_ERROR(dctx);
+
+ if (ictx->nqueued == 0)
+ return 0;
+
+ /* queue vector */
+ dentbuf = tpax_get_driver_dirents(dctx);
+ cdent = dentbuf->dbuf;
+
+ for (direntv=ictx->direntv; cdent; direntv++) {
+ *direntv = cdent;
+
+ addr = (uintptr_t)cdent;
+ addr += cdent->nsize;
+ cnext = (struct tpax_dirent *)addr;
+
+ if (cnext == dentbuf->cdent) {
+ dentbuf = dentbuf->next;
+ cnext = dentbuf ? dentbuf->dbuf : 0;
+ }
+
+ cdent = cnext;
+ }
+
+ return 0;
+}
diff --git a/src/logic/tpax_init_ustar_header.c b/src/meta/tpax_init_ustar_header.c
index fb83ba4..2479e28 100644
--- a/src/logic/tpax_init_ustar_header.c
+++ b/src/meta/tpax_init_ustar_header.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. */
/**************************************************************/
@@ -30,7 +30,7 @@ static void tpax_octal_write(char * ch, ssize_t len, uint64_t val)
}
}
-int tpax_init_ustar_header(
+int tpax_meta_init_ustar_header(
const struct tpax_driver_ctx * dctx,
const char * path,
const struct stat * st,
diff --git a/src/output/tpax_output_error.c b/src/output/tpax_output_error.c
index 6ecc7ce..bc724cd 100644
--- a/src/output/tpax_output_error.c
+++ b/src/output/tpax_output_error.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. */
/**************************************************************/
diff --git a/src/skin/tpax_skin_default.c b/src/skin/tpax_skin_default.c
index 4de94b4..1684553 100644
--- a/src/skin/tpax_skin_default.c
+++ b/src/skin/tpax_skin_default.c
@@ -1,32 +1,47 @@
#include "tpax_driver_impl.h"
+#include "tpax_visibility_impl.h"
#include "argv/argv.h"
-const struct argv_option tpax_default_options[] = {
- {"version", 0,TAG_VERSION,ARGV_OPTARG_NONE,0,0,0,
+const tpax_hidden struct argv_option tpax_default_options[] = {
+ {"Wversion", 0,TAG_VERSION,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"show version information"},
- {"help", 0,TAG_HELP,ARGV_OPTARG_OPTIONAL,0,"short|long",0,
- "show usage information [listing %s options only]"},
+ {"Whelp", 0,TAG_HELP,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
+ "show usage information"},
- {"list", 0,TAG_LIST,ARGV_OPTARG_NONE,0,0,0,
+ {"Wlist", 0,TAG_LIST,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"list mode (output names of archive members)"},
- {"read", 'r',TAG_READ,ARGV_OPTARG_NONE,0,0,0,
+ {"Wread", 'r',TAG_READ,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"read mode (extract matching archive members)"},
- {"write", 'w',TAG_WRITE,ARGV_OPTARG_NONE,0,0,0,
+ {"Write", 'w',TAG_WRITE,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"write mode (add specified files to archive)"},
- {"copy", 0,TAG_COPY,ARGV_OPTARG_NONE,0,0,0,
+ {"Wcopy", 0,TAG_COPY,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"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"},
- {"format", 'x',TAG_FORMAT,ARGV_OPTARG_REQUIRED,0,
+ {"Wformat", 'x',TAG_FORMAT,ARGV_OPTARG_REQUIRED,
+ ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_EQUAL,
"pax|cpio|ustar|rustar",0,
"archive format [%s]"},
- {"blksize", 'b',TAG_BLKSIZE,ARGV_OPTARG_REQUIRED,0,0,0,
+ {"Wblksize", 'b',TAG_BLKSIZE,ARGV_OPTARG_REQUIRED,
+ ARGV_OPTION_HYBRID_ONLY|ARGV_OPTION_HYBRID_EQUAL,0,0,
"(non-default) block-size; valid values are "
"in the range of 512 to 32256; keeping "
"the default format-specific block size "
@@ -34,20 +49,32 @@ const struct argv_option tpax_default_options[] = {
" 10240 for the ustar format) "
"is strongly recommended."},
- {"recurse", 0,TAG_RECURSE,ARGV_OPTARG_NONE,0,0,0,
+ {"Wrecurse", 0,TAG_RECURSE,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"recurse into directory archive members "
"(this is the tpax_main() default)"},
- {"no-recurse", 'd',TAG_NORECURSE,ARGV_OPTARG_NONE,0,0,0,
+ {"Wno-recurse",'d',TAG_NORECURSE,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"do not recurse into directory archive members"},
- {"strict-path-input",
- 0,TAG_STRICT_PATH,ARGV_OPTARG_NONE,0,0,0,
+ {"Wpreserve-atime",
+ 't',TAG_PRESERVE_ATIME,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
+ "when user has the necessary permissions, "
+ "set the access time of each file to the access "
+ "time that was reported by fstatat(3) prior to the "
+ "first read operation performed by pax"},
+
+ {"Wstrict-path-input",
+ 0,TAG_STRICT_PATH,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"do not allow file arguments (in write and copy modes) "
"to contain parent-directoy (dot dot) references"},
- {"pure-path-output",
- 0,TAG_PURE_PATH,ARGV_OPTARG_NONE,0,0,0,
+ {"Wpure-path-output",
+ 0,TAG_PURE_PATH,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
"output (in list mode) or store (in write mode) path "
"names in pure form, specifically by liminating all "
"this-dir (dot) elements from the listed/stored path "
diff --git a/src/tpax.c b/src/tpax.c
index be9d920..7cbbbfa 100644
--- a/src/tpax.c
+++ b/src/tpax.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. */
/**************************************************************/
diff --git a/src/helper/tpax_path_copy.c b/src/util/tpax_path_copy.c
index 454b6ea..046ddde 100644
--- a/src/helper/tpax_path_copy.c
+++ b/src/util/tpax_path_copy.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. */
/**************************************************************/
@@ -13,7 +13,7 @@
#include <tpax/tpax.h>
#include "tpax_driver_impl.h"
-int tpax_path_copy(
+int tpax_util_path_copy(
char * dstpath,
const char * srcpath,
size_t bufsize,
diff --git a/src/helper/tpax_stat_compare.c b/src/util/tpax_stat_compare.c
index c9ab660..2de6922 100644
--- a/src/helper/tpax_stat_compare.c
+++ b/src/util/tpax_stat_compare.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. */
/**************************************************************/
@@ -18,7 +18,7 @@
return (src -> member > dst -> member) \
? (1) : (-1)
-int tpax_stat_compare(
+int tpax_util_stat_compare(
const struct stat * src,
const struct stat * dst)
{