changeset 14475:dddba3937532 v8.1.0251

patch 8.1.0251: using full path is not supported for 'backupdir' commit https://github.com/vim/vim/commit/b782ba475a3f8f2b0be99dda164ba4545347f60f Author: Bram Moolenaar <Bram@vim.org> Date: Tue Aug 7 21:39:28 2018 +0200 patch 8.1.0251: using full path is not supported for 'backupdir' Problem: Using a full path is supported for 'directory' but not for 'backupdir'. (Mikolaj Machowski) Solution: Support 'backupdir' as well. (Christian Brabandt, closes #179)
author Christian Brabandt <cb@256bit.org>
date Tue, 07 Aug 2018 21:45:05 +0200
parents 6325f850efcf
children 756695a41362
files runtime/doc/options.txt src/Make_all.mak src/fileio.c src/memline.c src/proto/memline.pro src/testdir/test_alot.vim src/testdir/test_backup.vim src/version.c
diffstat 8 files changed, 125 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1054,6 +1054,14 @@ A jump table for the options with a shor
 	  name, precede it with a backslash.
 	- To include a comma in a directory name precede it with a backslash.
 	- A directory name may end in an '/'.
+	- For Unix and Win32, if a directory ends in two path separators "//",
+	  the swap file name will be built from the complete path to the file
+	  with all path separators changed to percent '%' signs. This will
+	  ensure file name uniqueness in the backup directory.
+	  On Win32, it is also possible to end with "\\".  However, When a
+	  separating comma is following, you must use "//", since "\\" will
+	  include the comma in the file name. Therefore it is recommended to
+	  use '//', instead of '\\'.
 	- Environment variables are expanded |:set_env|.
 	- Careful with '\' characters, type one before a space, type two to
 	  get one in the option (see |option-backslash|), for example: >
