On Wed, Aug 06, 2008 at 01:11:30PM +0200, Bram Moolenaar wrote:
> Matt Wozniski wrote:
> 
> > Try this:
> > 
> > In terminal 1:
> > touch a
> > ln -s a b
> > vim b
> > 
> > In terminal 2:
> > vim b
> > 
> > We get:
> > 
> > E325: ATTENTION
> > Found a swap file by the name "/tmp/vimtest/.a.swp"
> > ...
> >          file name: /tmp/vimtest/b
> > ...
> > While opening file "b"
> > 
> > So, we know that the file we're working on is "b", but that the
> > swapfile exists at "a".
> > 
> > Then, press 'r' to recover, and we get...
> > 
> > "b" 0L, 0C
> > E305: No swap file found for b
> > 
> > because recover is only looking for b.swp and not noticing a.swp.
> > Seems this should be easy to deal with, since we already know that
> > /tmp/vimtest/.a.swp is the swap file for /tmp/vimtest/b, but I don't
> > have time to dig in right now so I'll have to punt this to the list.
> 
> Yeah, that is wrong.  One more for the todo list...

This is happening because symlinks are resolved (if readlink(2) is
available) when creating a swapfile to make sure that swapfiles are
stored alongside the actual file being edited (in a default config).

ml_recover calls recover_names to get the list of potential file names,
so this needs to perform the same symlink resolution.  Attached is a
patch to fix this.

-- 
James
GPG Key: 1024D/61326D40 2003-09-02 James Vega <[EMAIL PROTECTED]>
diff --git a/src/memline.c b/src/memline.c
index f5a68b1..fb569f2 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -1364,6 +1364,88 @@ theend:
     return;
 }
 
+#ifdef HAVE_READLINK
+static int resolve_symlink __ARGS((char_u *fname, char_u *buf));
+
+/*
+ * Resolve a symlink in the last component of a file name.
+ * Note that f_resolve() does it for every part of the path, we don't do that
+ * here.
+ * If it worked returns OK and the resolved link in "buf[MAXPATHL]".
+ * Otherwise returns FAIL.
+ */
+    static int
+resolve_symlink(fname, buf)
+    char_u	*fname;
+    char_u	*buf;
+{
+    char_u	tmp[MAXPATHL];
+    int		ret;
+    int		depth = 0;
+
+    if (fname == NULL)
+	return FAIL;
+
+    /* Put the result so far in tmp[], starting with the original name. */
+    vim_strncpy(tmp, fname, MAXPATHL - 1);
+
+    for (;;)
+    {
+	/* Limit symlink depth to 100, catch recursive loops. */
+	if (++depth == 100)
+	{
+	    EMSG2(_("E773: Symlink loop for \"%s\""), fname);
+	    return FAIL;
+	}
+
+	ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
+	if (ret <= 0)
+	{
+	    if (errno == EINVAL || errno == ENOENT)
+	    {
+		/* Found non-symlink or not existing file, stop here.
+		 * When at the first level use the unmodifed name, skip the
+		 * call to vim_FullName(). */
+		if (depth == 1)
+		    return FAIL;
+
+		/* Use the resolved name in tmp[]. */
+		break;
+	    }
+
+	    /* There must be some error reading links, use original name. */
+	    return FAIL;
+	}
+	buf[ret] = NUL;
+
+	/*
+	 * Check whether the symlink is relative or absolute.
+	 * If it's relative, build a new path based on the directory
+	 * portion of the filename (if any) and the path the symlink
+	 * points to.
+	 */
+	if (mch_isFullName(buf))
+	    STRCPY(tmp, buf);
+	else
+	{
+	    char_u *tail;
+
+	    tail = gettail(tmp);
+	    if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
+		return FAIL;
+	    STRCPY(tail, buf);
+	}
+    }
+
+    /*
+     * Try to resolve the full name of the file so that the swapfile name will
+     * be consistent even when opening a relative symlink from different
+     * working directories.
+     */
+    return vim_FullName(tmp, buf, MAXPATHL, TRUE);
+}
+#endif
+
 /*
  * Find the names of swap files in current directory and the directory given
  * with the 'directory' option.
@@ -1390,6 +1472,17 @@ recover_names(fname, list, nr)
     int		i;
     char_u	*dirp;
     char_u	*dir_name;
+#ifdef HAVE_READLINK
+    char_u	fname_buf[MAXPATHL];
+    char_u	*fname_res;
+
+    /* 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;
+    else
+	fname_res = *fname;
+#endif
 
     if (list)
     {
@@ -1442,7 +1535,13 @@ recover_names(fname, list, nr)
 #endif
 	    }
 	    else
-		num_names = recov_file_names(names, *fname, TRUE);
+		num_names = recov_file_names(names,
+#ifdef HAVE_READLINK
+					     fname_res,
+#else
+					     *fname,
+#endif
+					     TRUE);
 	}
 	else			    /* check directory dir_name */
 	{
@@ -1479,12 +1578,24 @@ recover_names(fname, list, nr)
 		if (after_pathsep(dir_name, p) && p[-1] == p[-2])
 		{
 		    /* Ends with '//', Use Full path for swap name */
-		    tail = make_percent_swname(dir_name, *fname);
+		    tail = make_percent_swname(dir_name,
+#ifdef HAVE_READLINK
+					       fname_res
+#else
+					       *fname
+#endif
+					       );
 		}
 		else
 #endif
 		{
-		    tail = gettail(*fname);
+		    tail = gettail(
+#ifdef HAVE_READLINK
+				   fname_res
+#else
+				   *fname
+#endif
+				   );
 		    tail = concat_fnames(dir_name, tail, TRUE);
 		}
 		if (tail == NULL)
@@ -1524,11 +1635,18 @@ recover_names(fname, list, nr)
 	    struct stat	    st;
 	    char_u	    *swapname;
 
+	    swapname = modname(
+#ifdef HAVE_READLINK
+			       fname_res,
+#else
+			       *fname,
+#endif
 #if defined(VMS) || defined(RISCOS)
-	    swapname = modname(*fname, (char_u *)"_swp", FALSE);
+			       (char_u *)"_swp", FALSE
 #else
-	    swapname = modname(*fname, (char_u *)".swp", TRUE);
+			       (char_u *)".swp", TRUE
 #endif
+			      );
 	    if (swapname != NULL)
 	    {
 		if (mch_stat((char *)swapname, &st) != -1)	    /* It exists! */
@@ -3482,88 +3600,6 @@ ml_lineadd(buf, count)
     }
 }
 
