diff options
Diffstat (limited to 'src/internal/slibtool_symlink_impl.c')
-rw-r--r-- | src/internal/slibtool_symlink_impl.c | 89 |
1 files changed, 65 insertions, 24 deletions
diff --git a/src/internal/slibtool_symlink_impl.c b/src/internal/slibtool_symlink_impl.c index bb38333..bb117e2 100644 --- a/src/internal/slibtool_symlink_impl.c +++ b/src/internal/slibtool_symlink_impl.c @@ -1,6 +1,6 @@ /*******************************************************************/ -/* slibtool: a skinny libtool implementation, written in C */ -/* Copyright (C) 2016--2021 Z. Gilboa */ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ /* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ /*******************************************************************/ @@ -13,26 +13,32 @@ #include "slibtool_errinfo_impl.h" #include "slibtool_symlink_impl.h" #include "slibtool_readlink_impl.h" +#include "slibtool_realpath_impl.h" +#include "slibtool_snprintf_impl.h" +#include "slibtool_visibility_impl.h" #define SLBT_DEV_NULL_FLAGS (SLBT_DRIVER_ALL_STATIC \ | SLBT_DRIVER_DISABLE_SHARED \ | SLBT_DRIVER_DISABLE_STATIC) -int slbt_create_symlink( +slbt_hidden int slbt_create_symlink_ex( const struct slbt_driver_ctx * dctx, struct slbt_exec_ctx * ectx, + int fddst, const char * target, const char * lnkname, uint32_t options) { - int fdcwd; int fliteral; int fwrapper; int fdevnull; + size_t slen; char ** oargv; const char * slash; char * ln[5]; + char * dot; char * dotdot; + char * mark; char tmplnk [PATH_MAX]; char lnkarg [PATH_MAX]; char alnkarg[PATH_MAX]; @@ -45,18 +51,14 @@ int slbt_create_symlink( fdevnull = (options & SLBT_SYMLINK_DEVNULL); /* symlink is a placeholder? */ - if (fliteral && fdevnull) { + if (fliteral) { slash = target; - } else if ((dctx->cctx->drvflags & SLBT_DEV_NULL_FLAGS) - && !strcmp(target,"/dev/null")) { + /* .disabled .so or .a file */ + } else if (fdevnull) { slash = target; suffix = ".disabled"; - /* target is an absolute path? */ - } else if (fliteral) { - slash = target; - /* symlink target contains a dirname? */ } else if ((slash = strrchr(target,'/'))) { slash++; @@ -70,23 +72,52 @@ int slbt_create_symlink( dotdot = fwrapper ? "../" : ""; /* atarget */ - if ((size_t)snprintf(atarget,sizeof(atarget),"%s%s", - dotdot,slash) >= sizeof(atarget)) + if (slbt_snprintf(atarget,sizeof(atarget), + "%s%s",dotdot,slash) < 0) return SLBT_BUFFER_ERROR(dctx); /* tmplnk */ - if ((size_t)snprintf(tmplnk,sizeof(tmplnk),"%s.symlink.tmp", - lnkname) >= sizeof(tmplnk)) + if (slbt_snprintf(tmplnk,sizeof(tmplnk), + "%s.symlink.tmp", + lnkname) <0) return SLBT_BUFFER_ERROR(dctx); /* placeholder? */ + if (fdevnull) { + if (unlinkat(fddst,lnkname,0) && (errno != ENOENT)) + return SLBT_SYSTEM_ERROR(dctx,0); + + if ((dot = strrchr(lnkname,'.'))) { + if (!strcmp(dot,dctx->cctx->settings.dsosuffix)) { + strcpy(dot,".expsyms.a"); + + if (unlinkat(fddst,lnkname,0) && (errno != ENOENT)) + return SLBT_SYSTEM_ERROR(dctx,0); + + strcpy(dot,dctx->cctx->settings.dsosuffix); + } + } + } + if (suffix) { sprintf(alnkarg,"%s%s",lnkname,suffix); lnkname = alnkarg; } /* lnkarg */ - strcpy(lnkarg,lnkname); + if (fddst == slbt_driver_fdcwd(dctx)) { + strcpy(lnkarg,lnkname); + } else { + if (slbt_realpath(fddst,".",0,lnkarg,sizeof(lnkarg)) < 0) + return SLBT_BUFFER_ERROR(dctx); + + if ((slen = strlen(lnkarg)) + strlen(lnkname) + 1 >= PATH_MAX) + return SLBT_BUFFER_ERROR(dctx); + + mark = &lnkarg[slen]; + mark[0] = '/'; + strcpy(++mark,lnkname); + } /* ln argv (fake) */ ln[0] = "ln"; @@ -101,12 +132,12 @@ int slbt_create_symlink( /* step output */ if (!(dctx->cctx->drvflags & SLBT_DRIVER_SILENT)) { if (dctx->cctx->mode == SLBT_MODE_LINK) { - if (slbt_output_link(dctx,ectx)) { + if (slbt_output_link(ectx)) { ectx->argv = oargv; return SLBT_NESTED_ERROR(dctx); } } else { - if (slbt_output_install(dctx,ectx)) { + if (slbt_output_install(ectx)) { ectx->argv = oargv; return SLBT_NESTED_ERROR(dctx); } @@ -116,19 +147,29 @@ int slbt_create_symlink( /* restore execution context */ ectx->argv = oargv; - /* fdcwd */ - fdcwd = slbt_driver_fdcwd(dctx); - /* create symlink */ - if (symlinkat(atarget,fdcwd,tmplnk)) + if (symlinkat(atarget,fddst,tmplnk)) return SLBT_SYSTEM_ERROR(dctx,tmplnk); - return renameat(fdcwd,tmplnk,fdcwd,lnkname) + return renameat(fddst,tmplnk,fddst,lnkname) ? SLBT_SYSTEM_ERROR(dctx,lnkname) : 0; } -int slbt_symlink_is_a_placeholder(int fdcwd, char * lnkpath) +slbt_hidden int slbt_create_symlink( + const struct slbt_driver_ctx * dctx, + struct slbt_exec_ctx * ectx, + const char * target, + const char * lnkname, + uint32_t options) +{ + return slbt_create_symlink_ex( + dctx,ectx, + slbt_driver_fdcwd(dctx), + target,lnkname,options); +} + +slbt_hidden int slbt_symlink_is_a_placeholder(int fdcwd, const char * lnkpath) { size_t len; char slink [PATH_MAX]; |