[prev in list] [next in list] [prev in thread] [next in thread] 

List:       busybox
Subject:    Re: Patch to add "-r" option (create relative symlinks) to coreutils/ln
From:       Ross Thomas <halfacanuck () gmail ! com>
Date:       2016-06-19 7:57:05
Message-ID: CAJzZAcuk2PWjxDmFfw3snQmOCcGC806=L+O-L+R+qLJa71+23g () mail ! gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Thanks for the tip!

Here's the updated patch.


On Sat, Jun 18, 2016 at 12:41 PM, Tito <farmatito@tiscali.it> wrote:

>
>
> On 06/18/2016 05:24 PM, Ross Thomas wrote:
> > I recently had a need for the "-r" option to ln while using Busybox, and
> > it turned out to be easy enough to add, so here's a patch against
> v1.24.2.
> >
> > This is the first time I've poked at the BB source so it's possible I
> > overlooked something helpful in libbb, or am not using approved style,
> > or whatever. Suggestions welcome!
> >
> > Thanks,
> >
> > R
> >
>
> Hi,
> i think you could use something like:
>
>         opt_complementary = "-1:r?s"; /* min one arg */
>
> so to raise an error if -r is used without -s like real ln does:
>
>
> ln: cannot do --relative without --symbolic
>
> from libb/getopt32
>
>  "a?b"  A "?" between an option and a group of options means that
>         at least one of them is required to occur if the first option
>         occurs in preceding command line arguments.
>
>         For example from "id" applet:
>
>         // Don't allow -n -r -rn -ug -rug -nug -rnug
>         opt_complementary = "r?ug:n?ug:u--g:g--u";
>         flags = getopt32(argv, "rnug");
>
>         This example allowed only:
>         $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id
> -rng
>
> This is just a untested hint.
>
> Ciao,
> Tito
> _______________________________________________
> busybox mailing list
> busybox@busybox.net
> http://lists.busybox.net/mailman/listinfo/busybox
>