-#ifdef HAVE_READLINK
-static int resolve_symlink __ARGS((char_u *fname, char_u *buf));
-
-/*
- * Resolve a symlink in the last component of a file name.
- * Note that f_resolve() does it for every part of the path, we don't do that
- * here.
- * If it worked returns OK and the resolved link in "buf[MAXPATHL]".
- * Otherwise returns FAIL.
- */
-    static int
-resolve_symlink(fname, buf)
-    char_u	*fname;
-    char_u	*buf;
-{
-    char_u	tmp[MAXPATHL];
-    int		ret;
-    int		depth = 0;
-
-    if (fname == NULL)
-	return FAIL;
-
-    /* Put the result so far in tmp[], starting with the original name. */
-    vim_strncpy(tmp, fname, MAXPATHL - 1);
-
-    for (;;)
-    {
-	/* Limit symlink depth to 100, catch recursive loops. */
-	if (++depth == 100)
-	{
-	    EMSG2(_("E773: Symlink loop for \"%s\""), fname);
-	    return FAIL;
-	}
-
-	ret = readlink((char *)tmp, (char *)buf, MAXPATHL - 1);
-	if (ret <= 0)
-	{
-	    if (errno == EINVAL || errno == ENOENT)
-	    {
-		/* Found non-symlink or not existing file, stop here.
-		 * When at the first level use the unmodifed name, skip the
-		 * call to vim_FullName(). */
-		if (depth == 1)
-		    return FAIL;
-
-		/* Use the resolved name in tmp[]. */
-		break;
-	    }
-
-	    /* There must be some error reading links, use original name. */
-	    return FAIL;
-	}
-	buf[ret] = NUL;
-
-	/*
-	 * Check whether the symlink is relative or absolute.
-	 * If it's relative, build a new path based on the directory
-	 * portion of the filename (if any) and the path the symlink
-	 * points to.
-	 */
-	if (mch_isFullName(buf))
-	    STRCPY(tmp, buf);
-	else
-	{
-	    char_u *tail;
-
-	    tail = gettail(tmp);
-	    if (STRLEN(tail) + STRLEN(buf) >= MAXPATHL)
-		return FAIL;
-	    STRCPY(tail, buf);
-	}
-    }
-
-    /*
-     * Try to resolve the full name of the file so that the swapfile name will
-     * be consistent even when opening a relative symlink from different
-     * working directories.
-     */
-    return vim_FullName(tmp, buf, MAXPATHL, TRUE);
-}
-#endif
-
 /*
  * Make swap file name out of the file name and a directory name.
  * Returns pointer to allocated memory or NULL.

Attachment: signature.asc
Description: Digital signature

Raspunde prin e-mail lui