summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2023-09-23 00:15:46 -0700
committerKaz Kylheku <kaz@kylheku.com>2023-09-23 00:15:46 -0700
commit2df419cdb5295b405a98d24f0226cb42bfbf37d2 (patch)
tree8573aac3d9beecd34b10387df4147e1cc518bcc0
parent9e197d1ef054cd389a3ed89cfe66f80ac1a979f2 (diff)
downloadtxr-2df419cdb5295b405a98d24f0226cb42bfbf37d2.tar.gz
txr-2df419cdb5295b405a98d24f0226cb42bfbf37d2.tar.bz2
txr-2df419cdb5295b405a98d24f0226cb42bfbf37d2.zip
New function: rlink.
This uses the linkat function to implement a variant of link which resolves the source object if it is a symlink. * configure: test for linkat. * sysif.c (link_wrap_common): New static function, used by both link_wrap and rlink_wrap. (link_wrap): Now a one-liner which calls link_wrap_common. (rlink_wrap): New static function. (sysif_init): Register rlink intrinsic. * txr.1: Documented.
-rwxr-xr-xconfigure20
-rw-r--r--sysif.c23
-rw-r--r--txr.116
3 files changed, 55 insertions, 4 deletions
diff --git a/configure b/configure
index 51f7723c..256abb72 100755
--- a/configure
+++ b/configure
@@ -2665,6 +2665,26 @@ else
printf "no\n"
fi
+printf "Checking for linkat ... "
+
+cat > conftest.c <<!
+#include <unistd.h>
+#include <fcntl.h>
+
+int main(void)
+{
+ int e1 = linkat(AT_FDCWD, "foo", AT_FDCWD, "bar", AT_SYMLINK_FOLLOW);
+ return 0;
+}
+!
+if conftest ; then
+ printf "yes\n"
+ printf "#define HAVE_LINKAT 1\n" >> config.h
+ have_unistd=y
+else
+ printf "no\n"
+fi
+
printf "Checking for POSIX mkdir ... "
cat > conftest.c <<!
diff --git a/sysif.c b/sysif.c
index e8fa1dac..b02ec607 100644
--- a/sysif.c
+++ b/sysif.c
@@ -957,14 +957,18 @@ static val symlink_wrap(val target, val to)
return t;
}
-static val link_wrap(val target, val to)
+static val link_wrap_common(val target, val to, val follow_link, val self)
{
- val self = lit("link");
const wchar_t *wtarget = c_str(target, self);
const wchar_t *wto = c_str(to, self);
char *u8target = utf8_dup_to(wtarget);
char *u8to = utf8_dup_to(wto);
+#if HAVE_LINKAT
+ int err = linkat(AT_FDCWD, u8target, AT_FDCWD, u8to,
+ if3(follow_link, AT_SYMLINK_FOLLOW, 0));
+#else
int err = link(u8target, u8to);
+#endif
free(u8target);
free(u8to);
@@ -977,6 +981,18 @@ static val link_wrap(val target, val to)
return t;
}
+static val link_wrap(val target, val to)
+{
+ return link_wrap_common(target, to, nil, lit("link"));
+}
+
+#if HAVE_LINKAT
+static val rlink_wrap(val target, val to)
+{
+ return link_wrap_common(target, to, t, lit("rlink"));
+}
+#endif
+
static val readlink_wrap(val path)
{
val self = lit("readlink");
@@ -2783,6 +2799,9 @@ void sysif_init(void)
reg_fun(intern(lit("symlink"), user_package), func_n2(symlink_wrap));
reg_fun(intern(lit("link"), user_package), func_n2(link_wrap));
reg_fun(intern(lit("readlink"), user_package), func_n1(readlink_wrap));
+#if HAVE_LINKAT
+ reg_fun(intern(lit("rlink"), user_package), func_n2(rlink_wrap));
+#endif
#endif
#if HAVE_FCNTL
diff --git a/txr.1 b/txr.1
index f432e7c4..27843e6b 100644
--- a/txr.1
+++ b/txr.1
@@ -73601,10 +73601,11 @@ of the
.code s-ififo
type and the permission mode bits.
-.coNP Functions @ symlink and @ link
+.coNP Functions @, symlink @ link and @ rlink
.synb
.mets (symlink < target << path )
.mets (link < target << path )
+.mets (rlink < target << path )
.syne
.desc
The
@@ -73617,13 +73618,24 @@ are the absolute or relative path
.meta target
does not actually have to exist.
-The link function creates a hard link. The object at
+The
+.code link
+function creates a hard link. The object at
.meta target
is installed
into the filesystem at
.meta path
also.
+The
+.code rlink
+function is like
+.code link
+except that if
+.meta path
+is a symbolic link, it is resolved.
+
+
If these functions succeed, they return
.codn t .
Otherwise they throw an exception