# HG changeset patch # User Christian Brabandt # Date 1533671105 -7200 # Node ID dddba3937532c29eee6a34ff622d311f065da461 # Parent 6325f850efcf96bdf79d57284807fb82496c4ca0 patch 8.1.0251: using full path is not supported for 'backupdir' commit https://github.com/vim/vim/commit/b782ba475a3f8f2b0be99dda164ba4545347f60f Author: Bram Moolenaar 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) diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt --- 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. diff --git a/src/Make_all.mak b/src/Make_all.mak --- 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 \ diff --git a/src/fileio.c b/src/fileio.c --- 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 diff --git a/src/memline.c b/src/memline.c --- 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 "" (/"") */ - 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): diff --git a/src/proto/memline.pro b/src/proto/memline.pro --- 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 : */ diff --git a/src/testdir/test_alot.vim b/src/testdir/test_alot.vim --- 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 diff --git a/src/testdir/test_backup.vim b/src/testdir/test_backup.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 diff --git a/src/version.c b/src/version.c --- 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,