summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/driver/tpax_driver_ctx.c4
-rw-r--r--src/internal/tpax_driver_impl.h3
-rw-r--r--src/logic/tpax_archive_enqueue.c38
-rw-r--r--src/logic/tpax_archive_write.c52
-rw-r--r--src/logic/tpax_queue_vector.c10
-rw-r--r--src/skin/tpax_skin_default.c8
6 files changed, 111 insertions, 4 deletions
diff --git a/src/driver/tpax_driver_ctx.c b/src/driver/tpax_driver_ctx.c
index e8ecb9e..71b4656 100644
--- a/src/driver/tpax_driver_ctx.c
+++ b/src/driver/tpax_driver_ctx.c
@@ -530,6 +530,10 @@ int tpax_lib_get_driver_ctx(
cctx.drvflags |= TPAX_DRIVER_PRESERVE_ATIME;
break;
+ case TAG_PAX_SYMLINK_ARGS:
+ cctx.drvflags |= TPAX_DRIVER_PAX_SYMLINK_ARGS;
+ break;
+
case TAG_STRICT_PATH:
cctx.drvflags |= TPAX_DRIVER_STRICT_PATH_INPUT;
break;
diff --git a/src/internal/tpax_driver_impl.h b/src/internal/tpax_driver_impl.h
index 1e898e9..a074535 100644
--- a/src/internal/tpax_driver_impl.h
+++ b/src/internal/tpax_driver_impl.h
@@ -28,6 +28,8 @@
#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[];
@@ -46,6 +48,7 @@ enum app_tags {
TAG_STRICT_PATH,
TAG_PURE_PATH,
TAG_PRESERVE_ATIME,
+ TAG_PAX_SYMLINK_ARGS,
};
struct tpax_dirent {
diff --git a/src/logic/tpax_archive_enqueue.c b/src/logic/tpax_archive_enqueue.c
index 222b0ad..b81661b 100644
--- a/src/logic/tpax_archive_enqueue.c
+++ b/src/logic/tpax_archive_enqueue.c
@@ -400,6 +400,7 @@ int tpax_archive_enqueue(
const struct tpax_unit_ctx * uctx)
{
int fdat;
+ int fdlnk;
uintptr_t addr;
const char * name;
const char * mark;
@@ -409,11 +410,15 @@ int tpax_archive_enqueue(
struct tpax_dirent * cdent;
struct tpax_dirent * cnext;
struct dirent * dirent;
+ struct dirent * lnkent;
+ struct stat lnkst;
char entbuf[PATH_MAX + sizeof(struct dirent)];
+ char lnkbuf[PATH_MAX + sizeof(struct dirent)];
/* init */
fdat = tpax_driver_fdcwd(dctx);
dirent = (struct dirent *)entbuf;
+ lnkent = (struct dirent *)lnkbuf;
prefix = 0;
/* split path to prefix + basename */
@@ -449,6 +454,39 @@ int tpax_archive_enqueue(
TPAX_NESTED_ERROR(dctx),
0);
+ /* follow command-line symlink arguments as needed */
+ fdlnk = (uctx->link[0] && (dctx->cctx->drvflags & TPAX_DRIVER_PAX_SYMLINK_ARGS))
+ ? openat(fdat,uctx->link[0],O_RDONLY|O_CLOEXEC) : (-1);
+
+ if (fdlnk >= 0) {
+ if (fstat(fdlnk,&lnkst) <0) {
+ close(fdlnk);
+ return tpax_archive_enqueue_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ 0);
+ }
+
+ close(fdlnk);
+
+ if (tpax_dirent_init_from_uctx(&lnkst,uctx->link[0],lnkent) < 0)
+ return tpax_archive_enqueue_ret(
+ TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR),
+ 0);
+
+ cdent = tpax_get_driver_dirmark(dctx);
+ cdent->flags |= TPAX_ITEM_NAMEREF;
+
+ if (tpax_archive_add_queue_item(
+ dctx,lnkent,cdent,0,1,
+ TPAX_ITEM_EXPLICIT|TPAX_ITEM_SYMLINK,
+ 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);
diff --git a/src/logic/tpax_archive_write.c b/src/logic/tpax_archive_write.c
index 1a641bf..98d7dfc 100644
--- a/src/logic/tpax_archive_write.c
+++ b/src/logic/tpax_archive_write.c
@@ -80,8 +80,10 @@ static int tpax_archive_write_impl(
struct tpax_unit_ctx * uctx;
struct tpax_ustar_header uhdr;
const struct stat * st;
+ struct stat stbuf;
const char * path;
const char * slnk;
+ const char * mlnk;
off_t hpos;
off_t dpos;
int fdtmp;
@@ -91,6 +93,12 @@ static int tpax_archive_write_impl(
size_t buflen;
size_t cmplen;
void * membuf;
+ char * ch;
+ char pathbuf[PATH_MAX];
+
+ /* followed symlink? */
+ if (cdent->flags & TPAX_ITEM_NAMEREF)
+ return 0;
/* full path */
if (!(path = tpax_queue_item_full_path(dctx,cdent)))
@@ -104,6 +112,44 @@ static int tpax_archive_write_impl(
st = uctx->st;
slnk = uctx->link[0];
+ mlnk = 0;
+
+ if (cdent->flags & TPAX_ITEM_SYMLINK) {
+ st = &stbuf;
+ mlnk = slnk;
+ slnk = 0;
+ ch = 0;
+
+ if (mlnk[0] != '/') {
+ if (strlen(path) >= PATH_MAX)
+ return tpax_archive_write_ret(
+ TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR),
+ uctx);
+
+ strcpy(pathbuf,path);
+
+ ch = strrchr(pathbuf,'/');
+ }
+
+ if (ch && (++ch - pathbuf >= PATH_MAX))
+ return tpax_archive_write_ret(
+ TPAX_CUSTOM_ERROR(
+ dctx,
+ TPAX_ERR_FLOW_ERROR),
+ uctx);
+
+ if (ch) {
+ strcpy(ch,mlnk);
+ mlnk = pathbuf;
+ }
+
+ if (fstatat(fdcwd,mlnk,&stbuf,0) < 0)
+ return tpax_archive_write_ret(
+ TPAX_SYSTEM_ERROR(dctx),
+ uctx);
+ }
/* record errors */
tpax_driver_set_ectx(
@@ -136,14 +182,16 @@ static int tpax_archive_write_impl(
/* snapshot */
if (membuf) {
if (tpax_io_create_memory_snapshot(
- dctx,fdcwd,path,
+ dctx,fdcwd,
+ mlnk ? mlnk : path,
st,membuf) < 0)
return tpax_archive_write_ret(
TPAX_NESTED_ERROR(dctx),
uctx);
} else {
if ((fdtmp = tpax_io_create_tmpfs_snapshot(
- dctx,fdcwd,path,
+ dctx,fdcwd,
+ mlnk ? mlnk : path,
st)) < 0)
return tpax_archive_write_ret(
TPAX_NESTED_ERROR(dctx),
diff --git a/src/logic/tpax_queue_vector.c b/src/logic/tpax_queue_vector.c
index 82930b1..cae4da0 100644
--- a/src/logic/tpax_queue_vector.c
+++ b/src/logic/tpax_queue_vector.c
@@ -38,11 +38,17 @@ tpax_hidden const char * tpax_queue_item_full_path(
ch += sprintf(ch,"%s",pdirent[0]->prefix);
for (; pdirent > dirstck; ) {
- ch += sprintf(ch,"%s/",pdirent[0]->dirent.d_name);
+ if (!(pdirent[0]->flags & TPAX_ITEM_SYMLINK))
+ ch += sprintf(ch,"%s/",pdirent[0]->dirent.d_name);
+
pdirent--;
}
- sprintf(ch,"%s",pdirent[0]->dirent.d_name);
+ if (pdirent[0]->flags & TPAX_ITEM_SYMLINK) {
+ *--ch = '\0';
+ } else {
+ sprintf(ch,"%s",pdirent[0]->dirent.d_name);
+ }
return pathbuf;
}
diff --git a/src/skin/tpax_skin_default.c b/src/skin/tpax_skin_default.c
index 1684553..5bddb70 100644
--- a/src/skin/tpax_skin_default.c
+++ b/src/skin/tpax_skin_default.c
@@ -66,6 +66,14 @@ const tpax_hidden struct argv_option tpax_default_options[] = {
"time that was reported by fstatat(3) prior to the "
"first read operation performed by pax"},
+ {"Wpax-symlink-args",
+ 'H',TAG_PAX_SYMLINK_ARGS,ARGV_OPTARG_NONE,
+ ARGV_OPTION_HYBRID_ONLY,0,0,
+ "when a command-line argument is a symbolic link, "
+ "add the underlying (referenced) file-system object "
+ "or directory to the archive using the name of the "
+ "symbolic link."},
+
{"Wstrict-path-input",
0,TAG_STRICT_PATH,ARGV_OPTARG_NONE,
ARGV_OPTION_HYBRID_ONLY,0,0,