summaryrefslogtreecommitdiff
path: root/src/internal/slibtool_symlink_impl.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/internal/slibtool_symlink_impl.c')
-rw-r--r--src/internal/slibtool_symlink_impl.c89
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];