blob: db59223c295f7c884945b53f7d2bc8e9ad32ba10 [file] [log] [blame]
Bram Moolenaarc525e3a2017-02-18 16:59:02 +01001" Test :recover
2
3func Test_recover_root_dir()
4 " This used to access invalid memory.
5 split Xtest
6 set dir=/
7 call assert_fails('recover', 'E305:')
8 close!
9
Bram Moolenaar2a0b06d2017-05-18 16:23:43 +020010 if has('win32') || filewritable('/') == 2
Bram Moolenaar80345202017-02-18 22:43:19 +010011 " can write in / directory on MS-Windows
12 set dir=/notexist/
13 endif
Bram Moolenaarc525e3a2017-02-18 16:59:02 +010014 call assert_fails('split Xtest', 'E303:')
Bram Moolenaar00e192b2019-10-19 17:01:28 +020015
16 " No error with empty 'directory' setting.
17 set directory=
18 split XtestOK
19 close!
20
Bram Moolenaarc525e3a2017-02-18 16:59:02 +010021 set dir&
22endfunc
23
Bram Moolenaarf52f0602021-03-10 21:26:37 +010024" Make a copy of the current swap file to "Xswap".
25" Return the name of the swap file.
26func CopySwapfile()
27 preserve
28 " get the name of the swap file
29 let swname = split(execute("swapname"))[0]
30 let swname = substitute(swname, '[[:blank:][:cntrl:]]*\(.\{-}\)[[:blank:][:cntrl:]]*$', '\1', '')
31 " make a copy of the swap file in Xswap
32 set binary
33 exe 'sp ' . swname
34 w! Xswap
35 set nobinary
36 return swname
37endfunc
38
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +020039" Inserts 10000 lines with text to fill the swap file with two levels of pointer
40" blocks. Then recovers from the swap file and checks all text is restored.
41"
42" We need about 10000 lines of 100 characters to get two levels of pointer
43" blocks.
44func Test_swap_file()
Bram Moolenaar67418d92017-10-15 22:07:39 +020045 set fileformat=unix undolevels=-1
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +020046 edit! Xtest
47 let text = "\tabcdefghijklmnoparstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789abcdefghijklmnoparstuvwxyz0123456789"
48 let i = 1
49 let linecount = 10000
50 while i <= linecount
51 call append(i - 1, i . text)
52 let i += 1
53 endwhile
54 $delete
Bram Moolenaarf52f0602021-03-10 21:26:37 +010055
56 let swname = CopySwapfile()
57
Bram Moolenaar4a6fcf82017-10-12 21:29:22 +020058 new
59 only!
60 bwipe! Xtest
61 call rename('Xswap', swname)
62 recover Xtest
63 call delete(swname)
64 let linedollar = line('$')
65 call assert_equal(linecount, linedollar)
66 if linedollar < linecount
67 let linecount = linedollar
68 endif
69 let i = 1
70 while i <= linecount
71 call assert_equal(i . text, getline(i))
72 let i += 1
73 endwhile
74
75 set undolevels&
76 enew! | only
77endfunc
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +020078
Bram Moolenaarf52f0602021-03-10 21:26:37 +010079func Test_nocatch_process_still_running()
Bram Moolenaar6635ae12021-03-10 21:46:39 +010080 " sysinfo.uptime probably only works on Linux
Bram Moolenaar776b9542021-03-10 22:27:48 +010081 if !has('linux')
82 let g:skipped_reason = 'only works on Linux'
83 return
84 endif
Bram Moolenaar6635ae12021-03-10 21:46:39 +010085 " the GUI dialog can't be handled
Bram Moolenaar776b9542021-03-10 22:27:48 +010086 if has('gui_running')
87 let g:skipped_reason = 'only works in the terminal'
88 return
89 endif
Bram Moolenaarf52f0602021-03-10 21:26:37 +010090
91 " don't intercept existing swap file here
92 au! SwapExists
93
94 " Edit a file and grab its swapfile.
95 edit Xswaptest
96 call setline(1, ['a', 'b', 'c'])
97 let swname = CopySwapfile()
98
99 " Forget we edited this file
100 new
101 only!
102 bwipe! Xswaptest
103
104 call rename('Xswap', swname)
105 call feedkeys('e', 'tL')
106 redir => editOutput
107 edit Xswaptest
108 redir END
109 call assert_match('E325: ATTENTION', editOutput)
110 call assert_match('file name: .*Xswaptest', editOutput)
111 call assert_match('process ID: \d* (STILL RUNNING)', editOutput)
112
113 " Forget we edited this file
114 new
115 only!
116 bwipe! Xswaptest
117
118 " pretend we rebooted
119 call test_override("uptime", 0)
120 sleep 1
121
Bram Moolenaarf52f0602021-03-10 21:26:37 +0100122 call feedkeys('e', 'tL')
123 redir => editOutput
124 edit Xswaptest
125 redir END
126 call assert_match('E325: ATTENTION', editOutput)
127 call assert_notmatch('(STILL RUNNING)', editOutput)
128
129 call test_override("ALL", 0)
130 call delete(swname)
131endfunc
132
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200133" Test for :recover with multiple swap files
134func Test_recover_multiple_swap_files()
135 CheckUnix
136 new Xfile1
137 call setline(1, ['a', 'b', 'c'])
138 preserve
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200139 let b = readblob(swapname(''))
Bram Moolenaardb77cb32022-10-05 21:45:30 +0100140 call writefile(b, '.Xfile1.swm', 'D')
141 call writefile(b, '.Xfile1.swn', 'D')
142 call writefile(b, '.Xfile1.swo', 'D')
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200143 %bw!
144 call feedkeys(":recover Xfile1\<CR>3\<CR>q", 'xt')
145 call assert_equal(['a', 'b', 'c'], getline(1, '$'))
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200146 " try using out-of-range number to select a swap file
147 bw!
148 call feedkeys(":recover Xfile1\<CR>4\<CR>q", 'xt')
149 call assert_equal('Xfile1', @%)
150 call assert_equal([''], getline(1, '$'))
151 bw!
152 call feedkeys(":recover Xfile1\<CR>0\<CR>q", 'xt')
153 call assert_equal('Xfile1', @%)
154 call assert_equal([''], getline(1, '$'))
155 bw!
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200156endfunc
157
158" Test for :recover using an empty swap file
159func Test_recover_empty_swap_file()
160 CheckUnix
Bram Moolenaardb77cb32022-10-05 21:45:30 +0100161 call writefile([], '.Xfile1.swp', 'D')
Christian Brabandt1c7397f2023-09-05 20:40:25 +0200162 set dir=.
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200163 let msg = execute('recover Xfile1')
164 call assert_match('Unable to read block 0 from .Xfile1.swp', msg)
165 call assert_equal('Xfile1', @%)
166 bw!
Bram Moolenaarf2a8baf2021-09-14 22:58:23 +0200167
168 " make sure there are no old swap files laying around
169 for f in glob('.sw?', 0, 1)
170 call delete(f)
171 endfor
172
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200173 " :recover from an empty buffer
174 call assert_fails('recover', 'E305:')
Christian Brabandt1c7397f2023-09-05 20:40:25 +0200175 set dir&vim
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200176endfunc
177
178" Test for :recover using a corrupted swap file
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200179" Refer to the comments in the memline.c file for the swap file headers
180" definition.
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200181func Test_recover_corrupted_swap_file()
182 CheckUnix
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200183
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200184 " recover using a partial swap file
185 call writefile(0z1234, '.Xfile1.swp')
186 call assert_fails('recover Xfile1', 'E295:')
187 bw!
188
189 " recover using invalid content in the swap file
190 call writefile([repeat('1', 2*1024)], '.Xfile1.swp')
191 call assert_fails('recover Xfile1', 'E307:')
192 call delete('.Xfile1.swp')
193
194 " :recover using a swap file with a corrupted header
195 edit Xfile1
196 preserve
197 let sn = swapname('')
198 let b = readblob(sn)
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200199 let save_b = copy(b)
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200200 bw!
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200201
James McCoy6654ca72021-06-12 14:05:41 +0200202 " Not all fields are written in a system-independent manner. Detect whether
203 " the test is running on a little or big-endian system, so the correct
204 " corruption values can be set.
James McCoy37f341d2021-10-11 21:04:37 +0100205 " The B0_MAGIC_LONG field may be 32-bit or 64-bit, depending on the system,
206 " even though the value stored is only 32-bits. Therefore, need to check
207 " both the high and low 32-bits to compute these values.
208 let little_endian = (b[1008:1011] == 0z33323130) || (b[1012:1015] == 0z33323130)
209 let system_64bit = little_endian ? (b[1012:1015] == 0z00000000) : (b[1008:1011] == 0z00000000)
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200210
James McCoy6654ca72021-06-12 14:05:41 +0200211 " clear the B0_MAGIC_LONG field
Yegappan Lakshmanan576cb752021-06-30 21:30:10 +0200212 if system_64bit
213 let b[1008:1015] = 0z00000000.00000000
214 else
215 let b[1008:1011] = 0z00000000
216 endif
James McCoy6654ca72021-06-12 14:05:41 +0200217 call writefile(b, sn)
218 let msg = execute('recover Xfile1')
219 call assert_match('the file has been damaged', msg)
220 call assert_equal('Xfile1', @%)
221 call assert_equal([''], getline(1, '$'))
222 bw!
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200223
James McCoy6654ca72021-06-12 14:05:41 +0200224 " reduce the page size
225 let b = copy(save_b)
226 let b[12:15] = 0z00010000
227 call writefile(b, sn)
228 let msg = execute('recover Xfile1')
229 call assert_match('page size is smaller than minimum value', msg)
230 call assert_equal('Xfile1', @%)
231 call assert_equal([''], getline(1, '$'))
232 bw!
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200233
James McCoy6654ca72021-06-12 14:05:41 +0200234 " clear the pointer ID
235 let b = copy(save_b)
236 let b[4096:4097] = 0z0000
237 call writefile(b, sn)
238 call assert_fails('recover Xfile1', 'E310:')
239 call assert_equal('Xfile1', @%)
240 call assert_equal([''], getline(1, '$'))
241 bw!
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200242
James McCoy6654ca72021-06-12 14:05:41 +0200243 " set the number of pointers in a pointer block to zero
244 let b = copy(save_b)
245 let b[4098:4099] = 0z0000
246 call writefile(b, sn)
247 call assert_fails('recover Xfile1', 'E312:')
248 call assert_equal('Xfile1', @%)
249 call assert_equal(['???EMPTY BLOCK'], getline(1, '$'))
250 bw!
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200251
Bram Moolenaarb67ba032023-04-22 21:14:26 +0100252 " set the number of pointers in a pointer block to a large value
253 let b = copy(save_b)
254 let b[4098:4099] = 0zFFFF
255 call writefile(b, sn)
256 call assert_fails('recover Xfile1', 'E1364:')
257 call assert_equal('Xfile1', @%)
258 bw!
259
James McCoy6654ca72021-06-12 14:05:41 +0200260 " set the block number in a pointer entry to a negative number
261 let b = copy(save_b)
Yegappan Lakshmanan576cb752021-06-30 21:30:10 +0200262 if system_64bit
263 let b[4104:4111] = little_endian ? 0z00000000.00000080 : 0z80000000.00000000
264 else
265 let b[4104:4107] = little_endian ? 0z00000080 : 0z80000000
266 endif
James McCoy6654ca72021-06-12 14:05:41 +0200267 call writefile(b, sn)
268 call assert_fails('recover Xfile1', 'E312:')
269 call assert_equal('Xfile1', @%)
270 call assert_equal(['???LINES MISSING'], getline(1, '$'))
271 bw!
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200272
James McCoy6654ca72021-06-12 14:05:41 +0200273 " clear the data block ID
274 let b = copy(save_b)
275 let b[8192:8193] = 0z0000
276 call writefile(b, sn)
277 call assert_fails('recover Xfile1', 'E312:')
278 call assert_equal('Xfile1', @%)
279 call assert_equal(['???BLOCK MISSING'], getline(1, '$'))
280 bw!
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200281
James McCoy6654ca72021-06-12 14:05:41 +0200282 " set the number of lines in the data block to zero
283 let b = copy(save_b)
Yegappan Lakshmanan576cb752021-06-30 21:30:10 +0200284 if system_64bit
285 let b[8208:8215] = 0z00000000.00000000
286 else
287 let b[8208:8211] = 0z00000000
288 endif
James McCoy6654ca72021-06-12 14:05:41 +0200289 call writefile(b, sn)
290 call assert_fails('recover Xfile1', 'E312:')
291 call assert_equal('Xfile1', @%)
292 call assert_equal(['??? from here until ???END lines may have been inserted/deleted',
293 \ '???END'], getline(1, '$'))
294 bw!
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200295
Bram Moolenaarbf1b7132023-04-27 21:13:12 +0100296 " set the number of lines in the data block to a large value
297 let b = copy(save_b)
298 if system_64bit
299 let b[8208:8215] = 0z00FFFFFF.FFFFFF00
300 else
301 let b[8208:8211] = 0z00FFFF00
302 endif
303 call writefile(b, sn)
304 call assert_fails('recover Xfile1', 'E312:')
305 call assert_equal('Xfile1', @%)
306 call assert_equal(['??? from here until ???END lines may have been inserted/deleted',
307 \ '', '???', '??? lines may be missing',
308 \ '???END'], getline(1, '$'))
309 bw!
310
James McCoy6654ca72021-06-12 14:05:41 +0200311 " use an invalid text start for the lines in a data block
312 let b = copy(save_b)
Yegappan Lakshmanan576cb752021-06-30 21:30:10 +0200313 if system_64bit
314 let b[8216:8219] = 0z00000000
315 else
316 let b[8212:8215] = 0z00000000
317 endif
James McCoy6654ca72021-06-12 14:05:41 +0200318 call writefile(b, sn)
319 call assert_fails('recover Xfile1', 'E312:')
320 call assert_equal('Xfile1', @%)
321 call assert_equal(['???'], getline(1, '$'))
322 bw!
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200323
James McCoy6654ca72021-06-12 14:05:41 +0200324 " use an incorrect text end (db_txt_end) for the data block
325 let b = copy(save_b)
326 let b[8204:8207] = little_endian ? 0z80000000 : 0z00000080
327 call writefile(b, sn)
328 call assert_fails('recover Xfile1', 'E312:')
329 call assert_equal('Xfile1', @%)
330 call assert_equal(['??? from here until ???END lines may be messed up', '',
331 \ '???END'], getline(1, '$'))
332 bw!
333
334 " remove the data block
335 let b = copy(save_b)
336 call writefile(b[:8191], sn)
337 call assert_fails('recover Xfile1', 'E312:')
338 call assert_equal('Xfile1', @%)
339 call assert_equal(['???MANY LINES MISSING'], getline(1, '$'))
Yegappan Lakshmanan99285552021-06-06 17:12:46 +0200340
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200341 bw!
342 call delete(sn)
343endfunc
344
345" Test for :recover using an encrypted swap file
346func Test_recover_encrypted_swap_file()
zeertzjq780154b2022-11-17 15:23:52 +0000347 CheckFeature cryptv
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200348 CheckUnix
349
350 " Recover an encrypted file from the swap file without the original file
351 new Xfile1
352 call feedkeys(":X\<CR>vim\<CR>vim\<CR>", 'xt')
353 call setline(1, ['aaa', 'bbb', 'ccc'])
354 preserve
355 let b = readblob('.Xfile1.swp')
356 call writefile(b, '.Xfile1.swm')
357 bw!
358 call feedkeys(":recover Xfile1\<CR>vim\<CR>\<CR>", 'xt')
359 call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
360 bw!
361 call delete('.Xfile1.swm')
362
363 " Recover an encrypted file from the swap file with the original file
364 new Xfile1
365 call feedkeys(":X\<CR>vim\<CR>vim\<CR>", 'xt')
366 call setline(1, ['aaa', 'bbb', 'ccc'])
367 update
368 call setline(1, ['111', '222', '333'])
369 preserve
370 let b = readblob('.Xfile1.swp')
371 call writefile(b, '.Xfile1.swm')
372 bw!
373 call feedkeys(":recover Xfile1\<CR>vim\<CR>\<CR>", 'xt')
374 call assert_equal(['111', '222', '333'], getline(1, '$'))
375 call assert_true(&modified)
376 bw!
377 call delete('.Xfile1.swm')
378 call delete('Xfile1')
379endfunc
380
zeertzjqc029c132024-03-28 11:37:26 +0100381" Test for :recover using an unreadable swap file
Dominique Pelle923dce22021-11-21 11:36:04 +0000382func Test_recover_unreadable_swap_file()
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200383 CheckUnix
384 CheckNotRoot
385 new Xfile1
386 let b = readblob('.Xfile1.swp')
Bram Moolenaardb77cb32022-10-05 21:45:30 +0100387 call writefile(b, '.Xfile1.swm', 'D')
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200388 bw!
389 call setfperm('.Xfile1.swm', '-w-------')
390 call assert_fails('recover Xfile1', 'E306:')
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200391endfunc
392
393" Test for using :recover when the original file and the swap file have the
394" same contents.
395func Test_recover_unmodified_file()
396 CheckUnix
397 call writefile(['aaa', 'bbb', 'ccc'], 'Xfile1')
398 edit Xfile1
399 preserve
400 let b = readblob('.Xfile1.swp')
401 %bw!
Bram Moolenaardb77cb32022-10-05 21:45:30 +0100402 call writefile(b, '.Xfile1.swz', 'D')
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200403 let msg = execute('recover Xfile1')
404 call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
405 call assert_false(&modified)
406 call assert_match('Buffer contents equals file contents', msg)
407 bw!
408 call delete('Xfile1')
Yegappan Lakshmanan59b26232021-06-05 20:59:22 +0200409endfunc
410
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200411" Test for recovering a file when editing a symbolically linked file
412func Test_recover_symbolic_link()
413 CheckUnix
Bram Moolenaardb77cb32022-10-05 21:45:30 +0100414 call writefile(['aaa', 'bbb', 'ccc'], 'Xfile1', 'D')
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200415 silent !ln -s Xfile1 Xfile2
416 edit Xfile2
417 call assert_equal('.Xfile1.swp', fnamemodify(swapname(''), ':t'))
418 preserve
419 let b = readblob('.Xfile1.swp')
420 %bw!
421 call writefile([], 'Xfile1')
422 call writefile(b, '.Xfile1.swp')
423 silent! recover Xfile2
424 call assert_equal(['aaa', 'bbb', 'ccc'], getline(1, '$'))
425 call assert_true(&modified)
426 update
427 %bw!
428 call assert_equal(['aaa', 'bbb', 'ccc'], readfile('Xfile1'))
Yegappan Lakshmanan8cf02e52021-06-07 20:41:22 +0200429 call delete('Xfile2')
430 call delete('.Xfile1.swp')
431endfunc
432
Yegappan Lakshmanan30443242021-06-10 21:52:15 +0200433" Test for recovering a file when an autocmd moves the cursor to an invalid
434" line. This used to result in an internal error (E315) which is fixed
435" by 8.2.2966.
436func Test_recover_invalid_cursor_pos()
Bram Moolenaardb77cb32022-10-05 21:45:30 +0100437 call writefile([], 'Xfile1', 'D')
Yegappan Lakshmanan30443242021-06-10 21:52:15 +0200438 edit Xfile1
439 preserve
440 let b = readblob('.Xfile1.swp')
441 bw!
442 augroup Test
443 au!
444 au BufReadPost Xfile1 normal! 3G
445 augroup END
446 call writefile(range(1, 3), 'Xfile1')
Bram Moolenaardb77cb32022-10-05 21:45:30 +0100447 call writefile(b, '.Xfile1.swp', 'D')
Yegappan Lakshmanan30443242021-06-10 21:52:15 +0200448 try
449 recover Xfile1
450 catch /E308:/
451 " this test is for the :E315 internal error.
452 " ignore the 'E308: Original file may have been changed' error
453 endtry
454 redraw!
455 augroup Test
456 au!
457 augroup END
458 augroup! Test
Yegappan Lakshmanan30443242021-06-10 21:52:15 +0200459endfunc
460
461" Test for recovering a buffer without a name
462func Test_noname_buffer()
463 new
464 call setline(1, ['one', 'two'])
465 preserve
466 let sn = swapname('')
467 let b = readblob(sn)
468 bw!
Bram Moolenaardb77cb32022-10-05 21:45:30 +0100469 call writefile(b, sn, 'D')
Yegappan Lakshmanan30443242021-06-10 21:52:15 +0200470 exe "recover " .. sn
471 call assert_equal(['one', 'two'], getline(1, '$'))
Yegappan Lakshmanan30443242021-06-10 21:52:15 +0200472endfunc
473
Bram Moolenaar6d91bcb2020-08-12 18:50:36 +0200474" vim: shiftwidth=2 sts=2 expandtab