Commit: patch 9.1.2024: 'fsync' option cannot be set per buffer

0 views
Skip to first unread message

Christian Brabandt

unread,
9:45 AM (7 hours ago) 9:45 AM
to vim...@googlegroups.com
patch 9.1.2024: 'fsync' option cannot be set per buffer

Commit: https://github.com/vim/vim/commit/4d5b30372663e8ea356b25fe94334558c6ae283f
Author: glepnir <gleph...@gmail.com>
Date: Sat Dec 27 14:26:38 2025 +0000

patch 9.1.2024: 'fsync' option cannot be set per buffer

Problem: 'fsync' option cannot be set per buffer
Solution: Make 'fsync' option global-local
(glepnir)

closes: #19019

Signed-off-by: glepnir <gleph...@gmail.com>
Signed-off-by: Christian Brabandt <c...@256bit.org>

diff --git a/runtime/doc/options.txt b/runtime/doc/options.txt
index b1550dfcc..67c8b2904 100644
--- a/runtime/doc/options.txt
+++ b/runtime/doc/options.txt
@@ -1,4 +1,4 @@
-*options.txt* For Vim version 9.1. Last change: 2025 Dec 23
+*options.txt* For Vim version 9.1. Last change: 2025 Dec 27


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -4274,7 +4274,7 @@ A jump table for the options with a short description can be found at |Q_op|.

*'fsync'* *'fs'* *'nofsync'* *'nofs'*
'fsync' 'fs' boolean (default on)
- global
+ global or local to buffer |global-local|
When on, the library function fsync() will be called after writing a
file. This will flush a file to disk, ensuring that it is safely
written even on filesystems which do metadata-only journaling. This
@@ -4283,6 +4283,8 @@ A jump table for the options with a short description can be found at |Q_op|.
turning this off increases the chances of data loss after a crash. On
systems without an fsync() implementation, this variable is always
off.
+ This is a |global-local| option, so it can be set per buffer, for
+ example when writing to a slow filesystem.
Also see 'swapsync' for controlling fsync() on swap files.
'fsync' also applies to |writefile()| (unless a flag is used to
overrule it) and when writing undo files (see |undo-persistence|).
diff --git a/runtime/doc/version9.txt b/runtime/doc/version9.txt
index f1cfd0979..b626f2dea 100644
--- a/runtime/doc/version9.txt
+++ b/runtime/doc/version9.txt
@@ -1,4 +1,4 @@
-*version9.txt* For Vim version 9.1. Last change: 2025 Dec 21
+*version9.txt* For Vim version 9.1. Last change: 2025 Dec 27


VIM REFERENCE MANUAL by Bram Moolenaar
@@ -41727,6 +41727,7 @@ Options: ~
- 'guioptions': New value |'go-s'| to support fullscreen on MS-Windows GUI
(see also the below platform specific change).
- 'completepopup': Add more values to style popup windows.
+- 'fsync' is now a |global-local| option.

