summaryrefslogtreecommitdiff
path: root/src/internal
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal')
-rw-r--r--src/internal/argv/argv.h281
-rw-r--r--src/internal/tpax_dprintf_impl.c6
-rw-r--r--src/internal/tpax_driver_impl.h73
-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.c6
-rw-r--r--src/internal/tpax_visibility_impl.h26
11 files changed, 421 insertions, 54 deletions
diff --git a/src/internal/argv/argv.h b/src/internal/argv/argv.h
index 87c60d2..8efedda 100644
--- a/src/internal/argv/argv.h
+++ b/src/internal/argv/argv.h
@@ -13,6 +13,7 @@
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
+#include <ctype.h>
#include <unistd.h>
#define ARGV_VERBOSITY_NONE 0x00
@@ -57,16 +58,27 @@
#define ARGV_OPTION_HYBRID_EQUAL 0x04
#define ARGV_OPTION_HYBRID_COMMA 0x08
#define ARGV_OPTION_HYBRID_JOINED 0x10
+
+#define ARGV_OPTION_KEYVAL_PAIR 0X20
+#define ARGV_OPTION_KEYVAL_ARRAY 0X40
+#define ARGV_OPTION_KEYVAL_MASK (ARGV_OPTION_KEYVAL_PAIR \
+ | ARGV_OPTION_KEYVAL_ARRAY)
+
#define ARGV_OPTION_HYBRID_CIRCUS (ARGV_OPTION_HYBRID_SPACE \
| ARGV_OPTION_HYBRID_JOINED)
+
#define ARGV_OPTION_HYBRID_DUAL (ARGV_OPTION_HYBRID_SPACE \
| ARGV_OPTION_HYBRID_EQUAL)
+
#define ARGV_OPTION_HYBRID_SWITCH (ARGV_OPTION_HYBRID_ONLY \
| ARGV_OPTION_HYBRID_SPACE \
| ARGV_OPTION_HYBRID_EQUAL \
| ARGV_OPTION_HYBRID_COMMA \
| ARGV_OPTION_HYBRID_JOINED)
+#define ARGV_KEYVAL_ASSIGN 0x01
+#define ARGV_KEYVAL_OVERRIDE 0x02
+
enum argv_optarg {
ARGV_OPTARG_NONE,
ARGV_OPTARG_REQUIRED,
@@ -92,6 +104,9 @@ enum argv_error {
ARGV_ERROR_HYBRID_SPACE,
ARGV_ERROR_HYBRID_EQUAL,
ARGV_ERROR_HYBRID_COMMA,
+ ARGV_ERROR_KEYVAL_KEY,
+ ARGV_ERROR_KEYVAL_VALUE,
+ ARGV_ERROR_KEYVAL_ALLOC,
};
struct argv_option {
@@ -105,13 +120,20 @@ struct argv_option {
const char * description;
};
+struct argv_keyval {
+ const char * keyword;
+ const char * value;
+ int flags;
+};
+
struct argv_entry {
- const char * arg;
- int tag;
- bool fopt;
- bool fval;
- bool fnoscan;
- enum argv_error errcode;
+ const char * arg;
+ struct argv_keyval * keyv;
+ int tag;
+ bool fopt;
+ bool fval;
+ bool fnoscan;
+ enum argv_error errcode;
};
struct argv_meta {
@@ -129,6 +151,7 @@ struct argv_ctx {
const char * errch;
const struct argv_option * erropt;
const char * program;
+ size_t keyvlen;
};
#ifdef ARGV_DRIVER
@@ -136,6 +159,8 @@ struct argv_ctx {
struct argv_meta_impl {
char ** argv;
char * strbuf;
+ char * keyvbuf;
+ char * keyvmark;
struct argv_meta meta;
};
@@ -305,12 +330,131 @@ static inline const struct argv_option * option_from_tag(
return 0;
}
+static inline int argv_scan_keyval_array(struct argv_meta_impl * meta, struct argv_entry * entry)
+{
+ const char * ch;
+ char * dst;
+ int ncomma;
+ int cint;
+ struct argv_keyval * keyv;
+
+ /* count key[val] elements, assume no comma after last element */
+ for (ch=entry->arg,ncomma=1; *ch; ch++) {
+ if ((ch[0]=='\\') && (ch[1]==',')) {
+ ch++;
+
+ } else if ((ch[0]==',')) {
+ ncomma++;
+ }
+ }
+
+ /* keyval string buffer */
+ dst = meta->keyvmark;
+
+ /* allocate keyval array */
+ if (!(entry->keyv = calloc(ncomma+1,sizeof(*entry->keyv))))
+ return ARGV_ERROR_KEYVAL_ALLOC;
+
+ /* create keyval array */
+ entry->keyv->keyword = dst;
+
+ for (ch=entry->arg,keyv=entry->keyv; *ch; ch++) {
+ if ((ch[0]=='\\') && (ch[1]==',')) {
+ *dst++ = ',';
+ ch++;
+
+ } else if ((ch[0]==':') && (ch[1]=='=')) {
+ if (!keyv->keyword[0])
+ return ARGV_ERROR_KEYVAL_KEY;
+
+ keyv->flags = ARGV_KEYVAL_OVERRIDE;
+ keyv->value = ++dst;
+ ch++;
+
+ } else if ((ch[0]=='=')) {
+ if (!keyv->keyword[0])
+ return ARGV_ERROR_KEYVAL_KEY;
+
+ keyv->flags = ARGV_KEYVAL_ASSIGN;
+ keyv->value = ++dst;
+
+ } else if ((ch[0]==',')) {
+ for (; isblank(cint = ch[1]); )
+ ch++;
+
+ if (ch[1]) {
+ keyv++;
+ keyv->keyword = ++dst;
+ }
+ } else {
+ *dst++ = *ch;
+ }
+ }
+
+ /* keyval string buffer */
+ meta->keyvmark = ++dst;
+
+ return ARGV_ERROR_OK;
+}
+
+static inline int argv_scan_keyval_pair(struct argv_meta_impl * meta, struct argv_entry * entry)
+{
+ const char * ch;
+ char * dst;
+ struct argv_keyval * keyv;
+
+ /* keyval string buffer */
+ dst = meta->keyvmark;
+
+ /* allocate keyval array */
+ if (!(entry->keyv = calloc(2,sizeof(*entry->keyv))))
+ return ARGV_ERROR_KEYVAL_ALLOC;
+
+ /* create keyval array */
+ entry->keyv->keyword = dst;
+
+ for (ch=entry->arg,keyv=entry->keyv; *ch && !keyv->flags; ch++) {
+ if ((ch[0]=='\\') && (ch[1]==',')) {
+ *dst++ = ',';
+ ch++;
+
+ } else if ((ch[0]==':') && (ch[1]=='=')) {
+ if (!keyv->keyword[0])
+ return ARGV_ERROR_KEYVAL_KEY;
+
+ keyv->flags = ARGV_KEYVAL_OVERRIDE;
+ keyv->value = ++dst;
+ ch++;
+
+ } else if ((ch[0]=='=')) {
+ if (!keyv->keyword[0])
+ return ARGV_ERROR_KEYVAL_KEY;
+
+ keyv->flags = ARGV_KEYVAL_ASSIGN;
+ keyv->value = ++dst;
+
+ } else {
+ *dst++ = *ch;
+ }
+ }
+
+ for (; *ch; )
+ *dst++ = *ch++;
+
+ /* keyval string buffer */
+ meta->keyvmark = ++dst;
+
+ return ARGV_ERROR_OK;
+}
+
static void argv_scan(
char ** argv,
const struct argv_option ** optv,
struct argv_ctx * ctx,
struct argv_meta * meta)
{
+ struct argv_meta_impl * imeta;
+ uintptr_t addr;
char ** parg;
const char * ch;
const char * val;
@@ -324,6 +468,9 @@ static void argv_scan(
bool fhybrid;
bool fnoscan;
+ addr = (uintptr_t)meta - offsetof(struct argv_meta_impl,meta);
+ imeta = (struct argv_meta_impl *)addr;
+
parg = &argv[1];
ch = *parg;
ferr = ARGV_ERROR_OK;
@@ -495,13 +642,20 @@ static void argv_scan(
if (!option && !ctx->unitidx)
ctx->unitidx = parg - argv;
+ if (ferr == ARGV_ERROR_OK)
+ if (option && (option->flags & ARGV_OPTION_KEYVAL_MASK))
+ if (ctx->mode == ARGV_MODE_SCAN)
+ ctx->keyvlen += strlen(ch) + 1;
+
if (ferr != ARGV_ERROR_OK) {
ctx->errcode = ferr;
ctx->errch = ctx->errch ? ctx->errch : ch;
ctx->erropt = option;
ctx->erridx = parg - argv;
return;
- } else if (ctx->mode == ARGV_MODE_SCAN) {
+ }
+
+ if (ctx->mode == ARGV_MODE_SCAN) {
if (!fnoscan)
ctx->nentries++;
else if (fval)
@@ -511,12 +665,12 @@ static void argv_scan(
parg++;
ch = *parg;
}
+
} else if (ctx->mode == ARGV_MODE_COPY) {
if (fnoscan) {
if (fval) {
mentry->arg = ch;
mentry->fnoscan = true;
- mentry++;
}
parg++;
@@ -526,7 +680,6 @@ static void argv_scan(
mentry->tag = option->tag;
mentry->fopt = true;
mentry->fval = fval;
- mentry++;
if (fval) {
parg++;
@@ -534,11 +687,28 @@ static void argv_scan(
}
} else {
mentry->arg = ch;
- mentry++;
parg++;
ch = *parg;
}
}
+
+ if (option && (option->flags & ARGV_OPTION_KEYVAL_PAIR))
+ if (ctx->mode == ARGV_MODE_COPY)
+ ferr = argv_scan_keyval_pair(imeta,mentry);
+
+ if (option && (option->flags & ARGV_OPTION_KEYVAL_ARRAY))
+ if (ctx->mode == ARGV_MODE_COPY)
+ ferr = argv_scan_keyval_array(imeta,mentry);
+
+ if (ferr != ARGV_ERROR_OK) {
+ ctx->errcode = ferr;
+ ctx->errch = ctx->errch ? ctx->errch : ch;
+ ctx->erropt = option;
+ ctx->erridx = parg - argv;
+ return;
+ }
+
+ mentry++;
}
}
@@ -663,6 +833,14 @@ static void argv_show_error(int fd, struct argv_ctx * ctx)
break;
+ case ARGV_ERROR_KEYVAL_KEY:
+ argv_dprintf(fd,"illegal key detected in keyval argument\n");
+ break;
+
+ case ARGV_ERROR_KEYVAL_VALUE:
+ argv_dprintf(fd,"illegal value detected in keyval argument\n");
+ break;
+
case ARGV_ERROR_INTERNAL:
argv_dprintf(fd,"internal error");
break;
@@ -678,8 +856,10 @@ static void argv_show_status(
struct argv_ctx * ctx,
struct argv_meta * meta)
{
+ int i;
int argc;
char ** argv;
+ struct argv_keyval * keyv;
struct argv_entry * entry;
const struct argv_option * option;
char short_name[2] = {0};
@@ -698,7 +878,7 @@ static void argv_show_status(
argv_dprintf(fd,"argv[%d]: %s\n",argc,*argv);
argv_dprintf(fd,"\n\nparsed entries:\n");
- for (entry=meta->entries; entry->arg || entry->fopt; entry++)
+ for (entry=meta->entries; entry->arg || entry->fopt; entry++) {
if (entry->fopt) {
option = option_from_tag(optv,entry->tag);
short_name[0] = option->short_name;
@@ -709,14 +889,48 @@ static void argv_show_status(
else
argv_dprintf(fd,"[-%s,--%s]\n",
short_name,option->long_name);
- } else
+
+ if (entry->keyv) {
+ for (i=0,keyv=entry->keyv; keyv->keyword; i++,keyv++) {
+ switch (keyv->flags) {
+ case ARGV_KEYVAL_ASSIGN:
+ argv_dprintf(fd,"\tkeyval[%d]: <%s>=%s\n",
+ i,keyv->keyword,keyv->value);
+ break;
+
+ case ARGV_KEYVAL_OVERRIDE:
+ argv_dprintf(fd,"\tkeyval[%d]: <%s>:=%s\n",
+ i,keyv->keyword,keyv->value);
+ break;
+
+ default:
+ argv_dprintf(fd,"\tkeyval[%d]: <%s>\n",
+ i,keyv->keyword);
+ break;
+ }
+ }
+ }
+ } else {
argv_dprintf(fd,"<program arg> := %s\n",entry->arg);
+ }
+ }
argv_dprintf(fd,"\n\n");
}
static struct argv_meta * argv_free_impl(struct argv_meta_impl * imeta)
{
+ struct argv_entry * entry;
+ void * addr;
+
+ if (imeta->keyvbuf)
+ for (entry=imeta->meta.entries; entry->fopt || entry->arg; entry++)
+ if (entry->keyv)
+ free((addr = entry->keyv));
+
+ if (imeta->keyvbuf)
+ free(imeta->keyvbuf);
+
if (imeta->argv)
free(imeta->argv);
@@ -750,7 +964,8 @@ static struct argv_meta * argv_alloc(char ** argv, struct argv_ctx * ctx)
if (!(imeta->argv = calloc(argc+1,sizeof(char *))))
return argv_free_impl(imeta);
- else if (!(imeta->strbuf = calloc(1,size+1)))
+
+ if (!(imeta->strbuf = calloc(1,size+1)))
return argv_free_impl(imeta);
for (i=0,dst=imeta->strbuf; i<argc; i++) {
@@ -760,15 +975,27 @@ static struct argv_meta * argv_alloc(char ** argv, struct argv_ctx * ctx)
}
imeta->meta.argv = imeta->argv;
- } else
+ } else {
imeta->meta.argv = argv;
+ }
- if (!(imeta->meta.entries = calloc(
- ctx->nentries+1,
- sizeof(struct argv_entry))))
+ imeta->meta.entries = calloc(
+ ctx->nentries+1,
+ sizeof(struct argv_entry));
+
+ if (!imeta->meta.entries)
return argv_free_impl(imeta);
- else
- return &imeta->meta;
+
+ if (ctx->keyvlen) {
+ imeta->keyvbuf = calloc(
+ ctx->keyvlen,
+ sizeof(char));
+
+ if (!(imeta->keyvmark = imeta->keyvbuf))
+ return argv_free_impl(imeta);
+ }
+
+ return &imeta->meta;
}
static struct argv_meta * argv_get(
@@ -778,7 +1005,7 @@ static struct argv_meta * argv_get(
int fd)
{
struct argv_meta * meta;
- struct argv_ctx ctx = {flags,ARGV_MODE_SCAN,0,0,0,0,0,0,0};
+ struct argv_ctx ctx = {flags,ARGV_MODE_SCAN,0,0,0,0,0,0,0,0};
argv_scan(argv,optv,&ctx,0);
@@ -833,6 +1060,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 +1093,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 +1112,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) {
@@ -916,7 +1149,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..d340748 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,27 +26,42 @@
(TPAX_DRIVER_EXEC_MODE_WRITE | \
TPAX_DRIVER_EXEC_MODE_COPY)
+#define TPAX_ITEM_EXPLICIT 0X1
+#define TPAX_ITEM_IMPLICIT 0X2
+#define TPAX_ITEM_SYMLINK 0X4
+#define TPAX_ITEM_NAMEREF 0x8
+
extern const struct argv_option tpax_default_options[];
enum app_tags {
TAG_HELP,
TAG_VERSION,
+ TAG_VERBOSE,
TAG_LIST,
TAG_READ,
TAG_WRITE,
TAG_COPY,
+ TAG_FILE,
TAG_FORMAT,
TAG_BLKSIZE,
+ TAG_OPTIONS,
TAG_RECURSE,
TAG_NORECURSE,
TAG_STRICT_PATH,
TAG_PURE_PATH,
+ TAG_PRESERVE_ATIME,
+ TAG_PAX_SYMLINK_ARGS,
+ TAG_PAX_SYMLINK_ITEMS,
+ TAG_STRICT_DEVICE_ID,
};
struct tpax_dirent {
int fdat;
int depth;
+ int flags;
+ dev_t stdev;
size_t nsize;
+ const char * prefix;
const struct tpax_dirent * parent;
struct dirent dirent;
};
@@ -60,19 +75,28 @@ 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;
const struct tpax_unit_ctx * euctx;
const char * eunit;
+ struct argv_keyval ** keyvalv;
struct tpax_error_info ** errinfp;
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 +167,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 +227,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 +270,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 9dd9d40..aa78e40 100644
--- a/src/internal/tpax_tmpfile_impl.c
+++ b/src/internal/tpax_tmpfile_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. */
/**************************************************************/
@@ -14,6 +14,8 @@
#include <stdio.h>
#include <inttypes.h>
+#include "tpax_visibility_impl.h"
+
#define PPRIX64 "%"PRIx64
/* mkostemp might be guarded by non-standard macros */
@@ -55,7 +57,7 @@ static int tpax_mkostemp(char * tmplate)
return fd;
}
-int tpax_tmpfile(void)
+tpax_hidden int tpax_tmpfile(void)
{
int fd;
void * addr;
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