summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/eval.c2
-rw-r--r--src/fileio.c14
-rw-r--r--src/os_unix.c24
-rw-r--r--src/proto/os_unix.pro1
-rw-r--r--src/testdir/test_delete.vim61
-rw-r--r--src/version.c2
6 files changed, 101 insertions, 3 deletions
diff --git a/src/eval.c b/src/eval.c
index fb2cbe79e..aec1ea987 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -10418,7 +10418,7 @@ f_delete(argvars, rettv)
/* delete an empty directory */
rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1;
else if (STRCMP(flags, "rf") == 0)
- /* delete an directory recursively */
+ /* delete a directory recursively */
rettv->vval.v_number = delete_recursive(name);
else
EMSG2(_(e_invexpr2), flags);
diff --git a/src/fileio.c b/src/fileio.c
index 6dbdea21e..f809eb5bc 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -7294,7 +7294,19 @@ delete_recursive(char_u *name)
int i;
char_u *exp;
- if (mch_isdir(name))
+ /* A symbolic link to a directory itself is deleted, not the directory it
+ * points to. */
+ if (
+# if defined(WIN32)
+ mch_isdir(name) && !mch_is_symbolic_link(name)
+# else
+# ifdef UNIX
+ mch_isrealdir(name)
+# else
+ mch_isdir(name)
+# endif
+# endif
+ )
{
vim_snprintf((char *)NameBuff, MAXPATHL, "%s/*", name);
exp = vim_strsave(NameBuff);
diff --git a/src/os_unix.c b/src/os_unix.c
index 36196369c..d2e1c79bd 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -2994,7 +2994,7 @@ mch_hide(name)
}
/*
- * return TRUE if "name" is a directory
+ * return TRUE if "name" is a directory or a symlink to a directory
* return FALSE if "name" is not a directory
* return FALSE for error
*/
@@ -3015,6 +3015,28 @@ mch_isdir(name)
#endif
}
+/*
+ * return TRUE if "name" is a directory, NOT a symlink to a directory
+ * return FALSE if "name" is not a directory
+ * return FALSE for error
+ */
+ int
+mch_isrealdir(name)
+ char_u *name;
+{
+ struct stat statb;
+
+ if (*name == NUL) /* Some stat()s don't flag "" as an error. */
+ return FALSE;
+ if (lstat((char *)name, &statb))
+ return FALSE;
+#ifdef _POSIX_SOURCE
+ return (S_ISDIR(statb.st_mode) ? TRUE : FALSE);
+#else
+ return ((statb.st_mode & S_IFMT) == S_IFDIR ? TRUE : FALSE);
+#endif
+}
+
static int executable_file __ARGS((char_u *name));
/*
diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro
index 89dff7791..be6eb6f10 100644
--- a/src/proto/os_unix.pro
+++ b/src/proto/os_unix.pro
@@ -41,6 +41,7 @@ void mch_set_acl __ARGS((char_u *fname, vim_acl_T aclent));
void mch_free_acl __ARGS((vim_acl_T aclent));
void mch_hide __ARGS((char_u *name));
int mch_isdir __ARGS((char_u *name));
+int mch_isrealdir __ARGS((char_u *name));
int mch_can_exe __ARGS((char_u *name, char_u **path, int use_path));
int mch_nodetype __ARGS((char_u *name));
void mch_early_init __ARGS((void));
diff --git a/src/testdir/test_delete.vim b/src/testdir/test_delete.vim
index 6e2b9c86b..13c87a152 100644
--- a/src/testdir/test_delete.vim
+++ b/src/testdir/test_delete.vim
@@ -34,3 +34,64 @@ func Test_recursive_delete()
call assert_false(isdirectory('Xdir1'))
call assert_equal(-1, delete('Xdir1', 'd'))
endfunc
+
+func Test_symlink_delete()
+ if !has('unix')
+ return
+ endif
+ split Xfile
+ call setline(1, ['a', 'b'])
+ wq
+ silent !ln -s Xfile Xlink
+ " Delete the link, not the file
+ call assert_equal(0, delete('Xlink'))
+ call assert_equal(-1, delete('Xlink'))
+ call assert_equal(0, delete('Xfile'))
+endfunc
+
+func Test_symlink_dir_delete()
+ if !has('unix')
+ return
+ endif
+ call mkdir('Xdir1')
+ silent !ln -s Xdir1 Xlink
+ call assert_true(isdirectory('Xdir1'))
+ call assert_true(isdirectory('Xlink'))
+ " Delete the link, not the directory
+ call assert_equal(0, delete('Xlink'))
+ call assert_equal(-1, delete('Xlink'))
+ call assert_equal(0, delete('Xdir1', 'd'))
+endfunc
+
+func Test_symlink_recursive_delete()
+ if !has('unix')
+ return
+ endif
+ call mkdir('Xdir3')
+ call mkdir('Xdir3/subdir')
+ call mkdir('Xdir4')
+ split Xdir3/Xfile
+ call setline(1, ['a', 'b'])
+ w
+ w Xdir3/subdir/Xfile
+ w Xdir4/Xfile
+ close
+ silent !ln -s ../Xdir4 Xdir3/Xlink
+
+ call assert_true(isdirectory('Xdir3'))
+ call assert_equal(['a', 'b'], readfile('Xdir3/Xfile'))
+ call assert_true(isdirectory('Xdir3/subdir'))
+ call assert_equal(['a', 'b'], readfile('Xdir3/subdir/Xfile'))
+ call assert_true(isdirectory('Xdir4'))
+ call assert_true(isdirectory('Xdir3/Xlink'))
+ call assert_equal(['a', 'b'], readfile('Xdir4/Xfile'))
+
+ call assert_equal(0, delete('Xdir3', 'rf'))
+ call assert_false(isdirectory('Xdir3'))
+ call assert_equal(-1, delete('Xdir3', 'd'))
+ " symlink is deleted, not the directory it points to
+ call assert_true(isdirectory('Xdir4'))
+ call assert_equal(['a', 'b'], readfile('Xdir4/Xfile'))
+ call assert_equal(0, delete('Xdir4/Xfile'))
+ call assert_equal(0, delete('Xdir4', 'd'))
+endfunc
diff --git a/src/version.c b/src/version.c
index 8d9fda815..571cb682c 100644
--- a/src/version.c
+++ b/src/version.c
@@ -742,6 +742,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1114,
+/**/
1113,
/**/
1112,