patch 8.1.1371: cannot recover from a swap file

Problem:    Cannot recover from a swap file.
Solution:   Do not expand environment variables in the swap file name.
            Do not check the extension when we already know a file is a swap
            file.  (Ken Takata, closes 4415, closes #4369)
This commit is contained in:
Bram Moolenaar
2019-05-23 21:35:48 +02:00
parent 05b8b07e27
commit 99499b1c05
18 changed files with 168 additions and 64 deletions

View File

@@ -1071,7 +1071,7 @@ handle_swap_exists(bufref_T *old_curbuf)
/* User selected Recover at ATTENTION prompt. */ /* User selected Recover at ATTENTION prompt. */
msg_scroll = TRUE; msg_scroll = TRUE;
ml_recover(); ml_recover(FALSE);
msg_puts("\n"); /* don't overwrite the last message */ msg_puts("\n"); /* don't overwrite the last message */
cmdline_row = msg_row; cmdline_row = msg_row;
do_modelines(0); do_modelines(0);
@@ -4943,7 +4943,7 @@ do_arg_all(
if (i < alist->al_ga.ga_len if (i < alist->al_ga.ga_len
&& (AARGLIST(alist)[i].ae_fnum == buf->b_fnum && (AARGLIST(alist)[i].ae_fnum == buf->b_fnum
|| fullpathcmp(alist_name(&AARGLIST(alist)[i]), || fullpathcmp(alist_name(&AARGLIST(alist)[i]),
buf->b_ffname, TRUE) & FPC_SAME)) buf->b_ffname, TRUE, TRUE) & FPC_SAME))
{ {
int weight = 1; int weight = 1;

View File

@@ -7002,7 +7002,8 @@ fix_help_buffer(void)
copy_option_part(&p, NameBuff, MAXPATHL, ","); copy_option_part(&p, NameBuff, MAXPATHL, ",");
mustfree = FALSE; mustfree = FALSE;
rt = vim_getenv((char_u *)"VIMRUNTIME", &mustfree); rt = vim_getenv((char_u *)"VIMRUNTIME", &mustfree);
if (rt != NULL && fullpathcmp(rt, NameBuff, FALSE) != FPC_SAME) if (rt != NULL &&
fullpathcmp(rt, NameBuff, FALSE, TRUE) != FPC_SAME)
{ {
int fcount; int fcount;
char_u **fnames; char_u **fnames;
@@ -7224,7 +7225,7 @@ helptags_one(
*/ */
ga_init2(&ga, (int)sizeof(char_u *), 100); ga_init2(&ga, (int)sizeof(char_u *), 100);
if (add_help_tags || fullpathcmp((char_u *)"$VIMRUNTIME/doc", if (add_help_tags || fullpathcmp((char_u *)"$VIMRUNTIME/doc",
dir, FALSE) == FPC_SAME) dir, FALSE, TRUE) == FPC_SAME)
{ {
if (ga_grow(&ga, 1) == FAIL) if (ga_grow(&ga, 1) == FAIL)
got_int = TRUE; got_int = TRUE;

View File

@@ -1715,7 +1715,7 @@ editing_arg_idx(win_T *win)
&& (win->w_buffer->b_ffname == NULL && (win->w_buffer->b_ffname == NULL
|| !(fullpathcmp( || !(fullpathcmp(
alist_name(&WARGLIST(win)[win->w_arg_idx]), alist_name(&WARGLIST(win)[win->w_arg_idx]),
win->w_buffer->b_ffname, TRUE) & FPC_SAME)))); win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))));
} }
/* /*
@@ -1737,7 +1737,7 @@ check_arg_idx(win_T *win)
&& (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum && (win->w_buffer->b_fnum == GARGLIST[GARGCOUNT - 1].ae_fnum
|| (win->w_buffer->b_ffname != NULL || (win->w_buffer->b_ffname != NULL
&& (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]), && (fullpathcmp(alist_name(&GARGLIST[GARGCOUNT - 1]),
win->w_buffer->b_ffname, TRUE) & FPC_SAME)))) win->w_buffer->b_ffname, TRUE, TRUE) & FPC_SAME))))
arg_had_last = TRUE; arg_had_last = TRUE;
} }
else else

View File

@@ -6725,7 +6725,7 @@ ex_recover(exarg_T *eap)
&& (*eap->arg == NUL && (*eap->arg == NUL
|| setfname(curbuf, eap->arg, NULL, TRUE) == OK)) || setfname(curbuf, eap->arg, NULL, TRUE) == OK))
ml_recover(); ml_recover(TRUE);
recoverymode = FALSE; recoverymode = FALSE;
} }

View File

@@ -603,22 +603,22 @@ gui_init(void)
#endif #endif
if ( fullpathcmp((char_u *)USR_GVIMRC_FILE, if ( fullpathcmp((char_u *)USR_GVIMRC_FILE,
(char_u *)GVIMRC_FILE, FALSE) != FPC_SAME (char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
#ifdef SYS_GVIMRC_FILE #ifdef SYS_GVIMRC_FILE
&& fullpathcmp((char_u *)SYS_GVIMRC_FILE, && fullpathcmp((char_u *)SYS_GVIMRC_FILE,
(char_u *)GVIMRC_FILE, FALSE) != FPC_SAME (char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
#endif #endif
#ifdef USR_GVIMRC_FILE2 #ifdef USR_GVIMRC_FILE2
&& fullpathcmp((char_u *)USR_GVIMRC_FILE2, && fullpathcmp((char_u *)USR_GVIMRC_FILE2,
(char_u *)GVIMRC_FILE, FALSE) != FPC_SAME (char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
#endif #endif
#ifdef USR_GVIMRC_FILE3 #ifdef USR_GVIMRC_FILE3
&& fullpathcmp((char_u *)USR_GVIMRC_FILE3, && fullpathcmp((char_u *)USR_GVIMRC_FILE3,
(char_u *)GVIMRC_FILE, FALSE) != FPC_SAME (char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
#endif #endif
#ifdef USR_GVIMRC_FILE4 #ifdef USR_GVIMRC_FILE4
&& fullpathcmp((char_u *)USR_GVIMRC_FILE4, && fullpathcmp((char_u *)USR_GVIMRC_FILE4,
(char_u *)GVIMRC_FILE, FALSE) != FPC_SAME (char_u *)GVIMRC_FILE, FALSE, TRUE) != FPC_SAME
#endif #endif
) )
do_source((char_u *)GVIMRC_FILE, TRUE, DOSO_GVIMRC); do_source((char_u *)GVIMRC_FILE, TRUE, DOSO_GVIMRC);

View File

@@ -1401,10 +1401,10 @@ cs_insert_filelist(
#if defined(UNIX) #if defined(UNIX)
&& csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino && csinfo[j].st_dev == sb->st_dev && csinfo[j].st_ino == sb->st_ino
#else #else
/* compare pathnames first */ // compare pathnames first
&& ((fullpathcmp((char_u *)csinfo[j].fname, && ((fullpathcmp((char_u *)csinfo[j].fname,
(char_u *)fname, FALSE) & FPC_SAME) (char_u *)fname, FALSE, TRUE) & FPC_SAME)
/* test index file attributes too */ // test index file attributes too
|| (csinfo[j].nVolume == bhfi.dwVolumeSerialNumber || (csinfo[j].nVolume == bhfi.dwVolumeSerialNumber
&& csinfo[j].nIndexHigh == bhfi.nFileIndexHigh && csinfo[j].nIndexHigh == bhfi.nFileIndexHigh
&& csinfo[j].nIndexLow == bhfi.nFileIndexLow)) && csinfo[j].nIndexLow == bhfi.nFileIndexLow))

View File

@@ -2684,7 +2684,7 @@ create_windows(mparm_T *parmp UNUSED)
if (recoverymode) /* do recover */ if (recoverymode) /* do recover */
{ {
msg_scroll = TRUE; /* scroll message up */ msg_scroll = TRUE; /* scroll message up */
ml_recover(); ml_recover(TRUE);
if (curbuf->b_ml.ml_mfp == NULL) /* failed */ if (curbuf->b_ml.ml_mfp == NULL) /* failed */
getout(1); getout(1);
do_modelines(0); /* do modelines */ do_modelines(0); /* do modelines */
@@ -3101,18 +3101,18 @@ source_startup_scripts(mparm_T *parmp)
i = FAIL; i = FAIL;
if (fullpathcmp((char_u *)USR_VIMRC_FILE, if (fullpathcmp((char_u *)USR_VIMRC_FILE,
(char_u *)VIMRC_FILE, FALSE) != FPC_SAME (char_u *)VIMRC_FILE, FALSE, TRUE) != FPC_SAME
#ifdef USR_VIMRC_FILE2 #ifdef USR_VIMRC_FILE2
&& fullpathcmp((char_u *)USR_VIMRC_FILE2, && fullpathcmp((char_u *)USR_VIMRC_FILE2,
(char_u *)VIMRC_FILE, FALSE) != FPC_SAME (char_u *)VIMRC_FILE, FALSE, TRUE) != FPC_SAME
#endif #endif
#ifdef USR_VIMRC_FILE3 #ifdef USR_VIMRC_FILE3
&& fullpathcmp((char_u *)USR_VIMRC_FILE3, && fullpathcmp((char_u *)USR_VIMRC_FILE3,
(char_u *)VIMRC_FILE, FALSE) != FPC_SAME (char_u *)VIMRC_FILE, FALSE, TRUE) != FPC_SAME
#endif #endif
#ifdef SYS_VIMRC_FILE #ifdef SYS_VIMRC_FILE
&& fullpathcmp((char_u *)SYS_VIMRC_FILE, && fullpathcmp((char_u *)SYS_VIMRC_FILE,
(char_u *)VIMRC_FILE, FALSE) != FPC_SAME (char_u *)VIMRC_FILE, FALSE, TRUE) != FPC_SAME
#endif #endif
) )
i = do_source((char_u *)VIMRC_FILE, TRUE, DOSO_VIMRC); i = do_source((char_u *)VIMRC_FILE, TRUE, DOSO_VIMRC);
@@ -3127,10 +3127,10 @@ source_startup_scripts(mparm_T *parmp)
secure = 0; secure = 0;
#endif #endif
if ( fullpathcmp((char_u *)USR_EXRC_FILE, if ( fullpathcmp((char_u *)USR_EXRC_FILE,
(char_u *)EXRC_FILE, FALSE) != FPC_SAME (char_u *)EXRC_FILE, FALSE, TRUE) != FPC_SAME
#ifdef USR_EXRC_FILE2 #ifdef USR_EXRC_FILE2
&& fullpathcmp((char_u *)USR_EXRC_FILE2, && fullpathcmp((char_u *)USR_EXRC_FILE2,
(char_u *)EXRC_FILE, FALSE) != FPC_SAME (char_u *)EXRC_FILE, FALSE, TRUE) != FPC_SAME
#endif #endif
) )
(void)do_source((char_u *)EXRC_FILE, FALSE, DOSO_NONE); (void)do_source((char_u *)EXRC_FILE, FALSE, DOSO_NONE);

View File

@@ -1084,9 +1084,11 @@ add_b0_fenc(
/* /*
* Try to recover curbuf from the .swp file. * Try to recover curbuf from the .swp file.
* If "checkext" is TRUE, check the extension and detect whether it is
* a swap file.
*/ */
void void
ml_recover(void) ml_recover(int checkext)
{ {
buf_T *buf = NULL; buf_T *buf = NULL;
memfile_T *mfp = NULL; memfile_T *mfp = NULL;
@@ -1136,7 +1138,7 @@ ml_recover(void)
if (fname == NULL) /* When there is no file name */ if (fname == NULL) /* When there is no file name */
fname = (char_u *)""; fname = (char_u *)"";
len = (int)STRLEN(fname); len = (int)STRLEN(fname);
if (len >= 4 && if (checkext && len >= 4 &&
#if defined(VMS) #if defined(VMS)
STRNICMP(fname + len - 4, "_s", 2) STRNICMP(fname + len - 4, "_s", 2)
#else #else
@@ -1887,7 +1889,7 @@ recover_names(
if (num_names == 0) if (num_names == 0)
num_files = 0; num_files = 0;
else if (expand_wildcards(num_names, names, &num_files, &files, else if (expand_wildcards(num_names, names, &num_files, &files,
EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL) EW_NOTENV|EW_KEEPALL|EW_FILE|EW_SILENT) == FAIL)
num_files = 0; num_files = 0;
/* /*
@@ -1930,11 +1932,13 @@ recover_names(
&& (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL) && (p = curbuf->b_ml.ml_mfp->mf_fname) != NULL)
{ {
for (i = 0; i < num_files; ++i) for (i = 0; i < num_files; ++i)
if (fullpathcmp(p, files[i], TRUE) & FPC_SAME) // Do not expand wildcards, on windows would try to expand
// "%tmp%" in "%tmp%file".
if (fullpathcmp(p, files[i], TRUE, FALSE) & FPC_SAME)
{ {
/* Remove the name from files[i]. Move further entries // Remove the name from files[i]. Move further entries
* down. When the array becomes empty free it here, since // down. When the array becomes empty free it here, since
* FreeWild() won't be called below. */ // FreeWild() won't be called below.
vim_free(files[i]); vim_free(files[i]);
if (--num_files == 0) if (--num_files == 0)
vim_free(files); vim_free(files);

View File

@@ -2691,13 +2691,15 @@ home_replace_save(
* FPC_DIFF if they both exist and are different files. * FPC_DIFF if they both exist and are different files.
* FPC_NOTX if they both don't exist. * FPC_NOTX if they both don't exist.
* FPC_DIFFX if one of them doesn't exist. * FPC_DIFFX if one of them doesn't exist.
* For the first name environment variables are expanded * For the first name environment variables are expanded if "expandenv" is
* TRUE.
*/ */
int int
fullpathcmp( fullpathcmp(
char_u *s1, char_u *s1,
char_u *s2, char_u *s2,
int checkname) /* when both don't exist, check file names */ int checkname, // when both don't exist, check file names
int expandenv)
{ {
#ifdef UNIX #ifdef UNIX
char_u exp1[MAXPATHL]; char_u exp1[MAXPATHL];
@@ -2706,7 +2708,10 @@ fullpathcmp(
stat_T st1, st2; stat_T st1, st2;
int r1, r2; int r1, r2;
if (expandenv)
expand_env(s1, exp1, MAXPATHL); expand_env(s1, exp1, MAXPATHL);
else
vim_strncpy(exp1, s1, MAXPATHL - 1);
r1 = mch_stat((char *)exp1, &st1); r1 = mch_stat((char *)exp1, &st1);
r2 = mch_stat((char *)s2, &st2); r2 = mch_stat((char *)s2, &st2);
if (r1 != 0 && r2 != 0) if (r1 != 0 && r2 != 0)
@@ -2741,7 +2746,10 @@ fullpathcmp(
full1 = exp1 + MAXPATHL; full1 = exp1 + MAXPATHL;
full2 = full1 + MAXPATHL; full2 = full1 + MAXPATHL;
if (expandenv)
expand_env(s1, exp1, MAXPATHL); expand_env(s1, exp1, MAXPATHL);
else
vim_strncpy(exp1, s1, MAXPATHL - 1);
r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE); r1 = vim_FullName(exp1, full1, MAXPATHL, FALSE);
r2 = vim_FullName(s2, full2, MAXPATHL, FALSE); r2 = vim_FullName(s2, full2, MAXPATHL, FALSE);
@@ -4027,7 +4035,7 @@ gen_expand_wildcards(
/* /*
* First expand environment variables, "~/" and "~user/". * First expand environment variables, "~/" and "~user/".
*/ */
if (has_env_var(p) || *p == '~') if ((has_env_var(p) && !(flags & EW_NOTENV)) || *p == '~')
{ {
p = expand_env_save_opt(p, TRUE); p = expand_env_save_opt(p, TRUE);
if (p == NULL) if (p == NULL)

View File

@@ -9,7 +9,7 @@ void ml_close(buf_T *buf, int del_file);
void ml_close_all(int del_file); void ml_close_all(int del_file);
void ml_close_notmod(void); void ml_close_notmod(void);
void ml_timestamp(buf_T *buf); void ml_timestamp(buf_T *buf);
void ml_recover(void); void ml_recover(int checkext);
int recover_names(char_u *fname, int list, int nr, char_u **fname_out); int recover_names(char_u *fname, int list, int nr, char_u **fname_out);
char_u *make_percent_swname(char_u *dir, char_u *name); char_u *make_percent_swname(char_u *dir, char_u *name);
void get_b0_dict(char_u *fname, dict_T *d); void get_b0_dict(char_u *fname, dict_T *d);

View File

@@ -45,7 +45,7 @@ char_u *get_users(expand_T *xp, int idx);
int match_user(char_u *name); int match_user(char_u *name);
void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, int one); void home_replace(buf_T *buf, char_u *src, char_u *dst, int dstlen, int one);
char_u *home_replace_save(buf_T *buf, char_u *src); char_u *home_replace_save(buf_T *buf, char_u *src);
int fullpathcmp(char_u *s1, char_u *s2, int checkname); int fullpathcmp(char_u *s1, char_u *s2, int checkname, int expandenv);
char_u *gettail(char_u *fname); char_u *gettail(char_u *fname);
char_u *gettail_sep(char_u *fname); char_u *gettail_sep(char_u *fname);
char_u *getnextcomp(char_u *fname); char_u *getnextcomp(char_u *fname);

View File

@@ -5170,7 +5170,8 @@ find_pattern_in_path(
i = old_files; i = old_files;
if (i == max_path_depth) if (i == max_path_depth)
break; break;
if (fullpathcmp(new_fname, files[i].name, TRUE) & FPC_SAME) if (fullpathcmp(new_fname, files[i].name, TRUE, TRUE)
& FPC_SAME)
{ {
if (type != CHECK_PATH && if (type != CHECK_PATH &&
action == ACTION_SHOW_ALL && files[i].matched) action == ACTION_SHOW_ALL && files[i].matched)

View File

@@ -2343,7 +2343,7 @@ did_set_spelllang(win_T *wp)
/* Check if we loaded this language before. */ /* Check if we loaded this language before. */
for (slang = first_lang; slang != NULL; slang = slang->sl_next) for (slang = first_lang; slang != NULL; slang = slang->sl_next)
if (fullpathcmp(lang, slang->sl_fname, FALSE) == FPC_SAME) if (fullpathcmp(lang, slang->sl_fname, FALSE, TRUE) == FPC_SAME)
break; break;
} }
else else
@@ -2395,7 +2395,8 @@ did_set_spelllang(win_T *wp)
* Loop over the languages, there can be several files for "lang". * Loop over the languages, there can be several files for "lang".
*/ */
for (slang = first_lang; slang != NULL; slang = slang->sl_next) for (slang = first_lang; slang != NULL; slang = slang->sl_next)
if (filename ? fullpathcmp(lang, slang->sl_fname, FALSE) == FPC_SAME if (filename ? fullpathcmp(lang, slang->sl_fname, FALSE, TRUE)
== FPC_SAME
: STRICMP(lang, slang->sl_name) == 0) : STRICMP(lang, slang->sl_name) == 0)
{ {
region_mask = REGION_ALL; region_mask = REGION_ALL;
@@ -2463,7 +2464,8 @@ did_set_spelllang(win_T *wp)
for (c = 0; c < ga.ga_len; ++c) for (c = 0; c < ga.ga_len; ++c)
{ {
p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname; p = LANGP_ENTRY(ga, c)->lp_slang->sl_fname;
if (p != NULL && fullpathcmp(spf_name, p, FALSE) == FPC_SAME) if (p != NULL && fullpathcmp(spf_name, p, FALSE, TRUE)
== FPC_SAME)
break; break;
} }
if (c < ga.ga_len) if (c < ga.ga_len)
@@ -2472,7 +2474,8 @@ did_set_spelllang(win_T *wp)
/* Check if it was loaded already. */ /* Check if it was loaded already. */
for (slang = first_lang; slang != NULL; slang = slang->sl_next) for (slang = first_lang; slang != NULL; slang = slang->sl_next)
if (fullpathcmp(spf_name, slang->sl_fname, FALSE) == FPC_SAME) if (fullpathcmp(spf_name, slang->sl_fname, FALSE, TRUE)
== FPC_SAME)
break; break;
if (slang == NULL) if (slang == NULL)
{ {

View File

@@ -1734,7 +1734,7 @@ spell_reload_one(
for (slang = first_lang; slang != NULL; slang = slang->sl_next) for (slang = first_lang; slang != NULL; slang = slang->sl_next)
{ {
if (fullpathcmp(fname, slang->sl_fname, FALSE) == FPC_SAME) if (fullpathcmp(fname, slang->sl_fname, FALSE, TRUE) == FPC_SAME)
{ {
slang_clear(slang); slang_clear(slang);
if (spell_load_file(fname, NULL, slang, FALSE) == NULL) if (spell_load_file(fname, NULL, slang, FALSE) == NULL)
@@ -5440,7 +5440,7 @@ spell_make_sugfile(spellinfo_T *spin, char_u *wfname)
* It might have been done already by spell_reload_one(). * It might have been done already by spell_reload_one().
*/ */
for (slang = first_lang; slang != NULL; slang = slang->sl_next) for (slang = first_lang; slang != NULL; slang = slang->sl_next)
if (fullpathcmp(wfname, slang->sl_fname, FALSE) == FPC_SAME) if (fullpathcmp(wfname, slang->sl_fname, FALSE, TRUE) == FPC_SAME)
break; break;
if (slang == NULL) if (slang == NULL)
{ {

View File

@@ -3781,7 +3781,7 @@ test_for_current(
fullname = expand_tag_fname(fname, tag_fname, TRUE); fullname = expand_tag_fname(fname, tag_fname, TRUE);
if (fullname != NULL) if (fullname != NULL)
{ {
retval = (fullpathcmp(fullname, buf_ffname, TRUE) & FPC_SAME); retval = (fullpathcmp(fullname, buf_ffname, TRUE, TRUE) & FPC_SAME);
vim_free(fullname); vim_free(fullname);
} }
#ifdef FEAT_EMACS_TAGS #ifdef FEAT_EMACS_TAGS

View File

@@ -220,3 +220,87 @@ func Test_swapfile_delete()
augroup END augroup END
augroup! test_swapfile_delete augroup! test_swapfile_delete
endfunc endfunc
func Test_swap_recover()
autocmd! SwapExists
augroup test_swap_recover
autocmd!
autocmd SwapExists * let v:swapchoice = 'r'
augroup END
call mkdir('Xswap')
let $Xswap = 'foo' " Check for issue #4369.
set dir=Xswap//
" Create a valid swapfile by editing a file.
split Xswap/text
call setline(1, ['one', 'two', 'three'])
write " file is written, not modified
" read the swapfile as a Blob
let swapfile_name = swapname('%')
let swapfile_bytes = readfile(swapfile_name, 'B')
" Close the file and recreate the swap file.
quit
call writefile(swapfile_bytes, swapfile_name)
" Edit the file again. This triggers recovery.
try
split Xswap/text
catch
" E308 should be caught, not E305.
call assert_exception('E308:') " Original file may have been changed
endtry
" The file should be recovered.
call assert_equal(['one', 'two', 'three'], getline(1, 3))
quit!
call delete('Xswap/text')
call delete(swapfile_name)
call delete('Xswap', 'd')
unlet $Xswap
set dir&
augroup test_swap_recover
autocmd!
augroup END
augroup! test_swap_recover
endfunc
func Test_swap_recover_ext()
autocmd! SwapExists
augroup test_swap_recover_ext
autocmd!
autocmd SwapExists * let v:swapchoice = 'r'
augroup END
" Create a valid swapfile by editing a file with a special extension.
split Xtest.scr
call setline(1, ['one', 'two', 'three'])
write " file is written, not modified
write " write again to make sure the swapfile is created
" read the swapfile as a Blob
let swapfile_name = swapname('%')
let swapfile_bytes = readfile(swapfile_name, 'B')
" Close and delete the file and recreate the swap file.
quit
call delete('Xtest.scr')
call writefile(swapfile_bytes, swapfile_name)
" Edit the file again. This triggers recovery.
try
split Xtest.scr
catch
" E308 should be caught, not E306.
call assert_exception('E308:') " Original file may have been changed
endtry
" The file should be recovered.
call assert_equal(['one', 'two', 'three'], getline(1, 3))
quit!
call delete('Xtest.scr')
call delete(swapfile_name)
augroup test_swap_recover_ext
autocmd!
augroup END
augroup! test_swap_recover_ext
endfunc

View File

@@ -767,6 +767,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1371,
/**/ /**/
1370, 1370,
/**/ /**/

View File

@@ -781,26 +781,27 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define WILD_ICASE 0x100 #define WILD_ICASE 0x100
#define WILD_ALLLINKS 0x200 #define WILD_ALLLINKS 0x200
/* Flags for expand_wildcards() */ // Flags for expand_wildcards()
#define EW_DIR 0x01 /* include directory names */ #define EW_DIR 0x01 // include directory names
#define EW_FILE 0x02 /* include file names */ #define EW_FILE 0x02 // include file names
#define EW_NOTFOUND 0x04 /* include not found names */ #define EW_NOTFOUND 0x04 // include not found names
#define EW_ADDSLASH 0x08 /* append slash to directory name */ #define EW_ADDSLASH 0x08 // append slash to directory name
#define EW_KEEPALL 0x10 /* keep all matches */ #define EW_KEEPALL 0x10 // keep all matches
#define EW_SILENT 0x20 /* don't print "1 returned" from shell */ #define EW_SILENT 0x20 // don't print "1 returned" from shell
#define EW_EXEC 0x40 /* executable files */ #define EW_EXEC 0x40 // executable files
#define EW_PATH 0x80 /* search in 'path' too */ #define EW_PATH 0x80 // search in 'path' too
#define EW_ICASE 0x100 /* ignore case */ #define EW_ICASE 0x100 // ignore case
#define EW_NOERROR 0x200 /* no error for bad regexp */ #define EW_NOERROR 0x200 // no error for bad regexp
#define EW_NOTWILD 0x400 /* add match with literal name if exists */ #define EW_NOTWILD 0x400 // add match with literal name if exists
#define EW_KEEPDOLLAR 0x800 /* do not escape $, $var is expanded */ #define EW_KEEPDOLLAR 0x800 // do not escape $, $var is expanded
/* Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND // Note: mostly EW_NOTFOUND and EW_SILENT are mutually exclusive: EW_NOTFOUND
* is used when executing commands and EW_SILENT for interactive expanding. */ // is used when executing commands and EW_SILENT for interactive expanding.
#define EW_ALLLINKS 0x1000 /* also links not pointing to existing file */ #define EW_ALLLINKS 0x1000 // also links not pointing to existing file
#define EW_SHELLCMD 0x2000 /* called from expand_shellcmd(), don't check #define EW_SHELLCMD 0x2000 // called from expand_shellcmd(), don't check
* if executable is in $PATH */ // if executable is in $PATH
#define EW_DODOT 0x4000 /* also files starting with a dot */ #define EW_DODOT 0x4000 // also files starting with a dot
#define EW_EMPTYOK 0x8000 /* no matches is not an error */ #define EW_EMPTYOK 0x8000 // no matches is not an error
#define EW_NOTENV 0x10000 // do not expand environment variables
/* Flags for find_file_*() functions. */ /* Flags for find_file_*() functions. */
#define FINDFILE_FILE 0 /* only files */ #define FINDFILE_FILE 0 /* only files */