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);
}

Reply via email to