patch 9.2.1005: backupcopy=auto overwrites a file in place with umask
Commit:
https://github.com/vim/vim/commit/fd8aea135d146915e921699cd23887b654182810
Author: Pranav Dwivedi <
dwivedip...@gmail.com>
Date: Tue Aug 25 19:44:11 2026 +0000
patch 9.2.1005: backupcopy=auto overwrites a file in place with umask
Problem: backupcopy=auto overwrites a file in place when umask is restrictive.
The probe treats permission restore as impossible and writes in
place, keeping the same inode.
Solution: When creating the probe file, open() applies umask, so a 0644
file becomes 0600 with umask 0077. Use fchmod() to fix the
permissions of the probe (Pranav Dwivedi).
closes: #21137
Signed-off-by: Pranav Dwivedi <
dwivedip...@gmail.com>
Signed-off-by: Christian Brabandt <
c...@256bit.org>
diff --git a/src/bufwrite.c b/src/bufwrite.c
index 488ed94d9..51537010d 100644
--- a/src/bufwrite.c
+++ b/src/bufwrite.c
@@ -1209,7 +1209,7 @@ buf_write(
char_u tmp_fname[MAXPATHL];
int i;
- // Check if we can create a file and set the owner/group to
+ // Check if we can create a file and set the owner/group/mode to
// the ones from the original file.
// First find a file name that doesn't exist yet (use some
// arbitrary numbers).
@@ -1239,6 +1239,11 @@ buf_write(
# ifdef UNIX
# ifdef HAVE_FCHOWN
vim_ignored = fchown(fd, st_old.st_uid, st_old.st_gid);
+# endif
+# ifdef HAVE_FCHMOD
+ (void)mch_fsetperm(fd, perm);
+# else
+ (void)mch_setperm(tmp_fname, perm);
# endif
if (mch_stat((char *)tmp_fname, &st) < 0
|| st.st_uid != st_old.st_uid
diff --git a/src/testdir/test_writefile.vim b/src/testdir/test_writefile.vim
index cd427ad99..a2491f930 100644
--- a/src/testdir/test_writefile.vim
+++ b/src/testdir/test_writefile.vim
@@ -997,4 +997,24 @@ func Test_write_with_xattr_support()
bw!
endfunc
+func Test_backupcopy_auto_restrictive_umask()
+ CheckUnix
+ call writefile(['FOO'], 'Xumaskfile', 'D')
+ call setfperm('Xumaskfile', 'rw-r--r--')
+ let inode_before = systemlist('ls -i Xumaskfile')[0]->matchstr('^\s*\zs\d\+')
+ call writefile([
+ \ 'set backupcopy=auto writebackup nobackup backupskip=',
+ \ 'edit Xumaskfile',
+ \ 'call setline(1, ["BAR"])',
+ \ 'write',
+ \ 'qall!'
+ \ ], 'Xumaskscript', 'D')
+ call system('umask 0077; ' .. GetVimCommand() .. ' -i NONE -n -S Xumaskscript')
+ call assert_equal(0, v:shell_error)
+ call assert_equal(['BAR'], readfile('Xumaskfile'))
+ call assert_equal('rw-r--r--', getfperm('Xumaskfile'))
+ call assert_notequal(inode_before,
+ \ systemlist('ls -i Xumaskfile')[0]->matchstr('^\s*\zs\d\+'))
+endfunc
+
" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 41ea63f51..e4c218c29 100644
--- a/src/version.c
+++ b/src/version.c
@@ -763,6 +763,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 1005,
/**/
1004,
/**/