changeset 12857:ffdf2e4b5d9a v8.0.1305

patch 8.0.1305: writefile() never calls fsync() commit https://github.com/vim/vim/commit/7567d0b115e332f61a9f390aaccdf7825b891227 Author: Bram Moolenaar <Bram@vim.org> Date: Thu Nov 16 23:04:15 2017 +0100 patch 8.0.1305: writefile() never calls fsync() Problem: Writefile() never calls fsync(). Solution: Follow the 'fsync' option with override to enable or disable.
author Christian Brabandt <cb@256bit.org>
date Thu, 16 Nov 2017 23:15:05 +0100
parents 4c4a02a946f0
children 4f1870188845
files runtime/doc/eval.txt src/evalfunc.c src/fileio.c src/globals.h src/testdir/test_writefile.vim src/version.c
diffstat 6 files changed, 39 insertions(+), 5 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/eval.txt
+++ b/runtime/doc/eval.txt
@@ -1,4 +1,4 @@
-*eval.txt*	For Vim version 8.0.  Last change: 2017 Oct 28
+*eval.txt*	For Vim version 8.0.  Last change: 2017 Nov 16
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -8721,7 +8721,7 @@ winwidth({nr})						*winwidth()*
 		Examples: >
   :echo "The current window has " . winwidth(0) . " columns."
   :if winwidth(0) <= 50
-  :  exe "normal 50\<C-W>|"
+  :  50 wincmd |
   :endif
 <		For getting the terminal or screen size, see the 'columns'
 		option.
@@ -8762,8 +8762,17 @@ writefile({list}, {fname} [, {flags}])
 		appended to the file: >
 			:call writefile(["foo"], "event.log", "a")
 			:call writefile(["bar"], "event.log", "a")
-
-<		All NL characters are replaced with a NUL character.
+<
+		When {flags} contains "s" then fsync() is called after writing
+		the file.  This flushes the file to disk, if possible.  This
+		takes more time but avoids losing the file if the system
+		crashes.
+		When {flags} does not contain "S" or "s" then fsync is called
+		if the 'fsync' option is set.
+		When {flags} contains "S" then fsync() is not called, even
+		when 'fsync' is set.
+
+		All NL characters are replaced with a NUL character.
 		Inserting CR characters needs to be done before passing {list}
 		to writefile().
 		An existing file is overwritten, if possible.
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -13348,6 +13348,9 @@ f_writefile(typval_T *argvars, typval_T 
 {
     int		binary = FALSE;
     int		append = FALSE;
+#ifdef HAVE_FSYNC
+    int		do_fsync = p_fs;
+#endif
     char_u	*fname;
     FILE	*fd;
     int		ret = 0;
@@ -13380,6 +13383,12 @@ f_writefile(typval_T *argvars, typval_T 
 	    binary = TRUE;
 	if (vim_strchr(arg2, 'a') != NULL)
 	    append = TRUE;
+#ifdef HAVE_FSYNC
+	if (vim_strchr(arg2, 's') != NULL)
+	    do_fsync = TRUE;
+	else if (vim_strchr(arg2, 'S') != NULL)
+	    do_fsync = FALSE;
+#endif
     }
 
     fname = get_tv_string_chk(&argvars[1]);
@@ -13398,6 +13407,10 @@ f_writefile(typval_T *argvars, typval_T 
     {
 	if (write_list(fd, list, binary) == FAIL)
 	    ret = -1;
+#ifdef HAVE_FSYNC
+	else if (do_fsync && fsync(fileno(fd)) != 0)
+	    EMSG(_(e_fsync));
+#endif
 	fclose(fd);
     }
 
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -4771,7 +4771,7 @@ restore_backup:
 	 */
 	if (p_fs && fsync(fd) != 0 && !device)
 	{
-	    errmsg = (char_u *)_("E667: Fsync failed");
+	    errmsg = (char_u *)_(e_fsync);
 	    end = 0;
 	}
 #endif
--- a/src/globals.h
+++ b/src/globals.h
@@ -1449,6 +1449,9 @@ EXTERN char_u e_isadir2[]	INIT(= N_("E17
 #ifdef FEAT_LIBCALL
 EXTERN char_u e_libcall[]	INIT(= N_("E364: Library call failed for \"%s()\""));
 #endif
+#ifdef HAVE_FSYNC
+EXTERN char_u e_fsync[]		INIT(= N_("E667: Fsync failed"));
+#endif
 #if defined(DYNAMIC_PERL) \
 	|| defined(DYNAMIC_PYTHON) || defined(DYNAMIC_PYTHON3) \
 	|| defined(DYNAMIC_RUBY) \
--- a/src/testdir/test_writefile.vim
+++ b/src/testdir/test_writefile.vim
@@ -93,3 +93,10 @@ func Test_nowrite_quit_split()
   endif
   bwipe Xfile
 endfunc
+
+func Test_writefile_sync_arg()
+  " This doesn't check if fsync() works, only that the argument is accepted.
+  call writefile(['one'], 'Xtest', 's')
+  call writefile(['two'], 'Xtest', 'S')
+  call delete('Xtest')
+endfunc
--- a/src/version.c
+++ b/src/version.c
@@ -767,6 +767,8 @@ static char *(features[]) =
 static int included_patches[] =
 {   /* Add new patch number below this line */
 /**/
+    1305,
+/**/
     1304,
 /**/
     1303,