This patch implements fsync for Windows. I tested it using MinGW cross-compiler from a Fedora host, and wine instead of Windows:
./gnulib-tool --create-testdir --dir=/tmp/testdir fsync [Verify it configures & builds normally on Linux, then ...] [Create a test program, test.c (attached). Edit Makefile.am to compile the test program and link against libgnu.] autoreconf ./configure --host=i686-pc-mingw32 make WINEDEBUG=+relay wine ./test.exe [Grep through the debugging output for calls to FlushFileBuffers] I would like to add a test, but I couldn't work out how programs in the tests/ subdirectory get run and what their environment is, which is fairly crucial for this sort of system call. As far as I can tell, Windows doesn't have anything which corresponds to fdatasync(2). The sqlite sources which I'm copying this from just map this to fsync / FlushFileBuffers. So perhaps a simple enhancement to this would be to add this in the appropriate place: #define fdatasync fsync Windows does have an equivalent to sync(2) but it has two significant drawbacks. Firstly it works on a per-volume basis, and you need to grab a handle to the volume. There is no easy way to just sync everything, you'd need to enumerate available volumes. Secondly and more significantly it requires elevated privileges to do this operation, unlike Unix where anyone can sync. (Thanks to Jim Meyering for reviewing an earlier version of this patch). Rich. -- Richard Jones, Emerging Technologies, Red Hat http://et.redhat.com/~rjones virt-df lists disk usage of guests without needing to install any software inside the virtual machine. Supports Linux and Windows. http://et.redhat.com/~rjones/virt-df/
>From c518eebf6a0d0b1f7edd66a01dac9b9d39fb81c3 Mon Sep 17 00:00:00 2001 From: Richard Jones <[EMAIL PROTECTED](none)> Date: Wed, 1 Oct 2008 13:54:44 +0100 Subject: [PATCH] fsync implementation. --- MODULES.html.sh | 1 + NEWS | 2 + doc/posix-functions/fsync.texi | 8 ++-- lib/fsync.c | 62 ++++++++++++++++++++++++++++++++++++++++ lib/unistd.in.h | 17 +++++++++++ m4/fsync.m4 | 19 ++++++++++++ m4/unistd_h.m4 | 2 + modules/fsync | 24 +++++++++++++++ modules/unistd | 2 + 9 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 lib/fsync.c create mode 100644 m4/fsync.m4 create mode 100644 modules/fsync diff --git a/MODULES.html.sh b/MODULES.html.sh index afaf8ba..058125d 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -2110,6 +2110,7 @@ func_all_modules () func_module freopen func_module fseek func_module fseeko + func_module fsync func_module ftell func_module ftello func_module ftruncate diff --git a/NEWS b/NEWS index ef04cf4..4c6edfe 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,8 @@ User visible incompatible changes Date Modules Changes +2008-10-01 fsync This function has been implemented for Windows. + 2008-09-28 sockets When using this module, you now need to link with $(LIBSOCKET). diff --git a/doc/posix-functions/fsync.texi b/doc/posix-functions/fsync.texi index 405be40..fb88214 100644 --- a/doc/posix-functions/fsync.texi +++ b/doc/posix-functions/fsync.texi @@ -4,15 +4,15 @@ POSIX specification: @url{http://www.opengroup.org/susv3xsh/fsync.html} -Gnulib module: --- +Gnulib module: fsync Portability problems fixed by Gnulib: @itemize [EMAIL PROTECTED] +This function is missing on some platforms: +mingw. @end itemize Portability problems not fixed by Gnulib: @itemize [EMAIL PROTECTED] -This function is missing on some platforms: -mingw. @end itemize diff --git a/lib/fsync.c b/lib/fsync.c new file mode 100644 index 0000000..e353ebf --- /dev/null +++ b/lib/fsync.c @@ -0,0 +1,62 @@ +/* Emulate fsync on platforms which lack it, primarily Windows and + cross-compilers like MinGW. + + This is derived from sqlite3 sources and is in the public domain. + + Written by Richard W.M. Jones <rjones.at.redhat.com> +*/ + +#include <config.h> +#include <unistd.h> + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + +/* _get_osfhandle */ +#include <io.h> + +/* FlushFileBuffers */ +#define WIN32_LEAN_AND_MEAN +#include <windows.h> + +#include <errno.h> + +int +fsync (int fd) +{ + HANDLE h = (HANDLE) _get_osfhandle (fd); + DWORD err; + + if (h == INVALID_HANDLE_VALUE) + { + errno = EBADF; + return -1; + } + + if (!FlushFileBuffers (h)) + { + /* Translate some Windows errors into rough approximations of Unix + * errors. MSDN is useless as usual - in this case it doesn't + * document the full range of errors. + */ + err = GetLastError (); + switch (err) + { + /* eg. Trying to fsync a tty. */ + case ERROR_INVALID_HANDLE: + errno = EINVAL; + break; + + default: + errno = EIO; + } + return -1; + } + + return 0; +} + +#else /* Windows */ + +#error "This platform lacks fsync function, and Gnulib doesn't provide a replacement. This is a bug in Gnulib." + +#endif /* !Windows */ diff --git a/lib/unistd.in.h b/lib/unistd.in.h index e75b4cd..71eaa4d 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -140,6 +140,23 @@ extern int dup2 (int, int); #endif +#if @GNULIB_FSYNC@ +/* Synchronize changes to a file. + Return 0 if successful, otherwise -1 and errno set. + See POSIX:2001 specification + <http://www.opengroup.org/susv3xsh/fsync.html>. */ +# if [EMAIL PROTECTED]@ +extern int fsync (int fd); +# endif +#elif defined GNULIB_POSIXCHECK +# undef fsync +# define fsync(fd) \ + (GL_LINK_WARNING ("fsync is unportable - " \ + "use gnulib module fsync for portability"), \ + fsync (fd)) +#endif + + #if @GNULIB_FTRUNCATE@ # if [EMAIL PROTECTED]@ /* Change the size of the file to which FD is opened to become equal to LENGTH. diff --git a/m4/fsync.m4 b/m4/fsync.m4 new file mode 100644 index 0000000..eac7409 --- /dev/null +++ b/m4/fsync.m4 @@ -0,0 +1,19 @@ +# fsync.m4 serial 1 +dnl Copyright (C) 2008 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +AC_DEFUN([gl_FUNC_FSYNC], +[ + AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) + AC_CHECK_FUNCS_ONCE([fsync]) + if test $ac_cv_func_fsync = no; then + HAVE_FSYNC=0 + AC_LIBOBJ([fsync]) + gl_PREREQ_FSYNC + fi +]) + +# Prerequisites of lib/fsync.c. +AC_DEFUN([gl_PREREQ_FSYNC], [:]) diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4 index 0e76a52..9e9a56b 100644 --- a/m4/unistd_h.m4 +++ b/m4/unistd_h.m4 @@ -36,6 +36,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS], GNULIB_DUP2=0; AC_SUBST([GNULIB_DUP2]) GNULIB_ENVIRON=0; AC_SUBST([GNULIB_ENVIRON]) GNULIB_FCHDIR=0; AC_SUBST([GNULIB_FCHDIR]) + GNULIB_FSYNC=0; AC_SUBST([GNULIB_FSYNC]) GNULIB_FTRUNCATE=0; AC_SUBST([GNULIB_FTRUNCATE]) GNULIB_GETCWD=0; AC_SUBST([GNULIB_GETCWD]) GNULIB_GETLOGIN_R=0; AC_SUBST([GNULIB_GETLOGIN_R]) @@ -48,6 +49,7 @@ AC_DEFUN([gl_UNISTD_H_DEFAULTS], GNULIB_WRITE=0; AC_SUBST([GNULIB_WRITE]) dnl Assume proper GNU behavior unless another module says otherwise. HAVE_DUP2=1; AC_SUBST([HAVE_DUP2]) + HAVE_FSYNC=1; AC_SUBST([HAVE_FSYNC]) HAVE_FTRUNCATE=1; AC_SUBST([HAVE_FTRUNCATE]) HAVE_GETPAGESIZE=1; AC_SUBST([HAVE_GETPAGESIZE]) HAVE_READLINK=1; AC_SUBST([HAVE_READLINK]) diff --git a/modules/fsync b/modules/fsync new file mode 100644 index 0000000..3de3ee3 --- /dev/null +++ b/modules/fsync @@ -0,0 +1,24 @@ +Description: +fsync(2) function: synchronize writes to a file. + +Files: +lib/fsync.c +m4/fsync.m4 + +Depends-on: +unistd + +configure.ac: +gl_FUNC_FSYNC +gl_UNISTD_MODULE_INDICATOR([fsync]) + +Makefile.am: + +Include: +<unistd.h> + +License: +Public Domain + +Maintainer: +Richard W.M. Jones, Jim Meyering diff --git a/modules/unistd b/modules/unistd index 9410778..efd97b5 100644 --- a/modules/unistd +++ b/modules/unistd @@ -28,6 +28,7 @@ unistd.h: unistd.in.h -e 's|@''GNULIB_DUP2''@|$(GNULIB_DUP2)|g' \ -e 's|@''GNULIB_ENVIRON''@|$(GNULIB_ENVIRON)|g' \ -e 's|@''GNULIB_FCHDIR''@|$(GNULIB_FCHDIR)|g' \ + -e 's|@''GNULIB_FSYNC''@|$(GNULIB_FSYNC)|g' \ -e 's|@''GNULIB_FTRUNCATE''@|$(GNULIB_FTRUNCATE)|g' \ -e 's|@''GNULIB_GETCWD''@|$(GNULIB_GETCWD)|g' \ -e 's|@''GNULIB_GETLOGIN_R''@|$(GNULIB_GETLOGIN_R)|g' \ @@ -39,6 +40,7 @@ unistd.h: unistd.in.h -e 's|@''GNULIB_UNISTD_H_SIGPIPE''@|$(GNULIB_UNISTD_H_SIGPIPE)|g' \ -e 's|@''GNULIB_WRITE''@|$(GNULIB_WRITE)|g' \ -e 's|@''HAVE_DUP2''@|$(HAVE_DUP2)|g' \ + -e 's|@''HAVE_FSYNC''@|$(HAVE_FSYNC)|g' \ -e 's|@''HAVE_FTRUNCATE''@|$(HAVE_FTRUNCATE)|g' \ -e 's|@''HAVE_GETPAGESIZE''@|$(HAVE_GETPAGESIZE)|g' \ -e 's|@''HAVE_READLINK''@|$(HAVE_READLINK)|g' \ -- 1.6.0.1
/* Test fsync. */ #include <stdio.h> #include <fcntl.h> #include <errno.h> #include "unistd.h" int main () { int fd, r; errno = 0; r = fsync (0); printf ("fsync (0) returned %d, errno = %d\n", r, errno); fd = open ("z:\\tmp\\test", O_WRONLY|O_CREAT|O_TRUNC, 0644); write (fd, "hello", 5); errno = 0; r = fsync (fd); printf ("fsync (fd) returned %d, errno = %d\n", r, errno); close (fd); exit (0); }