To: vim_dev@googlegroups.com Subject: Patch 7.4.1114 Fcc: outbox From: Bram Moolenaar Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ------------ Patch 7.4.1114 (after 7.4.1107) Problem: delete() does not work well with symbolic links. Solution: Recognize symbolik links. Files: src/eval.c, src/fileio.c, src/os_unix.c, src/proto/os_unix.pro, src/testdir/test_delete.vim, runtime/doc/eval.txt *** ../vim-7.4.1113/src/eval.c 2016-01-17 14:58:43.235669165 +0100 --- src/eval.c 2016-01-17 15:35:11.980262328 +0100 *************** *** 10418,10424 **** /* delete an empty directory */ rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1; else if (STRCMP(flags, "rf") == 0) ! /* delete an directory recursively */ rettv->vval.v_number = delete_recursive(name); else EMSG2(_(e_invexpr2), flags); --- 10418,10424 ---- /* delete an empty directory */ rettv->vval.v_number = mch_rmdir(name) == 0 ? 0 : -1; else if (STRCMP(flags, "rf") == 0) ! /* delete a directory recursively */ rettv->vval.v_number = delete_recursive(name); else EMSG2(_(e_invexpr2), flags); *** ../vim-7.4.1113/src/fileio.c 2016-01-16 21:26:30.493956526 +0100 --- src/fileio.c 2016-01-17 15:50:05.422716732 +0100 *************** *** 7294,7300 **** int i; char_u *exp; ! if (mch_isdir(name)) { vim_snprintf((char *)NameBuff, MAXPATHL, "%s/*", name); exp = vim_strsave(NameBuff); --- 7294,7312 ---- int i; char_u *exp; ! /* 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); *** ../vim-7.4.1113/src/os_unix.c 2016-01-02 22:25:40.674710064 +0100 --- src/os_unix.c 2016-01-17 15:50:12.050645761 +0100 *************** *** 2994,3000 **** } /* ! * return TRUE if "name" is a directory * return FALSE if "name" is not a directory * return FALSE for error */ --- 2994,3000 ---- } /* ! * 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 */ *************** *** 3010,3015 **** --- 3010,3037 ---- 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 + } + + /* + * 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 *** ../vim-7.4.1113/src/proto/os_unix.pro 2015-12-31 19:06:56.040081995 +0100 --- src/proto/os_unix.pro 2016-01-17 15:49:42.830958226 +0100 *************** *** 41,46 **** --- 41,47 ---- 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)); *** ../vim-7.4.1113/src/testdir/test_delete.vim 2016-01-16 21:26:30.501956438 +0100 --- src/testdir/test_delete.vim 2016-01-17 15:32:17.638124457 +0100 *************** *** 34,36 **** --- 34,97 ---- 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 *** ../vim-7.4.1113/runtime/doc/eval.txt 2016-01-16 21:26:30.505956395 +0100 --- runtime/doc/eval.txt 2016-01-17 15:52:03.473452633 +0100 *************** *** 2741,2753 **** delete({fname} [, {flags}]) *delete()* Without {flags} or with {flags} empty: Deletes the file by the ! name {fname}. When {flags} is "d": Deletes the directory by the name ! {fname}. This fails when {fname} is not empty. When {flags} is "rf": Deletes the directory by the name ! {fname} and everything in it, recursively. Be careful! The result is a Number, which is 0 if the delete operation was successful and -1 when the deletion failed or partly failed. --- 2755,2768 ---- delete({fname} [, {flags}]) *delete()* Without {flags} or with {flags} empty: Deletes the file by the ! name {fname}. This also works when {fname} is a symbolic link. When {flags} is "d": Deletes the directory by the name ! {fname}. This fails when directory {fname} is not empty. When {flags} is "rf": Deletes the directory by the name ! {fname} and everything in it, recursively. BE CAREFUL! ! A symbolic link itself is deleted, not what it points to. The result is a Number, which is 0 if the delete operation was successful and -1 when the deletion failed or partly failed. *** ../vim-7.4.1113/src/version.c 2016-01-17 14:58:43.239669122 +0100 --- src/version.c 2016-01-17 15:55:10.031454839 +0100 *************** *** 743,744 **** --- 743,746 ---- { /* Add new patch number below this line */ + /**/ + 1114, /**/ -- If your company is not involved in something called "ISO 9000" you probably have no idea what it is. If your company _is_ involved in ISO 9000 then you definitely have no idea what it is. (Scott Adams - The Dilbert principle) /// Bram Moolenaar -- Bram@Moolenaar.net -- http://www.Moolenaar.net \\\ /// sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\ \\\ an exciting new programming language -- http://www.Zimbu.org /// \\\ help me help AIDS victims -- http://ICCF-Holland.org ///