From b782ba475a3f8f2b0be99dda164ba4545347f60f Mon Sep 17 00:00:00 2001 From: Bram Moolenaar Date: Tue, 7 Aug 2018 21:39:28 +0200 Subject: 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) --- runtime/doc/options.txt | 22 ++++++++++++----- src/Make_all.mak | 1 + src/fileio.c | 50 ++++++++++++++++++++++++++++++-------- src/memline.c | 15 ++++-------- src/proto/memline.pro | 1 + src/testdir/test_alot.vim | 1 + src/testdir/test_backup.vim | 58 +++++++++++++++++++++++++++++++++++++++++++++ src/version.c | 2 ++ 8 files changed, 124 insertions(+), 26 deletions(-) create mode 100644 src/testdir/test_backup.vim diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt index 8645c47333..eb455fc09b 100644 --- a/runtime/doc/options.txt +++ b/runtime/doc/options.txt @@ -1054,6 +1054,14 @@ A jump table for the options with a short description can be found at |Q_op|. 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 short description can be found at |Q_op|. - 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 index 9831f7b044..49ad4f0af8 100644 --- 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 index 281191cfbf..42f388a11f 100644 --- 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 count) #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 index be395fce6b..a2f0b4f626 100644 --- a/src/memline.c +++ b/src/memline.c @@ -262,9 +262,6 @@ static int fnamecmp_ino(char_u *, char_u *, long); #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; + char_u *d = NULL, *s, *f; - f = fix_fname(name != NULL ? name : (char_u *) ""); - d = NULL; + 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 index bddb902f48..727b24cc30 100644 --- a/src/proto/memline.pro +++ b/src/proto/memline.pro @@ -34,4 +34,5 @@ char_u *ml_encrypt_data(memfile_T *mfp, char_u *data, off_T offset, unsigned siz 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 index 1465a7abfc..16a3f7f8ac 100644 --- 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 index 0000000000..3187b58878 --- /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 index c9b0ec4dcb..432a7ab752 100644 --- a/src/version.c +++ b/src/version.c @@ -794,6 +794,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 251, /**/ 250, /**/ -- cgit v1.2.3