mirror of
https://github.com/neovim/neovim.git
synced 2025-09-06 03:18:16 +00:00
Merge pull request #21087 from zeertzjq/vim-8.2.1970
vim-patch:8.2.{1970,2016,2019,2026,2044,3041,3042}: check if process of swap file is still running
This commit is contained in:
@@ -1138,7 +1138,14 @@ void ml_recover(bool checkext)
|
||||
} else {
|
||||
msg(_("Recovery completed. Buffer contents equals file contents."));
|
||||
}
|
||||
msg_puts(_("\nYou may want to delete the .swp file now.\n\n"));
|
||||
msg_puts(_("\nYou may want to delete the .swp file now."));
|
||||
if (os_proc_running((int)char_to_long(b0p->b0_pid))) {
|
||||
// Warn there could be an active Vim on the same file, the user may
|
||||
// want to kill it.
|
||||
msg_puts(_("\nNote: process STILL RUNNING: "));
|
||||
msg_outnum(char_to_long(b0p->b0_pid));
|
||||
}
|
||||
msg_puts("\n\n");
|
||||
cmdline_row = msg_row;
|
||||
}
|
||||
redraw_curbuf_later(UPD_NOT_VALID);
|
||||
@@ -1533,14 +1540,28 @@ static bool swapfile_unchanged(char *fname)
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// Host name must be known and must equal the current host name, otherwise
|
||||
// comparing pid is meaningless.
|
||||
if (*(b0.b0_hname) == NUL) {
|
||||
ret = false;
|
||||
} else {
|
||||
char hostname[B0_HNAME_SIZE];
|
||||
os_get_hostname(hostname, B0_HNAME_SIZE);
|
||||
hostname[B0_HNAME_SIZE - 1] = NUL;
|
||||
b0.b0_hname[B0_HNAME_SIZE - 1] = NUL; // in case of corruption
|
||||
if (STRICMP(b0.b0_hname, hostname) != 0) {
|
||||
ret = false;
|
||||
}
|
||||
}
|
||||
|
||||
// process must be known and not running.
|
||||
long pid = char_to_long(b0.b0_pid);
|
||||
if (pid == 0L || os_proc_running((int)pid)) {
|
||||
ret = false;
|
||||
}
|
||||
|
||||
// TODO(bram): Should we check if the swap file was created on the current
|
||||
// system? And the current user?
|
||||
// We do not check the user, it should be irrelevant for whether the swap
|
||||
// file is still useful.
|
||||
|
||||
close(fd);
|
||||
return ret;
|
||||
|
@@ -264,5 +264,16 @@ Dictionary os_proc_info(int pid)
|
||||
/// Return true if process `pid` is running.
|
||||
bool os_proc_running(int pid)
|
||||
{
|
||||
return uv_kill(pid, 0) == 0;
|
||||
int err = uv_kill(pid, 0);
|
||||
// If there is no error the process must be running.
|
||||
if (err == 0) {
|
||||
return true;
|
||||
}
|
||||
// If the error is ESRCH then the process is not running.
|
||||
if (err == UV_ESRCH) {
|
||||
return false;
|
||||
}
|
||||
// If the process is running and owned by another user we get EPERM. With
|
||||
// other errors the process might be running, assuming it is then.
|
||||
return true;
|
||||
}
|
||||
|
@@ -203,8 +203,8 @@ func Test_swapfile_delete()
|
||||
" This test won't work as root because root can successfully run kill(1, 0)
|
||||
if !IsRoot()
|
||||
" Write the swapfile with a modified PID, now it will be automatically
|
||||
" deleted. Process one should never be Vim.
|
||||
let swapfile_bytes[24:27] = 0z01000000
|
||||
" deleted. Process 0x3fffffff most likely does not exist.
|
||||
let swapfile_bytes[24:27] = 0zffffff3f
|
||||
call writefile(swapfile_bytes, swapfile_name)
|
||||
let s:swapname = ''
|
||||
split XswapfileText
|
||||
@@ -421,6 +421,86 @@ func Test_swap_symlink()
|
||||
call delete('Xswapdir', 'rf')
|
||||
endfunc
|
||||
|
||||
func s:get_unused_pid(base)
|
||||
if has('job')
|
||||
" Execute 'echo' as a temporary job, and return its pid as an unused pid.
|
||||
if has('win32')
|
||||
let cmd = 'cmd /c echo'
|
||||
else
|
||||
let cmd = 'echo'
|
||||
endif
|
||||
let j = job_start(cmd)
|
||||
while job_status(j) ==# 'run'
|
||||
sleep 10m
|
||||
endwhile
|
||||
if job_status(j) ==# 'dead'
|
||||
return job_info(j).process
|
||||
endif
|
||||
endif
|
||||
" Must add four for MS-Windows to see it as a different one.
|
||||
return a:base + 4
|
||||
endfunc
|
||||
|
||||
func s:blob_to_pid(b)
|
||||
return a:b[3] * 16777216 + a:b[2] * 65536 + a:b[1] * 256 + a:b[0]
|
||||
endfunc
|
||||
|
||||
func s:pid_to_blob(i)
|
||||
let b = 0z
|
||||
let b[0] = and(a:i, 0xff)
|
||||
let b[1] = and(a:i / 256, 0xff)
|
||||
let b[2] = and(a:i / 65536, 0xff)
|
||||
let b[3] = and(a:i / 16777216, 0xff)
|
||||
return b
|
||||
endfunc
|
||||
|
||||
func Test_swap_auto_delete()
|
||||
" 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')
|
||||
|
||||
" Forget about the file, recreate the swap file, then edit it again. The
|
||||
" swap file should be automatically deleted.
|
||||
bwipe!
|
||||
" Change the process ID to avoid the "still running" warning.
|
||||
let swapfile_bytes[24:27] = s:pid_to_blob(s:get_unused_pid(
|
||||
\ s:blob_to_pid(swapfile_bytes[24:27])))
|
||||
call writefile(swapfile_bytes, swapfile_name)
|
||||
edit Xtest.scr
|
||||
" will end up using the same swap file after deleting the existing one
|
||||
call assert_equal(swapfile_name, swapname('%'))
|
||||
bwipe!
|
||||
|
||||
" create the swap file again, but change the host name so that it won't be
|
||||
" deleted
|
||||
autocmd! SwapExists
|
||||
augroup test_swap_recover_ext
|
||||
autocmd!
|
||||
autocmd SwapExists * let v:swapchoice = 'e'
|
||||
augroup END
|
||||
|
||||
" change the host name
|
||||
let swapfile_bytes[28 + 40] = swapfile_bytes[28 + 40] + 2
|
||||
call writefile(swapfile_bytes, swapfile_name)
|
||||
edit Xtest.scr
|
||||
call assert_equal(1, filereadable(swapfile_name))
|
||||
" will use another same swap file name
|
||||
call assert_notequal(swapfile_name, swapname('%'))
|
||||
bwipe!
|
||||
|
||||
call delete('Xtest.scr')
|
||||
call delete(swapfile_name)
|
||||
augroup test_swap_recover_ext
|
||||
autocmd!
|
||||
augroup END
|
||||
augroup! test_swap_recover_ext
|
||||
endfunc
|
||||
|
||||
func Test_no_swap_file()
|
||||
call assert_equal("\nNo swap file", execute('swapname'))
|
||||
endfunc
|
||||
|
Reference in New Issue
Block a user