@@ -2680,12 +2688,14 @@ A jump table for the options with a shor
 	- A directory starting with "./" (or ".\" for MS-DOS et al.) means to
 	  put the swap file relative to where the edited file is.  The leading
 	  "." is replaced with the path name of the edited file.
-	- For Unix and Win32, if a directory ends in two path separators "//"
-	  or "\\", the swap file name will be built from the complete path to
-	  the file with all path separators substituted to percent '%' signs.
-	  This will ensure file name uniqueness in the preserve directory.
-	  On Win32, when a separating comma is following, you must use "//",
-	  since "\\" will include the comma in the file name.
+	- For Unix and Win32, if a directory ends in two path separators "//",
+	  the swap file name will be built from the complete path to the file
+	  with all path separators substituted to percent '%' signs. This will
+	  ensure file name uniqueness in the preserve directory.
+	  On Win32, it is also possible to end with "\\".  However, When a
+	  separating comma is following, you must use "//", since "\\" will
+	  include the comma in the file name. Therefore it is recommended to
+	  use '//', instead of '\\'.
 	- Spaces after the comma are ignored, other spaces are considered part
 	  of the directory name.  To have a space at the start of a directory
 	  name, precede it with a backslash.
--- a/src/Make_all.mak
+++ b/src/Make_all.mak
@@ -12,6 +12,7 @@ NEW_TESTS = \
 	test_autocmd \
 	test_autoload \
 	test_backspace_opt \
+	test_backup \
 	test_blockedit \
 	test_breakindent \
 	test_bufline \
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3850,6 +3850,9 @@ buf_write(
 	    stat_T	st_new;
 	    char_u	*dirp;
 	    char_u	*rootname;
+#if defined(UNIX) || defined(WIN3264)
+	    char_u      *p;
+#endif
 #if defined(UNIX)
 	    int		did_set_shortname;
 	    mode_t	umask_save;
@@ -3887,6 +3890,17 @@ buf_write(
 		 * Isolate one directory name, using an entry in 'bdir'.
 		 */
 		(void)copy_option_part(&dirp, copybuf, BUFSIZE, ",");
+
+#if defined(UNIX) || defined(WIN3264)
+		p = copybuf + STRLEN(copybuf);
+		if (after_pathsep(copybuf, p) && p[-1] == p[-2])
+		    // Ends with '//', use full path
+		    if ((p = make_percent_swname(copybuf, fname)) != NULL)
+		    {
+			backup = modname(p, backup_ext, FALSE);
+			vim_free(p);
+		    }
+#endif
 		rootname = get_file_in_dir(fname, copybuf);
 		if (rootname == NULL)
 		{
@@ -3904,9 +3918,10 @@ buf_write(
 		for (;;)
 		{
 		    /*
-		     * Make backup file name.
+		     * Make the backup file name.
 		     */
-		    backup = buf_modname((buf->b_p_sn || buf->b_shortname),
+		    if (backup == NULL)
+			backup = buf_modname((buf->b_p_sn || buf->b_shortname),
 						 rootname, backup_ext, FALSE);
 		    if (backup == NULL)
 		    {
@@ -4108,14 +4123,29 @@ buf_write(
 		 * Isolate one directory name and make the backup file name.
 		 */
 		(void)copy_option_part(&dirp, IObuff, IOSIZE, ",");
-		rootname = get_file_in_dir(fname, IObuff);
-		if (rootname == NULL)
-		    backup = NULL;
-		else
+
+#if defined(UNIX) || defined(WIN3264)
+		p = IObuff + STRLEN(IObuff);
+		if (after_pathsep(IObuff, p) && p[-1] == p[-2])
+		    // path ends with '//', use full path
+		    if ((p = make_percent_swname(IObuff, fname)) != NULL)
+		    {
+			backup = modname(p, backup_ext, FALSE);
+			vim_free(p);
+		    }
+#endif
+		if (backup == NULL)
 		{
-		    backup = buf_modname((buf->b_p_sn || buf->b_shortname),
-						 rootname, backup_ext, FALSE);
-		    vim_free(rootname);
+		    rootname = get_file_in_dir(fname, IObuff);
+		    if (rootname == NULL)
+			backup = NULL;
+		    else
+		    {
+			backup = buf_modname(
+				(buf->b_p_sn || buf->b_shortname),
+						rootname, backup_ext, FALSE);
+			vim_free(rootname);
+		    }
 		}
 
 		if (backup != NULL)
@@ -6252,7 +6282,7 @@ shorten_filenames(char_u **fnames, int c
 #endif
 
 /*
- * add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
+ * Add extension to file name - change path/fo.o.h to path/fo.o.h.ext or
  * fo_o_h.ext for MSDOS or when shortname option set.
  *
  * Assumed that fname is a valid name found in the filesystem we assure that
--- a/src/memline.c
+++ b/src/memline.c
@@ -262,9 +262,6 @@ static int fnamecmp_ino(char_u *, char_u
 #endif
 static void long_to_char(long, char_u *);
 static long char_to_long(char_u *);
-#if defined(UNIX) || defined(WIN3264)
-static char_u *make_percent_swname(char_u *dir, char_u *name);
-#endif
 #ifdef FEAT_CRYPT
 static cryptstate_T *ml_crypt_prepare(memfile_T *mfp, off_T offset, int reading);
 #endif
@@ -2007,18 +2004,18 @@ recover_names(
     return file_count;
 }
 
-#if defined(UNIX) || defined(WIN3264)  /* Need _very_ long file names */
+#if defined(UNIX) || defined(WIN3264) || defined(PROTO)
 /*
+ * Need _very_ long file names.
  * Append the full path to name with path separators made into percent
  * signs, to dir. An unnamed buffer is handled as "" (<currentdir>/"")
  */
-    static char_u *
+    char_u *
 make_percent_swname(char_u *dir, char_u *name)
 {
-    char_u *d, *s, *f;
-
-    f = fix_fname(name != NULL ? name : (char_u *) "");
-    d = NULL;
+    char_u *d = NULL, *s, *f;
+
+    f = fix_fname(name != NULL ? name : (char_u *)"");
     if (f != NULL)
     {
 	s = alloc((unsigned)(STRLEN(f) + 1));
@@ -4070,8 +4067,6 @@ attention_message(
 }
 
 #if defined(FEAT_EVAL)
-static int do_swapexists(buf_T *buf, char_u *fname);
-
 /*
  * Trigger the SwapExists autocommands.
  * Returns a value for equivalent to do_dialog() (see below):
--- a/src/proto/memline.pro
+++ b/src/proto/memline.pro
@@ -34,4 +34,5 @@ char_u *ml_encrypt_data(memfile_T *mfp, 
 void ml_decrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned size);
 long ml_find_line_or_offset(buf_T *buf, linenr_T lnum, long *offp);
 void goto_byte(long cnt);
+char_u *make_percent_swname (char_u *dir, char_u *name);
 /* vim: set ft=c : */
--- a/src/testdir/test_alot.vim
+++ b/src/testdir/test_alot.vim
@@ -2,6 +2,7 @@
 " This makes testing go faster, since Vim doesn't need to restart.
 
 source test_assign.vim
+source test_backup.vim
 source test_bufline.vim
 source test_cd.vim
 source test_changedtick.vim
new file mode 100644
--- /dev/null
+++ b/src/testdir/test_backup.vim
@@ -0,0 +1,58 @@
+" Tests for the backup function
+
+func Test_backup()
+  set backup backupdir=.
+  new
+  call setline(1, ['line1', 'line2'])
+  :f Xbackup.txt
+  :w! Xbackup.txt
+  " backup file is only created after
+  " writing a second time (before overwriting)
+  :w! Xbackup.txt
+  let l = readfile('Xbackup.txt~')
+  call assert_equal(['line1', 'line2'], l)
+  bw!
+  set backup&vim backupdir&vim
+  call delete('Xbackup.txt')
+  call delete('Xbackup.txt~')
+endfunc
+
+func Test_backup2()
+  set backup backupdir=.//
+  new
+  call setline(1, ['line1', 'line2', 'line3'])
+  :f Xbackup.txt
+  :w! Xbackup.txt
+  " backup file is only created after
+  " writing a second time (before overwriting)
+  :w! Xbackup.txt
+  sp *Xbackup.txt~
+  call assert_equal(['line1', 'line2', 'line3'], getline(1,'$'))
+  let f=expand('%')
+  call assert_match('src%testdir%Xbackup.txt\~', f)
+  bw!
+  bw!
+  call delete('Xbackup.txt')
+  call delete(f)
+  set backup&vim backupdir&vim
+endfunc
+
+func Test_backup2_backupcopy()
+  set backup backupdir=.// backupcopy=yes
+  new
+  call setline(1, ['line1', 'line2', 'line3'])
+  :f Xbackup.txt
+  :w! Xbackup.txt
+  " backup file is only created after
+  " writing a second time (before overwriting)
+  :w! Xbackup.txt
+  sp *Xbackup.txt~
+  call assert_equal(['line1', 'line2', 'line3'], getline(1,'$'))
+  let f=expand('%')
+  call assert_match('src%testdir%Xbackup.txt\~', f)
+  bw!
+  bw!
+  call delete('Xbackup.txt')
+  call delete(f)
+  set backup&vim backupdir&vim backupcopy&vim
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -795,6 +795,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    251,
+/**/
     250,
 /**/
     249,