summaryrefslogtreecommitdiffstats
path: root/src/memline.c
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2005-12-12 22:05:50 +0000
committerBram Moolenaar <Bram@vim.org>2005-12-12 22:05:50 +0000
commit900b4d77f00b3ab7503d5e2865eca61ce5005c69 (patch)
treea838e8bfddf54ca5c6a2761b554b6ae137213c9b /src/memline.c
parent2c7a29c7fd2e51236a00435ed37e280cb98a2131 (diff)
updated for version 7.0168v7.0168
Diffstat (limited to 'src/memline.c')
-rw-r--r--src/memline.c112
1 files changed, 110 insertions, 2 deletions
diff --git a/src/memline.c b/src/memline.c
index a6ab42c4e2..a8e4025be2 100644
--- a/src/memline.c
+++ b/src/memline.c
@@ -3382,6 +3382,87 @@ 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) /* found non-symlink, 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.
@@ -3395,6 +3476,10 @@ makeswapname(fname, ffname, buf, dir_name)
char_u *dir_name;
{
char_u *r, *s;
+#ifdef HAVE_READLINK
+ char_u fname_buf[MAXPATHL];
+ char_u *fname_res;
+#endif
#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
s = dir_name + STRLEN(dir_name);
@@ -3410,6 +3495,15 @@ makeswapname(fname, ffname, buf, dir_name)
}
#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;
+ else
+ fname_res = fname;
+#endif
+
r = buf_modname(
#ifdef SHORT_FNAME
TRUE,
@@ -3420,7 +3514,11 @@ makeswapname(fname, ffname, buf, dir_name)
/* Avoid problems if fname has special chars, eg <Wimp$Scrap> */
ffname,
#else
+# ifdef HAVE_READLINK
+ fname_res,
+# else
fname,
+# endif
#endif
(char_u *)
#if defined(VMS) || defined(RISCOS)
@@ -3848,7 +3946,17 @@ findswapname(buf, dirp, old_fname)
if (fnamecmp(gettail(buf->b_ffname),
gettail(b0.b0_fname)) != 0
|| !same_directory(fname, buf->b_ffname))
- differ = TRUE;
+ {
+#ifdef CHECK_INODE
+ /* Symlinks may point to the same file even
+ * when the name differs, need to check the
+ * inode too. */
+ expand_env(b0.b0_fname, NameBuff, MAXPATHL);
+ if (fnamecmp_ino(buf->b_ffname, NameBuff,
+ char_to_long(b0.b0_ino)))
+#endif
+ differ = TRUE;
+ }
}
else
{
@@ -3859,7 +3967,7 @@ findswapname(buf, dirp, old_fname)
expand_env(b0.b0_fname, NameBuff, MAXPATHL);
#ifdef CHECK_INODE
if (fnamecmp_ino(buf->b_ffname, NameBuff,
- char_to_long(b0.b0_ino)))
+ char_to_long(b0.b0_ino)))
differ = TRUE;
#else
if (fnamecmp(NameBuff, buf->b_ffname) != 0)