From 5966ea105ea86e52a734e04267956e11efffc92d Mon Sep 17 00:00:00 2001
From: Bram Moolenaar <Bram@vim.org>
Date: Wed, 15 Jul 2020 15:30:05 +0200
Subject: [PATCH] patch 8.2.1219: symlink not followed if dirname ends in //
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Problem:    Symlink not followed if dirname ends in //.
Solution:   Resolve symlink earlier. (Tomáš Janoušek, closes #6454)
---
 src/memline.c             | 18 +++++++++---------
 src/testdir/test_swap.vim | 30 ++++++++++++++++++++++++++++++
 src/version.c             |  2 ++
 3 files changed, 41 insertions(+), 9 deletions(-)

diff --git a/src/memline.c b/src/memline.c
index 347b44d6a1..084a8b0fa4 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -3287,10 +3287,12 @@ ml_append_buf(
 #endif
 
 /*
- * Replace line lnum, with buffering, in current buffer.
+ * Replace line "lnum", with buffering, in current buffer.
  *
  * If "copy" is TRUE, make a copy of the line, otherwise the line has been
  * copied to allocated memory already.
+ * If "copy" is FALSE the "line" may be freed to add text properties!
+ * Do not use it after calling ml_replace().
  *
  * Check: The caller of this function should probably also call
  * changed_lines(), unless update_screen(NOT_VALID) is used.
@@ -4366,6 +4368,11 @@ makeswapname(
     char_u	*fname_res = fname;
 #ifdef HAVE_READLINK
     char_u	fname_buf[MAXPATHL];
+
+    // Expand symlink in the file name, so that we put the swap file with the
+    // actual file instead of with the symlink.
+    if (resolve_symlink(fname, fname_buf) == OK)
+	fname_res = fname_buf;
 #endif
 
 #if defined(UNIX) || defined(MSWIN)  // Need _very_ long file names
@@ -4375,7 +4382,7 @@ makeswapname(
     if (after_pathsep(dir_name, s) && len > 1 && s[-1] == s[-2])
     {			       // Ends with '//', Use Full path
 	r = NULL;
-	if ((s = make_percent_swname(dir_name, fname)) != NULL)
+	if ((s = make_percent_swname(dir_name, fname_res)) != NULL)
 	{
 	    r = modname(s, (char_u *)".swp", FALSE);
 	    vim_free(s);
@@ -4384,13 +4391,6 @@ makeswapname(
     }
 #endif
 
-#ifdef HAVE_READLINK
-    // Expand symlink in the file name, so that we put the swap file with the
-    // actual file instead of with the symlink.
-    if (resolve_symlink(fname, fname_buf) == OK)
-	fname_res = fname_buf;
-#endif
-
     r = buf_modname(
 	    (buf->b_p_sn || buf->b_shortname),
 	    fname_res,
diff --git a/src/testdir/test_swap.vim b/src/testdir/test_swap.vim
index 7889d4b480..5cd1018048 100644
--- a/src/testdir/test_swap.vim
+++ b/src/testdir/test_swap.vim
@@ -377,4 +377,34 @@ func Test_swap_prompt_splitwin()
   call delete('Xfile1')
 endfunc
 
+func Test_swap_symlink()
+  if !has("unix")
+    return
+  endif
+
+  call writefile(['text'], 'Xtestfile')
+  silent !ln -s -f Xtestfile Xtestlink
+
+  set dir=.
+
+  " Test that swap file uses the name of the file when editing through a
+  " symbolic link (so that editing the file twice is detected)
+  edit Xtestlink
+  call assert_match('Xtestfile\.swp$', s:swapname())
+  bwipe!
+
+  call mkdir('Xswapdir')
+  exe 'set dir=' . getcwd() . '/Xswapdir//'
+
+  " Check that this also works when 'directory' ends with '//'
+  edit Xtestlink
+  call assert_match('Xtestfile\.swp$', s:swapname())
+  bwipe!
+
+  set dir&
+  call delete('Xtestfile')
+  call delete('Xtestlink')
+  call delete('Xswapdir', 'rf')
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 44769fc503..eff78356b6 100644
--- a/src/version.c
+++ b/src/version.c
@@ -754,6 +754,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1219,
 /**/
     1218,
 /**/
-- 
GitLab