From 37f51391c8888c7f84e27ec6995fda5dd3af49c3 Mon Sep 17 00:00:00 2001 From: midipix Date: Thu, 6 Jun 2024 21:11:11 +0000 Subject: driver: implemented and integrated the -H (follow symlink args) cmdline option. --- include/tpax/tpax.h | 1 + src/driver/tpax_driver_ctx.c | 4 ++++ src/internal/tpax_driver_impl.h | 3 +++ src/logic/tpax_archive_enqueue.c | 38 +++++++++++++++++++++++++++++ src/logic/tpax_archive_write.c | 52 ++++++++++++++++++++++++++++++++++++++-- src/logic/tpax_queue_vector.c | 10 ++++++-- src/skin/tpax_skin_default.c | 8 +++++++ 7 files changed, 112 insertions(+), 4 deletions(-) diff --git a/include/tpax/tpax.h b/include/tpax/tpax.h index 2938d92..ec44b41 100644 --- a/include/tpax/tpax.h +++ b/include/tpax/tpax.h @@ -56,6 +56,7 @@ extern "C" { #define TPAX_DRIVER_PRESERVE_ATIME 0x1000000 #define TPAX_DRIVER_PRESERVE_MTIME 0x2000000 +#define TPAX_DRIVER_PAX_SYMLINK_ARGS 0x4000000 /* error flags */ #define TPAX_ERROR_TOP_LEVEL 0x0001 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, -- cgit v1.2.3