summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRémy Lefevre <lefevreremy@gmail.com>2013-04-02 02:48:28 +0100
committerPádraig Brady <P@draigBrady.com>2013-04-04 02:46:35 +0100
commite52293aa7fcf283758f97bc9bcc945707ccbce0a (patch)
treed663b5fd9420298f1032c623589fd23902f0d7e8 /src
parent20d7bce0f7e57d9a98f0ee811e31c757e9fedfff (diff)
downloadcoreutils-e52293aa7fcf283758f97bc9bcc945707ccbce0a.tar.xz
ln: --relative: fix updating of existing symlinks
Don't dereference an existing symlink being replaced. I.E. generate the symlink relative to the symlink's containing dir, rather than to some arbitrary place it points to. * src/ln.c (convert_abs_rel): Don't consider the final component of the symlink name when canonicalizing, as we want to avoid dereferencing the final component. * tests/ln/relative.sh: Add a test case. * NEWS: Mention the fix. Resolves http://bugs.gnu.org/14116
Diffstat (limited to 'src')
-rw-r--r--src/ln.c14
1 files changed, 8 insertions, 6 deletions
diff --git a/src/ln.c b/src/ln.c
index 1aa147324..2489b9ac7 100644
--- a/src/ln.c
+++ b/src/ln.c
@@ -132,22 +132,24 @@ target_directory_operand (char const *file)
static char *
convert_abs_rel (const char *from, const char *target)
{
- char *realtarget = canonicalize_filename_mode (target, CAN_MISSING);
+ /* Get dirname to generate paths relative to. We don't resolve
+ the full TARGET as the last component could be an existing symlink. */
+ char *targetdir = dir_name (target);
+
+ char *realdest = canonicalize_filename_mode (targetdir, CAN_MISSING);
char *realfrom = canonicalize_filename_mode (from, CAN_MISSING);
/* Write to a PATH_MAX buffer. */
char *relative_from = xmalloc (PATH_MAX);
- /* Get dirname to generate paths relative to. */
- realtarget[dir_len (realtarget)] = '\0';
-
- if (!relpath (realfrom, realtarget, relative_from, PATH_MAX))
+ if (!relpath (realfrom, realdest, relative_from, PATH_MAX))
{
free (relative_from);
relative_from = NULL;
}
- free (realtarget);
+ free (targetdir);
+ free (realdest);
free (realfrom);
return relative_from ? relative_from : xstrdup (from);