vim-patch:9.2.1005: backupcopy=auto overwrites a file in place with umask (#41502)

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: vim/vim#21137

fd8aea135d

Co-authored-by: Pranav Dwivedi <dwivedipranav2021@gmail.com>
This commit is contained in:
zeertzjq
2026-08-26 15:07:29 +08:00
committed by GitHub
parent f97bcbdf77
commit 0f0e89fd90
3 changed files with 32 additions and 1 deletions

View File

@@ -743,7 +743,7 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o
|| !os_fileinfo_id_equal(&file_info, file_info_old)) {
*backup_copyp = true;
} else {
// 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).
@@ -764,6 +764,7 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o
} else {
#ifdef UNIX
os_fchown(fd, (uv_uid_t)file_info_old->stat.st_uid, (uv_gid_t)file_info_old->stat.st_gid);
os_fsetperm(fd, perm);
if (!os_fileinfo(tmp_fname, &file_info)
|| file_info.stat.st_uid != file_info_old->stat.st_uid
|| file_info.stat.st_gid != file_info_old->stat.st_gid

View File

@@ -804,6 +804,16 @@ int os_setperm(const char *const name, int perm)
return (r == kLibuvSuccess ? OK : FAIL);
}
/// Set the permission of the file referred to by the open file descriptor.
///
/// @return `OK` for success, `FAIL` for failure.
int os_fsetperm(int fd, int perm)
{
int r;
RUN_UV_FS_FUNC(r, uv_fs_fchmod, fd, perm, NULL);
return (r == kLibuvSuccess ? OK : FAIL);
}
#ifdef HAVE_XATTR
/// Copy extended attributes from_file to to_file
void os_copy_xattr(const char *from_file, const char *to_file)

View File

@@ -1013,4 +1013,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