diff options
Diffstat (limited to 'src/util')
-rw-r--r-- | src/util/tpax_path_copy.c | 86 | ||||
-rw-r--r-- | src/util/tpax_path_replstr.c | 120 | ||||
-rw-r--r-- | src/util/tpax_stat_compare.c | 41 |
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; +} |