Ex commands: ~
- allow to specify a priority when defining a new sign |:sign-define|
diff --git a/src/buffer.c b/src/buffer.c
index 52aa13de2..7dca75307 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -2538,6 +2538,9 @@ free_buf_options(
clear_string_option(&buf->b_p_qe);
buf->b_p_ac = -1;
buf->b_p_ar = -1;
+#ifdef HAVE_FSYNC
+ buf->b_p_fs = -1;
+#endif
buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
clear_string_option(&buf->b_p_lw);
clear_string_option(&buf->b_p_bkc);
diff --git a/src/bufwrite.c b/src/bufwrite.c
index 342b5f36f..c1a495318 100644
--- a/src/bufwrite.c
+++ b/src/bufwrite.c
@@ -2199,7 +2199,8 @@ restore_backup:
// For a device do try the fsync() but don't complain if it does not
// work (could be a pipe).
// If the 'fsync' option is FALSE, don't fsync(). Useful for laptops.
- if (p_fs && vim_fsync(fd) != 0 && !device)
+ if ((buf->b_p_fs >= 0 ? buf->b_p_fs : p_fs) && vim_fsync(fd) != 0
+ && !device)
{
errmsg = (char_u *)_(e_fsync_failed);
end = 0;
diff --git a/src/option.c b/src/option.c
index b5594dd6e..1ec7efbf8 100644
--- a/src/option.c
+++ b/src/option.c
@@ -698,6 +698,9 @@ set_init_1(int clean_arg)
curbuf->b_p_initialized = TRUE;
curbuf->b_p_ac = -1;
curbuf->b_p_ar = -1; // no local 'autoread' value
+#ifdef HAVE_FSYNC
+ curbuf->b_p_fs = -1; // no local 'fsync' value
+#endif
curbuf->b_p_ul = NO_LOCAL_UNDOLEVEL;
check_buf_options(curbuf);
check_win_options(curwin);
@@ -2216,6 +2219,10 @@ do_set_option_bool(
value = -1;
else if ((int *)varp == &curbuf->b_p_ac && opt_flags == OPT_LOCAL)
value = -1;
+#ifdef HAVE_FSYNC
+ else if ((int *)varp == &curbuf->b_p_fs && opt_flags == OPT_LOCAL)
+ value = -1;
+#endif
else
value = *(int *)get_varp_scope(&(options[opt_idx]), OPT_GLOBAL);
}
@@ -6479,6 +6486,11 @@ unset_global_local_option(char_u *name, void *from)
case PV_AR:
buf->b_p_ar = -1;
break;
+#ifdef HAVE_FSYNC
+ case PV_FS:
+ buf->b_p_fs = -1;
+ break;
+#endif
case PV_BKC:
clear_string_option(&buf->b_p_bkc);
buf->b_bkc_flags = 0;
@@ -6613,6 +6625,9 @@ get_varp_scope(struct vimoption *p, int scope)
switch ((int)p->indir)
{
case PV_FP: return (char_u *)&(curbuf->b_p_fp);
+#ifdef HAVE_FSYNC
+ case PV_FS: return (char_u *)&(curbuf->b_p_fs);
+#endif
#ifdef FEAT_EVAL
case PV_FFU: return (char_u *)&(curbuf->b_p_ffu);
#endif
@@ -6737,6 +6752,10 @@ get_varp(struct vimoption *p)
#endif
case PV_FP: return *curbuf->b_p_fp != NUL
? (char_u *)&(curbuf->b_p_fp) : p->var;
+#ifdef HAVE_FSYNC
+ case PV_FS: return curbuf->b_p_fs >= 0
+ ? (char_u *)&(curbuf->b_p_fs) : p->var;
+#endif
#ifdef FEAT_EVAL
case PV_FFU: return *curbuf->b_p_ffu != NUL
? (char_u *)&(curbuf->b_p_ffu) : p->var;
@@ -7540,6 +7559,9 @@ buf_copy_options(buf_T *buf, int flags)
// are not copied, start using the global value
buf->b_p_ac = -1;
buf->b_p_ar = -1;
+#ifdef HAVE_FSYNC
+ buf->b_p_fs = -1;
+#endif
buf->b_p_ul = NO_LOCAL_UNDOLEVEL;
buf->b_p_bkc = empty_option;
buf->b_bkc_flags = 0;
diff --git a/src/option.h b/src/option.h
index f5c36ad89..7372ba924 100644
--- a/src/option.h
+++ b/src/option.h
@@ -1223,6 +1223,9 @@ enum
, BV_FF
, BV_FLP
, BV_FO
+#ifdef HAVE_FSYNC
+ , BV_FS
+#endif
, BV_FT
, BV_IMI
, BV_IMS
diff --git a/src/optiondefs.h b/src/optiondefs.h
index d888615f5..9e5612470 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -82,6 +82,9 @@
#define PV_FF OPT_BUF(BV_FF)
#define PV_FLP OPT_BUF(BV_FLP)
#define PV_FO OPT_BUF(BV_FO)
+#ifdef HAVE_FSYNC
+# define PV_FS OPT_BOTH(OPT_BUF(BV_FS))
+#endif
#define PV_FT OPT_BUF(BV_FT)
#define PV_IMI OPT_BUF(BV_IMI)
#define PV_IMS OPT_BUF(BV_IMS)
@@ -1172,7 +1175,7 @@ static struct vimoption options[] =
{(char_u *)"", (char_u *)0L} SCTX_INIT},
{"fsync", "fs", P_BOOL|P_SECURE|P_VI_DEF,
#ifdef HAVE_FSYNC
- (char_u *)&p_fs, PV_NONE, NULL, NULL,
+ (char_u *)&p_fs, PV_FS, NULL, NULL,
{(char_u *)TRUE, (char_u *)0L}
#else
(char_u *)NULL, PV_NONE, NULL, NULL,
diff --git a/src/structs.h b/src/structs.h
index 9b095c328..37f9cf5d1 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -3380,6 +3380,9 @@ struct file_buffer
char_u *b_p_fex; // 'formatexpr'
long_u b_p_fex_flags; // flags for 'formatexpr'
#endif
+#ifdef HAVE_FSYNC
+ int b_p_fs; // 'fsync'
+#endif
#ifdef FEAT_CRYPT
char_u *b_p_key; // 'key'
#endif
diff --git a/src/testdir/test_options.vim b/src/testdir/test_options.vim
index 2e4e9f727..c6c83bb98 100644
--- a/src/testdir/test_options.vim
+++ b/src/testdir/test_options.vim
@@ -1681,25 +1681,34 @@ endfunc

" Test for setting boolean global-local option value
func Test_set_boolean_global_local_option()
- setglobal autoread
- setlocal noautoread
+ CheckUnix
+
+ setglobal autoread fsync
+ setlocal noautoread nofsync
call assert_equal(1, &g:autoread)
call assert_equal(0, &l:autoread)
call assert_equal(0, &autoread)
+ call assert_equal(1, &g:fsync)
+ call assert_equal(0, &l:fsync)
+ call assert_equal(0, &fsync)

" :set {option}< set the effective value of {option} to its global value.
- set autoread<
+ set autoread< fsync<
call assert_equal(1, &l:autoread)
call assert_equal(1, &autoread)
+ call assert_equal(1, &l:fsync)
+ call assert_equal(1, &fsync)

" :setlocal {option}< removes the local value, so that the global value will be used.
- setglobal noautoread
- setlocal autoread
- setlocal autoread<
+ setglobal noautoread nofsync
+ setlocal autoread fsync
+ setlocal autoread< fsync<
call assert_equal(-1, &l:autoread)
call assert_equal(0, &autoread)
+ call assert_equal(-1, &l:fsync)
+ call assert_equal(0, &fsync)

- set autoread&
+ set autoread& fsync&
endfunc

func Test_set_in_sandbox()
diff --git a/src/undo.c b/src/undo.c
index b1747996b..f40aca660 100644
--- a/src/undo.c
+++ b/src/undo.c
@@ -1774,7 +1774,8 @@ u_write_undo(
#endif

#if defined(UNIX) && defined(HAVE_FSYNC)
- if (p_fs && fflush(fp) == 0 && vim_fsync(fd) != 0)
+ if ((buf->b_p_fs >= 0 ? buf->b_p_fs : p_fs) && fflush(fp) == 0
+ && vim_fsync(fd) != 0)
write_ok = FALSE;
#endif

diff --git a/src/version.c b/src/version.c
index fad0bdd58..f09ff1791 100644
--- a/src/version.c
+++ b/src/version.c
@@ -734,6 +734,8 @@ static char *(features[]) =

static int included_patches[] =
{ /* Add new patch number below this line */
+/**/
+ 2024,
/**/
2023,
/**/
Reply all
Reply to author
Forward
0 new messages