summaryrefslogtreecommitdiff
path: root/src/util
diff options
context:
space:
mode:
Diffstat (limited to 'src/util')
-rw-r--r--src/util/tpax_path_copy.c86
-rw-r--r--src/util/tpax_path_replstr.c120
-rw-r--r--src/util/tpax_stat_compare.c41
3 files changed, 247 insertions, 0 deletions
diff --git a/src/util/tpax_path_copy.c b/src/util/tpax_path_copy.c
new file mode 100644
index 0000000..046ddde
--- /dev/null
+++ b/src/util/tpax_path_copy.c
@@ -0,0 +1,86 @@
+/**************************************************************/
+/* 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 <errno.h>
+#include <sys/stat.h>
+
+#include <tpax/tpax.h>
+#include "tpax_driver_impl.h"
+
+int tpax_util_path_copy(
+ char * dstpath,
+ const char * srcpath,
+ size_t bufsize,
+ uint32_t flags,
+ size_t * nwritten)
+{
+ const char * src;
+ char * dst;
+ char * cap;
+
+ if (!bufsize) {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ src = srcpath;
+ dst = dstpath;
+ cap = &dst[bufsize];
+
+ if ((src[0] == '/') && (src[1] == '/') && (src[2] != '/')) {
+ *dst++ = *src++;
+ *dst++ = *src++;
+ }
+
+ if (flags & TPAX_DRIVER_PURE_PATH_OUTPUT)
+ if ((src[0] == '.') && (src[1] == '/'))
+ for (++src; *src=='/'; src++)
+ (void)0;
+
+ for (; *src; ) {
+ if ((src[0] == '.') && (src[1] == '.')) {
+ if ((src[2] == '/') || (src[2] == '\0')) {
+ if (flags & TPAX_DRIVER_STRICT_PATH_INPUT) {
+ errno = EINVAL;
+ return -1;
+ }
+ }
+ }
+
+ if (flags & TPAX_DRIVER_PURE_PATH_OUTPUT) {
+ if ((src[0] == '.') && (src[1] == '/') && (src[-1] == '/')) {
+ for (++src; *src=='/'; src++)
+ (void)0;
+
+ } else if ((src[0] == '/')) {
+ for (src++; *src=='/'; src++)
+ (void)0;
+
+ *dst++ = '/';
+
+ } else {
+ *dst++ = *src++;
+ }
+ } else {
+ *dst++ = *src++;
+ }
+
+ if (dst == cap) {
+ errno = ENOBUFS;
+ return -1;
+ }
+ }
+
+ if (nwritten)
+ *nwritten = dst - dstpath;
+
+ *dst = '\0';
+
+ return 0;
+}
diff --git a/src/util/tpax_path_replstr.c b/src/util/tpax_path_replstr.c
new file mode 100644
index 0000000..1935628
--- /dev/null
+++ b/src/util/tpax_path_replstr.c
@@ -0,0 +1,120 @@
+/**************************************************************/
+/* tpax: a topological pax implementation */
+/* Copyright (C) 2020--2024 SysDeer Technologies, LLC */
+/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
+/**************************************************************/
+
+#include <regex.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#include <tpax/tpax.h>
+#include "tpax_driver_impl.h"
+
+static int tpax_backref_idx(const char c)
+{
+ return ((c >= '1') && (c <= '9')) ? c - '0' : 0;
+}
+
+int tpax_util_path_replstr(
+ char * dstpath,
+ const char * srcpath,
+ const char * replstr,
+ const regex_t * regex,
+ size_t buflen,
+ int flags)
+{
+ int ret;
+ int idx;
+ regoff_t ro;
+ const char * ch;
+ char * dst;
+ size_t explen;
+ regmatch_t pmatch[11];
+
+ /* attempt to match */
+ switch (regexec(regex,srcpath,11,pmatch,0)) {
+ case 0:
+ break;
+
+ case REG_NOMATCH:
+ return 0;
+
+ default:
+ return -1;
+ }
+
+ /* copy bytes leading up to match */
+ if (buflen <= (explen = pmatch[0].rm_so)) {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ for (ro=0,dst=dstpath; ro<pmatch[0].rm_so; ro++)
+ *dst++ = srcpath[ro];
+
+ buflen -= explen;
+
+ /* copy replacement string */
+ for (ch=replstr,ret=0; buflen && *ch; ch++) {
+ /* <ampersand> stands for the entire matched string */
+ if (ch[0] == '&') {
+ idx = 0;
+
+ /* back-reference semantics: a matched subexpression or an empty string */
+ } else if ((ch[0] == '\\') && (idx = tpax_backref_idx(ch[1]))) {
+ if (pmatch[idx].rm_so < 0)
+ idx = -1;
+
+ ch++;
+
+ /* all other escaped characters */
+ } else if (ch[0] == '\\') {
+ *dst++ = *++ch;
+ idx = -1;
+ buflen--;
+
+ /* all other characters */
+ } else {
+ *dst++ = *ch;
+ idx = -1;
+ buflen--;
+ }
+
+ /* copy matched string or matched subexpression, if any */
+ if (idx >= 0) {
+ if (buflen <= (explen = (pmatch[idx].rm_eo - pmatch[idx].rm_so))) {
+ errno = ENOBUFS;
+ return -1;
+ }
+
+ for (ro=pmatch[idx].rm_so; ro<pmatch[idx].rm_eo; ro++)
+ *dst++ = srcpath[ro];
+
+ buflen -= explen;
+ }
+ }
+
+ /* replace further occurrences as needed */
+ if ((flags & TPAX_REPL_GLOBAL) && srcpath[pmatch[0].rm_eo])
+ ret = tpax_util_path_replstr(
+ dst,&srcpath[pmatch[0].rm_eo],replstr,
+ regex,buflen,flags);
+
+ if (ret < 0)
+ return -1;
+
+ /* copy remaining, non-matching bytes as needed */
+ if (ret == 0) {
+ for (ch=&srcpath[pmatch[0].rm_eo]; *ch; ch++)
+ *dst++ = *ch;
+
+ *dst = '\0';
+ }
+
+ /* all done */
+ ret += (dst - dstpath);
+
+ return ret;
+}
diff --git a/src/util/tpax_stat_compare.c b/src/util/tpax_stat_compare.c
new file mode 100644
index 0000000..2de6922
--- /dev/null
+++ b/src/util/tpax_stat_compare.c
@@ -0,0 +1,41 @@
+/**************************************************************/
+/* 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 <errno.h>
+#include <sys/stat.h>
+
+#include <tpax/tpax.h>
+#include "tpax_driver_impl.h"
+
+#define TPAX_STAT_COMPARE(member) \
+ if (src -> member - dst -> member) \
+ return (src -> member > dst -> member) \
+ ? (1) : (-1)
+
+int tpax_util_stat_compare(
+ const struct stat * src,
+ const struct stat * dst)
+{
+ TPAX_STAT_COMPARE(st_dev);
+ TPAX_STAT_COMPARE(st_ino);
+
+ TPAX_STAT_COMPARE(st_mode);
+ TPAX_STAT_COMPARE(st_uid);
+ TPAX_STAT_COMPARE(st_gid);
+
+ TPAX_STAT_COMPARE(st_rdev);
+ TPAX_STAT_COMPARE(st_size);
+ TPAX_STAT_COMPARE(st_blksize);
+ TPAX_STAT_COMPARE(st_blocks);
+
+ TPAX_STAT_COMPARE(st_mtim.tv_sec);
+ TPAX_STAT_COMPARE(st_mtim.tv_nsec);
+
+ return 0;
+}