[Attachment #5 (text/html)]

<div dir="ltr"><div>Thanks for the tip!<br><br></div>Here&#39;s the updated \
patch.<br><div><div><br><div class="gmail_extra"><br><div class="gmail_quote">On Sat, \
Jun 18, 2016 at 12:41 PM, Tito <span dir="ltr">&lt;<a \
href="mailto:farmatito@tiscali.it" \
target="_blank">farmatito@tiscali.it</a>&gt;</span> wrote:<br><blockquote \
class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc \
solid;padding-left:1ex"><div class="HOEnZb"><div class="h5"><br> <br>
On 06/18/2016 05:24 PM, Ross Thomas wrote:<br>
&gt; I recently had a need for the &quot;-r&quot; option to ln while using Busybox, \
and<br> &gt; it turned out to be easy enough to add, so here&#39;s a patch against \
v1.24.2.<br> &gt;<br>
&gt; This is the first time I&#39;ve poked at the BB source so it&#39;s possible \
I<br> &gt; overlooked something helpful in libbb, or am not using approved style,<br>
&gt; or whatever. Suggestions welcome!<br>
&gt;<br>
&gt; Thanks,<br>
&gt;<br>
&gt; R<br>
&gt;<br>
<br>
</div></div>Hi,<br>
i think you could use something like:<br>
<br>
            opt_complementary = &quot;-1:r?s&quot;; /* min one arg */<br>
<br>
so to raise an error if -r is used without -s like real ln does:<br>
<br>
<br>
ln: cannot do --relative without --symbolic<br>
<br>
from libb/getopt32<br>
<br>
  &quot;a?b&quot;   A &quot;?&quot; between an option and a group of options means \
                that<br>
            at least one of them is required to occur if the first option<br>
            occurs in preceding command line arguments.<br>
<br>
            For example from &quot;id&quot; applet:<br>
<br>
            // Don&#39;t allow -n -r -rn -ug -rug -nug -rnug<br>
            opt_complementary = &quot;r?ug:n?ug:u--g:g--u&quot;;<br>
            flags = getopt32(argv, &quot;rnug&quot;);<br>
<br>
            This example allowed only:<br>
            $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng<br>
<br>
This is just a untested hint.<br>
<br>
Ciao,<br>
Tito<br>
_______________________________________________<br>
busybox mailing list<br>
<a href="mailto:busybox@busybox.net">busybox@busybox.net</a><br>
<a href="http://lists.busybox.net/mailman/listinfo/busybox" rel="noreferrer" \
target="_blank">http://lists.busybox.net/mailman/listinfo/busybox</a><br> \
</blockquote></div><br></div></div></div></div>


["ln-r.patch" (text/x-diff)]

--- busybox-1.24.2/coreutils/ln.c.orig	2016-02-11 03:50:37.000000000 -0800
+++ busybox-1.24.2/coreutils/ln.c	2016-06-19 00:22:58.720032674 -0700
@@ -18,6 +18,7 @@
 //usage:     "\n	-s	Make symlinks instead of hardlinks"
 //usage:     "\n	-f	Remove existing destinations"
 //usage:     "\n	-n	Don't dereference symlinks - treat like normal file"
+//usage:     "\n	-r	Create symlinks relative to link location (with -s)"
 //usage:     "\n	-b	Make a backup of the target (if exists) before link operation"
 //usage:     "\n	-S suf	Use suffix instead of ~ when making backup files"
 //usage:     "\n	-T	2nd arg must be a DIR"
@@ -40,6 +41,74 @@
 #define LN_SUFFIX           (1 << 4)
 #define LN_VERBOSE          (1 << 5)
 #define LN_LINKFILE         (1 << 6)
+#define LN_RELATIVE         (1 << 7)
+
+
+static int common_prefix_length(const char *path1, const char *path2)
+{
+	const char *start1 = path1;
+
+	/* NB: Function assumes absolute paths */
+
+	/* Find common string prefix */
+
+	while (*path1 && *path2 && *path1 == *path2) {
+		path1++;
+		path2++;
+	}
+
+	/* Search backwards to common path-component prefix */
+
+	while (path1 > start1 && *path1 != '/') {
+		path1--;
+	}
+
+	return (path1 + 1) - start1;
+}
+
+static char *xmalloc_relativized_target(const char *target, const char *src)
+{
+	const char *target_abs, *src_abs, *src_last, *sp;
+	char *out, *op;
+	int out_len, common_len;
+
+	/* Absolutize both inputs */
+
+	target_abs = bb_simplify_path(target);
+	src_abs = bb_simplify_path(src);
+
+	/* Output can't be longer than twice the longest absolutized input */
+
+	out_len = 1 + 2 * MAX(strlen(target_abs), strlen(src_abs));
+	out = op = xmalloc(out_len);
+
+	/* Skip common leading components */
+
+	common_len = common_prefix_length(target_abs, src_abs);
+	sp = src_abs + common_len;
+
+	/* Output "../" for each non-tail component remaining in src */
+
+	src_last = bb_get_last_path_component_nostrip(src_abs);
+	while (sp < src_last) {
+		if ('/' == *sp) {
+			*op++ = '.';
+			*op++ = '.';
+			*op++ = '/';
+		}
+		sp++;
+	}
+
+	/* Append target postfix */
+
+	strcpy(op, target_abs + common_len);
+
+	free((char *)target_abs);
+	free((char *)src_abs);
+
+	return out;
+}
+
 
 int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int ln_main(int argc, char **argv)
@@ -49,12 +118,13 @@
 	char *last;
 	char *src_name;
 	char *src;
+	char *target;
 	char *suffix = (char*)"~";
 	struct stat statbuf;
 	int (*link_func)(const char *, const char *);
 
-	opt_complementary = "-1"; /* min one arg */
-	opts = getopt32(argv, "sfnbS:vT", &suffix);
+	opt_complementary = "-1r?s"; /* min one arg; cannot use -r without -s */
+	opts = getopt32(argv, "sfnbS:vTr", &suffix);
 
 	last = argv[argc - 1];
 	argv += optind;
@@ -120,19 +190,28 @@
 		}
 
 		link_func = link;
+		target = *argv;
 		if (opts & LN_SYMLINK) {
 			link_func = symlink;
+			if (opts & LN_RELATIVE) {
+				target = xmalloc_relativized_target(*argv, src);
+			}
 		}
 
 		if (opts & LN_VERBOSE) {
-			printf("'%s' -> '%s'\n", src, *argv);
+			printf("'%s' -> '%s'\n", src, target);
 		}
 
-		if (link_func(*argv, src) != 0) {
+		if (link_func(target, src) != 0) {
 			bb_simple_perror_msg(src);
 			status = EXIT_FAILURE;
 		}
 
+		if (target != *argv) {
+			free(target);
+			target = NULL;
+		}
+
 		free(src_name);
 	} while ((++argv)[1]);
 


_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic