aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/nvim/memline.c55
-rw-r--r--src/nvim/path.c11
-rw-r--r--src/nvim/testdir/Makefile2
-rw-r--r--src/nvim/testdir/test78.in46
-rw-r--r--src/nvim/testdir/test78.ok3
-rw-r--r--test/functional/ex_cmds/recover_spec.lua71
-rw-r--r--test/functional/helpers.lua11
-rw-r--r--test/functional/legacy/078_swapfile_recover_spec.lua80
8 files changed, 181 insertions, 98 deletions
diff --git a/src/nvim/memline.c b/src/nvim/memline.c
index 93fbbd512f..448f15cc07 100644
--- a/src/nvim/memline.c
+++ b/src/nvim/memline.c
@@ -824,7 +824,7 @@ void ml_recover(void)
(void)recover_names(fname, FALSE, i, &fname_used);
}
if (fname_used == NULL)
- goto theend; /* out of memory */
+ goto theend; // user chose invalid number.
/* When called from main() still need to initialize storage structure */
if (called_from_main && ml_open(curbuf) == FAIL)
@@ -1244,8 +1244,10 @@ theend:
mf_put(mfp, hp, false, false);
mf_close(mfp, false); /* will also free(mfp->mf_fname) */
}
- free(buf->b_ml.ml_stack);
- free(buf);
+ if (buf != NULL) { //may be NULL if swap file not found.
+ free(buf->b_ml.ml_stack);
+ free(buf);
+ }
if (serious_error && called_from_main)
ml_close(curbuf, TRUE);
else {
@@ -1321,53 +1323,35 @@ recover_names (
if (dir_name[0] == '.' && dir_name[1] == NUL) { /* check current dir */
if (fname == NULL) {
names[0] = vim_strsave((char_u *)"*.sw?");
-#if defined(UNIX) || defined(WIN3264)
/* For Unix names starting with a dot are special. MS-Windows
* supports this too, on some file systems. */
names[1] = vim_strsave((char_u *)".*.sw?");
names[2] = vim_strsave((char_u *)".sw?");
num_names = 3;
-#else
- num_names = 1;
-#endif
} else
num_names = recov_file_names(names, fname_res, TRUE);
} else { /* check directory dir_name */
if (fname == NULL) {
names[0] = concat_fnames(dir_name, (char_u *)"*.sw?", TRUE);
-#if defined(UNIX) || defined(WIN3264)
/* For Unix names starting with a dot are special. MS-Windows
* supports this too, on some file systems. */
names[1] = concat_fnames(dir_name, (char_u *)".*.sw?", TRUE);
names[2] = concat_fnames(dir_name, (char_u *)".sw?", TRUE);
num_names = 3;
-#else
- num_names = 1;
-#endif
} else {
-#if defined(UNIX) || defined(WIN3264)
p = dir_name + STRLEN(dir_name);
if (after_pathsep(dir_name, p) && p[-1] == p[-2]) {
/* Ends with '//', Use Full path for swap name */
tail = make_percent_swname(dir_name, fname_res);
- } else
-#endif
- tail = path_tail(fname_res);
- tail = concat_fnames(dir_name, tail, TRUE);
+ } else {
+ tail = path_tail(fname_res);
+ tail = concat_fnames(dir_name, tail, TRUE);
+ }
num_names = recov_file_names(names, tail, FALSE);
free(tail);
}
}
- // check for out-of-memory
- for (int i = 0; i < num_names; ++i) {
- if (names[i] == NULL) {
- for (int j = 0; j < num_names; ++j)
- free(names[j]);
- num_names = 0;
- break;
- }
- }
if (num_names == 0)
num_files = 0;
else if (expand_wildcards(num_names, names, &num_files, &files,
@@ -1453,7 +1437,6 @@ recover_names (
return file_count;
}
-#if defined(UNIX) || defined(WIN3264) /* 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>/"")
@@ -1475,7 +1458,6 @@ static char_u *make_percent_swname(char_u *dir, char_u *name)
}
return d;
}
-#endif
#ifdef UNIX
static int process_still_running;
@@ -1576,17 +1558,12 @@ static time_t swapfile_info(char_u *fname)
}
static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
+ FUNC_ATTR_NONNULL_ALL
{
- int num_names;
- char_u *p;
- int i;
-
- num_names = 0;
+ int num_names = 0;
- /*
- * May also add the file name with a dot prepended, for swap file in same
- * dir as original file.
- */
+ // May also add the file name with a dot prepended, for swap file in same
+ // dir as original file.
if (prepend_dot) {
names[num_names] = modname(path, (char_u *)".sw?", TRUE);
if (names[num_names] == NULL)
@@ -1597,8 +1574,8 @@ static int recov_file_names(char_u **names, char_u *path, int prepend_dot)
// Form the normal swap file name pattern by appending ".sw?".
names[num_names] = concat_fnames(path, (char_u *)".sw?", FALSE);
if (num_names >= 1) { /* check if we have the same name twice */
- p = names[num_names - 1];
- i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
+ char_u *p = names[num_names - 1];
+ int i = (int)STRLEN(names[num_names - 1]) - (int)STRLEN(names[num_names]);
if (i > 0)
p += i; /* file name has been expanded to full path */
@@ -3088,7 +3065,6 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
char_u fname_buf[MAXPATHL];
#endif
-#if defined(UNIX) || defined(WIN3264) /* Need _very_ long file names */
s = dir_name + STRLEN(dir_name);
if (after_pathsep(dir_name, s) && s[-1] == s[-2]) { /* Ends with '//', Use Full path */
r = NULL;
@@ -3098,7 +3074,6 @@ char_u *makeswapname(char_u *fname, char_u *ffname, buf_T *buf, char_u *dir_name
}
return r;
}
-#endif
#ifdef HAVE_READLINK
/* Expand symlink in the file name, so that we put the swap file with the
diff --git a/src/nvim/path.c b/src/nvim/path.c
index 9515205643..80f1947ccf 100644
--- a/src/nvim/path.c
+++ b/src/nvim/path.c
@@ -83,15 +83,12 @@ FileComparison path_full_compare(char_u *s1, char_u *s2, int checkname)
return kDifferentFiles;
}
-/// Get the tail of a path: the file name.
+/// Gets the tail (i.e., the filename segment) of a path `fname`.
///
-/// @param fname A file path.
-/// @return
-/// - Empty string, if fname is NULL.
-/// - The position of the last path separator + 1. (i.e. empty string, if
-/// fname ends in a slash).
-/// - Never NULL.
+/// @return pointer just past the last path separator (empty string, if fname
+/// ends in a slash), or empty string if fname is NULL.
char_u *path_tail(char_u *fname)
+ FUNC_ATTR_NONNULL_RET
{
if (fname == NULL) {
return (char_u *)"";
diff --git a/src/nvim/testdir/Makefile b/src/nvim/testdir/Makefile
index a530e3cf23..0a7c16e2cb 100644
--- a/src/nvim/testdir/Makefile
+++ b/src/nvim/testdir/Makefile
@@ -24,7 +24,7 @@ SCRIPTS := test_autoformat_join.out \
test61.out test62.out test63.out test64.out test65.out \
test68.out test69.out \
test71.out test73.out test74.out \
- test76.out test78.out test79.out test80.out \
+ test76.out test79.out test80.out \
test82.out test83.out \
test86.out test87.out test88.out \
test96.out \
diff --git a/src/nvim/testdir/test78.in b/src/nvim/testdir/test78.in
deleted file mode 100644
index cb0e51edd5..0000000000
--- a/src/nvim/testdir/test78.in
+++ /dev/null
@@ -1,46 +0,0 @@
-Inserts 10000 lines with text to fill the swap file with two levels of pointer
-blocks. Then recovers from the swap file and checks all text is restored.
-
-We need about 10000 lines of 100 characters to get two levels of pointer
-blocks.
-
-STARTTEST
-:so small.vim
-:set fileformat=unix undolevels=-1
-:e! Xtest
-ggdG
-:let text = "\tabcdefghijklmnoparstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnoparstuvwxyz0123456789"
-:let i = 1
-:let linecount = 10000
-:while i <= linecount | call append(i - 1, i . text) | let i += 1 | endwhile
-:preserve
-:" get the name of the swap file
-:redir => swapname
-:swapname
-:redir END
-:let swapname = substitute(swapname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
-:" make a copy of the swap file in Xswap
-:set bin
-:exe 'sp ' . swapname
-:w! Xswap
-:echo swapname
-:set nobin
-:new
-:only!
-:bwipe! Xtest
-:call rename('Xswap', swapname)
-:recover Xtest
-:call delete(swapname)
-:new
-:call append(0, 'recovery start')
-:wincmd w
-:let linedollar = line('$')
-:if linedollar < linecount | exe 'wincmd w' | call append(line('$'), "expected " . linecount . " lines but found only " . linedollar) | exe 'wincmd w' | let linecount = linedollar | endif
-:let i = 1
-:while i <= linecount | if getline(i) != i . text | exe 'wincmd w' | call append(line('$'), i . ' differs') | exe 'wincmd w' | endif | let i += 1 | endwhile
-:q!
-:call append(line('$'), 'recovery end')
-:w! test.out
-:qa!
-ENDTEST
-
diff --git a/src/nvim/testdir/test78.ok b/src/nvim/testdir/test78.ok
deleted file mode 100644
index 6c3ecefe3c..0000000000
--- a/src/nvim/testdir/test78.ok
+++ /dev/null
@@ -1,3 +0,0 @@
-recovery start
-
-recovery end
diff --git a/test/functional/ex_cmds/recover_spec.lua b/test/functional/ex_cmds/recover_spec.lua
new file mode 100644
index 0000000000..d4c9477133
--- /dev/null
+++ b/test/functional/ex_cmds/recover_spec.lua
@@ -0,0 +1,71 @@
+-- Tests for :recover
+
+local helpers = require('test.functional.helpers')
+local execute, eq, clear, eval, feed, expect, source =
+ helpers.execute, helpers.eq, helpers.clear, helpers.eval, helpers.feed,
+ helpers.expect, helpers.source
+
+describe(':recover', function()
+ before_each(clear)
+
+ it('fails if given a non-existent swapfile', function()
+ local swapname = 'bogus-swapfile'
+ execute('recover '..swapname) -- This should not segfault. #2117
+ eq('E305: No swap file found for '..swapname, eval('v:errmsg'))
+ end)
+
+end)
+
+describe(':preserve', function()
+ local swapdir = lfs.currentdir()..'/testdir_recover_spec'
+ before_each(function()
+ clear()
+ os.remove(swapdir)
+ lfs.mkdir(swapdir)
+ end)
+ after_each(function()
+ os.remove(swapdir)
+ end)
+
+ it("saves to custom 'directory' and (R)ecovers (issue #1836)", function()
+ local testfile = 'testfile_recover_spec'
+ local init = [[
+ set swapfile fileformat=unix undolevels=-1
+ set directory^=]]..swapdir..[[//
+ ]]
+
+ source(init)
+ execute('set swapfile fileformat=unix undolevels=-1')
+ -- Put swapdir at the start of the 'directory' list. #1836
+ execute('set directory^='..swapdir..'//')
+ execute('edit '..testfile)
+ feed('isometext<esc>')
+ execute('preserve')
+ source('redir => g:swapname | swapname | redir END')
+
+ local swappath1 = eval('g:swapname')
+
+ --TODO(justinmk): this is an ugly hack to force `helpers` to support
+ --multiple sessions.
+ local nvim2 = helpers.spawn({helpers.nvim_prog, '-u', 'NONE', '--embed'})
+ helpers.set_session(nvim2)
+
+ source(init)
+
+ -- Use the "SwapExists" event to choose the (R)ecover choice at the dialog.
+ execute('autocmd SwapExists * let v:swapchoice = "r"')
+ execute('silent edit '..testfile)
+ source('redir => g:swapname | swapname | redir END')
+
+ local swappath2 = eval('g:swapname')
+
+ -- swapfile from session 1 should end in .swp
+ assert(testfile..'.swp' == string.match(swappath1, '[^%%]+$'))
+
+ -- swapfile from session 2 should end in .swo
+ assert(testfile..'.swo' == string.match(swappath2, '[^%%]+$'))
+
+ expect('sometext')
+ end)
+
+end)
diff --git a/test/functional/helpers.lua b/test/functional/helpers.lua
index 393b42dda5..27c94c34a8 100644
--- a/test/functional/helpers.lua
+++ b/test/functional/helpers.lua
@@ -18,6 +18,10 @@ if nvim_dir == nvim_prog then
nvim_dir = "."
end
+-- Nvim "Unit Under Test" http://en.wikipedia.org/wiki/Device_under_test
+local NvimUUT = {}
+NvimUUT.__index = NvimUUT
+
local prepend_argv
if os.getenv('VALGRIND') then
@@ -49,6 +53,10 @@ end
local session, loop_running, loop_stopped, last_error
+local function set_session(s)
+ session = s
+end
+
local function request(method, ...)
local status, rv = session:request(method, ...)
if not status then
@@ -305,5 +313,6 @@ return {
curwin = curwin,
curtab = curtab,
curbuf_contents = curbuf_contents,
- wait = wait
+ wait = wait,
+ set_session = set_session
}
diff --git a/test/functional/legacy/078_swapfile_recover_spec.lua b/test/functional/legacy/078_swapfile_recover_spec.lua
new file mode 100644
index 0000000000..e250c91441
--- /dev/null
+++ b/test/functional/legacy/078_swapfile_recover_spec.lua
@@ -0,0 +1,80 @@
+-- Inserts 10000 lines with text to fill the swap file with two levels of
+-- pointer blocks. Then recovers from the swap file and checks all text is
+-- restored. We need about 10000 lines of 100 characters to get two levels of
+-- pointer blocks.
+
+local helpers = require('test.functional.helpers')
+local feed, insert, source = helpers.feed, helpers.insert, helpers.source
+local clear, execute, expect, source = helpers.clear, helpers.execute, helpers.expect, helpers.source
+local eval = helpers.eval
+
+describe('78', function()
+ setup(clear)
+ teardown(function()
+ os.remove(".Xtest.swp")
+ os.remove(".Xtest.swo")
+ end)
+
+ it('is working', function()
+ source([=[
+ set swapfile fileformat=unix undolevels=-1
+ e! Xtest
+ let text = "\tabcdefghijklmnoparstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnoparstuvwxyz0123456789"
+ let i = 1
+ let linecount = 10000
+ while i <= linecount | call append(i - 1, i . text) | let i += 1 | endwhile
+ preserve
+
+ " Get the name of the swap file, and clean up the :redir capture.
+ redir => g:swapname | swapname | redir END
+ let g:swapname = substitute(g:swapname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', 'g')
+ let g:swapname = fnameescape(g:swapname)
+
+ " Make a copy of the swap file in Xswap
+ set bin
+ exe 'sp ' . g:swapname
+ w! Xswap
+
+ set nobin
+ new
+ only!
+ bwipe! Xtest
+ call rename('Xswap', g:swapname)
+
+ "TODO(jkeyes): without 'silent', this hangs the test " at message:
+ " 'Recovery completed. You should check if everything is OK.'
+ silent recover Xtest
+
+ call delete(g:swapname)
+ new
+ call append(0, 'recovery start')
+ wincmd w
+
+ let g:linedollar = line('$')
+ if g:linedollar < linecount
+ wincmd w
+ call append(line('$'), "expected " . linecount
+ \ . " lines but found only " . g:linedollar)
+ wincmd w
+ let linecount = g:linedollar
+ endif
+
+ let i = 1
+ while i <= linecount
+ if getline(i) != i . text
+ exe 'wincmd w'
+ call append(line('$'), i . ' differs')
+ exe 'wincmd w'
+ endif
+ let i += 1
+ endwhile
+ q!
+ call append(line('$'), 'recovery end')
+ ]=])
+
+ expect([[
+ recovery start
+
+ recovery end]])
+ end)
+end)